1 //===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #include "InputInfo.h"
12 #include "CommonArgs.h"
13 #include "clang/Basic/VirtualFileSystem.h"
14 #include "clang/Driver/Compilation.h"
15 #include "clang/Driver/Driver.h"
16 #include "clang/Driver/DriverDiagnostic.h"
17 #include "clang/Driver/Options.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/Path.h"
23 using namespace clang::driver;
24 using namespace clang::driver::tools;
25 using namespace clang::driver::toolchains;
26 using namespace clang;
27 using namespace llvm::opt;
29 // Default hvx-length for various versions.
30 static StringRef getDefaultHvxLength(StringRef Cpu) {
31 return llvm::StringSwitch<StringRef>(Cpu)
38 static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
39 // Handle the unsupported values passed to mhvx-length.
40 if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
41 StringRef Val = A->getValue();
42 if (!Val.equals_lower("64b") && !Val.equals_lower("128b"))
43 D.Diag(diag::err_drv_unsupported_option_argument)
44 << A->getOption().getName() << Val;
48 // Handle hvx target features explicitly.
49 static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
50 std::vector<StringRef> &Features,
52 // Handle HVX warnings.
53 handleHVXWarnings(D, Args);
55 // Add the +hvx* features based on commandline flags.
56 StringRef HVXFeature, HVXLength;
57 StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
59 // Handle -mhvx, -mhvx=, -mno-hvx.
60 if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx,
61 options::OPT_mhexagon_hvx,
62 options::OPT_mhexagon_hvx_EQ)) {
63 if (A->getOption().matches(options::OPT_mno_hexagon_hvx))
65 if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
67 HVXFeature = Cpu = A->getValue();
68 HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
69 } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
71 HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
73 Features.push_back(HVXFeature);
76 // Handle -mhvx-length=.
77 if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
78 // These falgs are valid only if HVX in enabled.
80 D.Diag(diag::err_drv_invalid_hvx_length);
81 else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
82 HVXLength = A->getValue();
84 // Default hvx-length based on Cpu.
86 HVXLength = getDefaultHvxLength(Cpu);
88 if (!HVXLength.empty()) {
90 Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
91 Features.push_back(HVXFeature);
95 // Hexagon target features.
96 void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
97 std::vector<StringRef> &Features) {
98 handleTargetFeaturesGroup(Args, Features,
99 options::OPT_m_hexagon_Features_Group);
101 bool UseLongCalls = false;
102 if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
103 options::OPT_mno_long_calls)) {
104 if (A->getOption().matches(options::OPT_mlong_calls))
108 Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
111 handleHVXTargetFeatures(D, Args, Features, HasHVX);
113 if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX)
114 D.Diag(diag::warn_drv_vectorize_needs_hvx);
117 // Hexagon tools start.
118 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
119 ArgStringList &CmdArgs) const {
122 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
123 const InputInfo &Output,
124 const InputInfoList &Inputs,
126 const char *LinkingOutput) const {
127 claimNoWarnArgs(Args);
129 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
130 const Driver &D = HTC.getDriver();
131 ArgStringList CmdArgs;
133 CmdArgs.push_back("-march=hexagon");
135 RenderExtraToolArgs(JA, CmdArgs);
137 const char *AsName = "hexagon-llvm-mc";
138 CmdArgs.push_back("-filetype=obj");
139 CmdArgs.push_back(Args.MakeArgString(
141 toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
143 if (Output.isFilename()) {
144 CmdArgs.push_back("-o");
145 CmdArgs.push_back(Output.getFilename());
147 assert(Output.isNothing() && "Unexpected output");
148 CmdArgs.push_back("-fsyntax-only");
151 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
152 CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
155 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
157 // Only pass -x if gcc will understand it; otherwise hope gcc
158 // understands the suffix correctly. The main use case this would go
159 // wrong in is for linker inputs if they happened to have an odd
160 // suffix; really the only way to get this to happen is a command
161 // like '-x foobar a.c' which will treat a.c like a linker input.
163 // FIXME: For the linker case specifically, can we safely convert
164 // inputs into '-Wl,' options?
165 for (const auto &II : Inputs) {
166 // Don't try to pass LLVM or AST inputs to a generic gcc.
167 if (types::isLLVMIR(II.getType()))
168 D.Diag(clang::diag::err_drv_no_linker_llvm_support)
169 << HTC.getTripleString();
170 else if (II.getType() == types::TY_AST)
171 D.Diag(clang::diag::err_drv_no_ast_support)
172 << HTC.getTripleString();
173 else if (II.getType() == types::TY_ModuleFile)
174 D.Diag(diag::err_drv_no_module_support)
175 << HTC.getTripleString();
178 CmdArgs.push_back(II.getFilename());
180 // Don't render as input, we need gcc to do the translations.
181 // FIXME: What is this?
182 II.getInputArg().render(Args, CmdArgs);
185 auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
186 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
189 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
190 ArgStringList &CmdArgs) const {
194 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
195 const toolchains::HexagonToolChain &HTC,
196 const InputInfo &Output, const InputInfoList &Inputs,
197 const ArgList &Args, ArgStringList &CmdArgs,
198 const char *LinkingOutput) {
200 const Driver &D = HTC.getDriver();
202 //----------------------------------------------------------------------------
204 //----------------------------------------------------------------------------
205 bool IsStatic = Args.hasArg(options::OPT_static);
206 bool IsShared = Args.hasArg(options::OPT_shared);
207 bool IsPIE = Args.hasArg(options::OPT_pie);
208 bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
209 bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
210 bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
212 bool UseShared = IsShared && !IsStatic;
214 //----------------------------------------------------------------------------
215 // Silence warnings for various options
216 //----------------------------------------------------------------------------
217 Args.ClaimAllArgs(options::OPT_g_Group);
218 Args.ClaimAllArgs(options::OPT_emit_llvm);
219 Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
220 // handled somewhere else.
221 Args.ClaimAllArgs(options::OPT_static_libgcc);
223 //----------------------------------------------------------------------------
225 //----------------------------------------------------------------------------
226 if (Args.hasArg(options::OPT_s))
227 CmdArgs.push_back("-s");
229 if (Args.hasArg(options::OPT_r))
230 CmdArgs.push_back("-r");
232 for (const auto &Opt : HTC.ExtraOpts)
233 CmdArgs.push_back(Opt.c_str());
235 CmdArgs.push_back("-march=hexagon");
236 StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
237 CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
240 CmdArgs.push_back("-shared");
241 // The following should be the default, but doing as hexagon-gcc does.
242 CmdArgs.push_back("-call_shared");
246 CmdArgs.push_back("-static");
248 if (IsPIE && !IsShared)
249 CmdArgs.push_back("-pie");
251 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
252 CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
253 UseG0 = G.getValue() == 0;
256 //----------------------------------------------------------------------------
258 //----------------------------------------------------------------------------
259 CmdArgs.push_back("-o");
260 CmdArgs.push_back(Output.getFilename());
262 //----------------------------------------------------------------------------
264 //----------------------------------------------------------------------------
265 std::vector<std::string> OsLibs;
266 bool HasStandalone = false;
268 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
270 OsLibs.emplace_back(A->getValue());
271 HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
273 if (OsLibs.empty()) {
274 OsLibs.push_back("standalone");
275 HasStandalone = true;
278 //----------------------------------------------------------------------------
280 //----------------------------------------------------------------------------
281 const std::string MCpuSuffix = "/" + CpuVer.str();
282 const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
283 const std::string RootDir =
284 HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
285 const std::string StartSubDir =
286 "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
288 auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
289 const char *Name) -> std::string {
290 std::string RelName = SubDir + Name;
291 std::string P = HTC.GetFilePath(RelName.c_str());
292 if (llvm::sys::fs::exists(P))
294 return RootDir + RelName;
297 if (IncStdLib && IncStartFiles) {
300 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
301 CmdArgs.push_back(Args.MakeArgString(Crt0SA));
303 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
304 CmdArgs.push_back(Args.MakeArgString(Crt0));
306 std::string Init = UseShared
307 ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
308 : Find(RootDir, StartSubDir, "/init.o");
309 CmdArgs.push_back(Args.MakeArgString(Init));
312 //----------------------------------------------------------------------------
313 // Library Search Paths
314 //----------------------------------------------------------------------------
315 const ToolChain::path_list &LibPaths = HTC.getFilePaths();
316 for (const auto &LibPath : LibPaths)
317 CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
319 //----------------------------------------------------------------------------
321 //----------------------------------------------------------------------------
322 Args.AddAllArgs(CmdArgs,
323 {options::OPT_T_Group, options::OPT_e, options::OPT_s,
324 options::OPT_t, options::OPT_u_Group});
326 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
328 //----------------------------------------------------------------------------
330 //----------------------------------------------------------------------------
331 if (IncStdLib && IncDefLibs) {
333 if (HTC.ShouldLinkCXXStdlib(Args))
334 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
335 CmdArgs.push_back("-lm");
338 CmdArgs.push_back("--start-group");
341 for (StringRef Lib : OsLibs)
342 CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
343 CmdArgs.push_back("-lc");
345 CmdArgs.push_back("-lgcc");
347 CmdArgs.push_back("--end-group");
350 //----------------------------------------------------------------------------
352 //----------------------------------------------------------------------------
353 if (IncStdLib && IncStartFiles) {
354 std::string Fini = UseShared
355 ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
356 : Find(RootDir, StartSubDir, "/fini.o");
357 CmdArgs.push_back(Args.MakeArgString(Fini));
361 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
362 const InputInfo &Output,
363 const InputInfoList &Inputs,
365 const char *LinkingOutput) const {
366 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
368 ArgStringList CmdArgs;
369 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
372 std::string Linker = HTC.GetProgramPath("hexagon-link");
373 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
376 // Hexagon tools end.
378 /// Hexagon Toolchain
380 std::string HexagonToolChain::getHexagonTargetDir(
381 const std::string &InstalledDir,
382 const SmallVectorImpl<std::string> &PrefixDirs) const {
383 std::string InstallRelDir;
384 const Driver &D = getDriver();
386 // Locate the rest of the toolchain ...
387 for (auto &I : PrefixDirs)
388 if (D.getVFS().exists(I))
391 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
392 return InstallRelDir;
397 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
398 const ArgList &Args) {
400 if (Arg *A = Args.getLastArg(options::OPT_G)) {
402 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
403 options::OPT_fPIC)) {
408 if (!Gn.getAsInteger(10, G))
414 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
415 ToolChain::path_list &LibPaths) const {
416 const Driver &D = getDriver();
418 //----------------------------------------------------------------------------
420 //----------------------------------------------------------------------------
421 for (Arg *A : Args.filtered(options::OPT_L))
422 for (const char *Value : A->getValues())
423 LibPaths.push_back(Value);
425 //----------------------------------------------------------------------------
426 // Other standard paths
427 //----------------------------------------------------------------------------
428 std::vector<std::string> RootDirs;
429 std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
430 std::back_inserter(RootDirs));
432 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
434 if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
435 RootDirs.push_back(TargetDir);
437 bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
438 // Assume G0 with -shared.
439 bool HasG0 = Args.hasArg(options::OPT_shared);
440 if (auto G = getSmallDataThreshold(Args))
441 HasG0 = G.getValue() == 0;
443 const std::string CpuVer = GetTargetCPUVersion(Args).str();
444 for (auto &Dir : RootDirs) {
445 std::string LibDir = Dir + "/hexagon/lib";
446 std::string LibDirCpu = LibDir + '/' + CpuVer;
449 LibPaths.push_back(LibDirCpu + "/G0/pic");
450 LibPaths.push_back(LibDirCpu + "/G0");
452 LibPaths.push_back(LibDirCpu);
453 LibPaths.push_back(LibDir);
457 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
458 const llvm::opt::ArgList &Args)
459 : Linux(D, Triple, Args) {
460 const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
463 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
465 const std::string BinDir(TargetDir + "/bin");
466 if (D.getVFS().exists(BinDir))
467 getProgramPaths().push_back(BinDir);
469 ToolChain::path_list &LibPaths = getFilePaths();
471 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
472 // 'elf' OS type, so the Linux paths are not appropriate. When we actually
473 // support 'linux' we'll need to fix this up
475 getHexagonLibraryPaths(Args, LibPaths);
478 HexagonToolChain::~HexagonToolChain() {}
480 Tool *HexagonToolChain::buildAssembler() const {
481 return new tools::hexagon::Assembler(*this);
484 Tool *HexagonToolChain::buildLinker() const {
485 return new tools::hexagon::Linker(*this);
488 unsigned HexagonToolChain::getOptimizationLevel(
489 const llvm::opt::ArgList &DriverArgs) const {
490 // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
491 Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
495 if (A->getOption().matches(options::OPT_O0))
497 if (A->getOption().matches(options::OPT_Ofast) ||
498 A->getOption().matches(options::OPT_O4))
500 assert(A->getNumValues() != 0);
501 StringRef S(A->getValue());
502 if (S == "s" || S == "z" || S.empty())
508 if (S.getAsInteger(10, OptLevel))
513 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
514 ArgStringList &CC1Args,
515 Action::OffloadKind) const {
516 if (!DriverArgs.hasArg(options::OPT_ffp_contract)) {
517 unsigned OptLevel = getOptimizationLevel(DriverArgs);
519 CC1Args.push_back("-ffp-contract=fast");
521 if (DriverArgs.hasArg(options::OPT_ffixed_r19)) {
522 CC1Args.push_back("-target-feature");
523 CC1Args.push_back("+reserved-r19");
525 if (isAutoHVXEnabled(DriverArgs)) {
526 CC1Args.push_back("-mllvm");
527 CC1Args.push_back("-hexagon-autohvx");
531 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
532 ArgStringList &CC1Args) const {
533 if (DriverArgs.hasArg(options::OPT_nostdinc) ||
534 DriverArgs.hasArg(options::OPT_nostdlibinc))
537 const Driver &D = getDriver();
538 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
540 addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
544 void HexagonToolChain::addLibStdCxxIncludePaths(
545 const llvm::opt::ArgList &DriverArgs,
546 llvm::opt::ArgStringList &CC1Args) const {
547 const Driver &D = getDriver();
548 std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
549 addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
550 DriverArgs, CC1Args);
553 ToolChain::CXXStdlibType
554 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
555 Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
557 return ToolChain::CST_Libstdcxx;
559 StringRef Value = A->getValue();
560 if (Value != "libstdc++")
561 getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
563 return ToolChain::CST_Libstdcxx;
566 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
567 if (Arg *A = Args.getLastArg(options::OPT_fvectorize,
568 options::OPT_fno_vectorize))
569 return A->getOption().matches(options::OPT_fvectorize);
574 // Returns the default CPU for Hexagon. This is the default compilation target
575 // if no Hexagon processor is selected at the command-line.
577 const StringRef HexagonToolChain::GetDefaultCPU() {
581 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
582 Arg *CpuArg = nullptr;
583 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
586 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
587 if (CPU.startswith("hexagon"))
588 return CPU.substr(sizeof("hexagon") - 1);