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