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 // Hexagon tools start.
31 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
32 ArgStringList &CmdArgs) const {
35 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
36 const InputInfo &Output,
37 const InputInfoList &Inputs,
39 const char *LinkingOutput) const {
40 claimNoWarnArgs(Args);
42 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
43 const Driver &D = HTC.getDriver();
44 ArgStringList CmdArgs;
46 std::string MArchString = "-march=hexagon";
47 CmdArgs.push_back(Args.MakeArgString(MArchString));
49 RenderExtraToolArgs(JA, CmdArgs);
51 std::string AsName = "hexagon-llvm-mc";
52 std::string MCpuString = "-mcpu=hexagon" +
53 toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
54 CmdArgs.push_back("-filetype=obj");
55 CmdArgs.push_back(Args.MakeArgString(MCpuString));
57 if (Output.isFilename()) {
58 CmdArgs.push_back("-o");
59 CmdArgs.push_back(Output.getFilename());
61 assert(Output.isNothing() && "Unexpected output");
62 CmdArgs.push_back("-fsyntax-only");
65 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
66 std::string N = llvm::utostr(G.getValue());
67 CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N));
70 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
72 // Only pass -x if gcc will understand it; otherwise hope gcc
73 // understands the suffix correctly. The main use case this would go
74 // wrong in is for linker inputs if they happened to have an odd
75 // suffix; really the only way to get this to happen is a command
76 // like '-x foobar a.c' which will treat a.c like a linker input.
78 // FIXME: For the linker case specifically, can we safely convert
79 // inputs into '-Wl,' options?
80 for (const auto &II : Inputs) {
81 // Don't try to pass LLVM or AST inputs to a generic gcc.
82 if (types::isLLVMIR(II.getType()))
83 D.Diag(clang::diag::err_drv_no_linker_llvm_support)
84 << HTC.getTripleString();
85 else if (II.getType() == types::TY_AST)
86 D.Diag(clang::diag::err_drv_no_ast_support)
87 << HTC.getTripleString();
88 else if (II.getType() == types::TY_ModuleFile)
89 D.Diag(diag::err_drv_no_module_support)
90 << HTC.getTripleString();
93 CmdArgs.push_back(II.getFilename());
95 // Don't render as input, we need gcc to do the translations.
96 // FIXME: What is this?
97 II.getInputArg().render(Args, CmdArgs);
100 auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
101 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
104 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
105 ArgStringList &CmdArgs) const {
109 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
110 const toolchains::HexagonToolChain &HTC,
111 const InputInfo &Output, const InputInfoList &Inputs,
112 const ArgList &Args, ArgStringList &CmdArgs,
113 const char *LinkingOutput) {
115 const Driver &D = HTC.getDriver();
117 //----------------------------------------------------------------------------
119 //----------------------------------------------------------------------------
120 bool IsStatic = Args.hasArg(options::OPT_static);
121 bool IsShared = Args.hasArg(options::OPT_shared);
122 bool IsPIE = Args.hasArg(options::OPT_pie);
123 bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
124 bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
125 bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
127 bool UseShared = IsShared && !IsStatic;
129 //----------------------------------------------------------------------------
130 // Silence warnings for various options
131 //----------------------------------------------------------------------------
132 Args.ClaimAllArgs(options::OPT_g_Group);
133 Args.ClaimAllArgs(options::OPT_emit_llvm);
134 Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
135 // handled somewhere else.
136 Args.ClaimAllArgs(options::OPT_static_libgcc);
138 //----------------------------------------------------------------------------
140 //----------------------------------------------------------------------------
141 if (Args.hasArg(options::OPT_s))
142 CmdArgs.push_back("-s");
144 if (Args.hasArg(options::OPT_r))
145 CmdArgs.push_back("-r");
147 for (const auto &Opt : HTC.ExtraOpts)
148 CmdArgs.push_back(Opt.c_str());
150 CmdArgs.push_back("-march=hexagon");
152 toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
153 std::string MCpuString = "-mcpu=hexagon" + CpuVer;
154 CmdArgs.push_back(Args.MakeArgString(MCpuString));
157 CmdArgs.push_back("-shared");
158 // The following should be the default, but doing as hexagon-gcc does.
159 CmdArgs.push_back("-call_shared");
163 CmdArgs.push_back("-static");
165 if (IsPIE && !IsShared)
166 CmdArgs.push_back("-pie");
168 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
169 std::string N = llvm::utostr(G.getValue());
170 CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N));
171 UseG0 = G.getValue() == 0;
174 //----------------------------------------------------------------------------
176 //----------------------------------------------------------------------------
177 CmdArgs.push_back("-o");
178 CmdArgs.push_back(Output.getFilename());
180 //----------------------------------------------------------------------------
182 //----------------------------------------------------------------------------
183 std::vector<std::string> OsLibs;
184 bool HasStandalone = false;
186 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
188 OsLibs.emplace_back(A->getValue());
189 HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
191 if (OsLibs.empty()) {
192 OsLibs.push_back("standalone");
193 HasStandalone = true;
196 //----------------------------------------------------------------------------
198 //----------------------------------------------------------------------------
199 const std::string MCpuSuffix = "/" + CpuVer;
200 const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
201 const std::string RootDir =
202 HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
203 const std::string StartSubDir =
204 "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
206 auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
207 const char *Name) -> std::string {
208 std::string RelName = SubDir + Name;
209 std::string P = HTC.GetFilePath(RelName.c_str());
210 if (llvm::sys::fs::exists(P))
212 return RootDir + RelName;
215 if (IncStdLib && IncStartFiles) {
218 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
219 CmdArgs.push_back(Args.MakeArgString(Crt0SA));
221 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
222 CmdArgs.push_back(Args.MakeArgString(Crt0));
224 std::string Init = UseShared
225 ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
226 : Find(RootDir, StartSubDir, "/init.o");
227 CmdArgs.push_back(Args.MakeArgString(Init));
230 //----------------------------------------------------------------------------
231 // Library Search Paths
232 //----------------------------------------------------------------------------
233 const ToolChain::path_list &LibPaths = HTC.getFilePaths();
234 for (const auto &LibPath : LibPaths)
235 CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
237 //----------------------------------------------------------------------------
239 //----------------------------------------------------------------------------
240 Args.AddAllArgs(CmdArgs,
241 {options::OPT_T_Group, options::OPT_e, options::OPT_s,
242 options::OPT_t, options::OPT_u_Group});
244 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
246 //----------------------------------------------------------------------------
248 //----------------------------------------------------------------------------
249 if (IncStdLib && IncDefLibs) {
251 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
252 CmdArgs.push_back("-lm");
255 CmdArgs.push_back("--start-group");
258 for (const std::string &Lib : OsLibs)
259 CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
260 CmdArgs.push_back("-lc");
262 CmdArgs.push_back("-lgcc");
264 CmdArgs.push_back("--end-group");
267 //----------------------------------------------------------------------------
269 //----------------------------------------------------------------------------
270 if (IncStdLib && IncStartFiles) {
271 std::string Fini = UseShared
272 ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
273 : Find(RootDir, StartSubDir, "/fini.o");
274 CmdArgs.push_back(Args.MakeArgString(Fini));
278 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
279 const InputInfo &Output,
280 const InputInfoList &Inputs,
282 const char *LinkingOutput) const {
283 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
285 ArgStringList CmdArgs;
286 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
289 std::string Linker = HTC.GetProgramPath("hexagon-link");
290 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
293 // Hexagon tools end.
295 /// Hexagon Toolchain
297 std::string HexagonToolChain::getHexagonTargetDir(
298 const std::string &InstalledDir,
299 const SmallVectorImpl<std::string> &PrefixDirs) const {
300 std::string InstallRelDir;
301 const Driver &D = getDriver();
303 // Locate the rest of the toolchain ...
304 for (auto &I : PrefixDirs)
305 if (D.getVFS().exists(I))
308 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
309 return InstallRelDir;
314 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
315 const ArgList &Args) {
317 if (Arg *A = Args.getLastArg(options::OPT_G)) {
319 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
320 options::OPT_fPIC)) {
325 if (!Gn.getAsInteger(10, G))
331 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
332 ToolChain::path_list &LibPaths) const {
333 const Driver &D = getDriver();
335 //----------------------------------------------------------------------------
337 //----------------------------------------------------------------------------
338 for (Arg *A : Args.filtered(options::OPT_L))
339 for (const char *Value : A->getValues())
340 LibPaths.push_back(Value);
342 //----------------------------------------------------------------------------
343 // Other standard paths
344 //----------------------------------------------------------------------------
345 std::vector<std::string> RootDirs;
346 std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
347 std::back_inserter(RootDirs));
349 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
351 if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
352 RootDirs.push_back(TargetDir);
354 bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
355 // Assume G0 with -shared.
356 bool HasG0 = Args.hasArg(options::OPT_shared);
357 if (auto G = getSmallDataThreshold(Args))
358 HasG0 = G.getValue() == 0;
360 const std::string CpuVer = GetTargetCPUVersion(Args).str();
361 for (auto &Dir : RootDirs) {
362 std::string LibDir = Dir + "/hexagon/lib";
363 std::string LibDirCpu = LibDir + '/' + CpuVer;
366 LibPaths.push_back(LibDirCpu + "/G0/pic");
367 LibPaths.push_back(LibDirCpu + "/G0");
369 LibPaths.push_back(LibDirCpu);
370 LibPaths.push_back(LibDir);
374 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
375 const llvm::opt::ArgList &Args)
376 : Linux(D, Triple, Args) {
377 const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
380 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
382 const std::string BinDir(TargetDir + "/bin");
383 if (D.getVFS().exists(BinDir))
384 getProgramPaths().push_back(BinDir);
386 ToolChain::path_list &LibPaths = getFilePaths();
388 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
389 // 'elf' OS type, so the Linux paths are not appropriate. When we actually
390 // support 'linux' we'll need to fix this up
392 getHexagonLibraryPaths(Args, LibPaths);
395 HexagonToolChain::~HexagonToolChain() {}
397 Tool *HexagonToolChain::buildAssembler() const {
398 return new tools::hexagon::Assembler(*this);
401 Tool *HexagonToolChain::buildLinker() const {
402 return new tools::hexagon::Linker(*this);
405 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
406 ArgStringList &CC1Args) const {
407 if (DriverArgs.hasArg(options::OPT_nostdinc) ||
408 DriverArgs.hasArg(options::OPT_nostdlibinc))
411 const Driver &D = getDriver();
412 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
414 addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
418 void HexagonToolChain::addLibStdCxxIncludePaths(
419 const llvm::opt::ArgList &DriverArgs,
420 llvm::opt::ArgStringList &CC1Args) const {
421 const Driver &D = getDriver();
422 std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
423 addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
424 DriverArgs, CC1Args);
427 ToolChain::CXXStdlibType
428 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
429 Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
431 return ToolChain::CST_Libstdcxx;
433 StringRef Value = A->getValue();
434 if (Value != "libstdc++")
435 getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
437 return ToolChain::CST_Libstdcxx;
441 // Returns the default CPU for Hexagon. This is the default compilation target
442 // if no Hexagon processor is selected at the command-line.
444 const StringRef HexagonToolChain::GetDefaultCPU() {
448 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
449 Arg *CpuArg = nullptr;
450 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
453 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
454 if (CPU.startswith("hexagon"))
455 return CPU.substr(sizeof("hexagon") - 1);