• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "InputInfo.h"
12 #include "clang/Driver/Compilation.h"
13 #include "clang/Driver/Driver.h"
14 #include "clang/Driver/DriverDiagnostic.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 Cpu)29 static StringRef getDefaultHvxLength(StringRef Cpu) {
30   return llvm::StringSwitch<StringRef>(Cpu)
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_lower("64b") && !Val.equals_lower("128b"))
42       D.Diag(diag::err_drv_unsupported_option_argument)
43           << A->getOption().getName() << 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   // Add the +hvx* features based on commandline flags.
55   StringRef HVXFeature, HVXLength;
56 
57   // Handle -mhvx, -mhvx=, -mno-hvx.
58   if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx,
59                                options::OPT_mhexagon_hvx,
60                                options::OPT_mhexagon_hvx_EQ)) {
61     if (A->getOption().matches(options::OPT_mno_hexagon_hvx))
62       return;
63     if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
64       HasHVX = true;
65       HVXFeature = Cpu = A->getValue();
66       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
67     } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
68       HasHVX = true;
69       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
70     }
71     Features.push_back(HVXFeature);
72   }
73 
74   // Handle -mhvx-length=.
75   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
76     // These flags are valid only if HVX in enabled.
77     if (!HasHVX)
78       D.Diag(diag::err_drv_invalid_hvx_length);
79     else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
80       HVXLength = A->getValue();
81   }
82   // Default hvx-length based on Cpu.
83   else if (HasHVX)
84     HVXLength = getDefaultHvxLength(Cpu);
85 
86   if (!HVXLength.empty()) {
87     HVXFeature =
88         Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
89     Features.push_back(HVXFeature);
90   }
91 }
92 
93 // Hexagon target features.
getHexagonTargetFeatures(const Driver & D,const ArgList & Args,std::vector<StringRef> & Features)94 void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
95                                        std::vector<StringRef> &Features) {
96   handleTargetFeaturesGroup(Args, Features,
97                             options::OPT_m_hexagon_Features_Group);
98 
99   bool UseLongCalls = false;
100   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
101                                options::OPT_mno_long_calls)) {
102     if (A->getOption().matches(options::OPT_mlong_calls))
103       UseLongCalls = true;
104   }
105 
106   Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
107 
108   bool HasHVX = false;
109   StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
110   // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors
111   // have no dependency on micro-architecture.
112   const bool TinyCore = Cpu.contains('t');
113 
114   if (TinyCore)
115     Cpu = Cpu.take_front(Cpu.size() - 1);
116 
117   handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX);
118 
119   if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX)
120     D.Diag(diag::warn_drv_vectorize_needs_hvx);
121 }
122 
123 // Hexagon tools start.
RenderExtraToolArgs(const JobAction & JA,ArgStringList & CmdArgs) const124 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
125                                              ArgStringList &CmdArgs) const {
126 }
127 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const128 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
129                                       const InputInfo &Output,
130                                       const InputInfoList &Inputs,
131                                       const ArgList &Args,
132                                       const char *LinkingOutput) const {
133   claimNoWarnArgs(Args);
134 
135   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
136   const Driver &D = HTC.getDriver();
137   ArgStringList CmdArgs;
138 
139   CmdArgs.push_back("--arch=hexagon");
140 
141   RenderExtraToolArgs(JA, CmdArgs);
142 
143   const char *AsName = "llvm-mc";
144   CmdArgs.push_back("-filetype=obj");
145   CmdArgs.push_back(Args.MakeArgString(
146       "-mcpu=hexagon" +
147       toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
148 
149   if (Output.isFilename()) {
150     CmdArgs.push_back("-o");
151     CmdArgs.push_back(Output.getFilename());
152   } else {
153     assert(Output.isNothing() && "Unexpected output");
154     CmdArgs.push_back("-fsyntax-only");
155   }
156 
157   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
158     CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
159   }
160 
161   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
162 
163   // Only pass -x if gcc will understand it; otherwise hope gcc
164   // understands the suffix correctly. The main use case this would go
165   // wrong in is for linker inputs if they happened to have an odd
166   // suffix; really the only way to get this to happen is a command
167   // like '-x foobar a.c' which will treat a.c like a linker input.
168   //
169   // FIXME: For the linker case specifically, can we safely convert
170   // inputs into '-Wl,' options?
171   for (const auto &II : Inputs) {
172     // Don't try to pass LLVM or AST inputs to a generic gcc.
173     if (types::isLLVMIR(II.getType()))
174       D.Diag(clang::diag::err_drv_no_linker_llvm_support)
175           << HTC.getTripleString();
176     else if (II.getType() == types::TY_AST)
177       D.Diag(clang::diag::err_drv_no_ast_support)
178           << HTC.getTripleString();
179     else if (II.getType() == types::TY_ModuleFile)
180       D.Diag(diag::err_drv_no_module_support)
181           << HTC.getTripleString();
182 
183     if (II.isFilename())
184       CmdArgs.push_back(II.getFilename());
185     else
186       // Don't render as input, we need gcc to do the translations.
187       // FIXME: What is this?
188       II.getInputArg().render(Args, CmdArgs);
189   }
190 
191   auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
192   C.addCommand(std::make_unique<Command>(JA, *this,
193                                          ResponseFileSupport::AtFileCurCP(),
194                                          Exec, CmdArgs, Inputs, Output));
195 }
196 
RenderExtraToolArgs(const JobAction & JA,ArgStringList & CmdArgs) const197 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
198                                           ArgStringList &CmdArgs) const {
199 }
200 
201 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)202 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
203                          const toolchains::HexagonToolChain &HTC,
204                          const InputInfo &Output, const InputInfoList &Inputs,
205                          const ArgList &Args, ArgStringList &CmdArgs,
206                          const char *LinkingOutput) {
207 
208   const Driver &D = HTC.getDriver();
209 
210   //----------------------------------------------------------------------------
211   //
212   //----------------------------------------------------------------------------
213   bool IsStatic = Args.hasArg(options::OPT_static);
214   bool IsShared = Args.hasArg(options::OPT_shared);
215   bool IsPIE = Args.hasArg(options::OPT_pie);
216   bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
217   bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
218   bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
219   bool UseG0 = false;
220   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
221   bool UseLLD = (llvm::sys::path::filename(Exec).equals_lower("ld.lld") ||
222                  llvm::sys::path::stem(Exec).equals_lower("ld.lld"));
223   bool UseShared = IsShared && !IsStatic;
224   StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
225 
226   //----------------------------------------------------------------------------
227   // Silence warnings for various options
228   //----------------------------------------------------------------------------
229   Args.ClaimAllArgs(options::OPT_g_Group);
230   Args.ClaimAllArgs(options::OPT_emit_llvm);
231   Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
232                                      // handled somewhere else.
233   Args.ClaimAllArgs(options::OPT_static_libgcc);
234 
235   //----------------------------------------------------------------------------
236   //
237   //----------------------------------------------------------------------------
238   if (Args.hasArg(options::OPT_s))
239     CmdArgs.push_back("-s");
240 
241   if (Args.hasArg(options::OPT_r))
242     CmdArgs.push_back("-r");
243 
244   for (const auto &Opt : HTC.ExtraOpts)
245     CmdArgs.push_back(Opt.c_str());
246 
247   if (!UseLLD) {
248     CmdArgs.push_back("-march=hexagon");
249     CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
250   }
251 
252   if (IsShared) {
253     CmdArgs.push_back("-shared");
254     // The following should be the default, but doing as hexagon-gcc does.
255     CmdArgs.push_back("-call_shared");
256   }
257 
258   if (IsStatic)
259     CmdArgs.push_back("-static");
260 
261   if (IsPIE && !IsShared)
262     CmdArgs.push_back("-pie");
263 
264   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
265     CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
266     UseG0 = G.getValue() == 0;
267   }
268 
269   CmdArgs.push_back("-o");
270   CmdArgs.push_back(Output.getFilename());
271 
272   if (HTC.getTriple().isMusl()) {
273     if (!Args.hasArg(options::OPT_shared, options::OPT_static))
274       CmdArgs.push_back("-dynamic-linker=/lib/ld-musl-hexagon.so.1");
275 
276     if (!Args.hasArg(options::OPT_shared, options::OPT_nostartfiles,
277                      options::OPT_nostdlib))
278       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crt1.o"));
279     else if (Args.hasArg(options::OPT_shared) &&
280              !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib))
281       CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crti.o"));
282 
283     CmdArgs.push_back(
284         Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib"));
285     Args.AddAllArgs(CmdArgs,
286                     {options::OPT_T_Group, options::OPT_e, options::OPT_s,
287                      options::OPT_t, options::OPT_u_Group});
288     AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
289 
290     if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
291       CmdArgs.push_back("-lclang_rt.builtins-hexagon");
292       CmdArgs.push_back("-lc");
293     }
294     if (D.CCCIsCXX()) {
295       if (HTC.ShouldLinkCXXStdlib(Args))
296         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
297     }
298     return;
299   }
300 
301   //----------------------------------------------------------------------------
302   // moslib
303   //----------------------------------------------------------------------------
304   std::vector<std::string> OsLibs;
305   bool HasStandalone = false;
306   for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
307     A->claim();
308     OsLibs.emplace_back(A->getValue());
309     HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
310   }
311   if (OsLibs.empty()) {
312     OsLibs.push_back("standalone");
313     HasStandalone = true;
314   }
315 
316   //----------------------------------------------------------------------------
317   // Start Files
318   //----------------------------------------------------------------------------
319   const std::string MCpuSuffix = "/" + CpuVer.str();
320   const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
321   const std::string RootDir =
322       HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
323   const std::string StartSubDir =
324       "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
325 
326   auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
327                       const char *Name) -> std::string {
328     std::string RelName = SubDir + Name;
329     std::string P = HTC.GetFilePath(RelName.c_str());
330     if (llvm::sys::fs::exists(P))
331       return P;
332     return RootDir + RelName;
333   };
334 
335   if (IncStdLib && IncStartFiles) {
336     if (!IsShared) {
337       if (HasStandalone) {
338         std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
339         CmdArgs.push_back(Args.MakeArgString(Crt0SA));
340       }
341       std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
342       CmdArgs.push_back(Args.MakeArgString(Crt0));
343     }
344     std::string Init = UseShared
345           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
346           : Find(RootDir, StartSubDir, "/init.o");
347     CmdArgs.push_back(Args.MakeArgString(Init));
348   }
349 
350   //----------------------------------------------------------------------------
351   // Library Search Paths
352   //----------------------------------------------------------------------------
353   const ToolChain::path_list &LibPaths = HTC.getFilePaths();
354   for (const auto &LibPath : LibPaths)
355     CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
356 
357   //----------------------------------------------------------------------------
358   //
359   //----------------------------------------------------------------------------
360   Args.AddAllArgs(CmdArgs,
361                   {options::OPT_T_Group, options::OPT_e, options::OPT_s,
362                    options::OPT_t, options::OPT_u_Group});
363 
364   AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
365 
366   //----------------------------------------------------------------------------
367   // Libraries
368   //----------------------------------------------------------------------------
369   if (IncStdLib && IncDefLibs) {
370     if (D.CCCIsCXX()) {
371       if (HTC.ShouldLinkCXXStdlib(Args))
372         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
373       CmdArgs.push_back("-lm");
374     }
375 
376     CmdArgs.push_back("--start-group");
377 
378     if (!IsShared) {
379       for (StringRef Lib : OsLibs)
380         CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
381       CmdArgs.push_back("-lc");
382     }
383     CmdArgs.push_back("-lgcc");
384 
385     CmdArgs.push_back("--end-group");
386   }
387 
388   //----------------------------------------------------------------------------
389   // End files
390   //----------------------------------------------------------------------------
391   if (IncStdLib && IncStartFiles) {
392     std::string Fini = UseShared
393           ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
394           : Find(RootDir, StartSubDir, "/fini.o");
395     CmdArgs.push_back(Args.MakeArgString(Fini));
396   }
397 }
398 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const399 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
400                                    const InputInfo &Output,
401                                    const InputInfoList &Inputs,
402                                    const ArgList &Args,
403                                    const char *LinkingOutput) const {
404   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
405 
406   ArgStringList CmdArgs;
407   constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
408                            LinkingOutput);
409 
410   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
411   C.addCommand(std::make_unique<Command>(JA, *this,
412                                          ResponseFileSupport::AtFileCurCP(),
413                                          Exec, CmdArgs, Inputs, Output));
414 }
415 // Hexagon tools end.
416 
417 /// Hexagon Toolchain
418 
getHexagonTargetDir(const std::string & InstalledDir,const SmallVectorImpl<std::string> & PrefixDirs) const419 std::string HexagonToolChain::getHexagonTargetDir(
420       const std::string &InstalledDir,
421       const SmallVectorImpl<std::string> &PrefixDirs) const {
422   std::string InstallRelDir;
423   const Driver &D = getDriver();
424 
425   // Locate the rest of the toolchain ...
426   for (auto &I : PrefixDirs)
427     if (D.getVFS().exists(I))
428       return I;
429 
430   if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
431     return InstallRelDir;
432 
433   return InstalledDir;
434 }
435 
getSmallDataThreshold(const ArgList & Args)436 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
437       const ArgList &Args) {
438   StringRef Gn = "";
439   if (Arg *A = Args.getLastArg(options::OPT_G)) {
440     Gn = A->getValue();
441   } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
442                              options::OPT_fPIC)) {
443     Gn = "0";
444   }
445 
446   unsigned G;
447   if (!Gn.getAsInteger(10, G))
448     return G;
449 
450   return None;
451 }
452 
getHexagonLibraryPaths(const ArgList & Args,ToolChain::path_list & LibPaths) const453 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
454       ToolChain::path_list &LibPaths) const {
455   const Driver &D = getDriver();
456 
457   //----------------------------------------------------------------------------
458   // -L Args
459   //----------------------------------------------------------------------------
460   for (Arg *A : Args.filtered(options::OPT_L))
461     for (const char *Value : A->getValues())
462       LibPaths.push_back(Value);
463 
464   //----------------------------------------------------------------------------
465   // Other standard paths
466   //----------------------------------------------------------------------------
467   std::vector<std::string> RootDirs;
468   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
469             std::back_inserter(RootDirs));
470 
471   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
472                                               D.PrefixDirs);
473   if (llvm::find(RootDirs, TargetDir) == RootDirs.end())
474     RootDirs.push_back(TargetDir);
475 
476   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
477   // Assume G0 with -shared.
478   bool HasG0 = Args.hasArg(options::OPT_shared);
479   if (auto G = getSmallDataThreshold(Args))
480     HasG0 = G.getValue() == 0;
481 
482   const std::string CpuVer = GetTargetCPUVersion(Args).str();
483   for (auto &Dir : RootDirs) {
484     std::string LibDir = Dir + "/hexagon/lib";
485     std::string LibDirCpu = LibDir + '/' + CpuVer;
486     if (HasG0) {
487       if (HasPIC)
488         LibPaths.push_back(LibDirCpu + "/G0/pic");
489       LibPaths.push_back(LibDirCpu + "/G0");
490     }
491     LibPaths.push_back(LibDirCpu);
492     LibPaths.push_back(LibDir);
493   }
494 }
495 
HexagonToolChain(const Driver & D,const llvm::Triple & Triple,const llvm::opt::ArgList & Args)496 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
497                                    const llvm::opt::ArgList &Args)
498     : Linux(D, Triple, Args) {
499   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
500                                                     D.PrefixDirs);
501 
502   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
503   // program paths
504   const std::string BinDir(TargetDir + "/bin");
505   if (D.getVFS().exists(BinDir))
506     getProgramPaths().push_back(BinDir);
507 
508   ToolChain::path_list &LibPaths = getFilePaths();
509 
510   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
511   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
512   // support 'linux' we'll need to fix this up
513   LibPaths.clear();
514   getHexagonLibraryPaths(Args, LibPaths);
515 }
516 
~HexagonToolChain()517 HexagonToolChain::~HexagonToolChain() {}
518 
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const519 void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
520                                            ArgStringList &CmdArgs) const {
521   CXXStdlibType Type = GetCXXStdlibType(Args);
522   switch (Type) {
523   case ToolChain::CST_Libcxx:
524     CmdArgs.push_back("-lc++");
525     CmdArgs.push_back("-lc++abi");
526     CmdArgs.push_back("-lunwind");
527     break;
528 
529   case ToolChain::CST_Libstdcxx:
530     CmdArgs.push_back("-lstdc++");
531     break;
532   }
533 }
534 
buildAssembler() const535 Tool *HexagonToolChain::buildAssembler() const {
536   return new tools::hexagon::Assembler(*this);
537 }
538 
buildLinker() const539 Tool *HexagonToolChain::buildLinker() const {
540   return new tools::hexagon::Linker(*this);
541 }
542 
getOptimizationLevel(const llvm::opt::ArgList & DriverArgs) const543 unsigned HexagonToolChain::getOptimizationLevel(
544     const llvm::opt::ArgList &DriverArgs) const {
545   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
546   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
547   if (!A)
548     return 0;
549 
550   if (A->getOption().matches(options::OPT_O0))
551     return 0;
552   if (A->getOption().matches(options::OPT_Ofast) ||
553       A->getOption().matches(options::OPT_O4))
554     return 3;
555   assert(A->getNumValues() != 0);
556   StringRef S(A->getValue());
557   if (S == "s" || S == "z" || S.empty())
558     return 2;
559   if (S == "g")
560     return 1;
561 
562   unsigned OptLevel;
563   if (S.getAsInteger(10, OptLevel))
564     return 0;
565   return OptLevel;
566 }
567 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const568 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
569                                              ArgStringList &CC1Args,
570                                              Action::OffloadKind) const {
571 
572   bool UseInitArrayDefault = getTriple().isMusl();
573 
574   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
575                           options::OPT_fno_use_init_array,
576                           UseInitArrayDefault))
577     CC1Args.push_back("-fno-use-init-array");
578 
579   if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
580     CC1Args.push_back("-target-feature");
581     CC1Args.push_back("+reserved-r19");
582   }
583   if (isAutoHVXEnabled(DriverArgs)) {
584     CC1Args.push_back("-mllvm");
585     CC1Args.push_back("-hexagon-autohvx");
586   }
587 }
588 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const589 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
590                                                  ArgStringList &CC1Args) const {
591   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
592       DriverArgs.hasArg(options::OPT_nostdlibinc))
593     return;
594 
595   const Driver &D = getDriver();
596   if (!D.SysRoot.empty()) {
597     SmallString<128> P(D.SysRoot);
598     if (getTriple().isMusl())
599       llvm::sys::path::append(P, "usr/include");
600     else
601       llvm::sys::path::append(P, "include");
602     addExternCSystemInclude(DriverArgs, CC1Args, P.str());
603     return;
604   }
605 
606   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
607                                               D.PrefixDirs);
608   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
609 }
610 
addLibCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const611 void HexagonToolChain::addLibCxxIncludePaths(
612     const llvm::opt::ArgList &DriverArgs,
613     llvm::opt::ArgStringList &CC1Args) const {
614   const Driver &D = getDriver();
615   if (!D.SysRoot.empty() && getTriple().isMusl())
616     addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "", "", "",
617                              "", DriverArgs, CC1Args);
618   else if (getTriple().isMusl())
619     addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", "", "", "",
620                              DriverArgs, CC1Args);
621   else {
622     std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
623     addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++/v1", "", "", "",
624                              "", DriverArgs, CC1Args);
625   }
626 }
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const627 void HexagonToolChain::addLibStdCxxIncludePaths(
628     const llvm::opt::ArgList &DriverArgs,
629     llvm::opt::ArgStringList &CC1Args) const {
630   const Driver &D = getDriver();
631   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
632   addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
633                            DriverArgs, CC1Args);
634 }
635 
636 ToolChain::CXXStdlibType
GetCXXStdlibType(const ArgList & Args) const637 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
638   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
639   if (!A) {
640     if (getTriple().isMusl())
641       return ToolChain::CST_Libcxx;
642     else
643       return ToolChain::CST_Libstdcxx;
644   }
645   StringRef Value = A->getValue();
646   if (Value != "libstdc++" && Value != "libc++")
647     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
648 
649   if (Value == "libstdc++")
650     return ToolChain::CST_Libstdcxx;
651   else if (Value == "libc++")
652     return ToolChain::CST_Libcxx;
653   else
654     return ToolChain::CST_Libstdcxx;
655 }
656 
isAutoHVXEnabled(const llvm::opt::ArgList & Args)657 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
658   if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
659                                options::OPT_fno_vectorize))
660     return A->getOption().matches(options::OPT_fvectorize);
661   return false;
662 }
663 
664 //
665 // Returns the default CPU for Hexagon. This is the default compilation target
666 // if no Hexagon processor is selected at the command-line.
667 //
GetDefaultCPU()668 const StringRef HexagonToolChain::GetDefaultCPU() {
669   return "hexagonv60";
670 }
671 
GetTargetCPUVersion(const ArgList & Args)672 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
673   Arg *CpuArg = nullptr;
674   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
675     CpuArg = A;
676 
677   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
678   if (CPU.startswith("hexagon"))
679     return CPU.substr(sizeof("hexagon") - 1);
680   return CPU;
681 }
682