/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp
Line | Count | Source (jump to first uncovered line) |
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 "clang/Driver/Compilation.h" |
12 | | #include "clang/Driver/Driver.h" |
13 | | #include "clang/Driver/DriverDiagnostic.h" |
14 | | #include "clang/Driver/InputInfo.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. |
29 | 137 | static StringRef getDefaultHvxLength(StringRef HvxVer) { |
30 | 137 | return llvm::StringSwitch<StringRef>(HvxVer) |
31 | 137 | .Case("v60", "64b") |
32 | 137 | .Case("v62", "64b") |
33 | 137 | .Case("v65", "64b") |
34 | 137 | .Default("128b"); |
35 | 137 | } |
36 | | |
37 | 137 | static void handleHVXWarnings(const Driver &D, const ArgList &Args) { |
38 | | // Handle the unsupported values passed to mhvx-length. |
39 | 137 | if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { |
40 | 7 | StringRef Val = A->getValue(); |
41 | 7 | if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b")5 ) |
42 | 2 | D.Diag(diag::err_drv_unsupported_option_argument) |
43 | 2 | << A->getSpelling() << Val; |
44 | 7 | } |
45 | 137 | } |
46 | | |
47 | | // Handle hvx target features explicitly. |
48 | | static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, |
49 | | std::vector<StringRef> &Features, |
50 | 137 | StringRef Cpu, bool &HasHVX) { |
51 | | // Handle HVX warnings. |
52 | 137 | handleHVXWarnings(D, Args); |
53 | | |
54 | 186 | auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef { |
55 | 186 | const std::string &S = T.str(); |
56 | 186 | StringRef Opt(S); |
57 | 186 | if (Opt.endswith("=")) |
58 | 0 | Opt = Opt.drop_back(1); |
59 | 186 | if (Opt.startswith("mno-")) |
60 | 10 | Opt = Opt.drop_front(4); |
61 | 176 | else if (Opt.startswith("m")) |
62 | 8 | Opt = Opt.drop_front(1); |
63 | 186 | return Args.MakeArgString(Twine(Enable ? "+"176 : "-"10 ) + Twine(Opt)); |
64 | 186 | }; |
65 | | |
66 | 137 | auto withMinus = [](StringRef S) -> std::string { |
67 | 12 | return "-" + S.str(); |
68 | 12 | }; |
69 | | |
70 | | // Drop tiny core suffix for HVX version. |
71 | 137 | std::string HvxVer = |
72 | 137 | (Cpu.back() == 'T' || Cpu.back() == 't' ? Cpu.drop_back(1)0 : Cpu).str(); |
73 | 137 | HasHVX = false; |
74 | | |
75 | | // Handle -mhvx, -mhvx=, -mno-hvx. If versioned and versionless flags |
76 | | // are both present, the last one wins. |
77 | 137 | Arg *HvxEnablingArg = |
78 | 137 | Args.getLastArg(options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ, |
79 | 137 | options::OPT_mno_hexagon_hvx); |
80 | 137 | if (HvxEnablingArg) { |
81 | 88 | if (HvxEnablingArg->getOption().matches(options::OPT_mno_hexagon_hvx)) |
82 | 4 | HvxEnablingArg = nullptr; |
83 | 88 | } |
84 | | |
85 | 137 | if (HvxEnablingArg) { |
86 | | // If -mhvx[=] was given, it takes precedence. |
87 | 84 | if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx, |
88 | 84 | options::OPT_mhexagon_hvx_EQ)) { |
89 | | // If the version was given, set HvxVer. Otherwise HvxVer |
90 | | // will remain equal to the CPU version. |
91 | 84 | if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) |
92 | 38 | HvxVer = StringRef(A->getValue()).lower(); |
93 | 84 | } |
94 | 84 | HasHVX = true; |
95 | 84 | Features.push_back(makeFeature(Twine("hvx") + HvxVer, true)); |
96 | 84 | } else if (Arg *53 A53 = Args.getLastArg(options::OPT_mno_hexagon_hvx)) { |
97 | | // If there was an explicit -mno-hvx, add -hvx to target features. |
98 | 4 | Features.push_back(makeFeature(A->getOption().getName(), false)); |
99 | 4 | } |
100 | | |
101 | 137 | StringRef HvxLen = getDefaultHvxLength(HvxVer); |
102 | | |
103 | | // Handle -mhvx-length=. |
104 | 137 | if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { |
105 | | // These flags are valid only if HVX in enabled. |
106 | 7 | if (!HasHVX) |
107 | 3 | D.Diag(diag::err_drv_needs_hvx) << withMinus(A->getOption().getName()); |
108 | 4 | else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ)) |
109 | 4 | HvxLen = A->getValue(); |
110 | 7 | } |
111 | | |
112 | 137 | if (HasHVX) { |
113 | 84 | StringRef L = makeFeature(Twine("hvx-length") + HvxLen.lower(), true); |
114 | 84 | Features.push_back(L); |
115 | 84 | } |
116 | | |
117 | 137 | unsigned HvxVerNum; |
118 | | // getAsInteger returns 'true' on error. |
119 | 137 | if (StringRef(HvxVer).drop_front(1).getAsInteger(10, HvxVerNum)) |
120 | 0 | HvxVerNum = 0; |
121 | | |
122 | | // Handle HVX floating point flags. |
123 | 137 | auto checkFlagHvxVersion = |
124 | 137 | [&](auto FlagOn, auto FlagOff, |
125 | 274 | unsigned MinVerNum) -> std::optional<StringRef> { |
126 | | // Return an std::optional<StringRef>: |
127 | | // - std::nullopt indicates a verification failure, or that the flag was not |
128 | | // present in Args. |
129 | | // - Otherwise the returned value is that name of the feature to add |
130 | | // to Features. |
131 | 274 | Arg *A = Args.getLastArg(FlagOn, FlagOff); |
132 | 274 | if (!A) |
133 | 251 | return std::nullopt; |
134 | | |
135 | 23 | StringRef OptName = A->getOption().getName(); |
136 | 23 | if (A->getOption().matches(FlagOff)) |
137 | 6 | return makeFeature(OptName, false); |
138 | | |
139 | 17 | if (!HasHVX) { |
140 | 5 | D.Diag(diag::err_drv_needs_hvx) << withMinus(OptName); |
141 | 5 | return std::nullopt; |
142 | 5 | } |
143 | 12 | if (HvxVerNum < MinVerNum) { |
144 | 4 | D.Diag(diag::err_drv_needs_hvx_version) |
145 | 4 | << withMinus(OptName) << ("v" + std::to_string(HvxVerNum)); |
146 | 4 | return std::nullopt; |
147 | 4 | } |
148 | 8 | return makeFeature(OptName, true); |
149 | 12 | }; |
150 | | |
151 | 137 | if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_qfloat, |
152 | 137 | options::OPT_mno_hexagon_hvx_qfloat, 68)) { |
153 | 7 | Features.push_back(*F); |
154 | 7 | } |
155 | 137 | if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_ieee_fp, |
156 | 137 | options::OPT_mno_hexagon_hvx_ieee_fp, 68)) { |
157 | 7 | Features.push_back(*F); |
158 | 7 | } |
159 | 137 | } |
160 | | |
161 | | // Hexagon target features. |
162 | | void hexagon::getHexagonTargetFeatures(const Driver &D, |
163 | | const llvm::Triple &Triple, |
164 | | const ArgList &Args, |
165 | 137 | std::vector<StringRef> &Features) { |
166 | 137 | handleTargetFeaturesGroup(D, Triple, Args, Features, |
167 | 137 | options::OPT_m_hexagon_Features_Group); |
168 | | |
169 | 137 | bool UseLongCalls = false; |
170 | 137 | if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, |
171 | 137 | options::OPT_mno_long_calls)) { |
172 | 2 | if (A->getOption().matches(options::OPT_mlong_calls)) |
173 | 1 | UseLongCalls = true; |
174 | 2 | } |
175 | | |
176 | 137 | Features.push_back(UseLongCalls ? "+long-calls"1 : "-long-calls"136 ); |
177 | | |
178 | 137 | bool HasHVX = false; |
179 | 137 | StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); |
180 | | // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors |
181 | | // have no dependency on micro-architecture. |
182 | 137 | const bool TinyCore = Cpu.contains('t'); |
183 | | |
184 | 137 | if (TinyCore) |
185 | 3 | Cpu = Cpu.take_front(Cpu.size() - 1); |
186 | | |
187 | 137 | handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX); |
188 | | |
189 | 137 | if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX1 ) |
190 | 1 | D.Diag(diag::warn_drv_needs_hvx) << "auto-vectorization"; |
191 | 137 | } |
192 | | |
193 | | // Hexagon tools start. |
194 | | void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, |
195 | 0 | ArgStringList &CmdArgs) const { |
196 | 0 | } |
197 | | |
198 | | void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, |
199 | | const InputInfo &Output, |
200 | | const InputInfoList &Inputs, |
201 | | const ArgList &Args, |
202 | 0 | const char *LinkingOutput) const { |
203 | 0 | claimNoWarnArgs(Args); |
204 | |
|
205 | 0 | auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); |
206 | 0 | const Driver &D = HTC.getDriver(); |
207 | 0 | ArgStringList CmdArgs; |
208 | |
|
209 | 0 | CmdArgs.push_back("--arch=hexagon"); |
210 | |
|
211 | 0 | RenderExtraToolArgs(JA, CmdArgs); |
212 | |
|
213 | 0 | const char *AsName = "llvm-mc"; |
214 | 0 | CmdArgs.push_back("-filetype=obj"); |
215 | 0 | CmdArgs.push_back(Args.MakeArgString( |
216 | 0 | "-mcpu=hexagon" + |
217 | 0 | toolchains::HexagonToolChain::GetTargetCPUVersion(Args))); |
218 | |
|
219 | 0 | addSanitizerRuntimes(HTC, Args, CmdArgs); |
220 | |
|
221 | 0 | assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); |
222 | 0 | if (Output.isFilename()) { |
223 | 0 | CmdArgs.push_back("-o"); |
224 | 0 | CmdArgs.push_back(Output.getFilename()); |
225 | 0 | } else { |
226 | 0 | CmdArgs.push_back("-fsyntax-only"); |
227 | 0 | } |
228 | |
|
229 | 0 | if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_ieee_fp, |
230 | 0 | options::OPT_mno_hexagon_hvx_ieee_fp)) { |
231 | 0 | if (A->getOption().matches(options::OPT_mhexagon_hvx_ieee_fp)) |
232 | 0 | CmdArgs.push_back("-mhvx-ieee-fp"); |
233 | 0 | } |
234 | |
|
235 | 0 | if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { |
236 | 0 | CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(*G))); |
237 | 0 | } |
238 | |
|
239 | 0 | Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); |
240 | | |
241 | | // Only pass -x if gcc will understand it; otherwise hope gcc |
242 | | // understands the suffix correctly. The main use case this would go |
243 | | // wrong in is for linker inputs if they happened to have an odd |
244 | | // suffix; really the only way to get this to happen is a command |
245 | | // like '-x foobar a.c' which will treat a.c like a linker input. |
246 | | // |
247 | | // FIXME: For the linker case specifically, can we safely convert |
248 | | // inputs into '-Wl,' options? |
249 | 0 | for (const auto &II : Inputs) { |
250 | | // Don't try to pass LLVM or AST inputs to a generic gcc. |
251 | 0 | if (types::isLLVMIR(II.getType())) |
252 | 0 | D.Diag(clang::diag::err_drv_no_linker_llvm_support) |
253 | 0 | << HTC.getTripleString(); |
254 | 0 | else if (II.getType() == types::TY_AST) |
255 | 0 | D.Diag(clang::diag::err_drv_no_ast_support) |
256 | 0 | << HTC.getTripleString(); |
257 | 0 | else if (II.getType() == types::TY_ModuleFile) |
258 | 0 | D.Diag(diag::err_drv_no_module_support) |
259 | 0 | << HTC.getTripleString(); |
260 | |
|
261 | 0 | if (II.isFilename()) |
262 | 0 | CmdArgs.push_back(II.getFilename()); |
263 | 0 | else |
264 | | // Don't render as input, we need gcc to do the translations. |
265 | | // FIXME: What is this? |
266 | 0 | II.getInputArg().render(Args, CmdArgs); |
267 | 0 | } |
268 | |
|
269 | 0 | auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName)); |
270 | 0 | C.addCommand(std::make_unique<Command>(JA, *this, |
271 | 0 | ResponseFileSupport::AtFileCurCP(), |
272 | 0 | Exec, CmdArgs, Inputs, Output)); |
273 | 0 | } |
274 | | |
275 | | void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, |
276 | 0 | ArgStringList &CmdArgs) const { |
277 | 0 | } |
278 | | |
279 | | static void |
280 | | constructHexagonLinkArgs(Compilation &C, const JobAction &JA, |
281 | | const toolchains::HexagonToolChain &HTC, |
282 | | const InputInfo &Output, const InputInfoList &Inputs, |
283 | | const ArgList &Args, ArgStringList &CmdArgs, |
284 | 27 | const char *LinkingOutput) { |
285 | | |
286 | 27 | const Driver &D = HTC.getDriver(); |
287 | | |
288 | | //---------------------------------------------------------------------------- |
289 | | // |
290 | | //---------------------------------------------------------------------------- |
291 | 27 | bool IsStatic = Args.hasArg(options::OPT_static); |
292 | 27 | bool IsShared = Args.hasArg(options::OPT_shared); |
293 | 27 | bool IsPIE = Args.hasArg(options::OPT_pie); |
294 | 27 | bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); |
295 | 27 | bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); |
296 | 27 | bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); |
297 | 27 | bool UseG0 = false; |
298 | 27 | const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); |
299 | 27 | bool UseLLD = (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") || |
300 | 27 | llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")17 ); |
301 | 27 | bool UseShared = IsShared && !IsStatic1 ; |
302 | 27 | StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); |
303 | | |
304 | 27 | bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs); |
305 | 27 | bool NeedsXRayDeps = addXRayRuntime(HTC, Args, CmdArgs); |
306 | | |
307 | | //---------------------------------------------------------------------------- |
308 | | // Silence warnings for various options |
309 | | //---------------------------------------------------------------------------- |
310 | 27 | Args.ClaimAllArgs(options::OPT_g_Group); |
311 | 27 | Args.ClaimAllArgs(options::OPT_emit_llvm); |
312 | 27 | Args.ClaimAllArgs(options::OPT_w); // Other warning options are already |
313 | | // handled somewhere else. |
314 | 27 | Args.ClaimAllArgs(options::OPT_static_libgcc); |
315 | | |
316 | | //---------------------------------------------------------------------------- |
317 | | // |
318 | | //---------------------------------------------------------------------------- |
319 | 27 | if (Args.hasArg(options::OPT_s)) |
320 | 0 | CmdArgs.push_back("-s"); |
321 | | |
322 | 27 | if (Args.hasArg(options::OPT_r)) |
323 | 0 | CmdArgs.push_back("-r"); |
324 | | |
325 | 27 | for (const auto &Opt : HTC.ExtraOpts) |
326 | 0 | CmdArgs.push_back(Opt.c_str()); |
327 | | |
328 | 27 | if (!UseLLD) { |
329 | 17 | CmdArgs.push_back("-march=hexagon"); |
330 | 17 | CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); |
331 | 17 | } |
332 | | |
333 | 27 | if (IsShared) { |
334 | 1 | CmdArgs.push_back("-shared"); |
335 | | // The following should be the default, but doing as hexagon-gcc does. |
336 | 1 | CmdArgs.push_back("-call_shared"); |
337 | 1 | } |
338 | | |
339 | 27 | if (IsStatic) |
340 | 0 | CmdArgs.push_back("-static"); |
341 | | |
342 | 27 | if (IsPIE && !IsShared0 ) |
343 | 0 | CmdArgs.push_back("-pie"); |
344 | | |
345 | 27 | if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { |
346 | 1 | CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G))); |
347 | 1 | UseG0 = *G == 0; |
348 | 1 | } |
349 | | |
350 | 27 | CmdArgs.push_back("-o"); |
351 | 27 | CmdArgs.push_back(Output.getFilename()); |
352 | | |
353 | 27 | if (HTC.getTriple().isMusl()) { |
354 | 10 | if (!Args.hasArg(options::OPT_shared, options::OPT_static)) |
355 | 9 | CmdArgs.push_back("-dynamic-linker=/lib/ld-musl-hexagon.so.1"); |
356 | | |
357 | 10 | if (!Args.hasArg(options::OPT_shared, options::OPT_nostartfiles, |
358 | 10 | options::OPT_nostdlib)) |
359 | 7 | CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crt1.o")); |
360 | 3 | else if (Args.hasArg(options::OPT_shared) && |
361 | 3 | !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib)1 ) |
362 | 1 | CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crti.o")); |
363 | | |
364 | 10 | CmdArgs.push_back( |
365 | 10 | Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib")); |
366 | 10 | Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, |
367 | 10 | options::OPT_t, options::OPT_u_Group}); |
368 | 10 | AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); |
369 | | |
370 | 10 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { |
371 | 8 | if (NeedsSanitizerDeps) { |
372 | 0 | linkSanitizerRuntimeDeps(HTC, Args, CmdArgs); |
373 | |
|
374 | 0 | CmdArgs.push_back("-lunwind"); |
375 | 0 | } |
376 | 8 | if (NeedsXRayDeps) |
377 | 0 | linkXRayRuntimeDeps(HTC, Args, CmdArgs); |
378 | | |
379 | 8 | CmdArgs.push_back("-lclang_rt.builtins-hexagon"); |
380 | 8 | if (!Args.hasArg(options::OPT_nolibc)) |
381 | 7 | CmdArgs.push_back("-lc"); |
382 | 8 | } |
383 | 10 | if (D.CCCIsCXX()) { |
384 | 1 | if (HTC.ShouldLinkCXXStdlib(Args)) |
385 | 1 | HTC.AddCXXStdlibLibArgs(Args, CmdArgs); |
386 | 1 | } |
387 | 10 | const ToolChain::path_list &LibPaths = HTC.getFilePaths(); |
388 | 10 | for (const auto &LibPath : LibPaths) |
389 | 22 | CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); |
390 | 10 | Args.ClaimAllArgs(options::OPT_L); |
391 | 10 | return; |
392 | 10 | } |
393 | | |
394 | | //---------------------------------------------------------------------------- |
395 | | // moslib |
396 | | //---------------------------------------------------------------------------- |
397 | 17 | std::vector<std::string> OsLibs; |
398 | 17 | bool HasStandalone = false; |
399 | 17 | for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { |
400 | 0 | A->claim(); |
401 | 0 | OsLibs.emplace_back(A->getValue()); |
402 | 0 | HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); |
403 | 0 | } |
404 | 17 | if (OsLibs.empty()) { |
405 | 17 | OsLibs.push_back("standalone"); |
406 | 17 | HasStandalone = true; |
407 | 17 | } |
408 | | |
409 | | //---------------------------------------------------------------------------- |
410 | | // Start Files |
411 | | //---------------------------------------------------------------------------- |
412 | 17 | const std::string MCpuSuffix = "/" + CpuVer.str(); |
413 | 17 | const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; |
414 | 17 | const std::string RootDir = |
415 | 17 | HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; |
416 | 17 | const std::string StartSubDir = |
417 | 17 | "hexagon/lib" + (UseG0 ? MCpuG0Suffix0 : MCpuSuffix); |
418 | | |
419 | 17 | auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, |
420 | 68 | const char *Name) -> std::string { |
421 | 68 | std::string RelName = SubDir + Name; |
422 | 68 | std::string P = HTC.GetFilePath(RelName.c_str()); |
423 | 68 | if (llvm::sys::fs::exists(P)) |
424 | 0 | return P; |
425 | 68 | return RootDir + RelName; |
426 | 68 | }; |
427 | | |
428 | 17 | if (IncStdLib && IncStartFiles) { |
429 | 17 | if (!IsShared) { |
430 | 17 | if (HasStandalone) { |
431 | 17 | std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); |
432 | 17 | CmdArgs.push_back(Args.MakeArgString(Crt0SA)); |
433 | 17 | } |
434 | 17 | std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); |
435 | 17 | CmdArgs.push_back(Args.MakeArgString(Crt0)); |
436 | 17 | } |
437 | 17 | std::string Init = UseShared |
438 | 17 | ? Find(RootDir, StartSubDir + "/pic", "/initS.o")0 |
439 | 17 | : Find(RootDir, StartSubDir, "/init.o"); |
440 | 17 | CmdArgs.push_back(Args.MakeArgString(Init)); |
441 | 17 | } |
442 | | |
443 | | //---------------------------------------------------------------------------- |
444 | | // Library Search Paths |
445 | | //---------------------------------------------------------------------------- |
446 | 17 | const ToolChain::path_list &LibPaths = HTC.getFilePaths(); |
447 | 17 | for (const auto &LibPath : LibPaths) |
448 | 34 | CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); |
449 | 17 | Args.ClaimAllArgs(options::OPT_L); |
450 | | |
451 | | //---------------------------------------------------------------------------- |
452 | | // |
453 | | //---------------------------------------------------------------------------- |
454 | 17 | Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, |
455 | 17 | options::OPT_t, options::OPT_u_Group}); |
456 | | |
457 | 17 | AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); |
458 | | |
459 | | //---------------------------------------------------------------------------- |
460 | | // Libraries |
461 | | //---------------------------------------------------------------------------- |
462 | 17 | if (IncStdLib && IncDefLibs) { |
463 | 17 | if (D.CCCIsCXX()) { |
464 | 1 | if (HTC.ShouldLinkCXXStdlib(Args)) |
465 | 1 | HTC.AddCXXStdlibLibArgs(Args, CmdArgs); |
466 | 1 | CmdArgs.push_back("-lm"); |
467 | 1 | } |
468 | | |
469 | 17 | CmdArgs.push_back("--start-group"); |
470 | | |
471 | 17 | if (!IsShared) { |
472 | 17 | for (StringRef Lib : OsLibs) |
473 | 17 | CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); |
474 | 17 | if (!Args.hasArg(options::OPT_nolibc)) |
475 | 17 | CmdArgs.push_back("-lc"); |
476 | 17 | } |
477 | 17 | CmdArgs.push_back("-lgcc"); |
478 | | |
479 | 17 | CmdArgs.push_back("--end-group"); |
480 | 17 | } |
481 | | |
482 | | //---------------------------------------------------------------------------- |
483 | | // End files |
484 | | //---------------------------------------------------------------------------- |
485 | 17 | if (IncStdLib && IncStartFiles) { |
486 | 17 | std::string Fini = UseShared |
487 | 17 | ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")0 |
488 | 17 | : Find(RootDir, StartSubDir, "/fini.o"); |
489 | 17 | CmdArgs.push_back(Args.MakeArgString(Fini)); |
490 | 17 | } |
491 | 17 | } |
492 | | |
493 | | void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
494 | | const InputInfo &Output, |
495 | | const InputInfoList &Inputs, |
496 | | const ArgList &Args, |
497 | 27 | const char *LinkingOutput) const { |
498 | 27 | auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); |
499 | | |
500 | 27 | ArgStringList CmdArgs; |
501 | 27 | constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, |
502 | 27 | LinkingOutput); |
503 | | |
504 | 27 | const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); |
505 | 27 | C.addCommand(std::make_unique<Command>(JA, *this, |
506 | 27 | ResponseFileSupport::AtFileCurCP(), |
507 | 27 | Exec, CmdArgs, Inputs, Output)); |
508 | 27 | } |
509 | | // Hexagon tools end. |
510 | | |
511 | | /// Hexagon Toolchain |
512 | | |
513 | | std::string HexagonToolChain::getHexagonTargetDir( |
514 | | const std::string &InstalledDir, |
515 | 423 | const SmallVectorImpl<std::string> &PrefixDirs) const { |
516 | 423 | std::string InstallRelDir; |
517 | 423 | const Driver &D = getDriver(); |
518 | | |
519 | | // Locate the rest of the toolchain ... |
520 | 423 | for (auto &I : PrefixDirs) |
521 | 0 | if (D.getVFS().exists(I)) |
522 | 0 | return I; |
523 | | |
524 | 423 | if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) |
525 | 29 | return InstallRelDir; |
526 | | |
527 | 394 | return InstalledDir; |
528 | 423 | } |
529 | | |
530 | | std::optional<unsigned> |
531 | 301 | HexagonToolChain::getSmallDataThreshold(const ArgList &Args) { |
532 | 301 | StringRef Gn = ""; |
533 | 301 | if (Arg *A = Args.getLastArg(options::OPT_G)) { |
534 | 0 | Gn = A->getValue(); |
535 | 301 | } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, |
536 | 301 | options::OPT_fPIC)) { |
537 | 3 | Gn = "0"; |
538 | 3 | } |
539 | | |
540 | 301 | unsigned G; |
541 | 301 | if (!Gn.getAsInteger(10, G)) |
542 | 3 | return G; |
543 | | |
544 | 298 | return std::nullopt; |
545 | 301 | } |
546 | | |
547 | 68 | std::string HexagonToolChain::getCompilerRTPath() const { |
548 | 68 | SmallString<128> Dir(getDriver().SysRoot); |
549 | 68 | llvm::sys::path::append(Dir, "usr", "lib"); |
550 | 68 | if (!SelectedMultilibs.empty()) { |
551 | 68 | Dir += SelectedMultilibs.back().gccSuffix(); |
552 | 68 | } |
553 | 68 | return std::string(Dir.str()); |
554 | 68 | } |
555 | | |
556 | | void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, |
557 | 137 | ToolChain::path_list &LibPaths) const { |
558 | 137 | const Driver &D = getDriver(); |
559 | | |
560 | | //---------------------------------------------------------------------------- |
561 | | // -L Args |
562 | | //---------------------------------------------------------------------------- |
563 | 137 | for (Arg *A : Args.filtered(options::OPT_L)) |
564 | 1 | llvm::append_range(LibPaths, A->getValues()); |
565 | | |
566 | | //---------------------------------------------------------------------------- |
567 | | // Other standard paths |
568 | | //---------------------------------------------------------------------------- |
569 | 137 | std::vector<std::string> RootDirs; |
570 | 137 | std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), |
571 | 137 | std::back_inserter(RootDirs)); |
572 | | |
573 | 137 | std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), |
574 | 137 | D.PrefixDirs); |
575 | 137 | if (!llvm::is_contained(RootDirs, TargetDir)) |
576 | 137 | RootDirs.push_back(TargetDir); |
577 | | |
578 | 137 | bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); |
579 | | // Assume G0 with -shared. |
580 | 137 | bool HasG0 = Args.hasArg(options::OPT_shared); |
581 | 137 | if (auto G = getSmallDataThreshold(Args)) |
582 | 1 | HasG0 = *G == 0; |
583 | | |
584 | 137 | const std::string CpuVer = GetTargetCPUVersion(Args).str(); |
585 | 137 | for (auto &Dir : RootDirs) { |
586 | 137 | std::string LibDir = Dir + "/hexagon/lib"; |
587 | 137 | std::string LibDirCpu = LibDir + '/' + CpuVer; |
588 | 137 | if (HasG0) { |
589 | 1 | if (HasPIC) |
590 | 0 | LibPaths.push_back(LibDirCpu + "/G0/pic"); |
591 | 1 | LibPaths.push_back(LibDirCpu + "/G0"); |
592 | 1 | } |
593 | 137 | LibPaths.push_back(LibDirCpu); |
594 | 137 | LibPaths.push_back(LibDir); |
595 | 137 | } |
596 | 137 | } |
597 | | |
598 | | HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, |
599 | | const llvm::opt::ArgList &Args) |
600 | 137 | : Linux(D, Triple, Args) { |
601 | 137 | const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), |
602 | 137 | D.PrefixDirs); |
603 | | |
604 | | // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to |
605 | | // program paths |
606 | 137 | const std::string BinDir(TargetDir + "/bin"); |
607 | 137 | if (D.getVFS().exists(BinDir)) |
608 | 0 | getProgramPaths().push_back(BinDir); |
609 | | |
610 | 137 | ToolChain::path_list &LibPaths = getFilePaths(); |
611 | | |
612 | | // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets |
613 | | // 'elf' OS type, so the Linux paths are not appropriate. When we actually |
614 | | // support 'linux' we'll need to fix this up |
615 | 137 | LibPaths.clear(); |
616 | 137 | getHexagonLibraryPaths(Args, LibPaths); |
617 | 137 | } |
618 | | |
619 | 137 | HexagonToolChain::~HexagonToolChain() {} |
620 | | |
621 | | void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args, |
622 | 2 | ArgStringList &CmdArgs) const { |
623 | 2 | CXXStdlibType Type = GetCXXStdlibType(Args); |
624 | 2 | switch (Type) { |
625 | 2 | case ToolChain::CST_Libcxx: |
626 | 2 | CmdArgs.push_back("-lc++"); |
627 | 2 | if (Args.hasArg(options::OPT_fexperimental_library)) |
628 | 0 | CmdArgs.push_back("-lc++experimental"); |
629 | 2 | CmdArgs.push_back("-lc++abi"); |
630 | 2 | CmdArgs.push_back("-lunwind"); |
631 | 2 | break; |
632 | | |
633 | 0 | case ToolChain::CST_Libstdcxx: |
634 | 0 | CmdArgs.push_back("-lstdc++"); |
635 | 0 | break; |
636 | 2 | } |
637 | 2 | } |
638 | | |
639 | 0 | Tool *HexagonToolChain::buildAssembler() const { |
640 | 0 | return new tools::hexagon::Assembler(*this); |
641 | 0 | } |
642 | | |
643 | 27 | Tool *HexagonToolChain::buildLinker() const { |
644 | 27 | return new tools::hexagon::Linker(*this); |
645 | 27 | } |
646 | | |
647 | | unsigned HexagonToolChain::getOptimizationLevel( |
648 | 0 | const llvm::opt::ArgList &DriverArgs) const { |
649 | | // Copied in large part from lib/Frontend/CompilerInvocation.cpp. |
650 | 0 | Arg *A = DriverArgs.getLastArg(options::OPT_O_Group); |
651 | 0 | if (!A) |
652 | 0 | return 0; |
653 | | |
654 | 0 | if (A->getOption().matches(options::OPT_O0)) |
655 | 0 | return 0; |
656 | 0 | if (A->getOption().matches(options::OPT_Ofast) || |
657 | 0 | A->getOption().matches(options::OPT_O4)) |
658 | 0 | return 3; |
659 | 0 | assert(A->getNumValues() != 0); |
660 | 0 | StringRef S(A->getValue()); |
661 | 0 | if (S == "s" || S == "z" || S.empty()) |
662 | 0 | return 2; |
663 | 0 | if (S == "g") |
664 | 0 | return 1; |
665 | | |
666 | 0 | unsigned OptLevel; |
667 | 0 | if (S.getAsInteger(10, OptLevel)) |
668 | 0 | return 0; |
669 | 0 | return OptLevel; |
670 | 0 | } |
671 | | |
672 | | void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, |
673 | | ArgStringList &CC1Args, |
674 | 138 | Action::OffloadKind) const { |
675 | | |
676 | 138 | bool UseInitArrayDefault = getTriple().isMusl(); |
677 | | |
678 | 138 | if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, |
679 | 138 | options::OPT_fno_use_init_array, |
680 | 138 | UseInitArrayDefault)) |
681 | 128 | CC1Args.push_back("-fno-use-init-array"); |
682 | | |
683 | 138 | if (DriverArgs.hasArg(options::OPT_ffixed_r19)) { |
684 | 2 | CC1Args.push_back("-target-feature"); |
685 | 2 | CC1Args.push_back("+reserved-r19"); |
686 | 2 | } |
687 | 138 | if (isAutoHVXEnabled(DriverArgs)) { |
688 | 1 | CC1Args.push_back("-mllvm"); |
689 | 1 | CC1Args.push_back("-hexagon-autohvx"); |
690 | 1 | } |
691 | 138 | } |
692 | | |
693 | | void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
694 | 137 | ArgStringList &CC1Args) const { |
695 | 137 | if (DriverArgs.hasArg(options::OPT_nostdinc)) |
696 | 0 | return; |
697 | | |
698 | 137 | const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux()127 ; |
699 | 137 | const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux()10 ; |
700 | | |
701 | 137 | const Driver &D = getDriver(); |
702 | 137 | SmallString<128> ResourceDirInclude(D.ResourceDir); |
703 | 137 | if (!IsELF) { |
704 | 13 | llvm::sys::path::append(ResourceDirInclude, "include"); |
705 | 13 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && |
706 | 13 | (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)10 )) |
707 | 3 | addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); |
708 | 13 | } |
709 | 137 | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) |
710 | 0 | return; |
711 | | |
712 | 137 | const bool HasSysRoot = !D.SysRoot.empty(); |
713 | 137 | if (HasSysRoot) { |
714 | 7 | SmallString<128> P(D.SysRoot); |
715 | 7 | if (IsLinuxMusl) |
716 | 7 | llvm::sys::path::append(P, "usr/include"); |
717 | 0 | else |
718 | 0 | llvm::sys::path::append(P, "include"); |
719 | | |
720 | 7 | addExternCSystemInclude(DriverArgs, CC1Args, P.str()); |
721 | | // LOCAL_INCLUDE_DIR |
722 | 7 | addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include"); |
723 | | // TOOL_INCLUDE_DIR |
724 | 7 | AddMultilibIncludeArgs(DriverArgs, CC1Args); |
725 | 7 | } |
726 | | |
727 | 137 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl) |
728 | 10 | addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); |
729 | | |
730 | 137 | if (HasSysRoot) |
731 | 7 | return; |
732 | 130 | std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), |
733 | 130 | D.PrefixDirs); |
734 | 130 | addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); |
735 | 130 | } |
736 | | |
737 | | void HexagonToolChain::addLibCxxIncludePaths( |
738 | | const llvm::opt::ArgList &DriverArgs, |
739 | 2 | llvm::opt::ArgStringList &CC1Args) const { |
740 | 2 | const Driver &D = getDriver(); |
741 | 2 | if (!D.SysRoot.empty() && getTriple().isMusl()1 ) |
742 | 1 | addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "", |
743 | 1 | DriverArgs, CC1Args); |
744 | 1 | else if (getTriple().isMusl()) |
745 | 0 | addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs, |
746 | 0 | CC1Args); |
747 | 1 | else { |
748 | 1 | std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); |
749 | 1 | addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "", |
750 | 1 | DriverArgs, CC1Args); |
751 | 1 | } |
752 | 2 | } |
753 | | void HexagonToolChain::addLibStdCxxIncludePaths( |
754 | | const llvm::opt::ArgList &DriverArgs, |
755 | 1 | llvm::opt::ArgStringList &CC1Args) const { |
756 | 1 | const Driver &D = getDriver(); |
757 | 1 | std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); |
758 | 1 | addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "", |
759 | 1 | DriverArgs, CC1Args); |
760 | 1 | } |
761 | | |
762 | | ToolChain::CXXStdlibType |
763 | 5 | HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { |
764 | 5 | Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); |
765 | 5 | if (!A) { |
766 | 3 | if (getTriple().isMusl()) |
767 | 2 | return ToolChain::CST_Libcxx; |
768 | 1 | else |
769 | 1 | return ToolChain::CST_Libstdcxx; |
770 | 3 | } |
771 | 2 | StringRef Value = A->getValue(); |
772 | 2 | if (Value != "libstdc++" && Value != "libc++") |
773 | 0 | getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); |
774 | | |
775 | 2 | if (Value == "libstdc++") |
776 | 0 | return ToolChain::CST_Libstdcxx; |
777 | 2 | else if (Value == "libc++") |
778 | 2 | return ToolChain::CST_Libcxx; |
779 | 0 | else |
780 | 0 | return ToolChain::CST_Libstdcxx; |
781 | 2 | } |
782 | | |
783 | 275 | bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { |
784 | 275 | if (Arg *A = Args.getLastArg(options::OPT_fvectorize, |
785 | 275 | options::OPT_fno_vectorize)) |
786 | 4 | return A->getOption().matches(options::OPT_fvectorize); |
787 | 271 | return false; |
788 | 275 | } |
789 | | |
790 | | // |
791 | | // Returns the default CPU for Hexagon. This is the default compilation target |
792 | | // if no Hexagon processor is selected at the command-line. |
793 | | // |
794 | 155 | StringRef HexagonToolChain::GetDefaultCPU() { |
795 | 155 | return "hexagonv60"; |
796 | 155 | } |
797 | | |
798 | 460 | StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { |
799 | 460 | Arg *CpuArg = nullptr; |
800 | 460 | if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) |
801 | 305 | CpuArg = A; |
802 | | |
803 | 460 | StringRef CPU = CpuArg ? CpuArg->getValue()305 : GetDefaultCPU()155 ; |
804 | 460 | if (CPU.startswith("hexagon")) |
805 | 460 | return CPU.substr(sizeof("hexagon") - 1); |
806 | 0 | return CPU; |
807 | 460 | } |