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/Config/config.h"
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/Option/ArgList.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/Path.h"
24 using namespace clang::driver;
25 using namespace clang::driver::tools;
26 using namespace clang::driver::toolchains;
27 using namespace clang;
28 using namespace llvm::opt;
30 // Default hvx-length for various versions.
31 static StringRef getDefaultHvxLength(StringRef Cpu) {
32 return llvm::StringSwitch<StringRef>(Cpu)
39 static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
40 // Handle deprecated HVX double warnings.
41 if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_double))
42 D.Diag(diag::warn_drv_deprecated_arg)
43 << A->getAsString(Args) << "-mhvx-length=128B";
44 if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx_double))
45 D.Diag(diag::warn_drv_deprecated_arg) << A->getAsString(Args) << "-mno-hvx";
46 // Handle the unsupported values passed to mhvx-length.
47 if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
48 StringRef Val = A->getValue();
49 if (!Val.equals_lower("64b") && !Val.equals_lower("128b"))
50 D.Diag(diag::err_drv_unsupported_option_argument)
51 << A->getOption().getName() << Val;
55 // Handle hvx target features explicitly.
56 static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
57 std::vector<StringRef> &Features,
59 // Handle HVX warnings.
60 handleHVXWarnings(D, Args);
62 // Add the +hvx* features based on commandline flags.
63 StringRef HVXFeature, HVXLength;
64 StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
66 // Handle -mhvx, -mhvx=, -mno-hvx, -mno-hvx-double.
67 if (Arg *A = Args.getLastArg(
68 options::OPT_mno_hexagon_hvx, options::OPT_mno_hexagon_hvx_double,
69 options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ)) {
70 if (A->getOption().matches(options::OPT_mno_hexagon_hvx) ||
71 A->getOption().matches(options::OPT_mno_hexagon_hvx_double)) {
73 } else if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
75 HVXFeature = Cpu = A->getValue();
76 HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
77 } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
79 HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
81 Features.push_back(HVXFeature);
84 // Handle -mhvx-length=, -mhvx-double.
85 if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ,
86 options::OPT_mhexagon_hvx_double)) {
87 // These falgs are valid only if HVX in enabled.
89 D.Diag(diag::err_drv_invalid_hvx_length);
90 else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
91 HVXLength = A->getValue();
92 else if (A->getOption().matches(options::OPT_mhexagon_hvx_double))
95 // Default hvx-length based on Cpu.
97 HVXLength = getDefaultHvxLength(Cpu);
99 if (!HVXLength.empty()) {
101 Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
102 Features.push_back(HVXFeature);
106 // Hexagon target features.
107 void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
108 std::vector<StringRef> &Features) {
109 handleTargetFeaturesGroup(Args, Features,
110 options::OPT_m_hexagon_Features_Group);
112 bool UseLongCalls = false;
113 if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
114 options::OPT_mno_long_calls)) {
115 if (A->getOption().matches(options::OPT_mlong_calls))
119 Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
122 handleHVXTargetFeatures(D, Args, Features, HasHVX);
125 // Hexagon tools start.
126 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
127 ArgStringList &CmdArgs) const {
130 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
131 const InputInfo &Output,
132 const InputInfoList &Inputs,
134 const char *LinkingOutput) const {
135 claimNoWarnArgs(Args);
137 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
138 const Driver &D = HTC.getDriver();
139 ArgStringList CmdArgs;
141 CmdArgs.push_back("-march=hexagon");
143 RenderExtraToolArgs(JA, CmdArgs);
145 const char *AsName = "hexagon-llvm-mc";
146 CmdArgs.push_back("-filetype=obj");
147 CmdArgs.push_back(Args.MakeArgString(
149 toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
151 if (Output.isFilename()) {
152 CmdArgs.push_back("-o");
153 CmdArgs.push_back(Output.getFilename());
155 assert(Output.isNothing() && "Unexpected output");
156 CmdArgs.push_back("-fsyntax-only");
159 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
160 CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
163 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
165 // Only pass -x if gcc will understand it; otherwise hope gcc
166 // understands the suffix correctly. The main use case this would go
167 // wrong in is for linker inputs if they happened to have an odd
168 // suffix; really the only way to get this to happen is a command
169 // like '-x foobar a.c' which will treat a.c like a linker input.
171 // FIXME: For the linker case specifically, can we safely convert
172 // inputs into '-Wl,' options?
173 for (const auto &II : Inputs) {
174 // Don't try to pass LLVM or AST inputs to a generic gcc.
175 if (types::isLLVMIR(II.getType()))
176 D.Diag(clang::diag::err_drv_no_linker_llvm_support)
177 << HTC.getTripleString();
178 else if (II.getType() == types::TY_AST)
179 D.Diag(clang::diag::err_drv_no_ast_support)
180 << HTC.getTripleString();
181 else if (II.getType() == types::TY_ModuleFile)
182 D.Diag(diag::err_drv_no_module_support)
183 << HTC.getTripleString();
186 CmdArgs.push_back(II.getFilename());
188 // Don't render as input, we need gcc to do the translations.
189 // FIXME: What is this?
190 II.getInputArg().render(Args, CmdArgs);
193 auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
194 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
197 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
198 ArgStringList &CmdArgs) const {
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) {
208 const Driver &D = HTC.getDriver();
210 //----------------------------------------------------------------------------
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);
220 bool UseShared = IsShared && !IsStatic;
222 //----------------------------------------------------------------------------
223 // Silence warnings for various options
224 //----------------------------------------------------------------------------
225 Args.ClaimAllArgs(options::OPT_g_Group);
226 Args.ClaimAllArgs(options::OPT_emit_llvm);
227 Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
228 // handled somewhere else.
229 Args.ClaimAllArgs(options::OPT_static_libgcc);
231 //----------------------------------------------------------------------------
233 //----------------------------------------------------------------------------
234 if (Args.hasArg(options::OPT_s))
235 CmdArgs.push_back("-s");
237 if (Args.hasArg(options::OPT_r))
238 CmdArgs.push_back("-r");
240 for (const auto &Opt : HTC.ExtraOpts)
241 CmdArgs.push_back(Opt.c_str());
243 CmdArgs.push_back("-march=hexagon");
244 StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
245 CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
248 CmdArgs.push_back("-shared");
249 // The following should be the default, but doing as hexagon-gcc does.
250 CmdArgs.push_back("-call_shared");
254 CmdArgs.push_back("-static");
256 if (IsPIE && !IsShared)
257 CmdArgs.push_back("-pie");
259 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
260 CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
261 UseG0 = G.getValue() == 0;
264 //----------------------------------------------------------------------------
266 //----------------------------------------------------------------------------
267 CmdArgs.push_back("-o");
268 CmdArgs.push_back(Output.getFilename());
270 //----------------------------------------------------------------------------
272 //----------------------------------------------------------------------------
273 std::vector<std::string> OsLibs;
274 bool HasStandalone = false;
276 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
278 OsLibs.emplace_back(A->getValue());
279 HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
281 if (OsLibs.empty()) {
282 OsLibs.push_back("standalone");
283 HasStandalone = true;
286 //----------------------------------------------------------------------------
288 //----------------------------------------------------------------------------
289 const std::string MCpuSuffix = "/" + CpuVer.str();
290 const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
291 const std::string RootDir =
292 HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
293 const std::string StartSubDir =
294 "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
296 auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
297 const char *Name) -> std::string {
298 std::string RelName = SubDir + Name;
299 std::string P = HTC.GetFilePath(RelName.c_str());
300 if (llvm::sys::fs::exists(P))
302 return RootDir + RelName;
305 if (IncStdLib && IncStartFiles) {
308 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
309 CmdArgs.push_back(Args.MakeArgString(Crt0SA));
311 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
312 CmdArgs.push_back(Args.MakeArgString(Crt0));
314 std::string Init = UseShared
315 ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
316 : Find(RootDir, StartSubDir, "/init.o");
317 CmdArgs.push_back(Args.MakeArgString(Init));
320 //----------------------------------------------------------------------------
321 // Library Search Paths
322 //----------------------------------------------------------------------------
323 const ToolChain::path_list &LibPaths = HTC.getFilePaths();
324 for (const auto &LibPath : LibPaths)
325 CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
327 //----------------------------------------------------------------------------
329 //----------------------------------------------------------------------------
330 Args.AddAllArgs(CmdArgs,
331 {options::OPT_T_Group, options::OPT_e, options::OPT_s,
332 options::OPT_t, options::OPT_u_Group});
334 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
336 //----------------------------------------------------------------------------
338 //----------------------------------------------------------------------------
339 if (IncStdLib && IncDefLibs) {
341 if (HTC.ShouldLinkCXXStdlib(Args))
342 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
343 CmdArgs.push_back("-lm");
346 CmdArgs.push_back("--start-group");
349 for (StringRef Lib : OsLibs)
350 CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
351 CmdArgs.push_back("-lc");
353 CmdArgs.push_back("-lgcc");
355 CmdArgs.push_back("--end-group");
358 //----------------------------------------------------------------------------
360 //----------------------------------------------------------------------------
361 if (IncStdLib && IncStartFiles) {
362 std::string Fini = UseShared
363 ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
364 : Find(RootDir, StartSubDir, "/fini.o");
365 CmdArgs.push_back(Args.MakeArgString(Fini));
369 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
370 const InputInfo &Output,
371 const InputInfoList &Inputs,
373 const char *LinkingOutput) const {
374 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
376 ArgStringList CmdArgs;
377 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
380 std::string Linker = HTC.GetProgramPath("hexagon-link");
381 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
384 // Hexagon tools end.
386 /// Hexagon Toolchain
388 std::string HexagonToolChain::getHexagonTargetDir(
389 const std::string &InstalledDir,
390 const SmallVectorImpl<std::string> &PrefixDirs) const {
391 std::string InstallRelDir;
392 const Driver &D = getDriver();
394 // Locate the rest of the toolchain ...
395 for (auto &I : PrefixDirs)
396 if (D.getVFS().exists(I))
399 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
400 return InstallRelDir;
405 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
406 const ArgList &Args) {
408 if (Arg *A = Args.getLastArg(options::OPT_G)) {
410 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
411 options::OPT_fPIC)) {
416 if (!Gn.getAsInteger(10, G))
422 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
423 ToolChain::path_list &LibPaths) const {
424 const Driver &D = getDriver();
426 //----------------------------------------------------------------------------
428 //----------------------------------------------------------------------------
429 for (Arg *A : Args.filtered(options::OPT_L))
430 for (const char *Value : A->getValues())
431 LibPaths.push_back(Value);
433 //----------------------------------------------------------------------------
434 // Other standard paths
435 //----------------------------------------------------------------------------
436 std::vector<std::string> RootDirs;
437 std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
438 std::back_inserter(RootDirs));
440 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
442 if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
443 RootDirs.push_back(TargetDir);
445 bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
446 // Assume G0 with -shared.
447 bool HasG0 = Args.hasArg(options::OPT_shared);
448 if (auto G = getSmallDataThreshold(Args))
449 HasG0 = G.getValue() == 0;
451 const std::string CpuVer = GetTargetCPUVersion(Args).str();
452 for (auto &Dir : RootDirs) {
453 std::string LibDir = Dir + "/hexagon/lib";
454 std::string LibDirCpu = LibDir + '/' + CpuVer;
457 LibPaths.push_back(LibDirCpu + "/G0/pic");
458 LibPaths.push_back(LibDirCpu + "/G0");
460 LibPaths.push_back(LibDirCpu);
461 LibPaths.push_back(LibDir);
465 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
466 const llvm::opt::ArgList &Args)
467 : Linux(D, Triple, Args) {
468 const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
471 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
473 const std::string BinDir(TargetDir + "/bin");
474 if (D.getVFS().exists(BinDir))
475 getProgramPaths().push_back(BinDir);
477 ToolChain::path_list &LibPaths = getFilePaths();
479 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
480 // 'elf' OS type, so the Linux paths are not appropriate. When we actually
481 // support 'linux' we'll need to fix this up
483 getHexagonLibraryPaths(Args, LibPaths);
486 HexagonToolChain::~HexagonToolChain() {}
488 Tool *HexagonToolChain::buildAssembler() const {
489 return new tools::hexagon::Assembler(*this);
492 Tool *HexagonToolChain::buildLinker() const {
493 return new tools::hexagon::Linker(*this);
496 unsigned HexagonToolChain::getOptimizationLevel(
497 const llvm::opt::ArgList &DriverArgs) const {
498 // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
499 Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
503 if (A->getOption().matches(options::OPT_O0))
505 if (A->getOption().matches(options::OPT_Ofast) ||
506 A->getOption().matches(options::OPT_O4))
508 assert(A->getNumValues() != 0);
509 StringRef S(A->getValue());
510 if (S == "s" || S == "z" || S.empty())
516 if (S.getAsInteger(10, OptLevel))
521 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
522 ArgStringList &CC1Args,
523 Action::OffloadKind) const {
524 if (DriverArgs.hasArg(options::OPT_ffp_contract))
526 unsigned OptLevel = getOptimizationLevel(DriverArgs);
528 CC1Args.push_back("-ffp-contract=fast");
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;
567 // Returns the default CPU for Hexagon. This is the default compilation target
568 // if no Hexagon processor is selected at the command-line.
570 const StringRef HexagonToolChain::GetDefaultCPU() {
574 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
575 Arg *CpuArg = nullptr;
576 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
579 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
580 if (CPU.startswith("hexagon"))
581 return CPU.substr(sizeof("hexagon") - 1);