xref: /llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp (revision 96832a6bf7e0e7f1e8d634d38c44a1b32d512923)
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,
163                                        const llvm::Triple &Triple,
164                                        const ArgList &Args,
165                                        std::vector<StringRef> &Features) {
166   handleTargetFeaturesGroup(D, Triple, Args, Features,
167                             options::OPT_m_hexagon_Features_Group);
168 
169   bool UseLongCalls = false;
170   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
171                                options::OPT_mno_long_calls)) {
172     if (A->getOption().matches(options::OPT_mlong_calls))
173       UseLongCalls = true;
174   }
175 
176   Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
177 
178   bool HasHVX = false;
179   StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
180   // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors
181   // have no dependency on micro-architecture.
182   const bool TinyCore = Cpu.contains('t');
183 
184   if (TinyCore)
185     Cpu = Cpu.take_front(Cpu.size() - 1);
186 
187   handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX);
188 
189   if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX)
190     D.Diag(diag::warn_drv_needs_hvx) << "auto-vectorization";
191 }
192 
193 // Hexagon tools start.
194 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
195                                              ArgStringList &CmdArgs) const {
196 }
197 
198 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
199                                       const InputInfo &Output,
200                                       const InputInfoList &Inputs,
201                                       const ArgList &Args,
202                                       const char *LinkingOutput) const {
203   claimNoWarnArgs(Args);
204 
205   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
206   const Driver &D = HTC.getDriver();
207   ArgStringList CmdArgs;
208 
209   CmdArgs.push_back("--arch=hexagon");
210 
211   RenderExtraToolArgs(JA, CmdArgs);
212 
213   const char *AsName = "llvm-mc";
214   CmdArgs.push_back("-filetype=obj");
215   CmdArgs.push_back(Args.MakeArgString(
216       "-mcpu=hexagon" +
217       toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
218 
219   addSanitizerRuntimes(HTC, Args, CmdArgs);
220 
221   if (Output.isFilename()) {
222     CmdArgs.push_back("-o");
223     CmdArgs.push_back(Output.getFilename());
224   } else {
225     assert(Output.isNothing() && "Unexpected output");
226     CmdArgs.push_back("-fsyntax-only");
227   }
228 
229   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_ieee_fp,
230                                options::OPT_mno_hexagon_hvx_ieee_fp)) {
231     if (A->getOption().matches(options::OPT_mhexagon_hvx_ieee_fp))
232       CmdArgs.push_back("-mhvx-ieee-fp");
233   }
234 
235   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
236     CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(*G)));
237   }
238 
239   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
240 
241   // Only pass -x if gcc will understand it; otherwise hope gcc
242   // understands the suffix correctly. The main use case this would go
243   // wrong in is for linker inputs if they happened to have an odd
244   // suffix; really the only way to get this to happen is a command
245   // like '-x foobar a.c' which will treat a.c like a linker input.
246   //
247   // FIXME: For the linker case specifically, can we safely convert
248   // inputs into '-Wl,' options?
249   for (const auto &II : Inputs) {
250     // Don't try to pass LLVM or AST inputs to a generic gcc.
251     if (types::isLLVMIR(II.getType()))
252       D.Diag(clang::diag::err_drv_no_linker_llvm_support)
253           << HTC.getTripleString();
254     else if (II.getType() == types::TY_AST)
255       D.Diag(clang::diag::err_drv_no_ast_support)
256           << HTC.getTripleString();
257     else if (II.getType() == types::TY_ModuleFile)
258       D.Diag(diag::err_drv_no_module_support)
259           << HTC.getTripleString();
260 
261     if (II.isFilename())
262       CmdArgs.push_back(II.getFilename());
263     else
264       // Don't render as input, we need gcc to do the translations.
265       // FIXME: What is this?
266       II.getInputArg().render(Args, CmdArgs);
267   }
268 
269   auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
270   C.addCommand(std::make_unique<Command>(JA, *this,
271                                          ResponseFileSupport::AtFileCurCP(),
272                                          Exec, CmdArgs, Inputs, Output));
273 }
274 
275 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
276                                           ArgStringList &CmdArgs) const {
277 }
278 
279 static void
280 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
281                          const toolchains::HexagonToolChain &HTC,
282                          const InputInfo &Output, const InputInfoList &Inputs,
283                          const ArgList &Args, ArgStringList &CmdArgs,
284                          const char *LinkingOutput) {
285 
286   const Driver &D = HTC.getDriver();
287 
288   //----------------------------------------------------------------------------
289   //
290   //----------------------------------------------------------------------------
291   bool IsStatic = Args.hasArg(options::OPT_static);
292   bool IsShared = Args.hasArg(options::OPT_shared);
293   bool IsPIE = Args.hasArg(options::OPT_pie);
294   bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
295   bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
296   bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
297   bool UseG0 = false;
298   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
299   bool UseLLD = (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||
300                  llvm::sys::path::stem(Exec).equals_insensitive("ld.lld"));
301   bool UseShared = IsShared && !IsStatic;
302   StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
303 
304   bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs);
305   bool NeedsXRayDeps = addXRayRuntime(HTC, Args, CmdArgs);
306 
307   //----------------------------------------------------------------------------
308   // Silence warnings for various options
309   //----------------------------------------------------------------------------
310   Args.ClaimAllArgs(options::OPT_g_Group);
311   Args.ClaimAllArgs(options::OPT_emit_llvm);
312   Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
313                                      // handled somewhere else.
314   Args.ClaimAllArgs(options::OPT_static_libgcc);
315 
316   //----------------------------------------------------------------------------
317   //
318   //----------------------------------------------------------------------------
319   if (Args.hasArg(options::OPT_s))
320     CmdArgs.push_back("-s");
321 
322   if (Args.hasArg(options::OPT_r))
323     CmdArgs.push_back("-r");
324 
325   for (const auto &Opt : HTC.ExtraOpts)
326     CmdArgs.push_back(Opt.c_str());
327 
328   if (!UseLLD) {
329     CmdArgs.push_back("-march=hexagon");
330     CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
331   }
332 
333   if (IsShared) {
334     CmdArgs.push_back("-shared");
335     // The following should be the default, but doing as hexagon-gcc does.
336     CmdArgs.push_back("-call_shared");
337   }
338 
339   if (IsStatic)
340     CmdArgs.push_back("-static");
341 
342   if (IsPIE && !IsShared)
343     CmdArgs.push_back("-pie");
344 
345   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
346     CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G)));
347     UseG0 = *G == 0;
348   }
349 
350   CmdArgs.push_back("-o");
351   CmdArgs.push_back(Output.getFilename());
352 
353   if (HTC.getTriple().isMusl()) {
354     if (!Args.hasArg(options::OPT_shared, options::OPT_static))
355       CmdArgs.push_back("-dynamic-linker=/lib/ld-musl-hexagon.so.1");
356 
357     if (!Args.hasArg(options::OPT_shared, options::OPT_nostartfiles,
358                      options::OPT_nostdlib))
359       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crt1.o"));
360     else if (Args.hasArg(options::OPT_shared) &&
361              !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib))
362       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crti.o"));
363 
364     CmdArgs.push_back(
365         Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib"));
366     Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
367                               options::OPT_t, options::OPT_u_Group});
368     AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
369 
370     if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
371       if (NeedsSanitizerDeps) {
372         linkSanitizerRuntimeDeps(HTC, CmdArgs);
373 
374         CmdArgs.push_back("-lunwind");
375       }
376       if (NeedsXRayDeps)
377         linkXRayRuntimeDeps(HTC, CmdArgs);
378 
379       CmdArgs.push_back("-lclang_rt.builtins-hexagon");
380       CmdArgs.push_back("-lc");
381     }
382     if (D.CCCIsCXX()) {
383       if (HTC.ShouldLinkCXXStdlib(Args))
384         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
385     }
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   Args.ClaimAllArgs(options::OPT_L);
444 
445   //----------------------------------------------------------------------------
446   //
447   //----------------------------------------------------------------------------
448   Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, 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   if (!SelectedMultilibs.empty()) {
544     Dir += SelectedMultilibs.back().gccSuffix();
545   }
546   return std::string(Dir.str());
547 }
548 
549 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
550       ToolChain::path_list &LibPaths) const {
551   const Driver &D = getDriver();
552 
553   //----------------------------------------------------------------------------
554   // -L Args
555   //----------------------------------------------------------------------------
556   for (Arg *A : Args.filtered(options::OPT_L))
557     llvm::append_range(LibPaths, A->getValues());
558 
559   //----------------------------------------------------------------------------
560   // Other standard paths
561   //----------------------------------------------------------------------------
562   std::vector<std::string> RootDirs;
563   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
564             std::back_inserter(RootDirs));
565 
566   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
567                                               D.PrefixDirs);
568   if (!llvm::is_contained(RootDirs, TargetDir))
569     RootDirs.push_back(TargetDir);
570 
571   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
572   // Assume G0 with -shared.
573   bool HasG0 = Args.hasArg(options::OPT_shared);
574   if (auto G = getSmallDataThreshold(Args))
575     HasG0 = *G == 0;
576 
577   const std::string CpuVer = GetTargetCPUVersion(Args).str();
578   for (auto &Dir : RootDirs) {
579     std::string LibDir = Dir + "/hexagon/lib";
580     std::string LibDirCpu = LibDir + '/' + CpuVer;
581     if (HasG0) {
582       if (HasPIC)
583         LibPaths.push_back(LibDirCpu + "/G0/pic");
584       LibPaths.push_back(LibDirCpu + "/G0");
585     }
586     LibPaths.push_back(LibDirCpu);
587     LibPaths.push_back(LibDir);
588   }
589 }
590 
591 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
592                                    const llvm::opt::ArgList &Args)
593     : Linux(D, Triple, Args) {
594   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
595                                                     D.PrefixDirs);
596 
597   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
598   // program paths
599   const std::string BinDir(TargetDir + "/bin");
600   if (D.getVFS().exists(BinDir))
601     getProgramPaths().push_back(BinDir);
602 
603   ToolChain::path_list &LibPaths = getFilePaths();
604 
605   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
606   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
607   // support 'linux' we'll need to fix this up
608   LibPaths.clear();
609   getHexagonLibraryPaths(Args, LibPaths);
610 }
611 
612 HexagonToolChain::~HexagonToolChain() {}
613 
614 void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
615                                            ArgStringList &CmdArgs) const {
616   CXXStdlibType Type = GetCXXStdlibType(Args);
617   switch (Type) {
618   case ToolChain::CST_Libcxx:
619     CmdArgs.push_back("-lc++");
620     if (Args.hasArg(options::OPT_fexperimental_library))
621       CmdArgs.push_back("-lc++experimental");
622     CmdArgs.push_back("-lc++abi");
623     CmdArgs.push_back("-lunwind");
624     break;
625 
626   case ToolChain::CST_Libstdcxx:
627     CmdArgs.push_back("-lstdc++");
628     break;
629   }
630 }
631 
632 Tool *HexagonToolChain::buildAssembler() const {
633   return new tools::hexagon::Assembler(*this);
634 }
635 
636 Tool *HexagonToolChain::buildLinker() const {
637   return new tools::hexagon::Linker(*this);
638 }
639 
640 unsigned HexagonToolChain::getOptimizationLevel(
641     const llvm::opt::ArgList &DriverArgs) const {
642   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
643   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
644   if (!A)
645     return 0;
646 
647   if (A->getOption().matches(options::OPT_O0))
648     return 0;
649   if (A->getOption().matches(options::OPT_Ofast) ||
650       A->getOption().matches(options::OPT_O4))
651     return 3;
652   assert(A->getNumValues() != 0);
653   StringRef S(A->getValue());
654   if (S == "s" || S == "z" || S.empty())
655     return 2;
656   if (S == "g")
657     return 1;
658 
659   unsigned OptLevel;
660   if (S.getAsInteger(10, OptLevel))
661     return 0;
662   return OptLevel;
663 }
664 
665 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
666                                              ArgStringList &CC1Args,
667                                              Action::OffloadKind) const {
668 
669   bool UseInitArrayDefault = getTriple().isMusl();
670 
671   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
672                           options::OPT_fno_use_init_array,
673                           UseInitArrayDefault))
674     CC1Args.push_back("-fno-use-init-array");
675 
676   if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
677     CC1Args.push_back("-target-feature");
678     CC1Args.push_back("+reserved-r19");
679   }
680   if (isAutoHVXEnabled(DriverArgs)) {
681     CC1Args.push_back("-mllvm");
682     CC1Args.push_back("-hexagon-autohvx");
683   }
684 }
685 
686 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
687                                                  ArgStringList &CC1Args) const {
688   if (DriverArgs.hasArg(options::OPT_nostdinc))
689     return;
690 
691   const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux();
692   const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
693 
694   const Driver &D = getDriver();
695   SmallString<128> ResourceDirInclude(D.ResourceDir);
696   if (!IsELF) {
697     llvm::sys::path::append(ResourceDirInclude, "include");
698     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
699         (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)))
700       addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
701   }
702   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
703     return;
704 
705   const bool HasSysRoot = !D.SysRoot.empty();
706   if (HasSysRoot) {
707     SmallString<128> P(D.SysRoot);
708     if (IsLinuxMusl)
709       llvm::sys::path::append(P, "usr/include");
710     else
711       llvm::sys::path::append(P, "include");
712 
713     addExternCSystemInclude(DriverArgs, CC1Args, P.str());
714     // LOCAL_INCLUDE_DIR
715     addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include");
716     // TOOL_INCLUDE_DIR
717     AddMultilibIncludeArgs(DriverArgs, CC1Args);
718   }
719 
720   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl)
721     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
722 
723   if (HasSysRoot)
724     return;
725   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
726                                               D.PrefixDirs);
727   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
728 }
729 
730 void HexagonToolChain::addLibCxxIncludePaths(
731     const llvm::opt::ArgList &DriverArgs,
732     llvm::opt::ArgStringList &CC1Args) const {
733   const Driver &D = getDriver();
734   if (!D.SysRoot.empty() && getTriple().isMusl())
735     addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "",
736                              DriverArgs, CC1Args);
737   else if (getTriple().isMusl())
738     addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs,
739                              CC1Args);
740   else {
741     std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
742     addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "",
743                              DriverArgs, CC1Args);
744   }
745 }
746 void HexagonToolChain::addLibStdCxxIncludePaths(
747     const llvm::opt::ArgList &DriverArgs,
748     llvm::opt::ArgStringList &CC1Args) const {
749   const Driver &D = getDriver();
750   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
751   addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "",
752                            DriverArgs, CC1Args);
753 }
754 
755 ToolChain::CXXStdlibType
756 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
757   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
758   if (!A) {
759     if (getTriple().isMusl())
760       return ToolChain::CST_Libcxx;
761     else
762       return ToolChain::CST_Libstdcxx;
763   }
764   StringRef Value = A->getValue();
765   if (Value != "libstdc++" && Value != "libc++")
766     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
767 
768   if (Value == "libstdc++")
769     return ToolChain::CST_Libstdcxx;
770   else if (Value == "libc++")
771     return ToolChain::CST_Libcxx;
772   else
773     return ToolChain::CST_Libstdcxx;
774 }
775 
776 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
777   if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
778                                options::OPT_fno_vectorize))
779     return A->getOption().matches(options::OPT_fvectorize);
780   return false;
781 }
782 
783 //
784 // Returns the default CPU for Hexagon. This is the default compilation target
785 // if no Hexagon processor is selected at the command-line.
786 //
787 StringRef HexagonToolChain::GetDefaultCPU() {
788   return "hexagonv60";
789 }
790 
791 StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
792   Arg *CpuArg = nullptr;
793   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
794     CpuArg = A;
795 
796   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
797   if (CPU.startswith("hexagon"))
798     return CPU.substr(sizeof("hexagon") - 1);
799   return CPU;
800 }
801