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