1 //===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Hexagon.h"
10 #include "CommonArgs.h"
11 #include "clang/Driver/Compilation.h"
12 #include "clang/Driver/Driver.h"
13 #include "clang/Driver/DriverDiagnostic.h"
14 #include "clang/Driver/InputInfo.h"
15 #include "clang/Driver/Options.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/Option/ArgList.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Support/VirtualFileSystem.h"
21 
22 using namespace clang::driver;
23 using namespace clang::driver::tools;
24 using namespace clang::driver::toolchains;
25 using namespace clang;
26 using namespace llvm::opt;
27 
28 // Default hvx-length for various versions.
29 static StringRef getDefaultHvxLength(StringRef Cpu) {
30   return llvm::StringSwitch<StringRef>(Cpu)
31       .Case("v60", "64b")
32       .Case("v62", "64b")
33       .Case("v65", "64b")
34       .Default("128b");
35 }
36 
37 static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
38   // Handle the unsupported values passed to mhvx-length.
39   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
40     StringRef Val = A->getValue();
41     if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b"))
42       D.Diag(diag::err_drv_unsupported_option_argument)
43           << A->getOption().getName() << Val;
44   }
45 }
46 
47 // Handle hvx target features explicitly.
48 static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
49                                     std::vector<StringRef> &Features,
50                                     StringRef Cpu, bool &HasHVX) {
51   // Handle HVX warnings.
52   handleHVXWarnings(D, Args);
53 
54   // Add the +hvx* features based on commandline flags.
55   StringRef HVXFeature, HVXLength;
56 
57   // Handle -mhvx, -mhvx=, -mno-hvx.
58   if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx,
59                                options::OPT_mhexagon_hvx,
60                                options::OPT_mhexagon_hvx_EQ)) {
61     if (A->getOption().matches(options::OPT_mno_hexagon_hvx))
62       return;
63     if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
64       HasHVX = true;
65       HVXFeature = Cpu = A->getValue();
66       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
67     } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
68       HasHVX = true;
69       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
70     }
71     Features.push_back(HVXFeature);
72   }
73 
74   // Handle -mhvx-length=.
75   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
76     // These flags are valid only if HVX in enabled.
77     if (!HasHVX)
78       D.Diag(diag::err_drv_invalid_hvx_length);
79     else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
80       HVXLength = A->getValue();
81   }
82   // Default hvx-length based on Cpu.
83   else if (HasHVX)
84     HVXLength = getDefaultHvxLength(Cpu);
85 
86   if (!HVXLength.empty()) {
87     HVXFeature =
88         Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
89     Features.push_back(HVXFeature);
90   }
91 }
92 
93 // Hexagon target features.
94 void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
95                                        std::vector<StringRef> &Features) {
96   handleTargetFeaturesGroup(Args, Features,
97                             options::OPT_m_hexagon_Features_Group);
98 
99   bool UseLongCalls = false;
100   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
101                                options::OPT_mno_long_calls)) {
102     if (A->getOption().matches(options::OPT_mlong_calls))
103       UseLongCalls = true;
104   }
105 
106   Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
107 
108   bool HasHVX = false;
109   StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
110   // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors
111   // have no dependency on micro-architecture.
112   const bool TinyCore = Cpu.contains('t');
113 
114   if (TinyCore)
115     Cpu = Cpu.take_front(Cpu.size() - 1);
116 
117   handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX);
118 
119   if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX)
120     D.Diag(diag::warn_drv_vectorize_needs_hvx);
121 }
122 
123 // Hexagon tools start.
124 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
125                                              ArgStringList &CmdArgs) const {
126 }
127 
128 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
129                                       const InputInfo &Output,
130                                       const InputInfoList &Inputs,
131                                       const ArgList &Args,
132                                       const char *LinkingOutput) const {
133   claimNoWarnArgs(Args);
134 
135   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
136   const Driver &D = HTC.getDriver();
137   ArgStringList CmdArgs;
138 
139   CmdArgs.push_back("--arch=hexagon");
140 
141   RenderExtraToolArgs(JA, CmdArgs);
142 
143   const char *AsName = "llvm-mc";
144   CmdArgs.push_back("-filetype=obj");
145   CmdArgs.push_back(Args.MakeArgString(
146       "-mcpu=hexagon" +
147       toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
148 
149   addSanitizerRuntimes(HTC, Args, CmdArgs);
150 
151   if (Output.isFilename()) {
152     CmdArgs.push_back("-o");
153     CmdArgs.push_back(Output.getFilename());
154   } else {
155     assert(Output.isNothing() && "Unexpected output");
156     CmdArgs.push_back("-fsyntax-only");
157   }
158 
159   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
160     CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
161   }
162 
163   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
164 
165   // Only pass -x if gcc will understand it; otherwise hope gcc
166   // understands the suffix correctly. The main use case this would go
167   // wrong in is for linker inputs if they happened to have an odd
168   // suffix; really the only way to get this to happen is a command
169   // like '-x foobar a.c' which will treat a.c like a linker input.
170   //
171   // FIXME: For the linker case specifically, can we safely convert
172   // inputs into '-Wl,' options?
173   for (const auto &II : Inputs) {
174     // Don't try to pass LLVM or AST inputs to a generic gcc.
175     if (types::isLLVMIR(II.getType()))
176       D.Diag(clang::diag::err_drv_no_linker_llvm_support)
177           << HTC.getTripleString();
178     else if (II.getType() == types::TY_AST)
179       D.Diag(clang::diag::err_drv_no_ast_support)
180           << HTC.getTripleString();
181     else if (II.getType() == types::TY_ModuleFile)
182       D.Diag(diag::err_drv_no_module_support)
183           << HTC.getTripleString();
184 
185     if (II.isFilename())
186       CmdArgs.push_back(II.getFilename());
187     else
188       // Don't render as input, we need gcc to do the translations.
189       // FIXME: What is this?
190       II.getInputArg().render(Args, CmdArgs);
191   }
192 
193   auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
194   C.addCommand(std::make_unique<Command>(JA, *this,
195                                          ResponseFileSupport::AtFileCurCP(),
196                                          Exec, CmdArgs, Inputs, Output));
197 }
198 
199 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
200                                           ArgStringList &CmdArgs) const {
201 }
202 
203 static void
204 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
205                          const toolchains::HexagonToolChain &HTC,
206                          const InputInfo &Output, const InputInfoList &Inputs,
207                          const ArgList &Args, ArgStringList &CmdArgs,
208                          const char *LinkingOutput) {
209 
210   const Driver &D = HTC.getDriver();
211 
212   //----------------------------------------------------------------------------
213   //
214   //----------------------------------------------------------------------------
215   bool IsStatic = Args.hasArg(options::OPT_static);
216   bool IsShared = Args.hasArg(options::OPT_shared);
217   bool IsPIE = Args.hasArg(options::OPT_pie);
218   bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
219   bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
220   bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
221   bool UseG0 = false;
222   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
223   bool UseLLD = (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||
224                  llvm::sys::path::stem(Exec).equals_insensitive("ld.lld"));
225   bool UseShared = IsShared && !IsStatic;
226   StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
227 
228   bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs);
229   bool NeedsXRayDeps = addXRayRuntime(HTC, Args, CmdArgs);
230 
231   //----------------------------------------------------------------------------
232   // Silence warnings for various options
233   //----------------------------------------------------------------------------
234   Args.ClaimAllArgs(options::OPT_g_Group);
235   Args.ClaimAllArgs(options::OPT_emit_llvm);
236   Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
237                                      // handled somewhere else.
238   Args.ClaimAllArgs(options::OPT_static_libgcc);
239 
240   //----------------------------------------------------------------------------
241   //
242   //----------------------------------------------------------------------------
243   if (Args.hasArg(options::OPT_s))
244     CmdArgs.push_back("-s");
245 
246   if (Args.hasArg(options::OPT_r))
247     CmdArgs.push_back("-r");
248 
249   for (const auto &Opt : HTC.ExtraOpts)
250     CmdArgs.push_back(Opt.c_str());
251 
252   if (!UseLLD) {
253     CmdArgs.push_back("-march=hexagon");
254     CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
255   }
256 
257   if (IsShared) {
258     CmdArgs.push_back("-shared");
259     // The following should be the default, but doing as hexagon-gcc does.
260     CmdArgs.push_back("-call_shared");
261   }
262 
263   if (IsStatic)
264     CmdArgs.push_back("-static");
265 
266   if (IsPIE && !IsShared)
267     CmdArgs.push_back("-pie");
268 
269   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
270     CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
271     UseG0 = G.getValue() == 0;
272   }
273 
274   CmdArgs.push_back("-o");
275   CmdArgs.push_back(Output.getFilename());
276 
277   if (HTC.getTriple().isMusl()) {
278     if (!Args.hasArg(options::OPT_shared, options::OPT_static))
279       CmdArgs.push_back("-dynamic-linker=/lib/ld-musl-hexagon.so.1");
280 
281     if (!Args.hasArg(options::OPT_shared, options::OPT_nostartfiles,
282                      options::OPT_nostdlib))
283       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crt1.o"));
284     else if (Args.hasArg(options::OPT_shared) &&
285              !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib))
286       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crti.o"));
287 
288     CmdArgs.push_back(
289         Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib"));
290     Args.AddAllArgs(CmdArgs,
291                     {options::OPT_T_Group, options::OPT_e, options::OPT_s,
292                      options::OPT_t, options::OPT_u_Group});
293     AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
294 
295     if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
296       if (NeedsSanitizerDeps) {
297         linkSanitizerRuntimeDeps(HTC, CmdArgs);
298 
299         CmdArgs.push_back("-lunwind");
300       }
301       if (NeedsXRayDeps)
302         linkXRayRuntimeDeps(HTC, CmdArgs);
303 
304       CmdArgs.push_back("-lclang_rt.builtins-hexagon");
305       CmdArgs.push_back("-lc");
306     }
307     if (D.CCCIsCXX()) {
308       if (HTC.ShouldLinkCXXStdlib(Args))
309         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
310     }
311     return;
312   }
313 
314   //----------------------------------------------------------------------------
315   // moslib
316   //----------------------------------------------------------------------------
317   std::vector<std::string> OsLibs;
318   bool HasStandalone = false;
319   for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
320     A->claim();
321     OsLibs.emplace_back(A->getValue());
322     HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
323   }
324   if (OsLibs.empty()) {
325     OsLibs.push_back("standalone");
326     HasStandalone = true;
327   }
328 
329   //----------------------------------------------------------------------------
330   // Start Files
331   //----------------------------------------------------------------------------
332   const std::string MCpuSuffix = "/" + CpuVer.str();
333   const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
334   const std::string RootDir =
335       HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
336   const std::string StartSubDir =
337       "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
338 
339   auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
340                       const char *Name) -> std::string {
341     std::string RelName = SubDir + Name;
342     std::string P = HTC.GetFilePath(RelName.c_str());
343     if (llvm::sys::fs::exists(P))
344       return P;
345     return RootDir + RelName;
346   };
347 
348   if (IncStdLib && IncStartFiles) {
349     if (!IsShared) {
350       if (HasStandalone) {
351         std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
352         CmdArgs.push_back(Args.MakeArgString(Crt0SA));
353       }
354       std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
355       CmdArgs.push_back(Args.MakeArgString(Crt0));
356     }
357     std::string Init = UseShared
358           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
359           : Find(RootDir, StartSubDir, "/init.o");
360     CmdArgs.push_back(Args.MakeArgString(Init));
361   }
362 
363   //----------------------------------------------------------------------------
364   // Library Search Paths
365   //----------------------------------------------------------------------------
366   const ToolChain::path_list &LibPaths = HTC.getFilePaths();
367   for (const auto &LibPath : LibPaths)
368     CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
369 
370   //----------------------------------------------------------------------------
371   //
372   //----------------------------------------------------------------------------
373   Args.AddAllArgs(CmdArgs,
374                   {options::OPT_T_Group, options::OPT_e, options::OPT_s,
375                    options::OPT_t, options::OPT_u_Group});
376 
377   AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
378 
379   //----------------------------------------------------------------------------
380   // Libraries
381   //----------------------------------------------------------------------------
382   if (IncStdLib && IncDefLibs) {
383     if (D.CCCIsCXX()) {
384       if (HTC.ShouldLinkCXXStdlib(Args))
385         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
386       CmdArgs.push_back("-lm");
387     }
388 
389     CmdArgs.push_back("--start-group");
390 
391     if (!IsShared) {
392       for (StringRef Lib : OsLibs)
393         CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
394       CmdArgs.push_back("-lc");
395     }
396     CmdArgs.push_back("-lgcc");
397 
398     CmdArgs.push_back("--end-group");
399   }
400 
401   //----------------------------------------------------------------------------
402   // End files
403   //----------------------------------------------------------------------------
404   if (IncStdLib && IncStartFiles) {
405     std::string Fini = UseShared
406           ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
407           : Find(RootDir, StartSubDir, "/fini.o");
408     CmdArgs.push_back(Args.MakeArgString(Fini));
409   }
410 }
411 
412 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
413                                    const InputInfo &Output,
414                                    const InputInfoList &Inputs,
415                                    const ArgList &Args,
416                                    const char *LinkingOutput) const {
417   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
418 
419   ArgStringList CmdArgs;
420   constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
421                            LinkingOutput);
422 
423   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
424   C.addCommand(std::make_unique<Command>(JA, *this,
425                                          ResponseFileSupport::AtFileCurCP(),
426                                          Exec, CmdArgs, Inputs, Output));
427 }
428 // Hexagon tools end.
429 
430 /// Hexagon Toolchain
431 
432 std::string HexagonToolChain::getHexagonTargetDir(
433       const std::string &InstalledDir,
434       const SmallVectorImpl<std::string> &PrefixDirs) const {
435   std::string InstallRelDir;
436   const Driver &D = getDriver();
437 
438   // Locate the rest of the toolchain ...
439   for (auto &I : PrefixDirs)
440     if (D.getVFS().exists(I))
441       return I;
442 
443   if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
444     return InstallRelDir;
445 
446   return InstalledDir;
447 }
448 
449 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
450       const ArgList &Args) {
451   StringRef Gn = "";
452   if (Arg *A = Args.getLastArg(options::OPT_G)) {
453     Gn = A->getValue();
454   } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
455                              options::OPT_fPIC)) {
456     Gn = "0";
457   }
458 
459   unsigned G;
460   if (!Gn.getAsInteger(10, G))
461     return G;
462 
463   return None;
464 }
465 
466 std::string HexagonToolChain::getCompilerRTPath() const {
467   SmallString<128> Dir(getDriver().SysRoot);
468   llvm::sys::path::append(Dir, "usr", "lib");
469   Dir += SelectedMultilib.gccSuffix();
470   return std::string(Dir.str());
471 }
472 
473 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
474       ToolChain::path_list &LibPaths) const {
475   const Driver &D = getDriver();
476 
477   //----------------------------------------------------------------------------
478   // -L Args
479   //----------------------------------------------------------------------------
480   for (Arg *A : Args.filtered(options::OPT_L))
481     for (const char *Value : A->getValues())
482       LibPaths.push_back(Value);
483 
484   //----------------------------------------------------------------------------
485   // Other standard paths
486   //----------------------------------------------------------------------------
487   std::vector<std::string> RootDirs;
488   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
489             std::back_inserter(RootDirs));
490 
491   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
492                                               D.PrefixDirs);
493   if (!llvm::is_contained(RootDirs, TargetDir))
494     RootDirs.push_back(TargetDir);
495 
496   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
497   // Assume G0 with -shared.
498   bool HasG0 = Args.hasArg(options::OPT_shared);
499   if (auto G = getSmallDataThreshold(Args))
500     HasG0 = G.getValue() == 0;
501 
502   const std::string CpuVer = GetTargetCPUVersion(Args).str();
503   for (auto &Dir : RootDirs) {
504     std::string LibDir = Dir + "/hexagon/lib";
505     std::string LibDirCpu = LibDir + '/' + CpuVer;
506     if (HasG0) {
507       if (HasPIC)
508         LibPaths.push_back(LibDirCpu + "/G0/pic");
509       LibPaths.push_back(LibDirCpu + "/G0");
510     }
511     LibPaths.push_back(LibDirCpu);
512     LibPaths.push_back(LibDir);
513   }
514 }
515 
516 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
517                                    const llvm::opt::ArgList &Args)
518     : Linux(D, Triple, Args) {
519   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
520                                                     D.PrefixDirs);
521 
522   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
523   // program paths
524   const std::string BinDir(TargetDir + "/bin");
525   if (D.getVFS().exists(BinDir))
526     getProgramPaths().push_back(BinDir);
527 
528   ToolChain::path_list &LibPaths = getFilePaths();
529 
530   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
531   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
532   // support 'linux' we'll need to fix this up
533   LibPaths.clear();
534   getHexagonLibraryPaths(Args, LibPaths);
535 }
536 
537 HexagonToolChain::~HexagonToolChain() {}
538 
539 void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
540                                            ArgStringList &CmdArgs) const {
541   CXXStdlibType Type = GetCXXStdlibType(Args);
542   switch (Type) {
543   case ToolChain::CST_Libcxx:
544     CmdArgs.push_back("-lc++");
545     CmdArgs.push_back("-lc++abi");
546     CmdArgs.push_back("-lunwind");
547     break;
548 
549   case ToolChain::CST_Libstdcxx:
550     CmdArgs.push_back("-lstdc++");
551     break;
552   }
553 }
554 
555 Tool *HexagonToolChain::buildAssembler() const {
556   return new tools::hexagon::Assembler(*this);
557 }
558 
559 Tool *HexagonToolChain::buildLinker() const {
560   return new tools::hexagon::Linker(*this);
561 }
562 
563 unsigned HexagonToolChain::getOptimizationLevel(
564     const llvm::opt::ArgList &DriverArgs) const {
565   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
566   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
567   if (!A)
568     return 0;
569 
570   if (A->getOption().matches(options::OPT_O0))
571     return 0;
572   if (A->getOption().matches(options::OPT_Ofast) ||
573       A->getOption().matches(options::OPT_O4))
574     return 3;
575   assert(A->getNumValues() != 0);
576   StringRef S(A->getValue());
577   if (S == "s" || S == "z" || S.empty())
578     return 2;
579   if (S == "g")
580     return 1;
581 
582   unsigned OptLevel;
583   if (S.getAsInteger(10, OptLevel))
584     return 0;
585   return OptLevel;
586 }
587 
588 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
589                                              ArgStringList &CC1Args,
590                                              Action::OffloadKind) const {
591 
592   bool UseInitArrayDefault = getTriple().isMusl();
593 
594   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
595                           options::OPT_fno_use_init_array,
596                           UseInitArrayDefault))
597     CC1Args.push_back("-fno-use-init-array");
598 
599   if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
600     CC1Args.push_back("-target-feature");
601     CC1Args.push_back("+reserved-r19");
602   }
603   if (isAutoHVXEnabled(DriverArgs)) {
604     CC1Args.push_back("-mllvm");
605     CC1Args.push_back("-hexagon-autohvx");
606   }
607 }
608 
609 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
610                                                  ArgStringList &CC1Args) const {
611   if (DriverArgs.hasArg(options::OPT_nostdinc))
612     return;
613 
614   const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux();
615   const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
616 
617   const Driver &D = getDriver();
618   SmallString<128> ResourceDirInclude(D.ResourceDir);
619   if (!IsELF) {
620     llvm::sys::path::append(ResourceDirInclude, "include");
621     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
622         (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)))
623       addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
624   }
625   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
626     return;
627 
628   const bool HasSysRoot = !D.SysRoot.empty();
629   if (HasSysRoot) {
630     SmallString<128> P(D.SysRoot);
631     if (IsLinuxMusl)
632       llvm::sys::path::append(P, "usr/include");
633     else
634       llvm::sys::path::append(P, "include");
635 
636     addExternCSystemInclude(DriverArgs, CC1Args, P.str());
637     // LOCAL_INCLUDE_DIR
638     addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include");
639     // TOOL_INCLUDE_DIR
640     AddMultilibIncludeArgs(DriverArgs, CC1Args);
641   }
642 
643   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl)
644     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
645 
646   if (HasSysRoot)
647     return;
648   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
649                                               D.PrefixDirs);
650   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
651 }
652 
653 void HexagonToolChain::addLibCxxIncludePaths(
654     const llvm::opt::ArgList &DriverArgs,
655     llvm::opt::ArgStringList &CC1Args) const {
656   const Driver &D = getDriver();
657   if (!D.SysRoot.empty() && getTriple().isMusl())
658     addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "",
659                              DriverArgs, CC1Args);
660   else if (getTriple().isMusl())
661     addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs,
662                              CC1Args);
663   else {
664     std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
665     addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "",
666                              DriverArgs, CC1Args);
667   }
668 }
669 void HexagonToolChain::addLibStdCxxIncludePaths(
670     const llvm::opt::ArgList &DriverArgs,
671     llvm::opt::ArgStringList &CC1Args) const {
672   const Driver &D = getDriver();
673   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
674   addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "",
675                            DriverArgs, CC1Args);
676 }
677 
678 ToolChain::CXXStdlibType
679 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
680   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
681   if (!A) {
682     if (getTriple().isMusl())
683       return ToolChain::CST_Libcxx;
684     else
685       return ToolChain::CST_Libstdcxx;
686   }
687   StringRef Value = A->getValue();
688   if (Value != "libstdc++" && Value != "libc++")
689     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
690 
691   if (Value == "libstdc++")
692     return ToolChain::CST_Libstdcxx;
693   else if (Value == "libc++")
694     return ToolChain::CST_Libcxx;
695   else
696     return ToolChain::CST_Libstdcxx;
697 }
698 
699 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
700   if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
701                                options::OPT_fno_vectorize))
702     return A->getOption().matches(options::OPT_fvectorize);
703   return false;
704 }
705 
706 //
707 // Returns the default CPU for Hexagon. This is the default compilation target
708 // if no Hexagon processor is selected at the command-line.
709 //
710 StringRef HexagonToolChain::GetDefaultCPU() {
711   return "hexagonv60";
712 }
713 
714 StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
715   Arg *CpuArg = nullptr;
716   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
717     CpuArg = A;
718 
719   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
720   if (CPU.startswith("hexagon"))
721     return CPU.substr(sizeof("hexagon") - 1);
722   return CPU;
723 }
724