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