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