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.
getDefaultHvxLength(StringRef HvxVer)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 
handleHVXWarnings(const Driver & D,const ArgList & Args)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.
handleHVXTargetFeatures(const Driver & D,const ArgList & Args,std::vector<StringRef> & Features,StringRef Cpu,bool & HasHVX)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.ends_with("="))
58       Opt = Opt.drop_back(1);
59     if (Opt.starts_with("mno-"))
60       Opt = Opt.drop_front(4);
61     else if (Opt.starts_with("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.
getHexagonTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & 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.
RenderExtraToolArgs(const JobAction & JA,ArgStringList & CmdArgs) const194 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
195                                              ArgStringList &CmdArgs) const {
196 }
197 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const198 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   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
222   if (Output.isFilename()) {
223     CmdArgs.push_back("-o");
224     CmdArgs.push_back(Output.getFilename());
225   } else {
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 
RenderExtraToolArgs(const JobAction & JA,ArgStringList & CmdArgs) const275 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
276                                           ArgStringList &CmdArgs) const {
277 }
278 
279 static void
constructHexagonLinkArgs(Compilation & C,const JobAction & JA,const toolchains::HexagonToolChain & HTC,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,ArgStringList & CmdArgs,const char * LinkingOutput)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, Args, CmdArgs);
373 
374         CmdArgs.push_back("-lunwind");
375       }
376       if (NeedsXRayDeps)
377         linkXRayRuntimeDeps(HTC, Args, CmdArgs);
378 
379       CmdArgs.push_back("-lclang_rt.builtins-hexagon");
380       if (!Args.hasArg(options::OPT_nolibc))
381         CmdArgs.push_back("-lc");
382     }
383     if (D.CCCIsCXX()) {
384       if (HTC.ShouldLinkCXXStdlib(Args))
385         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
386     }
387     const ToolChain::path_list &LibPaths = HTC.getFilePaths();
388     for (const auto &LibPath : LibPaths)
389       CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
390     Args.ClaimAllArgs(options::OPT_L);
391     return;
392   }
393 
394   //----------------------------------------------------------------------------
395   // moslib
396   //----------------------------------------------------------------------------
397   std::vector<std::string> OsLibs;
398   bool HasStandalone = false;
399   for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
400     A->claim();
401     OsLibs.emplace_back(A->getValue());
402     HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
403   }
404   if (OsLibs.empty()) {
405     OsLibs.push_back("standalone");
406     HasStandalone = true;
407   }
408 
409   //----------------------------------------------------------------------------
410   // Start Files
411   //----------------------------------------------------------------------------
412   const std::string MCpuSuffix = "/" + CpuVer.str();
413   const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
414   const std::string RootDir =
415       HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
416   const std::string StartSubDir =
417       "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
418 
419   auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
420                       const char *Name) -> std::string {
421     std::string RelName = SubDir + Name;
422     std::string P = HTC.GetFilePath(RelName.c_str());
423     if (llvm::sys::fs::exists(P))
424       return P;
425     return RootDir + RelName;
426   };
427 
428   if (IncStdLib && IncStartFiles) {
429     if (!IsShared) {
430       if (HasStandalone) {
431         std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
432         CmdArgs.push_back(Args.MakeArgString(Crt0SA));
433       }
434       std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
435       CmdArgs.push_back(Args.MakeArgString(Crt0));
436     }
437     std::string Init = UseShared
438           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
439           : Find(RootDir, StartSubDir, "/init.o");
440     CmdArgs.push_back(Args.MakeArgString(Init));
441   }
442 
443   //----------------------------------------------------------------------------
444   // Library Search Paths
445   //----------------------------------------------------------------------------
446   const ToolChain::path_list &LibPaths = HTC.getFilePaths();
447   for (const auto &LibPath : LibPaths)
448     CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
449   Args.ClaimAllArgs(options::OPT_L);
450 
451   //----------------------------------------------------------------------------
452   //
453   //----------------------------------------------------------------------------
454   Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
455                             options::OPT_t, options::OPT_u_Group});
456 
457   AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
458 
459   //----------------------------------------------------------------------------
460   // Libraries
461   //----------------------------------------------------------------------------
462   if (IncStdLib && IncDefLibs) {
463     if (D.CCCIsCXX()) {
464       if (HTC.ShouldLinkCXXStdlib(Args))
465         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
466       CmdArgs.push_back("-lm");
467     }
468 
469     CmdArgs.push_back("--start-group");
470 
471     if (!IsShared) {
472       for (StringRef Lib : OsLibs)
473         CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
474       if (!Args.hasArg(options::OPT_nolibc))
475         CmdArgs.push_back("-lc");
476     }
477     CmdArgs.push_back("-lgcc");
478 
479     CmdArgs.push_back("--end-group");
480   }
481 
482   //----------------------------------------------------------------------------
483   // End files
484   //----------------------------------------------------------------------------
485   if (IncStdLib && IncStartFiles) {
486     std::string Fini = UseShared
487           ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
488           : Find(RootDir, StartSubDir, "/fini.o");
489     CmdArgs.push_back(Args.MakeArgString(Fini));
490   }
491 }
492 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const493 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
494                                    const InputInfo &Output,
495                                    const InputInfoList &Inputs,
496                                    const ArgList &Args,
497                                    const char *LinkingOutput) const {
498   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
499 
500   ArgStringList CmdArgs;
501   constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
502                            LinkingOutput);
503 
504   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
505   C.addCommand(std::make_unique<Command>(JA, *this,
506                                          ResponseFileSupport::AtFileCurCP(),
507                                          Exec, CmdArgs, Inputs, Output));
508 }
509 // Hexagon tools end.
510 
511 /// Hexagon Toolchain
512 
getHexagonTargetDir(const std::string & InstalledDir,const SmallVectorImpl<std::string> & PrefixDirs) const513 std::string HexagonToolChain::getHexagonTargetDir(
514       const std::string &InstalledDir,
515       const SmallVectorImpl<std::string> &PrefixDirs) const {
516   std::string InstallRelDir;
517   const Driver &D = getDriver();
518 
519   // Locate the rest of the toolchain ...
520   for (auto &I : PrefixDirs)
521     if (D.getVFS().exists(I))
522       return I;
523 
524   if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
525     return InstallRelDir;
526 
527   return InstalledDir;
528 }
529 
530 std::optional<unsigned>
getSmallDataThreshold(const ArgList & Args)531 HexagonToolChain::getSmallDataThreshold(const ArgList &Args) {
532   StringRef Gn = "";
533   if (Arg *A = Args.getLastArg(options::OPT_G)) {
534     Gn = A->getValue();
535   } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
536                              options::OPT_fPIC)) {
537     Gn = "0";
538   }
539 
540   unsigned G;
541   if (!Gn.getAsInteger(10, G))
542     return G;
543 
544   return std::nullopt;
545 }
546 
getCompilerRTPath() const547 std::string HexagonToolChain::getCompilerRTPath() const {
548   SmallString<128> Dir(getDriver().SysRoot);
549   llvm::sys::path::append(Dir, "usr", "lib");
550   if (!SelectedMultilibs.empty()) {
551     Dir += SelectedMultilibs.back().gccSuffix();
552   }
553   return std::string(Dir);
554 }
555 
getHexagonLibraryPaths(const ArgList & Args,ToolChain::path_list & LibPaths) const556 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
557       ToolChain::path_list &LibPaths) const {
558   const Driver &D = getDriver();
559 
560   //----------------------------------------------------------------------------
561   // -L Args
562   //----------------------------------------------------------------------------
563   for (Arg *A : Args.filtered(options::OPT_L))
564     llvm::append_range(LibPaths, A->getValues());
565 
566   //----------------------------------------------------------------------------
567   // Other standard paths
568   //----------------------------------------------------------------------------
569   std::vector<std::string> RootDirs;
570   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
571             std::back_inserter(RootDirs));
572 
573   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
574                                               D.PrefixDirs);
575   if (!llvm::is_contained(RootDirs, TargetDir))
576     RootDirs.push_back(TargetDir);
577 
578   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
579   // Assume G0 with -shared.
580   bool HasG0 = Args.hasArg(options::OPT_shared);
581   if (auto G = getSmallDataThreshold(Args))
582     HasG0 = *G == 0;
583 
584   const std::string CpuVer = GetTargetCPUVersion(Args).str();
585   for (auto &Dir : RootDirs) {
586     std::string LibDir = Dir + "/hexagon/lib";
587     std::string LibDirCpu = LibDir + '/' + CpuVer;
588     if (HasG0) {
589       if (HasPIC)
590         LibPaths.push_back(LibDirCpu + "/G0/pic");
591       LibPaths.push_back(LibDirCpu + "/G0");
592     }
593     LibPaths.push_back(LibDirCpu);
594     LibPaths.push_back(LibDir);
595   }
596 }
597 
HexagonToolChain(const Driver & D,const llvm::Triple & Triple,const llvm::opt::ArgList & Args)598 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
599                                    const llvm::opt::ArgList &Args)
600     : Linux(D, Triple, Args) {
601   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
602                                                     D.PrefixDirs);
603 
604   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
605   // program paths
606   const std::string BinDir(TargetDir + "/bin");
607   if (D.getVFS().exists(BinDir))
608     getProgramPaths().push_back(BinDir);
609 
610   ToolChain::path_list &LibPaths = getFilePaths();
611 
612   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
613   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
614   // support 'linux' we'll need to fix this up
615   LibPaths.clear();
616   getHexagonLibraryPaths(Args, LibPaths);
617 }
618 
~HexagonToolChain()619 HexagonToolChain::~HexagonToolChain() {}
620 
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const621 void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
622                                            ArgStringList &CmdArgs) const {
623   CXXStdlibType Type = GetCXXStdlibType(Args);
624   switch (Type) {
625   case ToolChain::CST_Libcxx:
626     CmdArgs.push_back("-lc++");
627     if (Args.hasArg(options::OPT_fexperimental_library))
628       CmdArgs.push_back("-lc++experimental");
629     CmdArgs.push_back("-lc++abi");
630     CmdArgs.push_back("-lunwind");
631     break;
632 
633   case ToolChain::CST_Libstdcxx:
634     CmdArgs.push_back("-lstdc++");
635     break;
636   }
637 }
638 
buildAssembler() const639 Tool *HexagonToolChain::buildAssembler() const {
640   return new tools::hexagon::Assembler(*this);
641 }
642 
buildLinker() const643 Tool *HexagonToolChain::buildLinker() const {
644   return new tools::hexagon::Linker(*this);
645 }
646 
getOptimizationLevel(const llvm::opt::ArgList & DriverArgs) const647 unsigned HexagonToolChain::getOptimizationLevel(
648     const llvm::opt::ArgList &DriverArgs) const {
649   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
650   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
651   if (!A)
652     return 0;
653 
654   if (A->getOption().matches(options::OPT_O0))
655     return 0;
656   if (A->getOption().matches(options::OPT_Ofast) ||
657       A->getOption().matches(options::OPT_O4))
658     return 3;
659   assert(A->getNumValues() != 0);
660   StringRef S(A->getValue());
661   if (S == "s" || S == "z" || S.empty())
662     return 2;
663   if (S == "g")
664     return 1;
665 
666   unsigned OptLevel;
667   if (S.getAsInteger(10, OptLevel))
668     return 0;
669   return OptLevel;
670 }
671 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const672 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
673                                              ArgStringList &CC1Args,
674                                              Action::OffloadKind) const {
675 
676   bool UseInitArrayDefault = getTriple().isMusl();
677 
678   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
679                           options::OPT_fno_use_init_array,
680                           UseInitArrayDefault))
681     CC1Args.push_back("-fno-use-init-array");
682 
683   if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
684     CC1Args.push_back("-target-feature");
685     CC1Args.push_back("+reserved-r19");
686   }
687   if (isAutoHVXEnabled(DriverArgs)) {
688     CC1Args.push_back("-mllvm");
689     CC1Args.push_back("-hexagon-autohvx");
690   }
691 }
692 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const693 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
694                                                  ArgStringList &CC1Args) const {
695   if (DriverArgs.hasArg(options::OPT_nostdinc))
696     return;
697 
698   const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux();
699   const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
700 
701   const Driver &D = getDriver();
702   SmallString<128> ResourceDirInclude(D.ResourceDir);
703   if (!IsELF) {
704     llvm::sys::path::append(ResourceDirInclude, "include");
705     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
706         (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)))
707       addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
708   }
709   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
710     return;
711 
712   const bool HasSysRoot = !D.SysRoot.empty();
713   if (HasSysRoot) {
714     SmallString<128> P(D.SysRoot);
715     if (IsLinuxMusl)
716       llvm::sys::path::append(P, "usr/include");
717     else
718       llvm::sys::path::append(P, "include");
719 
720     addExternCSystemInclude(DriverArgs, CC1Args, P.str());
721     // LOCAL_INCLUDE_DIR
722     addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include");
723     // TOOL_INCLUDE_DIR
724     AddMultilibIncludeArgs(DriverArgs, CC1Args);
725   }
726 
727   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl)
728     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
729 
730   if (HasSysRoot)
731     return;
732   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
733                                               D.PrefixDirs);
734   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
735 }
736 
addLibCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const737 void HexagonToolChain::addLibCxxIncludePaths(
738     const llvm::opt::ArgList &DriverArgs,
739     llvm::opt::ArgStringList &CC1Args) const {
740   const Driver &D = getDriver();
741   if (!D.SysRoot.empty() && getTriple().isMusl())
742     addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "",
743                              DriverArgs, CC1Args);
744   else if (getTriple().isMusl())
745     addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs,
746                              CC1Args);
747   else {
748     std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
749     addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "",
750                              DriverArgs, CC1Args);
751   }
752 }
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const753 void HexagonToolChain::addLibStdCxxIncludePaths(
754     const llvm::opt::ArgList &DriverArgs,
755     llvm::opt::ArgStringList &CC1Args) const {
756   const Driver &D = getDriver();
757   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
758   addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "",
759                            DriverArgs, CC1Args);
760 }
761 
762 ToolChain::CXXStdlibType
GetCXXStdlibType(const ArgList & Args) const763 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
764   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
765   if (!A) {
766     if (getTriple().isMusl())
767       return ToolChain::CST_Libcxx;
768     else
769       return ToolChain::CST_Libstdcxx;
770   }
771   StringRef Value = A->getValue();
772   if (Value != "libstdc++" && Value != "libc++")
773     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
774 
775   if (Value == "libstdc++")
776     return ToolChain::CST_Libstdcxx;
777   else if (Value == "libc++")
778     return ToolChain::CST_Libcxx;
779   else
780     return ToolChain::CST_Libstdcxx;
781 }
782 
isAutoHVXEnabled(const llvm::opt::ArgList & Args)783 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
784   if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
785                                options::OPT_fno_vectorize))
786     return A->getOption().matches(options::OPT_fvectorize);
787   return false;
788 }
789 
790 //
791 // Returns the default CPU for Hexagon. This is the default compilation target
792 // if no Hexagon processor is selected at the command-line.
793 //
GetDefaultCPU()794 StringRef HexagonToolChain::GetDefaultCPU() {
795   return "hexagonv60";
796 }
797 
GetTargetCPUVersion(const ArgList & Args)798 StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
799   Arg *CpuArg = nullptr;
800   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
801     CpuArg = A;
802 
803   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
804   if (CPU.starts_with("hexagon"))
805     return CPU.substr(sizeof("hexagon") - 1);
806   return CPU;
807 }
808