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