1 | //===- ToolChain.cpp - Collections of tools for one platform --------------===// |
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 "clang/Driver/ToolChain.h" |
10 | #include "ToolChains/Arch/AArch64.h" |
11 | #include "ToolChains/Arch/ARM.h" |
12 | #include "ToolChains/Clang.h" |
13 | #include "ToolChains/CommonArgs.h" |
14 | #include "ToolChains/Flang.h" |
15 | #include "ToolChains/InterfaceStubs.h" |
16 | #include "clang/Basic/ObjCRuntime.h" |
17 | #include "clang/Basic/Sanitizers.h" |
18 | #include "clang/Config/config.h" |
19 | #include "clang/Driver/Action.h" |
20 | #include "clang/Driver/Driver.h" |
21 | #include "clang/Driver/DriverDiagnostic.h" |
22 | #include "clang/Driver/InputInfo.h" |
23 | #include "clang/Driver/Job.h" |
24 | #include "clang/Driver/Options.h" |
25 | #include "clang/Driver/SanitizerArgs.h" |
26 | #include "clang/Driver/XRayArgs.h" |
27 | #include "llvm/ADT/STLExtras.h" |
28 | #include "llvm/ADT/SmallString.h" |
29 | #include "llvm/ADT/StringExtras.h" |
30 | #include "llvm/ADT/StringRef.h" |
31 | #include "llvm/ADT/Twine.h" |
32 | #include "llvm/Config/llvm-config.h" |
33 | #include "llvm/MC/MCTargetOptions.h" |
34 | #include "llvm/MC/TargetRegistry.h" |
35 | #include "llvm/Option/Arg.h" |
36 | #include "llvm/Option/ArgList.h" |
37 | #include "llvm/Option/OptTable.h" |
38 | #include "llvm/Option/Option.h" |
39 | #include "llvm/Support/ErrorHandling.h" |
40 | #include "llvm/Support/FileSystem.h" |
41 | #include "llvm/Support/FileUtilities.h" |
42 | #include "llvm/Support/Path.h" |
43 | #include "llvm/Support/VersionTuple.h" |
44 | #include "llvm/Support/VirtualFileSystem.h" |
45 | #include "llvm/TargetParser/AArch64TargetParser.h" |
46 | #include "llvm/TargetParser/TargetParser.h" |
47 | #include "llvm/TargetParser/Triple.h" |
48 | #include <cassert> |
49 | #include <cstddef> |
50 | #include <cstring> |
51 | #include <string> |
52 | |
53 | using namespace clang; |
54 | using namespace driver; |
55 | using namespace tools; |
56 | using namespace llvm; |
57 | using namespace llvm::opt; |
58 | |
59 | static llvm::opt::Arg *GetRTTIArgument(const ArgList &Args) { |
60 | return Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext, |
61 | options::OPT_fno_rtti, options::OPT_frtti); |
62 | } |
63 | |
64 | static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, |
65 | const llvm::Triple &Triple, |
66 | const Arg *CachedRTTIArg) { |
67 | // Explicit rtti/no-rtti args |
68 | if (CachedRTTIArg) { |
69 | if (CachedRTTIArg->getOption().matches(options::ID: OPT_frtti)) |
70 | return ToolChain::RM_Enabled; |
71 | else |
72 | return ToolChain::RM_Disabled; |
73 | } |
74 | |
75 | // -frtti is default, except for the PS4/PS5 and DriverKit. |
76 | bool NoRTTI = Triple.isPS() || Triple.isDriverKit(); |
77 | return NoRTTI ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; |
78 | } |
79 | |
80 | static ToolChain::ExceptionsMode CalculateExceptionsMode(const ArgList &Args) { |
81 | if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, |
82 | true)) { |
83 | return ToolChain::EM_Enabled; |
84 | } |
85 | return ToolChain::EM_Disabled; |
86 | } |
87 | |
88 | ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, |
89 | const ArgList &Args) |
90 | : D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)), |
91 | CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)), |
92 | CachedExceptionsMode(CalculateExceptionsMode(Args)) { |
93 | auto addIfExists = [this](path_list &List, const std::string &Path) { |
94 | if (getVFS().exists(Path)) |
95 | List.push_back(Elt: Path); |
96 | }; |
97 | |
98 | if (std::optional<std::string> Path = getRuntimePath()) |
99 | getLibraryPaths().push_back(Elt: *Path); |
100 | if (std::optional<std::string> Path = getStdlibPath()) |
101 | getFilePaths().push_back(Elt: *Path); |
102 | for (const auto &Path : getArchSpecificLibPaths()) |
103 | addIfExists(getFilePaths(), Path); |
104 | } |
105 | |
106 | llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> |
107 | ToolChain::executeToolChainProgram(StringRef Executable) const { |
108 | llvm::SmallString<64> OutputFile; |
109 | llvm::sys::fs::createTemporaryFile(Prefix: "toolchain-program" , Suffix: "txt" , ResultPath&: OutputFile); |
110 | llvm::FileRemover OutputRemover(OutputFile.c_str()); |
111 | std::optional<llvm::StringRef> Redirects[] = { |
112 | {"" }, |
113 | OutputFile.str(), |
114 | {"" }, |
115 | }; |
116 | |
117 | std::string ErrorMessage; |
118 | if (llvm::sys::ExecuteAndWait(Program: Executable, Args: {}, Env: {}, Redirects, |
119 | /* SecondsToWait */ 0, |
120 | /*MemoryLimit*/ 0, ErrMsg: &ErrorMessage)) |
121 | return llvm::createStringError(EC: std::error_code(), |
122 | S: Executable + ": " + ErrorMessage); |
123 | |
124 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf = |
125 | llvm::MemoryBuffer::getFile(Filename: OutputFile.c_str()); |
126 | if (!OutputBuf) |
127 | return llvm::createStringError(EC: OutputBuf.getError(), |
128 | S: "Failed to read stdout of " + Executable + |
129 | ": " + OutputBuf.getError().message()); |
130 | return std::move(*OutputBuf); |
131 | } |
132 | |
133 | void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { |
134 | Triple.setEnvironment(Env); |
135 | if (EffectiveTriple != llvm::Triple()) |
136 | EffectiveTriple.setEnvironment(Env); |
137 | } |
138 | |
139 | ToolChain::~ToolChain() = default; |
140 | |
141 | llvm::vfs::FileSystem &ToolChain::getVFS() const { |
142 | return getDriver().getVFS(); |
143 | } |
144 | |
145 | bool ToolChain::useIntegratedAs() const { |
146 | return Args.hasFlag(options::OPT_fintegrated_as, |
147 | options::OPT_fno_integrated_as, |
148 | IsIntegratedAssemblerDefault()); |
149 | } |
150 | |
151 | bool ToolChain::useIntegratedBackend() const { |
152 | assert( |
153 | ((IsIntegratedBackendDefault() && IsIntegratedBackendSupported()) || |
154 | (!IsIntegratedBackendDefault() || IsNonIntegratedBackendSupported())) && |
155 | "(Non-)integrated backend set incorrectly!" ); |
156 | |
157 | bool IBackend = Args.hasFlag(options::OPT_fintegrated_objemitter, |
158 | options::OPT_fno_integrated_objemitter, |
159 | IsIntegratedBackendDefault()); |
160 | |
161 | // Diagnose when integrated-objemitter options are not supported by this |
162 | // toolchain. |
163 | unsigned DiagID; |
164 | if ((IBackend && !IsIntegratedBackendSupported()) || |
165 | (!IBackend && !IsNonIntegratedBackendSupported())) |
166 | DiagID = clang::diag::err_drv_unsupported_opt_for_target; |
167 | else |
168 | DiagID = clang::diag::warn_drv_unsupported_opt_for_target; |
169 | Arg *A = Args.getLastArg(options::OPT_fno_integrated_objemitter); |
170 | if (A && !IsNonIntegratedBackendSupported()) |
171 | D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple(); |
172 | A = Args.getLastArg(options::OPT_fintegrated_objemitter); |
173 | if (A && !IsIntegratedBackendSupported()) |
174 | D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple(); |
175 | |
176 | return IBackend; |
177 | } |
178 | |
179 | bool ToolChain::useRelaxRelocations() const { |
180 | return ENABLE_X86_RELAX_RELOCATIONS; |
181 | } |
182 | |
183 | bool ToolChain::defaultToIEEELongDouble() const { |
184 | return PPC_LINUX_DEFAULT_IEEELONGDOUBLE && getTriple().isOSLinux(); |
185 | } |
186 | |
187 | static void getAArch64MultilibFlags(const Driver &D, |
188 | const llvm::Triple &Triple, |
189 | const llvm::opt::ArgList &Args, |
190 | Multilib::flags_list &Result) { |
191 | std::vector<StringRef> Features; |
192 | tools::aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS: false); |
193 | const auto UnifiedFeatures = tools::unifyTargetFeatures(Features); |
194 | llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(), |
195 | UnifiedFeatures.end()); |
196 | std::vector<std::string> MArch; |
197 | for (const auto &Ext : AArch64::Extensions) |
198 | if (FeatureSet.contains(V: Ext.Feature)) |
199 | MArch.push_back(x: Ext.Name.str()); |
200 | for (const auto &Ext : AArch64::Extensions) |
201 | if (FeatureSet.contains(V: Ext.NegFeature)) |
202 | MArch.push_back(x: ("no" + Ext.Name).str()); |
203 | StringRef ArchName; |
204 | for (const auto &ArchInfo : AArch64::ArchInfos) |
205 | if (FeatureSet.contains(V: ArchInfo->ArchFeature)) |
206 | ArchName = ArchInfo->Name; |
207 | assert(!ArchName.empty() && "at least one architecture should be found" ); |
208 | MArch.insert(position: MArch.begin(), x: ("-march=" + ArchName).str()); |
209 | Result.push_back(x: llvm::join(R&: MArch, Separator: "+" )); |
210 | } |
211 | |
212 | static void getARMMultilibFlags(const Driver &D, |
213 | const llvm::Triple &Triple, |
214 | const llvm::opt::ArgList &Args, |
215 | Multilib::flags_list &Result) { |
216 | std::vector<StringRef> Features; |
217 | llvm::ARM::FPUKind FPUKind = tools::arm::getARMTargetFeatures( |
218 | D, Triple, Args, Features, ForAS: false /*ForAs*/, ForMultilib: true /*ForMultilib*/); |
219 | const auto UnifiedFeatures = tools::unifyTargetFeatures(Features); |
220 | llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(), |
221 | UnifiedFeatures.end()); |
222 | std::vector<std::string> MArch; |
223 | for (const auto &Ext : ARM::ARCHExtNames) |
224 | if (FeatureSet.contains(V: Ext.Feature)) |
225 | MArch.push_back(x: Ext.Name.str()); |
226 | for (const auto &Ext : ARM::ARCHExtNames) |
227 | if (FeatureSet.contains(V: Ext.NegFeature)) |
228 | MArch.push_back(x: ("no" + Ext.Name).str()); |
229 | MArch.insert(position: MArch.begin(), x: ("-march=" + Triple.getArchName()).str()); |
230 | Result.push_back(x: llvm::join(R&: MArch, Separator: "+" )); |
231 | |
232 | switch (FPUKind) { |
233 | #define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) \ |
234 | case llvm::ARM::KIND: \ |
235 | Result.push_back("-mfpu=" NAME); \ |
236 | break; |
237 | #include "llvm/TargetParser/ARMTargetParser.def" |
238 | default: |
239 | llvm_unreachable("Invalid FPUKind" ); |
240 | } |
241 | |
242 | switch (arm::getARMFloatABI(D, Triple, Args)) { |
243 | case arm::FloatABI::Soft: |
244 | Result.push_back(x: "-mfloat-abi=soft" ); |
245 | break; |
246 | case arm::FloatABI::SoftFP: |
247 | Result.push_back(x: "-mfloat-abi=softfp" ); |
248 | break; |
249 | case arm::FloatABI::Hard: |
250 | Result.push_back(x: "-mfloat-abi=hard" ); |
251 | break; |
252 | case arm::FloatABI::Invalid: |
253 | llvm_unreachable("Invalid float ABI" ); |
254 | } |
255 | } |
256 | |
257 | Multilib::flags_list |
258 | ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { |
259 | using namespace clang::driver::options; |
260 | |
261 | std::vector<std::string> Result; |
262 | const llvm::Triple Triple(ComputeEffectiveClangTriple(Args)); |
263 | Result.push_back(x: "--target=" + Triple.str()); |
264 | |
265 | switch (Triple.getArch()) { |
266 | case llvm::Triple::aarch64: |
267 | case llvm::Triple::aarch64_32: |
268 | case llvm::Triple::aarch64_be: |
269 | getAArch64MultilibFlags(D, Triple, Args, Result); |
270 | break; |
271 | case llvm::Triple::arm: |
272 | case llvm::Triple::armeb: |
273 | case llvm::Triple::thumb: |
274 | case llvm::Triple::thumbeb: |
275 | getARMMultilibFlags(D, Triple, Args, Result); |
276 | break; |
277 | default: |
278 | break; |
279 | } |
280 | |
281 | // Include fno-exceptions and fno-rtti |
282 | // to improve multilib selection |
283 | if (getRTTIMode() == ToolChain::RTTIMode::RM_Disabled) |
284 | Result.push_back(x: "-fno-rtti" ); |
285 | else |
286 | Result.push_back(x: "-frtti" ); |
287 | |
288 | if (getExceptionsMode() == ToolChain::ExceptionsMode::EM_Disabled) |
289 | Result.push_back(x: "-fno-exceptions" ); |
290 | else |
291 | Result.push_back(x: "-fexceptions" ); |
292 | |
293 | // Sort and remove duplicates. |
294 | std::sort(first: Result.begin(), last: Result.end()); |
295 | Result.erase(first: std::unique(first: Result.begin(), last: Result.end()), last: Result.end()); |
296 | return Result; |
297 | } |
298 | |
299 | SanitizerArgs |
300 | ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const { |
301 | SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked); |
302 | SanitizerArgsChecked = true; |
303 | return SanArgs; |
304 | } |
305 | |
306 | const XRayArgs& ToolChain::getXRayArgs() const { |
307 | if (!XRayArguments) |
308 | XRayArguments.reset(p: new XRayArgs(*this, Args)); |
309 | return *XRayArguments; |
310 | } |
311 | |
312 | namespace { |
313 | |
314 | struct DriverSuffix { |
315 | const char *Suffix; |
316 | const char *ModeFlag; |
317 | }; |
318 | |
319 | } // namespace |
320 | |
321 | static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { |
322 | // A list of known driver suffixes. Suffixes are compared against the |
323 | // program name in order. If there is a match, the frontend type is updated as |
324 | // necessary by applying the ModeFlag. |
325 | static const DriverSuffix DriverSuffixes[] = { |
326 | {.Suffix: "clang" , .ModeFlag: nullptr}, |
327 | {.Suffix: "clang++" , .ModeFlag: "--driver-mode=g++" }, |
328 | {.Suffix: "clang-c++" , .ModeFlag: "--driver-mode=g++" }, |
329 | {.Suffix: "clang-cc" , .ModeFlag: nullptr}, |
330 | {.Suffix: "clang-cpp" , .ModeFlag: "--driver-mode=cpp" }, |
331 | {.Suffix: "clang-g++" , .ModeFlag: "--driver-mode=g++" }, |
332 | {.Suffix: "clang-gcc" , .ModeFlag: nullptr}, |
333 | {.Suffix: "clang-cl" , .ModeFlag: "--driver-mode=cl" }, |
334 | {.Suffix: "cc" , .ModeFlag: nullptr}, |
335 | {.Suffix: "cpp" , .ModeFlag: "--driver-mode=cpp" }, |
336 | {.Suffix: "cl" , .ModeFlag: "--driver-mode=cl" }, |
337 | {.Suffix: "++" , .ModeFlag: "--driver-mode=g++" }, |
338 | {.Suffix: "flang" , .ModeFlag: "--driver-mode=flang" }, |
339 | {.Suffix: "clang-dxc" , .ModeFlag: "--driver-mode=dxc" }, |
340 | }; |
341 | |
342 | for (const auto &DS : DriverSuffixes) { |
343 | StringRef Suffix(DS.Suffix); |
344 | if (ProgName.ends_with(Suffix)) { |
345 | Pos = ProgName.size() - Suffix.size(); |
346 | return &DS; |
347 | } |
348 | } |
349 | return nullptr; |
350 | } |
351 | |
352 | /// Normalize the program name from argv[0] by stripping the file extension if |
353 | /// present and lower-casing the string on Windows. |
354 | static std::string normalizeProgramName(llvm::StringRef Argv0) { |
355 | std::string ProgName = std::string(llvm::sys::path::filename(path: Argv0)); |
356 | if (is_style_windows(S: llvm::sys::path::Style::native)) { |
357 | // Transform to lowercase for case insensitive file systems. |
358 | std::transform(first: ProgName.begin(), last: ProgName.end(), result: ProgName.begin(), |
359 | unary_op: ::tolower); |
360 | } |
361 | return ProgName; |
362 | } |
363 | |
364 | static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) { |
365 | // Try to infer frontend type and default target from the program name by |
366 | // comparing it against DriverSuffixes in order. |
367 | |
368 | // If there is a match, the function tries to identify a target as prefix. |
369 | // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target |
370 | // prefix "x86_64-linux". If such a target prefix is found, it may be |
371 | // added via -target as implicit first argument. |
372 | const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos); |
373 | |
374 | if (!DS && ProgName.ends_with(Suffix: ".exe" )) { |
375 | // Try again after stripping the executable suffix: |
376 | // clang++.exe -> clang++ |
377 | ProgName = ProgName.drop_back(N: StringRef(".exe" ).size()); |
378 | DS = FindDriverSuffix(ProgName, Pos); |
379 | } |
380 | |
381 | if (!DS) { |
382 | // Try again after stripping any trailing version number: |
383 | // clang++3.5 -> clang++ |
384 | ProgName = ProgName.rtrim(Chars: "0123456789." ); |
385 | DS = FindDriverSuffix(ProgName, Pos); |
386 | } |
387 | |
388 | if (!DS) { |
389 | // Try again after stripping trailing -component. |
390 | // clang++-tot -> clang++ |
391 | ProgName = ProgName.slice(Start: 0, End: ProgName.rfind(C: '-')); |
392 | DS = FindDriverSuffix(ProgName, Pos); |
393 | } |
394 | return DS; |
395 | } |
396 | |
397 | ParsedClangName |
398 | ToolChain::getTargetAndModeFromProgramName(StringRef PN) { |
399 | std::string ProgName = normalizeProgramName(Argv0: PN); |
400 | size_t SuffixPos; |
401 | const DriverSuffix *DS = parseDriverSuffix(ProgName, Pos&: SuffixPos); |
402 | if (!DS) |
403 | return {}; |
404 | size_t SuffixEnd = SuffixPos + strlen(s: DS->Suffix); |
405 | |
406 | size_t LastComponent = ProgName.rfind(c: '-', pos: SuffixPos); |
407 | if (LastComponent == std::string::npos) |
408 | return ParsedClangName(ProgName.substr(pos: 0, n: SuffixEnd), DS->ModeFlag); |
409 | std::string ModeSuffix = ProgName.substr(pos: LastComponent + 1, |
410 | n: SuffixEnd - LastComponent - 1); |
411 | |
412 | // Infer target from the prefix. |
413 | StringRef Prefix(ProgName); |
414 | Prefix = Prefix.slice(Start: 0, End: LastComponent); |
415 | std::string IgnoredError; |
416 | bool IsRegistered = |
417 | llvm::TargetRegistry::lookupTarget(Triple: std::string(Prefix), Error&: IgnoredError); |
418 | return ParsedClangName{std::string(Prefix), ModeSuffix, DS->ModeFlag, |
419 | IsRegistered}; |
420 | } |
421 | |
422 | StringRef ToolChain::getDefaultUniversalArchName() const { |
423 | // In universal driver terms, the arch name accepted by -arch isn't exactly |
424 | // the same as the ones that appear in the triple. Roughly speaking, this is |
425 | // an inverse of the darwin::getArchTypeForDarwinArchName() function. |
426 | switch (Triple.getArch()) { |
427 | case llvm::Triple::aarch64: { |
428 | if (getTriple().isArm64e()) |
429 | return "arm64e" ; |
430 | return "arm64" ; |
431 | } |
432 | case llvm::Triple::aarch64_32: |
433 | return "arm64_32" ; |
434 | case llvm::Triple::ppc: |
435 | return "ppc" ; |
436 | case llvm::Triple::ppcle: |
437 | return "ppcle" ; |
438 | case llvm::Triple::ppc64: |
439 | return "ppc64" ; |
440 | case llvm::Triple::ppc64le: |
441 | return "ppc64le" ; |
442 | default: |
443 | return Triple.getArchName(); |
444 | } |
445 | } |
446 | |
447 | std::string ToolChain::getInputFilename(const InputInfo &Input) const { |
448 | return Input.getFilename(); |
449 | } |
450 | |
451 | ToolChain::UnwindTableLevel |
452 | ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { |
453 | return UnwindTableLevel::None; |
454 | } |
455 | |
456 | Tool *ToolChain::getClang() const { |
457 | if (!Clang) |
458 | Clang.reset(p: new tools::Clang(*this, useIntegratedBackend())); |
459 | return Clang.get(); |
460 | } |
461 | |
462 | Tool *ToolChain::getFlang() const { |
463 | if (!Flang) |
464 | Flang.reset(p: new tools::Flang(*this)); |
465 | return Flang.get(); |
466 | } |
467 | |
468 | Tool *ToolChain::buildAssembler() const { |
469 | return new tools::ClangAs(*this); |
470 | } |
471 | |
472 | Tool *ToolChain::buildLinker() const { |
473 | llvm_unreachable("Linking is not supported by this toolchain" ); |
474 | } |
475 | |
476 | Tool *ToolChain::buildStaticLibTool() const { |
477 | llvm_unreachable("Creating static lib is not supported by this toolchain" ); |
478 | } |
479 | |
480 | Tool *ToolChain::getAssemble() const { |
481 | if (!Assemble) |
482 | Assemble.reset(p: buildAssembler()); |
483 | return Assemble.get(); |
484 | } |
485 | |
486 | Tool *ToolChain::getClangAs() const { |
487 | if (!Assemble) |
488 | Assemble.reset(p: new tools::ClangAs(*this)); |
489 | return Assemble.get(); |
490 | } |
491 | |
492 | Tool *ToolChain::getLink() const { |
493 | if (!Link) |
494 | Link.reset(p: buildLinker()); |
495 | return Link.get(); |
496 | } |
497 | |
498 | Tool *ToolChain::getStaticLibTool() const { |
499 | if (!StaticLibTool) |
500 | StaticLibTool.reset(p: buildStaticLibTool()); |
501 | return StaticLibTool.get(); |
502 | } |
503 | |
504 | Tool *ToolChain::getIfsMerge() const { |
505 | if (!IfsMerge) |
506 | IfsMerge.reset(p: new tools::ifstool::Merger(*this)); |
507 | return IfsMerge.get(); |
508 | } |
509 | |
510 | Tool *ToolChain::getOffloadBundler() const { |
511 | if (!OffloadBundler) |
512 | OffloadBundler.reset(p: new tools::OffloadBundler(*this)); |
513 | return OffloadBundler.get(); |
514 | } |
515 | |
516 | Tool *ToolChain::getOffloadPackager() const { |
517 | if (!OffloadPackager) |
518 | OffloadPackager.reset(p: new tools::OffloadPackager(*this)); |
519 | return OffloadPackager.get(); |
520 | } |
521 | |
522 | Tool *ToolChain::getLinkerWrapper() const { |
523 | if (!LinkerWrapper) |
524 | LinkerWrapper.reset(p: new tools::LinkerWrapper(*this, getLink())); |
525 | return LinkerWrapper.get(); |
526 | } |
527 | |
528 | Tool *ToolChain::getTool(Action::ActionClass AC) const { |
529 | switch (AC) { |
530 | case Action::AssembleJobClass: |
531 | return getAssemble(); |
532 | |
533 | case Action::IfsMergeJobClass: |
534 | return getIfsMerge(); |
535 | |
536 | case Action::LinkJobClass: |
537 | return getLink(); |
538 | |
539 | case Action::StaticLibJobClass: |
540 | return getStaticLibTool(); |
541 | |
542 | case Action::InputClass: |
543 | case Action::BindArchClass: |
544 | case Action::OffloadClass: |
545 | case Action::LipoJobClass: |
546 | case Action::DsymutilJobClass: |
547 | case Action::VerifyDebugInfoJobClass: |
548 | case Action::BinaryAnalyzeJobClass: |
549 | llvm_unreachable("Invalid tool kind." ); |
550 | |
551 | case Action::CompileJobClass: |
552 | case Action::PrecompileJobClass: |
553 | case Action::PreprocessJobClass: |
554 | case Action::ExtractAPIJobClass: |
555 | case Action::AnalyzeJobClass: |
556 | case Action::MigrateJobClass: |
557 | case Action::VerifyPCHJobClass: |
558 | case Action::BackendJobClass: |
559 | return getClang(); |
560 | |
561 | case Action::OffloadBundlingJobClass: |
562 | case Action::OffloadUnbundlingJobClass: |
563 | return getOffloadBundler(); |
564 | |
565 | case Action::OffloadPackagerJobClass: |
566 | return getOffloadPackager(); |
567 | case Action::LinkerWrapperJobClass: |
568 | return getLinkerWrapper(); |
569 | } |
570 | |
571 | llvm_unreachable("Invalid tool kind." ); |
572 | } |
573 | |
574 | static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, |
575 | const ArgList &Args) { |
576 | const llvm::Triple &Triple = TC.getTriple(); |
577 | bool IsWindows = Triple.isOSWindows(); |
578 | |
579 | if (TC.isBareMetal()) |
580 | return Triple.getArchName(); |
581 | |
582 | if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) |
583 | return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) |
584 | ? "armhf" |
585 | : "arm" ; |
586 | |
587 | // For historic reasons, Android library is using i686 instead of i386. |
588 | if (TC.getArch() == llvm::Triple::x86 && Triple.isAndroid()) |
589 | return "i686" ; |
590 | |
591 | if (TC.getArch() == llvm::Triple::x86_64 && Triple.isX32()) |
592 | return "x32" ; |
593 | |
594 | return llvm::Triple::getArchTypeName(Kind: TC.getArch()); |
595 | } |
596 | |
597 | StringRef ToolChain::getOSLibName() const { |
598 | if (Triple.isOSDarwin()) |
599 | return "darwin" ; |
600 | |
601 | switch (Triple.getOS()) { |
602 | case llvm::Triple::FreeBSD: |
603 | return "freebsd" ; |
604 | case llvm::Triple::NetBSD: |
605 | return "netbsd" ; |
606 | case llvm::Triple::OpenBSD: |
607 | return "openbsd" ; |
608 | case llvm::Triple::Solaris: |
609 | return "sunos" ; |
610 | case llvm::Triple::AIX: |
611 | return "aix" ; |
612 | default: |
613 | return getOS(); |
614 | } |
615 | } |
616 | |
617 | std::string ToolChain::getCompilerRTPath() const { |
618 | SmallString<128> Path(getDriver().ResourceDir); |
619 | if (isBareMetal()) { |
620 | llvm::sys::path::append(path&: Path, a: "lib" , b: getOSLibName()); |
621 | if (!SelectedMultilibs.empty()) { |
622 | Path += SelectedMultilibs.back().gccSuffix(); |
623 | } |
624 | } else if (Triple.isOSUnknown()) { |
625 | llvm::sys::path::append(path&: Path, a: "lib" ); |
626 | } else { |
627 | llvm::sys::path::append(path&: Path, a: "lib" , b: getOSLibName()); |
628 | } |
629 | return std::string(Path); |
630 | } |
631 | |
632 | std::string ToolChain::getCompilerRTBasename(const ArgList &Args, |
633 | StringRef Component, |
634 | FileType Type) const { |
635 | std::string CRTAbsolutePath = getCompilerRT(Args, Component, Type); |
636 | return llvm::sys::path::filename(path: CRTAbsolutePath).str(); |
637 | } |
638 | |
639 | std::string ToolChain::buildCompilerRTBasename(const llvm::opt::ArgList &Args, |
640 | StringRef Component, |
641 | FileType Type, |
642 | bool AddArch) const { |
643 | const llvm::Triple &TT = getTriple(); |
644 | bool IsITANMSVCWindows = |
645 | TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment(); |
646 | |
647 | const char *Prefix = |
648 | IsITANMSVCWindows || Type == ToolChain::FT_Object ? "" : "lib" ; |
649 | const char *Suffix; |
650 | switch (Type) { |
651 | case ToolChain::FT_Object: |
652 | Suffix = IsITANMSVCWindows ? ".obj" : ".o" ; |
653 | break; |
654 | case ToolChain::FT_Static: |
655 | Suffix = IsITANMSVCWindows ? ".lib" : ".a" ; |
656 | break; |
657 | case ToolChain::FT_Shared: |
658 | Suffix = TT.isOSWindows() |
659 | ? (TT.isWindowsGNUEnvironment() ? ".dll.a" : ".lib" ) |
660 | : ".so" ; |
661 | break; |
662 | } |
663 | |
664 | std::string ArchAndEnv; |
665 | if (AddArch) { |
666 | StringRef Arch = getArchNameForCompilerRTLib(TC: *this, Args); |
667 | const char *Env = TT.isAndroid() ? "-android" : "" ; |
668 | ArchAndEnv = ("-" + Arch + Env).str(); |
669 | } |
670 | return (Prefix + Twine("clang_rt." ) + Component + ArchAndEnv + Suffix).str(); |
671 | } |
672 | |
673 | std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, |
674 | FileType Type) const { |
675 | // Check for runtime files in the new layout without the architecture first. |
676 | std::string CRTBasename = |
677 | buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); |
678 | SmallString<128> Path; |
679 | for (const auto &LibPath : getLibraryPaths()) { |
680 | SmallString<128> P(LibPath); |
681 | llvm::sys::path::append(path&: P, a: CRTBasename); |
682 | if (getVFS().exists(Path: P)) |
683 | return std::string(P); |
684 | if (Path.empty()) |
685 | Path = P; |
686 | } |
687 | if (getTriple().isOSAIX()) |
688 | Path.clear(); |
689 | |
690 | // Check the filename for the old layout if the new one does not exist. |
691 | CRTBasename = |
692 | buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/true); |
693 | SmallString<128> OldPath(getCompilerRTPath()); |
694 | llvm::sys::path::append(path&: OldPath, a: CRTBasename); |
695 | if (Path.empty() || getVFS().exists(Path: OldPath)) |
696 | return std::string(OldPath); |
697 | |
698 | // If none is found, use a file name from the new layout, which may get |
699 | // printed in an error message, aiding users in knowing what Clang is |
700 | // looking for. |
701 | return std::string(Path); |
702 | } |
703 | |
704 | const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, |
705 | StringRef Component, |
706 | FileType Type) const { |
707 | return Args.MakeArgString(Str: getCompilerRT(Args, Component, Type)); |
708 | } |
709 | |
710 | // Android target triples contain a target version. If we don't have libraries |
711 | // for the exact target version, we should fall back to the next newest version |
712 | // or a versionless path, if any. |
713 | std::optional<std::string> |
714 | ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const { |
715 | llvm::Triple TripleWithoutLevel(getTriple()); |
716 | TripleWithoutLevel.setEnvironmentName("android" ); // remove any version number |
717 | const std::string &TripleWithoutLevelStr = TripleWithoutLevel.str(); |
718 | unsigned TripleVersion = getTriple().getEnvironmentVersion().getMajor(); |
719 | unsigned BestVersion = 0; |
720 | |
721 | SmallString<32> TripleDir; |
722 | bool UsingUnversionedDir = false; |
723 | std::error_code EC; |
724 | for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Dir: BaseDir, EC), LE; |
725 | !EC && LI != LE; LI = LI.increment(EC)) { |
726 | StringRef DirName = llvm::sys::path::filename(path: LI->path()); |
727 | StringRef DirNameSuffix = DirName; |
728 | if (DirNameSuffix.consume_front(Prefix: TripleWithoutLevelStr)) { |
729 | if (DirNameSuffix.empty() && TripleDir.empty()) { |
730 | TripleDir = DirName; |
731 | UsingUnversionedDir = true; |
732 | } else { |
733 | unsigned Version; |
734 | if (!DirNameSuffix.getAsInteger(Radix: 10, Result&: Version) && Version > BestVersion && |
735 | Version < TripleVersion) { |
736 | BestVersion = Version; |
737 | TripleDir = DirName; |
738 | UsingUnversionedDir = false; |
739 | } |
740 | } |
741 | } |
742 | } |
743 | |
744 | if (TripleDir.empty()) |
745 | return {}; |
746 | |
747 | SmallString<128> P(BaseDir); |
748 | llvm::sys::path::append(path&: P, a: TripleDir); |
749 | if (UsingUnversionedDir) |
750 | D.Diag(diag::DiagID: warn_android_unversioned_fallback) << P << getTripleString(); |
751 | return std::string(P); |
752 | } |
753 | |
754 | std::optional<std::string> |
755 | ToolChain::getTargetSubDirPath(StringRef BaseDir) const { |
756 | auto getPathForTriple = |
757 | [&](const llvm::Triple &Triple) -> std::optional<std::string> { |
758 | SmallString<128> P(BaseDir); |
759 | llvm::sys::path::append(path&: P, a: Triple.str()); |
760 | if (getVFS().exists(Path: P)) |
761 | return std::string(P); |
762 | return {}; |
763 | }; |
764 | |
765 | if (auto Path = getPathForTriple(getTriple())) |
766 | return *Path; |
767 | |
768 | // When building with per target runtime directories, various ways of naming |
769 | // the Arm architecture may have been normalised to simply "arm". |
770 | // For example "armv8l" (Armv8 AArch32 little endian) is replaced with "arm". |
771 | // Since an armv8l system can use libraries built for earlier architecture |
772 | // versions assuming endian and float ABI match. |
773 | // |
774 | // Original triple: armv8l-unknown-linux-gnueabihf |
775 | // Runtime triple: arm-unknown-linux-gnueabihf |
776 | // |
777 | // We do not do this for armeb (big endian) because doing so could make us |
778 | // select little endian libraries. In addition, all known armeb triples only |
779 | // use the "armeb" architecture name. |
780 | // |
781 | // M profile Arm is bare metal and we know they will not be using the per |
782 | // target runtime directory layout. |
783 | if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) { |
784 | llvm::Triple ArmTriple = getTriple(); |
785 | ArmTriple.setArch(Kind: Triple::arm); |
786 | if (auto Path = getPathForTriple(ArmTriple)) |
787 | return *Path; |
788 | } |
789 | |
790 | if (getTriple().isAndroid()) |
791 | return getFallbackAndroidTargetPath(BaseDir); |
792 | |
793 | return {}; |
794 | } |
795 | |
796 | std::optional<std::string> ToolChain::getRuntimePath() const { |
797 | SmallString<128> P(D.ResourceDir); |
798 | llvm::sys::path::append(path&: P, a: "lib" ); |
799 | if (auto Ret = getTargetSubDirPath(BaseDir: P)) |
800 | return Ret; |
801 | // Darwin does not use per-target runtime directory. |
802 | if (Triple.isOSDarwin()) |
803 | return {}; |
804 | llvm::sys::path::append(path&: P, a: Triple.str()); |
805 | return std::string(P); |
806 | } |
807 | |
808 | std::optional<std::string> ToolChain::getStdlibPath() const { |
809 | SmallString<128> P(D.Dir); |
810 | llvm::sys::path::append(path&: P, a: ".." , b: "lib" ); |
811 | return getTargetSubDirPath(BaseDir: P); |
812 | } |
813 | |
814 | ToolChain::path_list ToolChain::getArchSpecificLibPaths() const { |
815 | path_list Paths; |
816 | |
817 | auto AddPath = [&](const ArrayRef<StringRef> &SS) { |
818 | SmallString<128> Path(getDriver().ResourceDir); |
819 | llvm::sys::path::append(path&: Path, a: "lib" ); |
820 | for (auto &S : SS) |
821 | llvm::sys::path::append(path&: Path, a: S); |
822 | Paths.push_back(Elt: std::string(Path)); |
823 | }; |
824 | |
825 | AddPath({getTriple().str()}); |
826 | AddPath({getOSLibName(), llvm::Triple::getArchTypeName(Kind: getArch())}); |
827 | return Paths; |
828 | } |
829 | |
830 | bool ToolChain::needsProfileRT(const ArgList &Args) { |
831 | if (Args.hasArg(options::OPT_noprofilelib)) |
832 | return false; |
833 | |
834 | return Args.hasArg(options::OPT_fprofile_generate) || |
835 | Args.hasArg(options::OPT_fprofile_generate_EQ) || |
836 | Args.hasArg(options::OPT_fcs_profile_generate) || |
837 | Args.hasArg(options::OPT_fcs_profile_generate_EQ) || |
838 | Args.hasArg(options::OPT_fprofile_instr_generate) || |
839 | Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || |
840 | Args.hasArg(options::OPT_fcreate_profile) || |
841 | Args.hasArg(options::OPT_forder_file_instrumentation); |
842 | } |
843 | |
844 | bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) { |
845 | return Args.hasArg(options::OPT_coverage) || |
846 | Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, |
847 | false); |
848 | } |
849 | |
850 | Tool *ToolChain::SelectTool(const JobAction &JA) const { |
851 | if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang(); |
852 | if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); |
853 | Action::ActionClass AC = JA.getKind(); |
854 | if (AC == Action::AssembleJobClass && useIntegratedAs() && |
855 | !getTriple().isOSAIX()) |
856 | return getClangAs(); |
857 | return getTool(AC); |
858 | } |
859 | |
860 | std::string ToolChain::GetFilePath(const char *Name) const { |
861 | return D.GetFilePath(Name, TC: *this); |
862 | } |
863 | |
864 | std::string ToolChain::GetProgramPath(const char *Name) const { |
865 | return D.GetProgramPath(Name, TC: *this); |
866 | } |
867 | |
868 | std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { |
869 | if (LinkerIsLLD) |
870 | *LinkerIsLLD = false; |
871 | |
872 | // Get -fuse-ld= first to prevent -Wunused-command-line-argument. -fuse-ld= is |
873 | // considered as the linker flavor, e.g. "bfd", "gold", or "lld". |
874 | const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ); |
875 | StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; |
876 | |
877 | // --ld-path= takes precedence over -fuse-ld= and specifies the executable |
878 | // name. -B, COMPILER_PATH and PATH and consulted if the value does not |
879 | // contain a path component separator. |
880 | // -fuse-ld=lld can be used with --ld-path= to inform clang that the binary |
881 | // that --ld-path= points to is lld. |
882 | if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) { |
883 | std::string Path(A->getValue()); |
884 | if (!Path.empty()) { |
885 | if (llvm::sys::path::parent_path(path: Path).empty()) |
886 | Path = GetProgramPath(Name: A->getValue()); |
887 | if (llvm::sys::fs::can_execute(Path)) { |
888 | if (LinkerIsLLD) |
889 | *LinkerIsLLD = UseLinker == "lld" ; |
890 | return std::string(Path); |
891 | } |
892 | } |
893 | getDriver().Diag(diag::DiagID: err_drv_invalid_linker_name) << A->getAsString(Args); |
894 | return GetProgramPath(Name: getDefaultLinker()); |
895 | } |
896 | // If we're passed -fuse-ld= with no argument, or with the argument ld, |
897 | // then use whatever the default system linker is. |
898 | if (UseLinker.empty() || UseLinker == "ld" ) { |
899 | const char *DefaultLinker = getDefaultLinker(); |
900 | if (llvm::sys::path::is_absolute(path: DefaultLinker)) |
901 | return std::string(DefaultLinker); |
902 | else |
903 | return GetProgramPath(Name: DefaultLinker); |
904 | } |
905 | |
906 | // Extending -fuse-ld= to an absolute or relative path is unexpected. Checking |
907 | // for the linker flavor is brittle. In addition, prepending "ld." or "ld64." |
908 | // to a relative path is surprising. This is more complex due to priorities |
909 | // among -B, COMPILER_PATH and PATH. --ld-path= should be used instead. |
910 | if (UseLinker.contains(C: '/')) |
911 | getDriver().Diag(diag::DiagID: warn_drv_fuse_ld_path); |
912 | |
913 | if (llvm::sys::path::is_absolute(path: UseLinker)) { |
914 | // If we're passed what looks like an absolute path, don't attempt to |
915 | // second-guess that. |
916 | if (llvm::sys::fs::can_execute(Path: UseLinker)) |
917 | return std::string(UseLinker); |
918 | } else { |
919 | llvm::SmallString<8> LinkerName; |
920 | if (Triple.isOSDarwin()) |
921 | LinkerName.append(RHS: "ld64." ); |
922 | else |
923 | LinkerName.append(RHS: "ld." ); |
924 | LinkerName.append(RHS: UseLinker); |
925 | |
926 | std::string LinkerPath(GetProgramPath(Name: LinkerName.c_str())); |
927 | if (llvm::sys::fs::can_execute(Path: LinkerPath)) { |
928 | if (LinkerIsLLD) |
929 | *LinkerIsLLD = UseLinker == "lld" ; |
930 | return LinkerPath; |
931 | } |
932 | } |
933 | |
934 | if (A) |
935 | getDriver().Diag(diag::DiagID: err_drv_invalid_linker_name) << A->getAsString(Args); |
936 | |
937 | return GetProgramPath(Name: getDefaultLinker()); |
938 | } |
939 | |
940 | std::string ToolChain::GetStaticLibToolPath() const { |
941 | // TODO: Add support for static lib archiving on Windows |
942 | if (Triple.isOSDarwin()) |
943 | return GetProgramPath(Name: "libtool" ); |
944 | return GetProgramPath(Name: "llvm-ar" ); |
945 | } |
946 | |
947 | types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { |
948 | types::ID id = types::lookupTypeForExtension(Ext); |
949 | |
950 | // Flang always runs the preprocessor and has no notion of "preprocessed |
951 | // fortran". Here, TY_PP_Fortran is coerced to TY_Fortran to avoid treating |
952 | // them differently. |
953 | if (D.IsFlangMode() && id == types::TY_PP_Fortran) |
954 | id = types::TY_Fortran; |
955 | |
956 | return id; |
957 | } |
958 | |
959 | bool ToolChain::HasNativeLLVMSupport() const { |
960 | return false; |
961 | } |
962 | |
963 | bool ToolChain::isCrossCompiling() const { |
964 | llvm::Triple HostTriple(LLVM_HOST_TRIPLE); |
965 | switch (HostTriple.getArch()) { |
966 | // The A32/T32/T16 instruction sets are not separate architectures in this |
967 | // context. |
968 | case llvm::Triple::arm: |
969 | case llvm::Triple::armeb: |
970 | case llvm::Triple::thumb: |
971 | case llvm::Triple::thumbeb: |
972 | return getArch() != llvm::Triple::arm && getArch() != llvm::Triple::thumb && |
973 | getArch() != llvm::Triple::armeb && getArch() != llvm::Triple::thumbeb; |
974 | default: |
975 | return HostTriple.getArch() != getArch(); |
976 | } |
977 | } |
978 | |
979 | ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const { |
980 | return ObjCRuntime(isNonFragile ? ObjCRuntime::GNUstep : ObjCRuntime::GCC, |
981 | VersionTuple()); |
982 | } |
983 | |
984 | llvm::ExceptionHandling |
985 | ToolChain::GetExceptionModel(const llvm::opt::ArgList &Args) const { |
986 | return llvm::ExceptionHandling::None; |
987 | } |
988 | |
989 | bool ToolChain::isThreadModelSupported(const StringRef Model) const { |
990 | if (Model == "single" ) { |
991 | // FIXME: 'single' is only supported on ARM and WebAssembly so far. |
992 | return Triple.getArch() == llvm::Triple::arm || |
993 | Triple.getArch() == llvm::Triple::armeb || |
994 | Triple.getArch() == llvm::Triple::thumb || |
995 | Triple.getArch() == llvm::Triple::thumbeb || Triple.isWasm(); |
996 | } else if (Model == "posix" ) |
997 | return true; |
998 | |
999 | return false; |
1000 | } |
1001 | |
1002 | std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, |
1003 | types::ID InputType) const { |
1004 | switch (getTriple().getArch()) { |
1005 | default: |
1006 | return getTripleString(); |
1007 | |
1008 | case llvm::Triple::x86_64: { |
1009 | llvm::Triple Triple = getTriple(); |
1010 | if (!Triple.isOSBinFormatMachO()) |
1011 | return getTripleString(); |
1012 | |
1013 | if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { |
1014 | // x86_64h goes in the triple. Other -march options just use the |
1015 | // vanilla triple we already have. |
1016 | StringRef MArch = A->getValue(); |
1017 | if (MArch == "x86_64h" ) |
1018 | Triple.setArchName(MArch); |
1019 | } |
1020 | return Triple.getTriple(); |
1021 | } |
1022 | case llvm::Triple::aarch64: { |
1023 | llvm::Triple Triple = getTriple(); |
1024 | if (!Triple.isOSBinFormatMachO()) |
1025 | return getTripleString(); |
1026 | |
1027 | if (Triple.isArm64e()) |
1028 | return getTripleString(); |
1029 | |
1030 | // FIXME: older versions of ld64 expect the "arm64" component in the actual |
1031 | // triple string and query it to determine whether an LTO file can be |
1032 | // handled. Remove this when we don't care any more. |
1033 | Triple.setArchName("arm64" ); |
1034 | return Triple.getTriple(); |
1035 | } |
1036 | case llvm::Triple::aarch64_32: |
1037 | return getTripleString(); |
1038 | case llvm::Triple::arm: |
1039 | case llvm::Triple::armeb: |
1040 | case llvm::Triple::thumb: |
1041 | case llvm::Triple::thumbeb: { |
1042 | llvm::Triple Triple = getTriple(); |
1043 | tools::arm::setArchNameInTriple(D: getDriver(), Args, InputType, Triple); |
1044 | tools::arm::setFloatABIInTriple(D: getDriver(), Args, triple&: Triple); |
1045 | return Triple.getTriple(); |
1046 | } |
1047 | } |
1048 | } |
1049 | |
1050 | std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, |
1051 | types::ID InputType) const { |
1052 | return ComputeLLVMTriple(Args, InputType); |
1053 | } |
1054 | |
1055 | std::string ToolChain::computeSysRoot() const { |
1056 | return D.SysRoot; |
1057 | } |
1058 | |
1059 | void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
1060 | ArgStringList &CC1Args) const { |
1061 | // Each toolchain should provide the appropriate include flags. |
1062 | } |
1063 | |
1064 | void ToolChain::addClangTargetOptions( |
1065 | const ArgList &DriverArgs, ArgStringList &CC1Args, |
1066 | Action::OffloadKind DeviceOffloadKind) const {} |
1067 | |
1068 | void ToolChain::addClangCC1ASTargetOptions(const ArgList &Args, |
1069 | ArgStringList &CC1ASArgs) const {} |
1070 | |
1071 | void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} |
1072 | |
1073 | void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, |
1074 | llvm::opt::ArgStringList &CmdArgs) const { |
1075 | if (!needsProfileRT(Args) && !needsGCovInstrumentation(Args)) |
1076 | return; |
1077 | |
1078 | CmdArgs.push_back(Elt: getCompilerRTArgString(Args, Component: "profile" )); |
1079 | } |
1080 | |
1081 | ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( |
1082 | const ArgList &Args) const { |
1083 | if (runtimeLibType) |
1084 | return *runtimeLibType; |
1085 | |
1086 | const Arg* A = Args.getLastArg(options::OPT_rtlib_EQ); |
1087 | StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_RTLIB; |
1088 | |
1089 | // Only use "platform" in tests to override CLANG_DEFAULT_RTLIB! |
1090 | if (LibName == "compiler-rt" ) |
1091 | runtimeLibType = ToolChain::RLT_CompilerRT; |
1092 | else if (LibName == "libgcc" ) |
1093 | runtimeLibType = ToolChain::RLT_Libgcc; |
1094 | else if (LibName == "platform" ) |
1095 | runtimeLibType = GetDefaultRuntimeLibType(); |
1096 | else { |
1097 | if (A) |
1098 | getDriver().Diag(diag::DiagID: err_drv_invalid_rtlib_name) |
1099 | << A->getAsString(Args); |
1100 | |
1101 | runtimeLibType = GetDefaultRuntimeLibType(); |
1102 | } |
1103 | |
1104 | return *runtimeLibType; |
1105 | } |
1106 | |
1107 | ToolChain::UnwindLibType ToolChain::GetUnwindLibType( |
1108 | const ArgList &Args) const { |
1109 | if (unwindLibType) |
1110 | return *unwindLibType; |
1111 | |
1112 | const Arg *A = Args.getLastArg(options::OPT_unwindlib_EQ); |
1113 | StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_UNWINDLIB; |
1114 | |
1115 | if (LibName == "none" ) |
1116 | unwindLibType = ToolChain::UNW_None; |
1117 | else if (LibName == "platform" || LibName == "" ) { |
1118 | ToolChain::RuntimeLibType RtLibType = GetRuntimeLibType(Args); |
1119 | if (RtLibType == ToolChain::RLT_CompilerRT) { |
1120 | if (getTriple().isAndroid() || getTriple().isOSAIX()) |
1121 | unwindLibType = ToolChain::UNW_CompilerRT; |
1122 | else |
1123 | unwindLibType = ToolChain::UNW_None; |
1124 | } else if (RtLibType == ToolChain::RLT_Libgcc) |
1125 | unwindLibType = ToolChain::UNW_Libgcc; |
1126 | } else if (LibName == "libunwind" ) { |
1127 | if (GetRuntimeLibType(Args) == RLT_Libgcc) |
1128 | getDriver().Diag(diag::DiagID: err_drv_incompatible_unwindlib); |
1129 | unwindLibType = ToolChain::UNW_CompilerRT; |
1130 | } else if (LibName == "libgcc" ) |
1131 | unwindLibType = ToolChain::UNW_Libgcc; |
1132 | else { |
1133 | if (A) |
1134 | getDriver().Diag(diag::DiagID: err_drv_invalid_unwindlib_name) |
1135 | << A->getAsString(Args); |
1136 | |
1137 | unwindLibType = GetDefaultUnwindLibType(); |
1138 | } |
1139 | |
1140 | return *unwindLibType; |
1141 | } |
1142 | |
1143 | ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ |
1144 | if (cxxStdlibType) |
1145 | return *cxxStdlibType; |
1146 | |
1147 | const Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); |
1148 | StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_CXX_STDLIB; |
1149 | |
1150 | // Only use "platform" in tests to override CLANG_DEFAULT_CXX_STDLIB! |
1151 | if (LibName == "libc++" ) |
1152 | cxxStdlibType = ToolChain::CST_Libcxx; |
1153 | else if (LibName == "libstdc++" ) |
1154 | cxxStdlibType = ToolChain::CST_Libstdcxx; |
1155 | else if (LibName == "platform" ) |
1156 | cxxStdlibType = GetDefaultCXXStdlibType(); |
1157 | else { |
1158 | if (A) |
1159 | getDriver().Diag(diag::DiagID: err_drv_invalid_stdlib_name) |
1160 | << A->getAsString(Args); |
1161 | |
1162 | cxxStdlibType = GetDefaultCXXStdlibType(); |
1163 | } |
1164 | |
1165 | return *cxxStdlibType; |
1166 | } |
1167 | |
1168 | /// Utility function to add a system include directory to CC1 arguments. |
1169 | /*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs, |
1170 | ArgStringList &CC1Args, |
1171 | const Twine &Path) { |
1172 | CC1Args.push_back(Elt: "-internal-isystem" ); |
1173 | CC1Args.push_back(Elt: DriverArgs.MakeArgString(Str: Path)); |
1174 | } |
1175 | |
1176 | /// Utility function to add a system include directory with extern "C" |
1177 | /// semantics to CC1 arguments. |
1178 | /// |
1179 | /// Note that this should be used rarely, and only for directories that |
1180 | /// historically and for legacy reasons are treated as having implicit extern |
1181 | /// "C" semantics. These semantics are *ignored* by and large today, but its |
1182 | /// important to preserve the preprocessor changes resulting from the |
1183 | /// classification. |
1184 | /*static*/ void ToolChain::addExternCSystemInclude(const ArgList &DriverArgs, |
1185 | ArgStringList &CC1Args, |
1186 | const Twine &Path) { |
1187 | CC1Args.push_back(Elt: "-internal-externc-isystem" ); |
1188 | CC1Args.push_back(Elt: DriverArgs.MakeArgString(Str: Path)); |
1189 | } |
1190 | |
1191 | void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, |
1192 | ArgStringList &CC1Args, |
1193 | const Twine &Path) { |
1194 | if (llvm::sys::fs::exists(Path)) |
1195 | addExternCSystemInclude(DriverArgs, CC1Args, Path); |
1196 | } |
1197 | |
1198 | /// Utility function to add a list of system include directories to CC1. |
1199 | /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, |
1200 | ArgStringList &CC1Args, |
1201 | ArrayRef<StringRef> Paths) { |
1202 | for (const auto &Path : Paths) { |
1203 | CC1Args.push_back(Elt: "-internal-isystem" ); |
1204 | CC1Args.push_back(Elt: DriverArgs.MakeArgString(Str: Path)); |
1205 | } |
1206 | } |
1207 | |
1208 | /*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A, |
1209 | const Twine &B, const Twine &C, |
1210 | const Twine &D) { |
1211 | SmallString<128> Result(Path); |
1212 | llvm::sys::path::append(path&: Result, style: llvm::sys::path::Style::posix, a: A, b: B, c: C, d: D); |
1213 | return std::string(Result); |
1214 | } |
1215 | |
1216 | std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const { |
1217 | std::error_code EC; |
1218 | int MaxVersion = 0; |
1219 | std::string MaxVersionString; |
1220 | SmallString<128> Path(IncludePath); |
1221 | llvm::sys::path::append(path&: Path, a: "c++" ); |
1222 | for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Dir: Path, EC), LE; |
1223 | !EC && LI != LE; LI = LI.increment(EC)) { |
1224 | StringRef VersionText = llvm::sys::path::filename(path: LI->path()); |
1225 | int Version; |
1226 | if (VersionText[0] == 'v' && |
1227 | !VersionText.slice(Start: 1, End: StringRef::npos).getAsInteger(Radix: 10, Result&: Version)) { |
1228 | if (Version > MaxVersion) { |
1229 | MaxVersion = Version; |
1230 | MaxVersionString = std::string(VersionText); |
1231 | } |
1232 | } |
1233 | } |
1234 | if (!MaxVersion) |
1235 | return "" ; |
1236 | return MaxVersionString; |
1237 | } |
1238 | |
1239 | void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, |
1240 | ArgStringList &CC1Args) const { |
1241 | // Header search paths should be handled by each of the subclasses. |
1242 | // Historically, they have not been, and instead have been handled inside of |
1243 | // the CC1-layer frontend. As the logic is hoisted out, this generic function |
1244 | // will slowly stop being called. |
1245 | // |
1246 | // While it is being called, replicate a bit of a hack to propagate the |
1247 | // '-stdlib=' flag down to CC1 so that it can in turn customize the C++ |
1248 | // header search paths with it. Once all systems are overriding this |
1249 | // function, the CC1 flag and this line can be removed. |
1250 | DriverArgs.AddAllArgs(Output&: CC1Args, options::Id0: OPT_stdlib_EQ); |
1251 | } |
1252 | |
1253 | void ToolChain::AddClangCXXStdlibIsystemArgs( |
1254 | const llvm::opt::ArgList &DriverArgs, |
1255 | llvm::opt::ArgStringList &CC1Args) const { |
1256 | DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem); |
1257 | // This intentionally only looks at -nostdinc++, and not -nostdinc or |
1258 | // -nostdlibinc. The purpose of -stdlib++-isystem is to support toolchain |
1259 | // setups with non-standard search logic for the C++ headers, while still |
1260 | // allowing users of the toolchain to bring their own C++ headers. Such a |
1261 | // toolchain likely also has non-standard search logic for the C headers and |
1262 | // uses -nostdinc to suppress the default logic, but -stdlib++-isystem should |
1263 | // still work in that case and only be suppressed by an explicit -nostdinc++ |
1264 | // in a project using the toolchain. |
1265 | if (!DriverArgs.hasArg(options::OPT_nostdincxx)) |
1266 | for (const auto &P : |
1267 | DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem)) |
1268 | addSystemInclude(DriverArgs, CC1Args, P); |
1269 | } |
1270 | |
1271 | bool ToolChain::ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const { |
1272 | return getDriver().CCCIsCXX() && |
1273 | !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, |
1274 | options::OPT_nostdlibxx); |
1275 | } |
1276 | |
1277 | void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, |
1278 | ArgStringList &CmdArgs) const { |
1279 | assert(!Args.hasArg(options::OPT_nostdlibxx) && |
1280 | "should not have called this" ); |
1281 | CXXStdlibType Type = GetCXXStdlibType(Args); |
1282 | |
1283 | switch (Type) { |
1284 | case ToolChain::CST_Libcxx: |
1285 | CmdArgs.push_back(Elt: "-lc++" ); |
1286 | if (Args.hasArg(options::OPT_fexperimental_library)) |
1287 | CmdArgs.push_back(Elt: "-lc++experimental" ); |
1288 | break; |
1289 | |
1290 | case ToolChain::CST_Libstdcxx: |
1291 | CmdArgs.push_back(Elt: "-lstdc++" ); |
1292 | break; |
1293 | } |
1294 | } |
1295 | |
1296 | void ToolChain::AddFilePathLibArgs(const ArgList &Args, |
1297 | ArgStringList &CmdArgs) const { |
1298 | for (const auto &LibPath : getFilePaths()) |
1299 | if(LibPath.length() > 0) |
1300 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: StringRef("-L" ) + LibPath)); |
1301 | } |
1302 | |
1303 | void ToolChain::AddCCKextLibArgs(const ArgList &Args, |
1304 | ArgStringList &CmdArgs) const { |
1305 | CmdArgs.push_back(Elt: "-lcc_kext" ); |
1306 | } |
1307 | |
1308 | bool ToolChain::isFastMathRuntimeAvailable(const ArgList &Args, |
1309 | std::string &Path) const { |
1310 | // Do not check for -fno-fast-math or -fno-unsafe-math when -Ofast passed |
1311 | // (to keep the linker options consistent with gcc and clang itself). |
1312 | if (!isOptimizationLevelFast(Args)) { |
1313 | // Check if -ffast-math or -funsafe-math. |
1314 | Arg *A = |
1315 | Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math, |
1316 | options::OPT_funsafe_math_optimizations, |
1317 | options::OPT_fno_unsafe_math_optimizations); |
1318 | |
1319 | if (!A || A->getOption().getID() == options::OPT_fno_fast_math || |
1320 | A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations) |
1321 | return false; |
1322 | } |
1323 | // If crtfastmath.o exists add it to the arguments. |
1324 | Path = GetFilePath(Name: "crtfastmath.o" ); |
1325 | return (Path != "crtfastmath.o" ); // Not found. |
1326 | } |
1327 | |
1328 | bool ToolChain::addFastMathRuntimeIfAvailable(const ArgList &Args, |
1329 | ArgStringList &CmdArgs) const { |
1330 | std::string Path; |
1331 | if (isFastMathRuntimeAvailable(Args, Path)) { |
1332 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: Path)); |
1333 | return true; |
1334 | } |
1335 | |
1336 | return false; |
1337 | } |
1338 | |
1339 | Expected<SmallVector<std::string>> |
1340 | ToolChain::getSystemGPUArchs(const llvm::opt::ArgList &Args) const { |
1341 | return SmallVector<std::string>(); |
1342 | } |
1343 | |
1344 | SanitizerMask ToolChain::getSupportedSanitizers() const { |
1345 | // Return sanitizers which don't require runtime support and are not |
1346 | // platform dependent. |
1347 | |
1348 | SanitizerMask Res = |
1349 | (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | |
1350 | (SanitizerKind::CFI & ~SanitizerKind::CFIICall) | |
1351 | SanitizerKind::CFICastStrict | SanitizerKind::FloatDivideByZero | |
1352 | SanitizerKind::KCFI | SanitizerKind::UnsignedIntegerOverflow | |
1353 | SanitizerKind::UnsignedShiftBase | SanitizerKind::ImplicitConversion | |
1354 | SanitizerKind::Nullability | SanitizerKind::LocalBounds; |
1355 | if (getTriple().getArch() == llvm::Triple::x86 || |
1356 | getTriple().getArch() == llvm::Triple::x86_64 || |
1357 | getTriple().getArch() == llvm::Triple::arm || getTriple().isWasm() || |
1358 | getTriple().isAArch64() || getTriple().isRISCV() || |
1359 | getTriple().isLoongArch64()) |
1360 | Res |= SanitizerKind::CFIICall; |
1361 | if (getTriple().getArch() == llvm::Triple::x86_64 || |
1362 | getTriple().isAArch64(PointerWidth: 64) || getTriple().isRISCV()) |
1363 | Res |= SanitizerKind::ShadowCallStack; |
1364 | if (getTriple().isAArch64(PointerWidth: 64)) |
1365 | Res |= SanitizerKind::MemTag; |
1366 | return Res; |
1367 | } |
1368 | |
1369 | void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, |
1370 | ArgStringList &CC1Args) const {} |
1371 | |
1372 | void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, |
1373 | ArgStringList &CC1Args) const {} |
1374 | |
1375 | llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> |
1376 | ToolChain::getDeviceLibs(const ArgList &DriverArgs) const { |
1377 | return {}; |
1378 | } |
1379 | |
1380 | void ToolChain::AddIAMCUIncludeArgs(const ArgList &DriverArgs, |
1381 | ArgStringList &CC1Args) const {} |
1382 | |
1383 | static VersionTuple separateMSVCFullVersion(unsigned Version) { |
1384 | if (Version < 100) |
1385 | return VersionTuple(Version); |
1386 | |
1387 | if (Version < 10000) |
1388 | return VersionTuple(Version / 100, Version % 100); |
1389 | |
1390 | unsigned Build = 0, Factor = 1; |
1391 | for (; Version > 10000; Version = Version / 10, Factor = Factor * 10) |
1392 | Build = Build + (Version % 10) * Factor; |
1393 | return VersionTuple(Version / 100, Version % 100, Build); |
1394 | } |
1395 | |
1396 | VersionTuple |
1397 | ToolChain::computeMSVCVersion(const Driver *D, |
1398 | const llvm::opt::ArgList &Args) const { |
1399 | const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version); |
1400 | const Arg *MSCompatibilityVersion = |
1401 | Args.getLastArg(options::OPT_fms_compatibility_version); |
1402 | |
1403 | if (MSCVersion && MSCompatibilityVersion) { |
1404 | if (D) |
1405 | D->Diag(diag::err_drv_argument_not_allowed_with) |
1406 | << MSCVersion->getAsString(Args) |
1407 | << MSCompatibilityVersion->getAsString(Args); |
1408 | return VersionTuple(); |
1409 | } |
1410 | |
1411 | if (MSCompatibilityVersion) { |
1412 | VersionTuple MSVT; |
1413 | if (MSVT.tryParse(string: MSCompatibilityVersion->getValue())) { |
1414 | if (D) |
1415 | D->Diag(diag::err_drv_invalid_value) |
1416 | << MSCompatibilityVersion->getAsString(Args) |
1417 | << MSCompatibilityVersion->getValue(); |
1418 | } else { |
1419 | return MSVT; |
1420 | } |
1421 | } |
1422 | |
1423 | if (MSCVersion) { |
1424 | unsigned Version = 0; |
1425 | if (StringRef(MSCVersion->getValue()).getAsInteger(Radix: 10, Result&: Version)) { |
1426 | if (D) |
1427 | D->Diag(diag::err_drv_invalid_value) |
1428 | << MSCVersion->getAsString(Args) << MSCVersion->getValue(); |
1429 | } else { |
1430 | return separateMSVCFullVersion(Version); |
1431 | } |
1432 | } |
1433 | |
1434 | return VersionTuple(); |
1435 | } |
1436 | |
1437 | llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( |
1438 | const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, |
1439 | SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const { |
1440 | DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); |
1441 | const OptTable &Opts = getDriver().getOpts(); |
1442 | bool Modified = false; |
1443 | |
1444 | // Handle -Xopenmp-target flags |
1445 | for (auto *A : Args) { |
1446 | // Exclude flags which may only apply to the host toolchain. |
1447 | // Do not exclude flags when the host triple (AuxTriple) |
1448 | // matches the current toolchain triple. If it is not present |
1449 | // at all, target and host share a toolchain. |
1450 | if (A->getOption().matches(options::OPT_m_Group)) { |
1451 | // Pass code object version to device toolchain |
1452 | // to correctly set metadata in intermediate files. |
1453 | if (SameTripleAsHost || |
1454 | A->getOption().matches(options::OPT_mcode_object_version_EQ)) |
1455 | DAL->append(A); |
1456 | else |
1457 | Modified = true; |
1458 | continue; |
1459 | } |
1460 | |
1461 | unsigned Index; |
1462 | unsigned Prev; |
1463 | bool XOpenMPTargetNoTriple = |
1464 | A->getOption().matches(options::OPT_Xopenmp_target); |
1465 | |
1466 | if (A->getOption().matches(options::OPT_Xopenmp_target_EQ)) { |
1467 | llvm::Triple TT(getOpenMPTriple(TripleStr: A->getValue(N: 0))); |
1468 | |
1469 | // Passing device args: -Xopenmp-target=<triple> -opt=val. |
1470 | if (TT.getTriple() == getTripleString()) |
1471 | Index = Args.getBaseArgs().MakeIndex(String0: A->getValue(N: 1)); |
1472 | else |
1473 | continue; |
1474 | } else if (XOpenMPTargetNoTriple) { |
1475 | // Passing device args: -Xopenmp-target -opt=val. |
1476 | Index = Args.getBaseArgs().MakeIndex(String0: A->getValue(N: 0)); |
1477 | } else { |
1478 | DAL->append(A); |
1479 | continue; |
1480 | } |
1481 | |
1482 | // Parse the argument to -Xopenmp-target. |
1483 | Prev = Index; |
1484 | std::unique_ptr<Arg> XOpenMPTargetArg(Opts.ParseOneArg(Args, Index)); |
1485 | if (!XOpenMPTargetArg || Index > Prev + 1) { |
1486 | getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args) |
1487 | << A->getAsString(Args); |
1488 | continue; |
1489 | } |
1490 | if (XOpenMPTargetNoTriple && XOpenMPTargetArg && |
1491 | Args.getAllArgValues(options::OPT_fopenmp_targets_EQ).size() != 1) { |
1492 | getDriver().Diag(diag::err_drv_Xopenmp_target_missing_triple); |
1493 | continue; |
1494 | } |
1495 | XOpenMPTargetArg->setBaseArg(A); |
1496 | A = XOpenMPTargetArg.release(); |
1497 | AllocatedArgs.push_back(Elt: A); |
1498 | DAL->append(A); |
1499 | Modified = true; |
1500 | } |
1501 | |
1502 | if (Modified) |
1503 | return DAL; |
1504 | |
1505 | delete DAL; |
1506 | return nullptr; |
1507 | } |
1508 | |
1509 | // TODO: Currently argument values separated by space e.g. |
1510 | // -Xclang -mframe-pointer=no cannot be passed by -Xarch_. This should be |
1511 | // fixed. |
1512 | void ToolChain::TranslateXarchArgs( |
1513 | const llvm::opt::DerivedArgList &Args, llvm::opt::Arg *&A, |
1514 | llvm::opt::DerivedArgList *DAL, |
1515 | SmallVectorImpl<llvm::opt::Arg *> *AllocatedArgs) const { |
1516 | const OptTable &Opts = getDriver().getOpts(); |
1517 | unsigned ValuePos = 1; |
1518 | if (A->getOption().matches(options::OPT_Xarch_device) || |
1519 | A->getOption().matches(options::OPT_Xarch_host)) |
1520 | ValuePos = 0; |
1521 | |
1522 | unsigned Index = Args.getBaseArgs().MakeIndex(String0: A->getValue(N: ValuePos)); |
1523 | unsigned Prev = Index; |
1524 | std::unique_ptr<llvm::opt::Arg> XarchArg(Opts.ParseOneArg(Args, Index)); |
1525 | |
1526 | // If the argument parsing failed or more than one argument was |
1527 | // consumed, the -Xarch_ argument's parameter tried to consume |
1528 | // extra arguments. Emit an error and ignore. |
1529 | // |
1530 | // We also want to disallow any options which would alter the |
1531 | // driver behavior; that isn't going to work in our model. We |
1532 | // use options::NoXarchOption to control this. |
1533 | if (!XarchArg || Index > Prev + 1) { |
1534 | getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) |
1535 | << A->getAsString(Args); |
1536 | return; |
1537 | } else if (XarchArg->getOption().hasFlag(Val: options::NoXarchOption)) { |
1538 | auto &Diags = getDriver().getDiags(); |
1539 | unsigned DiagID = |
1540 | Diags.getCustomDiagID(L: DiagnosticsEngine::Error, |
1541 | FormatString: "invalid Xarch argument: '%0', not all driver " |
1542 | "options can be forwared via Xarch argument" ); |
1543 | Diags.Report(DiagID) << A->getAsString(Args); |
1544 | return; |
1545 | } |
1546 | XarchArg->setBaseArg(A); |
1547 | A = XarchArg.release(); |
1548 | if (!AllocatedArgs) |
1549 | DAL->AddSynthesizedArg(A); |
1550 | else |
1551 | AllocatedArgs->push_back(Elt: A); |
1552 | } |
1553 | |
1554 | llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs( |
1555 | const llvm::opt::DerivedArgList &Args, StringRef BoundArch, |
1556 | Action::OffloadKind OFK, |
1557 | SmallVectorImpl<llvm::opt::Arg *> *AllocatedArgs) const { |
1558 | DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); |
1559 | bool Modified = false; |
1560 | |
1561 | bool IsDevice = OFK != Action::OFK_None && OFK != Action::OFK_Host; |
1562 | for (Arg *A : Args) { |
1563 | bool NeedTrans = false; |
1564 | bool Skip = false; |
1565 | if (A->getOption().matches(options::OPT_Xarch_device)) { |
1566 | NeedTrans = IsDevice; |
1567 | Skip = !IsDevice; |
1568 | } else if (A->getOption().matches(options::OPT_Xarch_host)) { |
1569 | NeedTrans = !IsDevice; |
1570 | Skip = IsDevice; |
1571 | } else if (A->getOption().matches(options::OPT_Xarch__) && IsDevice) { |
1572 | // Do not translate -Xarch_ options for non CUDA/HIP toolchain since |
1573 | // they may need special translation. |
1574 | // Skip this argument unless the architecture matches BoundArch |
1575 | if (BoundArch.empty() || A->getValue(N: 0) != BoundArch) |
1576 | Skip = true; |
1577 | else |
1578 | NeedTrans = true; |
1579 | } |
1580 | if (NeedTrans || Skip) |
1581 | Modified = true; |
1582 | if (NeedTrans) |
1583 | TranslateXarchArgs(Args, A, DAL, AllocatedArgs); |
1584 | if (!Skip) |
1585 | DAL->append(A); |
1586 | } |
1587 | |
1588 | if (Modified) |
1589 | return DAL; |
1590 | |
1591 | delete DAL; |
1592 | return nullptr; |
1593 | } |
1594 | |