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