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)));
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.value())));
344     UseG0 = G.value() == 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     llvm::append_range(LibPaths, A->getValues());
555 
556   //----------------------------------------------------------------------------
557   // Other standard paths
558   //----------------------------------------------------------------------------
559   std::vector<std::string> RootDirs;
560   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
561             std::back_inserter(RootDirs));
562 
563   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
564                                               D.PrefixDirs);
565   if (!llvm::is_contained(RootDirs, TargetDir))
566     RootDirs.push_back(TargetDir);
567 
568   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
569   // Assume G0 with -shared.
570   bool HasG0 = Args.hasArg(options::OPT_shared);
571   if (auto G = getSmallDataThreshold(Args))
572     HasG0 = *G == 0;
573 
574   const std::string CpuVer = GetTargetCPUVersion(Args).str();
575   for (auto &Dir : RootDirs) {
576     std::string LibDir = Dir + "/hexagon/lib";
577     std::string LibDirCpu = LibDir + '/' + CpuVer;
578     if (HasG0) {
579       if (HasPIC)
580         LibPaths.push_back(LibDirCpu + "/G0/pic");
581       LibPaths.push_back(LibDirCpu + "/G0");
582     }
583     LibPaths.push_back(LibDirCpu);
584     LibPaths.push_back(LibDir);
585   }
586 }
587 
588 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
589                                    const llvm::opt::ArgList &Args)
590     : Linux(D, Triple, Args) {
591   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
592                                                     D.PrefixDirs);
593 
594   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
595   // program paths
596   const std::string BinDir(TargetDir + "/bin");
597   if (D.getVFS().exists(BinDir))
598     getProgramPaths().push_back(BinDir);
599 
600   ToolChain::path_list &LibPaths = getFilePaths();
601 
602   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
603   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
604   // support 'linux' we'll need to fix this up
605   LibPaths.clear();
606   getHexagonLibraryPaths(Args, LibPaths);
607 }
608 
609 HexagonToolChain::~HexagonToolChain() {}
610 
611 void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
612                                            ArgStringList &CmdArgs) const {
613   CXXStdlibType Type = GetCXXStdlibType(Args);
614   switch (Type) {
615   case ToolChain::CST_Libcxx:
616     CmdArgs.push_back("-lc++");
617     if (Args.hasArg(options::OPT_fexperimental_library))
618       CmdArgs.push_back("-lc++experimental");
619     CmdArgs.push_back("-lc++abi");
620     CmdArgs.push_back("-lunwind");
621     break;
622 
623   case ToolChain::CST_Libstdcxx:
624     CmdArgs.push_back("-lstdc++");
625     break;
626   }
627 }
628 
629 Tool *HexagonToolChain::buildAssembler() const {
630   return new tools::hexagon::Assembler(*this);
631 }
632 
633 Tool *HexagonToolChain::buildLinker() const {
634   return new tools::hexagon::Linker(*this);
635 }
636 
637 unsigned HexagonToolChain::getOptimizationLevel(
638     const llvm::opt::ArgList &DriverArgs) const {
639   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
640   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
641   if (!A)
642     return 0;
643 
644   if (A->getOption().matches(options::OPT_O0))
645     return 0;
646   if (A->getOption().matches(options::OPT_Ofast) ||
647       A->getOption().matches(options::OPT_O4))
648     return 3;
649   assert(A->getNumValues() != 0);
650   StringRef S(A->getValue());
651   if (S == "s" || S == "z" || S.empty())
652     return 2;
653   if (S == "g")
654     return 1;
655 
656   unsigned OptLevel;
657   if (S.getAsInteger(10, OptLevel))
658     return 0;
659   return OptLevel;
660 }
661 
662 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
663                                              ArgStringList &CC1Args,
664                                              Action::OffloadKind) const {
665 
666   bool UseInitArrayDefault = getTriple().isMusl();
667 
668   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
669                           options::OPT_fno_use_init_array,
670                           UseInitArrayDefault))
671     CC1Args.push_back("-fno-use-init-array");
672 
673   if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
674     CC1Args.push_back("-target-feature");
675     CC1Args.push_back("+reserved-r19");
676   }
677   if (isAutoHVXEnabled(DriverArgs)) {
678     CC1Args.push_back("-mllvm");
679     CC1Args.push_back("-hexagon-autohvx");
680   }
681 }
682 
683 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
684                                                  ArgStringList &CC1Args) const {
685   if (DriverArgs.hasArg(options::OPT_nostdinc))
686     return;
687 
688   const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux();
689   const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
690 
691   const Driver &D = getDriver();
692   SmallString<128> ResourceDirInclude(D.ResourceDir);
693   if (!IsELF) {
694     llvm::sys::path::append(ResourceDirInclude, "include");
695     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
696         (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)))
697       addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
698   }
699   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
700     return;
701 
702   const bool HasSysRoot = !D.SysRoot.empty();
703   if (HasSysRoot) {
704     SmallString<128> P(D.SysRoot);
705     if (IsLinuxMusl)
706       llvm::sys::path::append(P, "usr/include");
707     else
708       llvm::sys::path::append(P, "include");
709 
710     addExternCSystemInclude(DriverArgs, CC1Args, P.str());
711     // LOCAL_INCLUDE_DIR
712     addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include");
713     // TOOL_INCLUDE_DIR
714     AddMultilibIncludeArgs(DriverArgs, CC1Args);
715   }
716 
717   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl)
718     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
719 
720   if (HasSysRoot)
721     return;
722   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
723                                               D.PrefixDirs);
724   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
725 }
726 
727 void HexagonToolChain::addLibCxxIncludePaths(
728     const llvm::opt::ArgList &DriverArgs,
729     llvm::opt::ArgStringList &CC1Args) const {
730   const Driver &D = getDriver();
731   if (!D.SysRoot.empty() && getTriple().isMusl())
732     addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "",
733                              DriverArgs, CC1Args);
734   else if (getTriple().isMusl())
735     addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs,
736                              CC1Args);
737   else {
738     std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
739     addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "",
740                              DriverArgs, CC1Args);
741   }
742 }
743 void HexagonToolChain::addLibStdCxxIncludePaths(
744     const llvm::opt::ArgList &DriverArgs,
745     llvm::opt::ArgStringList &CC1Args) const {
746   const Driver &D = getDriver();
747   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
748   addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "",
749                            DriverArgs, CC1Args);
750 }
751 
752 ToolChain::CXXStdlibType
753 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
754   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
755   if (!A) {
756     if (getTriple().isMusl())
757       return ToolChain::CST_Libcxx;
758     else
759       return ToolChain::CST_Libstdcxx;
760   }
761   StringRef Value = A->getValue();
762   if (Value != "libstdc++" && Value != "libc++")
763     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
764 
765   if (Value == "libstdc++")
766     return ToolChain::CST_Libstdcxx;
767   else if (Value == "libc++")
768     return ToolChain::CST_Libcxx;
769   else
770     return ToolChain::CST_Libstdcxx;
771 }
772 
773 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
774   if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
775                                options::OPT_fno_vectorize))
776     return A->getOption().matches(options::OPT_fvectorize);
777   return false;
778 }
779 
780 //
781 // Returns the default CPU for Hexagon. This is the default compilation target
782 // if no Hexagon processor is selected at the command-line.
783 //
784 StringRef HexagonToolChain::GetDefaultCPU() {
785   return "hexagonv60";
786 }
787 
788 StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
789   Arg *CpuArg = nullptr;
790   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
791     CpuArg = A;
792 
793   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
794   if (CPU.startswith("hexagon"))
795     return CPU.substr(sizeof("hexagon") - 1);
796   return CPU;
797 }
798