blob: b1e65bf2fb181962c01eaf528e22a32e778911ac [file] [log] [blame]
David L. Jonesf561aba2017-03-08 01:02:16 +00001//===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Hexagon.h"
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"
23
24using namespace clang::driver;
25using namespace clang::driver::tools;
26using namespace clang::driver::toolchains;
27using namespace clang;
28using namespace llvm::opt;
29
30// Hexagon tools start.
31void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
32 ArgStringList &CmdArgs) const {
33}
34
35void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
36 const InputInfo &Output,
37 const InputInfoList &Inputs,
38 const ArgList &Args,
39 const char *LinkingOutput) const {
40 claimNoWarnArgs(Args);
41
42 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
43 const Driver &D = HTC.getDriver();
44 ArgStringList CmdArgs;
45
46 std::string MArchString = "-march=hexagon";
47 CmdArgs.push_back(Args.MakeArgString(MArchString));
48
49 RenderExtraToolArgs(JA, CmdArgs);
50
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));
56
57 if (Output.isFilename()) {
58 CmdArgs.push_back("-o");
59 CmdArgs.push_back(Output.getFilename());
60 } else {
61 assert(Output.isNothing() && "Unexpected output");
62 CmdArgs.push_back("-fsyntax-only");
63 }
64
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));
68 }
69
70 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
71
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.
77 //
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();
91
92 if (II.isFilename())
93 CmdArgs.push_back(II.getFilename());
94 else
95 // Don't render as input, we need gcc to do the translations.
96 // FIXME: What is this?
97 II.getInputArg().render(Args, CmdArgs);
98 }
99
100 auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
101 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
102}
103
104void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
105 ArgStringList &CmdArgs) const {
106}
107
108static void
109constructHexagonLinkArgs(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) {
114
115 const Driver &D = HTC.getDriver();
116
117 //----------------------------------------------------------------------------
118 //
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);
126 bool UseG0 = false;
127 bool UseShared = IsShared && !IsStatic;
128
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);
137
138 //----------------------------------------------------------------------------
139 //
140 //----------------------------------------------------------------------------
141 if (Args.hasArg(options::OPT_s))
142 CmdArgs.push_back("-s");
143
144 if (Args.hasArg(options::OPT_r))
145 CmdArgs.push_back("-r");
146
147 for (const auto &Opt : HTC.ExtraOpts)
148 CmdArgs.push_back(Opt.c_str());
149
150 CmdArgs.push_back("-march=hexagon");
151 std::string CpuVer =
152 toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
153 std::string MCpuString = "-mcpu=hexagon" + CpuVer;
154 CmdArgs.push_back(Args.MakeArgString(MCpuString));
155
156 if (IsShared) {
157 CmdArgs.push_back("-shared");
158 // The following should be the default, but doing as hexagon-gcc does.
159 CmdArgs.push_back("-call_shared");
160 }
161
162 if (IsStatic)
163 CmdArgs.push_back("-static");
164
165 if (IsPIE && !IsShared)
166 CmdArgs.push_back("-pie");
167
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;
172 }
173
174 //----------------------------------------------------------------------------
175 //
176 //----------------------------------------------------------------------------
177 CmdArgs.push_back("-o");
178 CmdArgs.push_back(Output.getFilename());
179
180 //----------------------------------------------------------------------------
181 // moslib
182 //----------------------------------------------------------------------------
183 std::vector<std::string> OsLibs;
184 bool HasStandalone = false;
185
186 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
187 A->claim();
188 OsLibs.emplace_back(A->getValue());
189 HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
190 }
191 if (OsLibs.empty()) {
192 OsLibs.push_back("standalone");
193 HasStandalone = true;
194 }
195
196 //----------------------------------------------------------------------------
197 // Start Files
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);
205
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))
211 return P;
212 return RootDir + RelName;
213 };
214
215 if (IncStdLib && IncStartFiles) {
216 if (!IsShared) {
217 if (HasStandalone) {
218 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
219 CmdArgs.push_back(Args.MakeArgString(Crt0SA));
220 }
221 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
222 CmdArgs.push_back(Args.MakeArgString(Crt0));
223 }
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));
228 }
229
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));
236
237 //----------------------------------------------------------------------------
238 //
239 //----------------------------------------------------------------------------
240 Args.AddAllArgs(CmdArgs,
241 {options::OPT_T_Group, options::OPT_e, options::OPT_s,
242 options::OPT_t, options::OPT_u_Group});
243
244 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
245
246 //----------------------------------------------------------------------------
247 // Libraries
248 //----------------------------------------------------------------------------
249 if (IncStdLib && IncDefLibs) {
250 if (D.CCCIsCXX()) {
251 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
252 CmdArgs.push_back("-lm");
253 }
254
255 CmdArgs.push_back("--start-group");
256
257 if (!IsShared) {
258 for (const std::string &Lib : OsLibs)
259 CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
260 CmdArgs.push_back("-lc");
261 }
262 CmdArgs.push_back("-lgcc");
263
264 CmdArgs.push_back("--end-group");
265 }
266
267 //----------------------------------------------------------------------------
268 // End files
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));
275 }
276}
277
278void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
279 const InputInfo &Output,
280 const InputInfoList &Inputs,
281 const ArgList &Args,
282 const char *LinkingOutput) const {
283 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
284
285 ArgStringList CmdArgs;
286 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
287 LinkingOutput);
288
289 std::string Linker = HTC.GetProgramPath("hexagon-link");
290 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
291 CmdArgs, Inputs));
292}
293// Hexagon tools end.
294
295/// Hexagon Toolchain
296
297std::string HexagonToolChain::getHexagonTargetDir(
298 const std::string &InstalledDir,
299 const SmallVectorImpl<std::string> &PrefixDirs) const {
300 std::string InstallRelDir;
301 const Driver &D = getDriver();
302
303 // Locate the rest of the toolchain ...
304 for (auto &I : PrefixDirs)
305 if (D.getVFS().exists(I))
306 return I;
307
308 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
309 return InstallRelDir;
310
311 return InstalledDir;
312}
313
314Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
315 const ArgList &Args) {
316 StringRef Gn = "";
317 if (Arg *A = Args.getLastArg(options::OPT_G)) {
318 Gn = A->getValue();
319 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
320 options::OPT_fPIC)) {
321 Gn = "0";
322 }
323
324 unsigned G;
325 if (!Gn.getAsInteger(10, G))
326 return G;
327
328 return None;
329}
330
331void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
332 ToolChain::path_list &LibPaths) const {
333 const Driver &D = getDriver();
334
335 //----------------------------------------------------------------------------
336 // -L Args
337 //----------------------------------------------------------------------------
338 for (Arg *A : Args.filtered(options::OPT_L))
339 for (const char *Value : A->getValues())
340 LibPaths.push_back(Value);
341
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));
348
349 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
350 D.PrefixDirs);
351 if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
352 RootDirs.push_back(TargetDir);
353
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;
359
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;
364 if (HasG0) {
365 if (HasPIC)
366 LibPaths.push_back(LibDirCpu + "/G0/pic");
367 LibPaths.push_back(LibDirCpu + "/G0");
368 }
369 LibPaths.push_back(LibDirCpu);
370 LibPaths.push_back(LibDir);
371 }
372}
373
374HexagonToolChain::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(),
378 D.PrefixDirs);
379
380 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
381 // program paths
382 const std::string BinDir(TargetDir + "/bin");
383 if (D.getVFS().exists(BinDir))
384 getProgramPaths().push_back(BinDir);
385
386 ToolChain::path_list &LibPaths = getFilePaths();
387
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
391 LibPaths.clear();
392 getHexagonLibraryPaths(Args, LibPaths);
393}
394
395HexagonToolChain::~HexagonToolChain() {}
396
397Tool *HexagonToolChain::buildAssembler() const {
398 return new tools::hexagon::Assembler(*this);
399}
400
401Tool *HexagonToolChain::buildLinker() const {
402 return new tools::hexagon::Linker(*this);
403}
404
Krzysztof Parzyszekdcda9452017-04-25 20:51:51 +0000405unsigned HexagonToolChain::getOptimizationLevel(
406 const llvm::opt::ArgList &DriverArgs) const {
407 // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
408 Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
409 if (!A)
410 return 0;
411
412 if (A->getOption().matches(options::OPT_O0))
413 return 0;
414 if (A->getOption().matches(options::OPT_Ofast))
415 return 3;
416 assert(A->getNumValues() != 0);
417 StringRef S(A->getValue());
418 if (S == "s" || S == "z" || S.empty())
419 return 2;
420 if (S == "g")
421 return 1;
422
423 unsigned OptLevel;
424 if (S.getAsInteger(10, OptLevel))
425 return 0;
426 return OptLevel;
427}
428
429void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
430 ArgStringList &CC1Args) const {
431 if (DriverArgs.hasArg(options::OPT_ffp_contract))
432 return;
433 unsigned OptLevel = getOptimizationLevel(DriverArgs);
434 if (OptLevel >= 3)
435 CC1Args.push_back("-ffp-contract=fast");
436}
437
David L. Jonesf561aba2017-03-08 01:02:16 +0000438void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
439 ArgStringList &CC1Args) const {
440 if (DriverArgs.hasArg(options::OPT_nostdinc) ||
441 DriverArgs.hasArg(options::OPT_nostdlibinc))
442 return;
443
444 const Driver &D = getDriver();
445 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
446 D.PrefixDirs);
447 addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
448}
449
450
451void HexagonToolChain::addLibStdCxxIncludePaths(
452 const llvm::opt::ArgList &DriverArgs,
453 llvm::opt::ArgStringList &CC1Args) const {
454 const Driver &D = getDriver();
455 std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
456 addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
457 DriverArgs, CC1Args);
458}
459
460ToolChain::CXXStdlibType
461HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
462 Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
463 if (!A)
464 return ToolChain::CST_Libstdcxx;
465
466 StringRef Value = A->getValue();
467 if (Value != "libstdc++")
468 getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
469
470 return ToolChain::CST_Libstdcxx;
471}
472
473//
474// Returns the default CPU for Hexagon. This is the default compilation target
475// if no Hexagon processor is selected at the command-line.
476//
477const StringRef HexagonToolChain::GetDefaultCPU() {
478 return "hexagonv60";
479}
480
481const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
482 Arg *CpuArg = nullptr;
483 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
484 CpuArg = A;
485
486 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
487 if (CPU.startswith("hexagon"))
488 return CPU.substr(sizeof("hexagon") - 1);
489 return CPU;
490}