1 | //===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ARM.h" |
10 | #include "clang/Driver/Driver.h" |
11 | #include "clang/Driver/Options.h" |
12 | #include "llvm/ADT/StringSwitch.h" |
13 | #include "llvm/Option/ArgList.h" |
14 | #include "llvm/TargetParser/ARMTargetParser.h" |
15 | #include "llvm/TargetParser/Host.h" |
16 | |
17 | using namespace clang::driver; |
18 | using namespace clang::driver::tools; |
19 | using namespace clang; |
20 | using namespace llvm::opt; |
21 | |
22 | // Get SubArch (vN). |
23 | int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) { |
24 | llvm::StringRef Arch = Triple.getArchName(); |
25 | return llvm::ARM::parseArchVersion(Arch); |
26 | } |
27 | |
28 | // True if M-profile. |
29 | bool arm::isARMMProfile(const llvm::Triple &Triple) { |
30 | llvm::StringRef Arch = Triple.getArchName(); |
31 | return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; |
32 | } |
33 | |
34 | // On Arm the endianness of the output file is determined by the target and |
35 | // can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and |
36 | // '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a |
37 | // normalized triple so we must handle the flag here. |
38 | bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) { |
39 | if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, |
40 | options::OPT_mbig_endian)) { |
41 | return !A->getOption().matches(options::ID: OPT_mlittle_endian); |
42 | } |
43 | |
44 | return Triple.getArch() == llvm::Triple::armeb || |
45 | Triple.getArch() == llvm::Triple::thumbeb; |
46 | } |
47 | |
48 | // True if A-profile. |
49 | bool arm::isARMAProfile(const llvm::Triple &Triple) { |
50 | llvm::StringRef Arch = Triple.getArchName(); |
51 | return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::A; |
52 | } |
53 | |
54 | /// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? |
55 | bool arm::isARMEABIBareMetal(const llvm::Triple &Triple) { |
56 | auto arch = Triple.getArch(); |
57 | if (arch != llvm::Triple::arm && arch != llvm::Triple::thumb && |
58 | arch != llvm::Triple::armeb && arch != llvm::Triple::thumbeb) |
59 | return false; |
60 | |
61 | if (Triple.getVendor() != llvm::Triple::UnknownVendor) |
62 | return false; |
63 | |
64 | if (Triple.getOS() != llvm::Triple::UnknownOS) |
65 | return false; |
66 | |
67 | if (Triple.getEnvironment() != llvm::Triple::EABI && |
68 | Triple.getEnvironment() != llvm::Triple::EABIHF) |
69 | return false; |
70 | |
71 | return true; |
72 | } |
73 | |
74 | // Get Arch/CPU from args. |
75 | void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, |
76 | llvm::StringRef &CPU, bool FromAs) { |
77 | if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) |
78 | CPU = A->getValue(); |
79 | if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) |
80 | Arch = A->getValue(); |
81 | if (!FromAs) |
82 | return; |
83 | |
84 | for (const Arg *A : |
85 | Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { |
86 | // Use getValues because -Wa can have multiple arguments |
87 | // e.g. -Wa,-mcpu=foo,-mcpu=bar |
88 | for (StringRef Value : A->getValues()) { |
89 | if (Value.starts_with("-mcpu=")) |
90 | CPU = Value.substr(6); |
91 | if (Value.starts_with("-march=")) |
92 | Arch = Value.substr(7); |
93 | } |
94 | } |
95 | } |
96 | |
97 | // Handle -mhwdiv=. |
98 | // FIXME: Use ARMTargetParser. |
99 | static void getARMHWDivFeatures(const Driver &D, const Arg *A, |
100 | const ArgList &Args, StringRef HWDiv, |
101 | std::vector<StringRef> &Features) { |
102 | uint64_t HWDivID = llvm::ARM::parseHWDiv(HWDiv); |
103 | if (!llvm::ARM::getHWDivFeatures(HWDivKind: HWDivID, Features)) |
104 | D.Diag(clang::diag::DiagID: err_drv_clang_unsupported) << A->getAsString(Args); |
105 | } |
106 | |
107 | // Handle -mfpu=. |
108 | static llvm::ARM::FPUKind getARMFPUFeatures(const Driver &D, const Arg *A, |
109 | const ArgList &Args, StringRef FPU, |
110 | std::vector<StringRef> &Features) { |
111 | llvm::ARM::FPUKind FPUKind = llvm::ARM::parseFPU(FPU); |
112 | if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) |
113 | D.Diag(clang::diag::DiagID: err_drv_clang_unsupported) << A->getAsString(Args); |
114 | return FPUKind; |
115 | } |
116 | |
117 | // Decode ARM features from string like +[no]featureA+[no]featureB+... |
118 | static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU, |
119 | llvm::ARM::ArchKind ArchKind, |
120 | std::vector<StringRef> &Features, |
121 | llvm::ARM::FPUKind &ArgFPUKind) { |
122 | SmallVector<StringRef, 8> Split; |
123 | text.split(A&: Split, Separator: StringRef("+"), MaxSplit: -1, KeepEmpty: false); |
124 | |
125 | for (StringRef Feature : Split) { |
126 | if (!appendArchExtFeatures(CPU, AK: ArchKind, ArchExt: Feature, Features, ArgFPUKind)) |
127 | return false; |
128 | } |
129 | return true; |
130 | } |
131 | |
132 | static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, |
133 | std::vector<StringRef> &Features) { |
134 | CPU = CPU.split(Separator: "+").first; |
135 | if (CPU != "generic") { |
136 | llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); |
137 | uint64_t Extension = llvm::ARM::getDefaultExtensions(CPU, AK: ArchKind); |
138 | llvm::ARM::getExtensionFeatures(Extensions: Extension, Features); |
139 | } |
140 | } |
141 | |
142 | // Check if -march is valid by checking if it can be canonicalised and parsed. |
143 | // getARMArch is used here instead of just checking the -march value in order |
144 | // to handle -march=native correctly. |
145 | static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, |
146 | llvm::StringRef ArchName, llvm::StringRef CPUName, |
147 | std::vector<StringRef> &Features, |
148 | const llvm::Triple &Triple, |
149 | llvm::ARM::FPUKind &ArgFPUKind) { |
150 | std::pair<StringRef, StringRef> Split = ArchName.split(Separator: "+"); |
151 | |
152 | std::string MArch = arm::getARMArch(Arch: ArchName, Triple); |
153 | llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Arch: MArch); |
154 | if (ArchKind == llvm::ARM::ArchKind::INVALID || |
155 | (Split.second.size() && |
156 | !DecodeARMFeatures(D, text: Split.second, CPU: CPUName, ArchKind, Features, |
157 | ArgFPUKind))) |
158 | D.Diag(clang::diag::DiagID: err_drv_unsupported_option_argument) |
159 | << A->getSpelling() << A->getValue(); |
160 | } |
161 | |
162 | // Check -mcpu=. Needs ArchName to handle -mcpu=generic. |
163 | static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, |
164 | llvm::StringRef CPUName, llvm::StringRef ArchName, |
165 | std::vector<StringRef> &Features, |
166 | const llvm::Triple &Triple, |
167 | llvm::ARM::FPUKind &ArgFPUKind) { |
168 | std::pair<StringRef, StringRef> Split = CPUName.split(Separator: "+"); |
169 | |
170 | std::string CPU = arm::getARMTargetCPU(CPU: CPUName, Arch: ArchName, Triple); |
171 | llvm::ARM::ArchKind ArchKind = |
172 | arm::getLLVMArchKindForARM(CPU, Arch: ArchName, Triple); |
173 | if (ArchKind == llvm::ARM::ArchKind::INVALID || |
174 | (Split.second.size() && !DecodeARMFeatures(D, text: Split.second, CPU, ArchKind, |
175 | Features, ArgFPUKind))) |
176 | D.Diag(clang::diag::DiagID: err_drv_unsupported_option_argument) |
177 | << A->getSpelling() << A->getValue(); |
178 | } |
179 | |
180 | // If -mfloat-abi=hard or -mhard-float are specified explicitly then check that |
181 | // floating point registers are available on the target CPU. |
182 | static void checkARMFloatABI(const Driver &D, const ArgList &Args, |
183 | bool HasFPRegs) { |
184 | if (HasFPRegs) |
185 | return; |
186 | const Arg *A = |
187 | Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, |
188 | options::OPT_mfloat_abi_EQ); |
189 | if (A && (A->getOption().matches(options::ID: OPT_mhard_float) || |
190 | (A->getOption().matches(options::ID: OPT_mfloat_abi_EQ) && |
191 | A->getValue() == StringRef("hard")))) |
192 | D.Diag(clang::diag::DiagID: warn_drv_no_floating_point_registers) |
193 | << A->getAsString(Args); |
194 | } |
195 | |
196 | bool arm::useAAPCSForMachO(const llvm::Triple &T) { |
197 | // The backend is hardwired to assume AAPCS for M-class processors, ensure |
198 | // the frontend matches that. |
199 | return T.getEnvironment() == llvm::Triple::EABI || |
200 | T.getEnvironment() == llvm::Triple::EABIHF || |
201 | T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(Triple: T); |
202 | } |
203 | |
204 | // Check whether the architecture backend has support for the MRC/MCR |
205 | // instructions that are used to set the hard thread pointer ("CP15 C13 |
206 | // Thread id"). |
207 | // This is not identical to ability to use the instruction, as the ARMV6K |
208 | // variants can only use it in Arm mode since they don't support Thumb2 |
209 | // encoding. |
210 | bool arm::isHardTPSupported(const llvm::Triple &Triple) { |
211 | int Ver = getARMSubArchVersionNumber(Triple); |
212 | llvm::ARM::ArchKind AK = llvm::ARM::parseArch(Arch: Triple.getArchName()); |
213 | return AK == llvm::ARM::ArchKind::ARMV6K || |
214 | AK == llvm::ARM::ArchKind::ARMV6KZ || |
215 | (Ver >= 7 && !isARMMProfile(Triple)); |
216 | } |
217 | |
218 | // Checks whether the architecture is capable of supporting the Thumb2 encoding |
219 | static bool supportsThumb2Encoding(const llvm::Triple &Triple) { |
220 | int Ver = arm::getARMSubArchVersionNumber(Triple); |
221 | llvm::ARM::ArchKind AK = llvm::ARM::parseArch(Arch: Triple.getArchName()); |
222 | return AK == llvm::ARM::ArchKind::ARMV6T2 || |
223 | (Ver >= 7 && AK != llvm::ARM::ArchKind::ARMV8MBaseline); |
224 | } |
225 | |
226 | // Select mode for reading thread pointer (-mtp=soft/cp15). |
227 | arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args, |
228 | const llvm::Triple &Triple, bool ForAS) { |
229 | Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ); |
230 | if (A && A->getValue() != StringRef("auto")) { |
231 | arm::ReadTPMode ThreadPointer = |
232 | llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) |
233 | .Case(S: "cp15", Value: ReadTPMode::TPIDRURO) |
234 | .Case(S: "tpidrurw", Value: ReadTPMode::TPIDRURW) |
235 | .Case(S: "tpidruro", Value: ReadTPMode::TPIDRURO) |
236 | .Case(S: "tpidrprw", Value: ReadTPMode::TPIDRPRW) |
237 | .Case(S: "soft", Value: ReadTPMode::Soft) |
238 | .Default(Value: ReadTPMode::Invalid); |
239 | if ((ThreadPointer == ReadTPMode::TPIDRURW || |
240 | ThreadPointer == ReadTPMode::TPIDRURO || |
241 | ThreadPointer == ReadTPMode::TPIDRPRW) && |
242 | !isHardTPSupported(Triple) && !ForAS) { |
243 | D.Diag(diag::DiagID: err_target_unsupported_tp_hard) << Triple.getArchName(); |
244 | return ReadTPMode::Invalid; |
245 | } |
246 | if (ThreadPointer != ReadTPMode::Invalid) |
247 | return ThreadPointer; |
248 | if (StringRef(A->getValue()).empty()) |
249 | D.Diag(diag::DiagID: err_drv_missing_arg_mtp) << A->getAsString(Args); |
250 | else |
251 | D.Diag(diag::DiagID: err_drv_invalid_mtp) << A->getAsString(Args); |
252 | return ReadTPMode::Invalid; |
253 | } |
254 | // In auto mode we enable HW mode only if both the hardware supports it and |
255 | // the thumb2 encoding. For example ARMV6T2 supports thumb2, but not hardware. |
256 | // ARMV6K has HW suport, but not thumb2. Otherwise we could enable it for |
257 | // ARMV6K in thumb mode. |
258 | bool autoUseHWTPMode = |
259 | isHardTPSupported(Triple) && supportsThumb2Encoding(Triple); |
260 | return autoUseHWTPMode ? ReadTPMode::TPIDRURO : ReadTPMode::Soft; |
261 | } |
262 | |
263 | void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, |
264 | types::ID InputType, llvm::Triple &Triple) { |
265 | StringRef MCPU, MArch; |
266 | if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) |
267 | MCPU = A->getValue(); |
268 | if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) |
269 | MArch = A->getValue(); |
270 | |
271 | std::string CPU = Triple.isOSBinFormatMachO() |
272 | ? tools::arm::getARMCPUForMArch(Arch: MArch, Triple).str() |
273 | : tools::arm::getARMTargetCPU(CPU: MCPU, Arch: MArch, Triple); |
274 | StringRef Suffix = tools::arm::getLLVMArchSuffixForARM(CPU, Arch: MArch, Triple); |
275 | |
276 | bool IsBigEndian = Triple.getArch() == llvm::Triple::armeb || |
277 | Triple.getArch() == llvm::Triple::thumbeb; |
278 | // Handle pseudo-target flags '-mlittle-endian'/'-EL' and |
279 | // '-mbig-endian'/'-EB'. |
280 | if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, |
281 | options::OPT_mbig_endian)) { |
282 | IsBigEndian = !A->getOption().matches(options::ID: OPT_mlittle_endian); |
283 | } |
284 | std::string ArchName = IsBigEndian ? "armeb": "arm"; |
285 | |
286 | // FIXME: Thumb should just be another -target-feaure, not in the triple. |
287 | bool IsMProfile = |
288 | llvm::ARM::parseArchProfile(Arch: Suffix) == llvm::ARM::ProfileKind::M; |
289 | bool ThumbDefault = IsMProfile || |
290 | // Thumb2 is the default for V7 on Darwin. |
291 | (llvm::ARM::parseArchVersion(Arch: Suffix) == 7 && |
292 | Triple.isOSBinFormatMachO()) || |
293 | // FIXME: this is invalid for WindowsCE |
294 | Triple.isOSWindows(); |
295 | |
296 | // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for |
297 | // M-Class CPUs/architecture variants, which is not supported. |
298 | bool ARMModeRequested = |
299 | !Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault); |
300 | if (IsMProfile && ARMModeRequested) { |
301 | if (MCPU.size()) |
302 | D.Diag(diag::DiagID: err_cpu_unsupported_isa) << CPU << "ARM"; |
303 | else |
304 | D.Diag(diag::DiagID: err_arch_unsupported_isa) |
305 | << tools::arm::getARMArch(Arch: MArch, Triple) << "ARM"; |
306 | } |
307 | |
308 | // Check to see if an explicit choice to use thumb has been made via |
309 | // -mthumb. For assembler files we must check for -mthumb in the options |
310 | // passed to the assembler via -Wa or -Xassembler. |
311 | bool IsThumb = false; |
312 | if (InputType != types::TY_PP_Asm) |
313 | IsThumb = |
314 | Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault); |
315 | else { |
316 | // Ideally we would check for these flags in |
317 | // CollectArgsForIntegratedAssembler but we can't change the ArchName at |
318 | // that point. |
319 | llvm::StringRef WaMArch, WaMCPU; |
320 | for (const auto *A : |
321 | Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { |
322 | for (StringRef Value : A->getValues()) { |
323 | // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm. |
324 | if (Value == "-mthumb") |
325 | IsThumb = true; |
326 | else if (Value.starts_with("-march=")) |
327 | WaMArch = Value.substr(7); |
328 | else if (Value.starts_with("-mcpu=")) |
329 | WaMCPU = Value.substr(6); |
330 | } |
331 | } |
332 | |
333 | if (WaMCPU.size() || WaMArch.size()) { |
334 | // The way this works means that we prefer -Wa,-mcpu's architecture |
335 | // over -Wa,-march. Which matches the compiler behaviour. |
336 | Suffix = tools::arm::getLLVMArchSuffixForARM(CPU: WaMCPU, Arch: WaMArch, Triple); |
337 | } |
338 | } |
339 | |
340 | // Assembly files should start in ARM mode, unless arch is M-profile, or |
341 | // -mthumb has been passed explicitly to the assembler. Windows is always |
342 | // thumb. |
343 | if (IsThumb || IsMProfile || Triple.isOSWindows()) { |
344 | if (IsBigEndian) |
345 | ArchName = "thumbeb"; |
346 | else |
347 | ArchName = "thumb"; |
348 | } |
349 | Triple.setArchName(ArchName + Suffix.str()); |
350 | } |
351 | |
352 | void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, |
353 | llvm::Triple &Triple) { |
354 | if (Triple.isOSLiteOS()) { |
355 | Triple.setEnvironment(llvm::Triple::OpenHOS); |
356 | return; |
357 | } |
358 | |
359 | bool isHardFloat = |
360 | (arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard); |
361 | |
362 | switch (Triple.getEnvironment()) { |
363 | case llvm::Triple::GNUEABI: |
364 | case llvm::Triple::GNUEABIHF: |
365 | Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHF |
366 | : llvm::Triple::GNUEABI); |
367 | break; |
368 | case llvm::Triple::GNUEABIT64: |
369 | case llvm::Triple::GNUEABIHFT64: |
370 | Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHFT64 |
371 | : llvm::Triple::GNUEABIT64); |
372 | break; |
373 | case llvm::Triple::EABI: |
374 | case llvm::Triple::EABIHF: |
375 | Triple.setEnvironment(isHardFloat ? llvm::Triple::EABIHF |
376 | : llvm::Triple::EABI); |
377 | break; |
378 | case llvm::Triple::MuslEABI: |
379 | case llvm::Triple::MuslEABIHF: |
380 | Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF |
381 | : llvm::Triple::MuslEABI); |
382 | break; |
383 | case llvm::Triple::OpenHOS: |
384 | break; |
385 | default: { |
386 | arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple); |
387 | if (DefaultABI != arm::FloatABI::Invalid && |
388 | isHardFloat != (DefaultABI == arm::FloatABI::Hard)) { |
389 | Arg *ABIArg = |
390 | Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, |
391 | options::OPT_mfloat_abi_EQ); |
392 | assert(ABIArg && "Non-default float abi expected to be from arg"); |
393 | D.Diag(diag::DiagID: err_drv_unsupported_opt_for_target) |
394 | << ABIArg->getAsString(Args) << Triple.getTriple(); |
395 | } |
396 | break; |
397 | } |
398 | } |
399 | } |
400 | |
401 | arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { |
402 | return arm::getARMFloatABI(D: TC.getDriver(), Triple: TC.getEffectiveTriple(), Args); |
403 | } |
404 | |
405 | arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { |
406 | auto SubArch = getARMSubArchVersionNumber(Triple); |
407 | switch (Triple.getOS()) { |
408 | case llvm::Triple::Darwin: |
409 | case llvm::Triple::MacOSX: |
410 | case llvm::Triple::IOS: |
411 | case llvm::Triple::TvOS: |
412 | case llvm::Triple::DriverKit: |
413 | case llvm::Triple::XROS: |
414 | // Darwin defaults to "softfp" for v6 and v7. |
415 | if (Triple.isWatchABI()) |
416 | return FloatABI::Hard; |
417 | else |
418 | return (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; |
419 | |
420 | case llvm::Triple::WatchOS: |
421 | return FloatABI::Hard; |
422 | |
423 | // FIXME: this is invalid for WindowsCE |
424 | case llvm::Triple::Win32: |
425 | // It is incorrect to select hard float ABI on MachO platforms if the ABI is |
426 | // "apcs-gnu". |
427 | if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(T: Triple)) |
428 | return FloatABI::Soft; |
429 | return FloatABI::Hard; |
430 | |
431 | case llvm::Triple::NetBSD: |
432 | switch (Triple.getEnvironment()) { |
433 | case llvm::Triple::EABIHF: |
434 | case llvm::Triple::GNUEABIHF: |
435 | return FloatABI::Hard; |
436 | default: |
437 | return FloatABI::Soft; |
438 | } |
439 | break; |
440 | |
441 | case llvm::Triple::FreeBSD: |
442 | switch (Triple.getEnvironment()) { |
443 | case llvm::Triple::GNUEABIHF: |
444 | return FloatABI::Hard; |
445 | default: |
446 | // FreeBSD defaults to soft float |
447 | return FloatABI::Soft; |
448 | } |
449 | break; |
450 | |
451 | case llvm::Triple::Haiku: |
452 | case llvm::Triple::OpenBSD: |
453 | return FloatABI::SoftFP; |
454 | |
455 | default: |
456 | if (Triple.isOHOSFamily()) |
457 | return FloatABI::Soft; |
458 | switch (Triple.getEnvironment()) { |
459 | case llvm::Triple::GNUEABIHF: |
460 | case llvm::Triple::GNUEABIHFT64: |
461 | case llvm::Triple::MuslEABIHF: |
462 | case llvm::Triple::EABIHF: |
463 | return FloatABI::Hard; |
464 | case llvm::Triple::Android: |
465 | case llvm::Triple::GNUEABI: |
466 | case llvm::Triple::GNUEABIT64: |
467 | case llvm::Triple::MuslEABI: |
468 | case llvm::Triple::EABI: |
469 | // EABI is always AAPCS, and if it was not marked 'hard', it's softfp |
470 | return FloatABI::SoftFP; |
471 | default: |
472 | return FloatABI::Invalid; |
473 | } |
474 | } |
475 | return FloatABI::Invalid; |
476 | } |
477 | |
478 | // Select the float ABI as determined by -msoft-float, -mhard-float, and |
479 | // -mfloat-abi=. |
480 | arm::FloatABI arm::getARMFloatABI(const Driver &D, const llvm::Triple &Triple, |
481 | const ArgList &Args) { |
482 | arm::FloatABI ABI = FloatABI::Invalid; |
483 | if (Arg *A = |
484 | Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, |
485 | options::OPT_mfloat_abi_EQ)) { |
486 | if (A->getOption().matches(options::ID: OPT_msoft_float)) { |
487 | ABI = FloatABI::Soft; |
488 | } else if (A->getOption().matches(options::ID: OPT_mhard_float)) { |
489 | ABI = FloatABI::Hard; |
490 | } else { |
491 | ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue()) |
492 | .Case(S: "soft", Value: FloatABI::Soft) |
493 | .Case(S: "softfp", Value: FloatABI::SoftFP) |
494 | .Case(S: "hard", Value: FloatABI::Hard) |
495 | .Default(Value: FloatABI::Invalid); |
496 | if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
497 | D.Diag(diag::DiagID: err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
498 | ABI = FloatABI::Soft; |
499 | } |
500 | } |
501 | } |
502 | |
503 | // If unspecified, choose the default based on the platform. |
504 | if (ABI == FloatABI::Invalid) |
505 | ABI = arm::getDefaultFloatABI(Triple); |
506 | |
507 | if (ABI == FloatABI::Invalid) { |
508 | // Assume "soft", but warn the user we are guessing. |
509 | if (Triple.isOSBinFormatMachO() && |
510 | Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em) |
511 | ABI = FloatABI::Hard; |
512 | else |
513 | ABI = FloatABI::Soft; |
514 | |
515 | if (Triple.getOS() != llvm::Triple::UnknownOS || |
516 | !Triple.isOSBinFormatMachO()) |
517 | D.Diag(diag::DiagID: warn_drv_assuming_mfloat_abi_is) << "soft"; |
518 | } |
519 | |
520 | assert(ABI != FloatABI::Invalid && "must select an ABI"); |
521 | return ABI; |
522 | } |
523 | |
524 | static bool hasIntegerMVE(const std::vector<StringRef> &F) { |
525 | auto MVE = llvm::find(Range: llvm::reverse(C: F), Val: "+mve"); |
526 | auto NoMVE = llvm::find(Range: llvm::reverse(C: F), Val: "-mve"); |
527 | return MVE != F.rend() && |
528 | (NoMVE == F.rend() || std::distance(first: MVE, last: NoMVE) > 0); |
529 | } |
530 | |
531 | llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, |
532 | const llvm::Triple &Triple, |
533 | const ArgList &Args, |
534 | std::vector<StringRef> &Features, |
535 | bool ForAS, bool ForMultilib) { |
536 | bool KernelOrKext = |
537 | Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); |
538 | arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); |
539 | std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch; |
540 | |
541 | // This vector will accumulate features from the architecture |
542 | // extension suffixes on -mcpu and -march (e.g. the 'bar' in |
543 | // -mcpu=foo+bar). We want to apply those after the features derived |
544 | // from the FPU, in case -mfpu generates a negative feature which |
545 | // the +bar is supposed to override. |
546 | std::vector<StringRef> ExtensionFeatures; |
547 | |
548 | if (!ForAS) { |
549 | // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these |
550 | // yet (it uses the -mfloat-abi and -msoft-float options), and it is |
551 | // stripped out by the ARM target. We should probably pass this a new |
552 | // -target-option, which is handled by the -cc1/-cc1as invocation. |
553 | // |
554 | // FIXME2: For consistency, it would be ideal if we set up the target |
555 | // machine state the same when using the frontend or the assembler. We don't |
556 | // currently do that for the assembler, we pass the options directly to the |
557 | // backend and never even instantiate the frontend TargetInfo. If we did, |
558 | // and used its handleTargetFeatures hook, then we could ensure the |
559 | // assembler and the frontend behave the same. |
560 | |
561 | // Use software floating point operations? |
562 | if (ABI == arm::FloatABI::Soft) |
563 | Features.push_back(x: "+soft-float"); |
564 | |
565 | // Use software floating point argument passing? |
566 | if (ABI != arm::FloatABI::Hard) |
567 | Features.push_back(x: "+soft-float-abi"); |
568 | } else { |
569 | // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down |
570 | // to the assembler correctly. |
571 | for (const Arg *A : |
572 | Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { |
573 | // We use getValues here because you can have many options per -Wa |
574 | // We will keep the last one we find for each of these |
575 | for (StringRef Value : A->getValues()) { |
576 | if (Value.starts_with("-mfpu=")) { |
577 | WaFPU = std::make_pair(A, Value.substr(6)); |
578 | } else if (Value.starts_with("-mcpu=")) { |
579 | WaCPU = std::make_pair(A, Value.substr(6)); |
580 | } else if (Value.starts_with("-mhwdiv=")) { |
581 | WaHDiv = std::make_pair(A, Value.substr(8)); |
582 | } else if (Value.starts_with("-march=")) { |
583 | WaArch = std::make_pair(A, Value.substr(7)); |
584 | } |
585 | } |
586 | } |
587 | |
588 | // The integrated assembler doesn't implement e_flags setting behavior for |
589 | // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For |
590 | // compatibility we accept but warn. |
591 | if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) |
592 | A->ignoreTargetSpecific(); |
593 | } |
594 | |
595 | arm::ReadTPMode TPMode = getReadTPMode(D, Args, Triple, ForAS); |
596 | |
597 | if (TPMode == ReadTPMode::TPIDRURW) |
598 | Features.push_back(x: "+read-tp-tpidrurw"); |
599 | else if (TPMode == ReadTPMode::TPIDRPRW) |
600 | Features.push_back(x: "+read-tp-tpidrprw"); |
601 | else if (TPMode == ReadTPMode::TPIDRURO) |
602 | Features.push_back(x: "+read-tp-tpidruro"); |
603 | |
604 | const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); |
605 | const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); |
606 | StringRef ArchName; |
607 | StringRef CPUName; |
608 | llvm::ARM::FPUKind ArchArgFPUKind = llvm::ARM::FK_INVALID; |
609 | llvm::ARM::FPUKind CPUArgFPUKind = llvm::ARM::FK_INVALID; |
610 | |
611 | // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. |
612 | if (WaCPU) { |
613 | if (CPUArg) |
614 | D.Diag(clang::diag::warn_drv_unused_argument) |
615 | << CPUArg->getAsString(Args); |
616 | CPUName = WaCPU->second; |
617 | CPUArg = WaCPU->first; |
618 | } else if (CPUArg) |
619 | CPUName = CPUArg->getValue(); |
620 | |
621 | // Check -march. ClangAs gives preference to -Wa,-march=. |
622 | if (WaArch) { |
623 | if (ArchArg) |
624 | D.Diag(clang::diag::warn_drv_unused_argument) |
625 | << ArchArg->getAsString(Args); |
626 | ArchName = WaArch->second; |
627 | // This will set any features after the base architecture. |
628 | checkARMArchName(D, A: WaArch->first, Args, ArchName, CPUName, |
629 | Features&: ExtensionFeatures, Triple, ArgFPUKind&: ArchArgFPUKind); |
630 | // The base architecture was handled in ToolChain::ComputeLLVMTriple because |
631 | // triple is read only by this point. |
632 | } else if (ArchArg) { |
633 | ArchName = ArchArg->getValue(); |
634 | checkARMArchName(D, A: ArchArg, Args, ArchName, CPUName, Features&: ExtensionFeatures, |
635 | Triple, ArgFPUKind&: ArchArgFPUKind); |
636 | } |
637 | |
638 | // Add CPU features for generic CPUs |
639 | if (CPUName == "native") { |
640 | for (auto &F : llvm::sys::getHostCPUFeatures()) |
641 | Features.push_back( |
642 | x: Args.MakeArgString(Str: (F.second ? "+": "-") + F.first())); |
643 | } else if (!CPUName.empty()) { |
644 | // This sets the default features for the specified CPU. We certainly don't |
645 | // want to override the features that have been explicitly specified on the |
646 | // command line. Therefore, process them directly instead of appending them |
647 | // at the end later. |
648 | DecodeARMFeaturesFromCPU(D, CPU: CPUName, Features); |
649 | } |
650 | |
651 | if (CPUArg) |
652 | checkARMCPUName(D, A: CPUArg, Args, CPUName, ArchName, Features&: ExtensionFeatures, |
653 | Triple, ArgFPUKind&: CPUArgFPUKind); |
654 | |
655 | // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a |
656 | // longstanding behavior. |
657 | (void)Args.getLastArg(options::OPT_mtune_EQ); |
658 | |
659 | // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. |
660 | llvm::ARM::FPUKind FPUKind = llvm::ARM::FK_INVALID; |
661 | const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); |
662 | if (WaFPU) { |
663 | if (FPUArg) |
664 | D.Diag(clang::diag::warn_drv_unused_argument) |
665 | << FPUArg->getAsString(Args); |
666 | (void)getARMFPUFeatures(D, A: WaFPU->first, Args, FPU: WaFPU->second, Features); |
667 | } else if (FPUArg) { |
668 | FPUKind = getARMFPUFeatures(D, A: FPUArg, Args, FPU: FPUArg->getValue(), Features); |
669 | } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) == 7) { |
670 | const char *AndroidFPU = "neon"; |
671 | FPUKind = llvm::ARM::parseFPU(FPU: AndroidFPU); |
672 | if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) |
673 | D.Diag(clang::diag::err_drv_clang_unsupported) |
674 | << std::string("-mfpu=") + AndroidFPU; |
675 | } else if (ArchArgFPUKind != llvm::ARM::FK_INVALID || |
676 | CPUArgFPUKind != llvm::ARM::FK_INVALID) { |
677 | FPUKind = |
678 | CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind; |
679 | (void)llvm::ARM::getFPUFeatures(FPUKind, Features); |
680 | } else { |
681 | std::string CPU = arm::getARMTargetCPU(CPU: CPUName, Arch: ArchName, Triple); |
682 | bool Generic = CPU == "generic"; |
683 | if (Generic && (Triple.isOSWindows() || Triple.isOSDarwin()) && |
684 | getARMSubArchVersionNumber(Triple) >= 7) { |
685 | FPUKind = llvm::ARM::parseFPU(FPU: "neon"); |
686 | } else { |
687 | llvm::ARM::ArchKind ArchKind = |
688 | arm::getLLVMArchKindForARM(CPU, Arch: ArchName, Triple); |
689 | FPUKind = llvm::ARM::getDefaultFPU(CPU, AK: ArchKind); |
690 | } |
691 | (void)llvm::ARM::getFPUFeatures(FPUKind, Features); |
692 | } |
693 | |
694 | // Now we've finished accumulating features from arch, cpu and fpu, |
695 | // we can append the ones for architecture extensions that we |
696 | // collected separately. |
697 | Features.insert(position: std::end(cont&: Features), |
698 | first: std::begin(cont&: ExtensionFeatures), last: std::end(cont&: ExtensionFeatures)); |
699 | |
700 | // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. |
701 | const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); |
702 | if (WaHDiv) { |
703 | if (HDivArg) |
704 | D.Diag(clang::diag::warn_drv_unused_argument) |
705 | << HDivArg->getAsString(Args); |
706 | getARMHWDivFeatures(D, A: WaHDiv->first, Args, HWDiv: WaHDiv->second, Features); |
707 | } else if (HDivArg) |
708 | getARMHWDivFeatures(D, A: HDivArg, Args, HWDiv: HDivArg->getValue(), Features); |
709 | |
710 | // Handle (arch-dependent) fp16fml/fullfp16 relationship. |
711 | // Must happen before any features are disabled due to soft-float. |
712 | // FIXME: this fp16fml option handling will be reimplemented after the |
713 | // TargetParser rewrite. |
714 | const auto ItRNoFullFP16 = std::find(first: Features.rbegin(), last: Features.rend(), val: "-fullfp16"); |
715 | const auto ItRFP16FML = std::find(first: Features.rbegin(), last: Features.rend(), val: "+fp16fml"); |
716 | if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_4a) { |
717 | const auto ItRFullFP16 = std::find(first: Features.rbegin(), last: Features.rend(), val: "+fullfp16"); |
718 | if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { |
719 | // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. |
720 | // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. |
721 | if (std::find(first: Features.rbegin(), last: ItRFullFP16, val: "-fp16fml") == ItRFullFP16) |
722 | Features.push_back(x: "+fp16fml"); |
723 | } |
724 | else |
725 | goto fp16_fml_fallthrough; |
726 | } |
727 | else { |
728 | fp16_fml_fallthrough: |
729 | // In both of these cases, putting the 'other' feature on the end of the vector will |
730 | // result in the same effect as placing it immediately after the current feature. |
731 | if (ItRNoFullFP16 < ItRFP16FML) |
732 | Features.push_back(x: "-fp16fml"); |
733 | else if (ItRNoFullFP16 > ItRFP16FML) |
734 | Features.push_back(x: "+fullfp16"); |
735 | } |
736 | |
737 | // Setting -msoft-float/-mfloat-abi=soft, -mfpu=none, or adding +nofp to |
738 | // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in |
739 | // this case). Note that the ABI can also be set implicitly by the target |
740 | // selected. |
741 | bool HasFPRegs = true; |
742 | if (ABI == arm::FloatABI::Soft) { |
743 | llvm::ARM::getFPUFeatures(FPUKind: llvm::ARM::FK_NONE, Features); |
744 | |
745 | // Disable all features relating to hardware FP, not already disabled by the |
746 | // above call. |
747 | Features.insert(position: Features.end(), |
748 | l: {"-dotprod", "-fp16fml", "-bf16", "-mve", "-mve.fp"}); |
749 | HasFPRegs = false; |
750 | FPUKind = llvm::ARM::FK_NONE; |
751 | } else if (FPUKind == llvm::ARM::FK_NONE || |
752 | ArchArgFPUKind == llvm::ARM::FK_NONE || |
753 | CPUArgFPUKind == llvm::ARM::FK_NONE) { |
754 | // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to |
755 | // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the |
756 | // FPU, but not the FPU registers, thus MVE-I, which depends only on the |
757 | // latter, is still supported. |
758 | Features.insert(position: Features.end(), |
759 | l: {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"}); |
760 | HasFPRegs = hasIntegerMVE(F: Features); |
761 | FPUKind = llvm::ARM::FK_NONE; |
762 | } |
763 | if (!HasFPRegs) |
764 | Features.emplace_back(args: "-fpregs"); |
765 | |
766 | // En/disable crc code generation. |
767 | if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { |
768 | if (A->getOption().matches(options::OPT_mcrc)) |
769 | Features.push_back(x: "+crc"); |
770 | else |
771 | Features.push_back(x: "-crc"); |
772 | } |
773 | |
774 | // Invalid value of the __ARM_FEATURE_MVE macro when an explicit -mfpu= option |
775 | // disables MVE-FP -mfpu=fpv5-d16 or -mfpu=fpv5-sp-d16 disables the scalar |
776 | // half-precision floating-point operations feature. Therefore, because the |
777 | // M-profile Vector Extension (MVE) floating-point feature requires the scalar |
778 | // half-precision floating-point operations, this option also disables the MVE |
779 | // floating-point feature: -mve.fp |
780 | if (FPUKind == llvm::ARM::FK_FPV5_D16 || FPUKind == llvm::ARM::FK_FPV5_SP_D16) |
781 | Features.push_back(x: "-mve.fp"); |
782 | |
783 | // If SIMD has been disabled and the selected FPU supports NEON, then features |
784 | // that rely on NEON instructions should also be disabled. |
785 | bool HasSimd = false; |
786 | const auto ItSimd = |
787 | llvm::find_if(Range: llvm::reverse(C&: Features), |
788 | P: [](const StringRef F) { return F.contains(Other: "neon"); }); |
789 | const bool FPUSupportsNeon = (llvm::ARM::FPUNames[FPUKind].NeonSupport == |
790 | llvm::ARM::NeonSupportLevel::Neon) || |
791 | (llvm::ARM::FPUNames[FPUKind].NeonSupport == |
792 | llvm::ARM::NeonSupportLevel::Crypto); |
793 | if (ItSimd != Features.rend()) |
794 | HasSimd = ItSimd->starts_with(Prefix: "+"); |
795 | if (!HasSimd && FPUSupportsNeon) |
796 | Features.insert(position: Features.end(), |
797 | l: {"-sha2", "-aes", "-crypto", "-dotprod", "-bf16", "-i8mm"}); |
798 | |
799 | // For Arch >= ARMv8.0 && A or R profile: crypto = sha2 + aes |
800 | // Rather than replace within the feature vector, determine whether each |
801 | // algorithm is enabled and append this to the end of the vector. |
802 | // The algorithms can be controlled by their specific feature or the crypto |
803 | // feature, so their status can be determined by the last occurance of |
804 | // either in the vector. This allows one to supercede the other. |
805 | // e.g. +crypto+noaes in -march/-mcpu should enable sha2, but not aes |
806 | // FIXME: this needs reimplementation after the TargetParser rewrite |
807 | bool HasSHA2 = false; |
808 | bool HasAES = false; |
809 | bool HasBF16 = false; |
810 | bool HasDotprod = false; |
811 | bool HasI8MM = false; |
812 | const auto ItCrypto = |
813 | llvm::find_if(Range: llvm::reverse(C&: Features), P: [](const StringRef F) { |
814 | return F.contains(Other: "crypto"); |
815 | }); |
816 | const auto ItSHA2 = |
817 | llvm::find_if(Range: llvm::reverse(C&: Features), P: [](const StringRef F) { |
818 | return F.contains(Other: "crypto") || F.contains(Other: "sha2"); |
819 | }); |
820 | const auto ItAES = |
821 | llvm::find_if(Range: llvm::reverse(C&: Features), P: [](const StringRef F) { |
822 | return F.contains(Other: "crypto") || F.contains(Other: "aes"); |
823 | }); |
824 | const auto ItBF16 = |
825 | llvm::find_if(Range: llvm::reverse(C&: Features), |
826 | P: [](const StringRef F) { return F.contains(Other: "bf16"); }); |
827 | const auto ItDotprod = |
828 | llvm::find_if(Range: llvm::reverse(C&: Features), |
829 | P: [](const StringRef F) { return F.contains(Other: "dotprod"); }); |
830 | const auto ItI8MM = |
831 | llvm::find_if(Range: llvm::reverse(C&: Features), |
832 | P: [](const StringRef F) { return F.contains(Other: "i8mm"); }); |
833 | if (ItSHA2 != Features.rend()) |
834 | HasSHA2 = ItSHA2->starts_with(Prefix: "+"); |
835 | if (ItAES != Features.rend()) |
836 | HasAES = ItAES->starts_with(Prefix: "+"); |
837 | if (ItBF16 != Features.rend()) |
838 | HasBF16 = ItBF16->starts_with(Prefix: "+"); |
839 | if (ItDotprod != Features.rend()) |
840 | HasDotprod = ItDotprod->starts_with(Prefix: "+"); |
841 | if (ItI8MM != Features.rend()) |
842 | HasI8MM = ItI8MM->starts_with(Prefix: "+"); |
843 | if (ItCrypto != Features.rend()) { |
844 | if (HasSHA2 && HasAES) |
845 | Features.push_back(x: "+crypto"); |
846 | else |
847 | Features.push_back(x: "-crypto"); |
848 | if (HasSHA2) |
849 | Features.push_back(x: "+sha2"); |
850 | else |
851 | Features.push_back(x: "-sha2"); |
852 | if (HasAES) |
853 | Features.push_back(x: "+aes"); |
854 | else |
855 | Features.push_back(x: "-aes"); |
856 | } |
857 | // If any of these features are enabled, NEON should also be enabled. |
858 | if (HasAES || HasSHA2 || HasBF16 || HasDotprod || HasI8MM) |
859 | Features.push_back(x: "+neon"); |
860 | |
861 | if (HasSHA2 || HasAES) { |
862 | StringRef ArchSuffix = arm::getLLVMArchSuffixForARM( |
863 | CPU: arm::getARMTargetCPU(CPU: CPUName, Arch: ArchName, Triple), Arch: ArchName, Triple); |
864 | llvm::ARM::ProfileKind ArchProfile = |
865 | llvm::ARM::parseArchProfile(Arch: ArchSuffix); |
866 | if (!((llvm::ARM::parseArchVersion(Arch: ArchSuffix) >= 8) && |
867 | (ArchProfile == llvm::ARM::ProfileKind::A || |
868 | ArchProfile == llvm::ARM::ProfileKind::R))) { |
869 | if (HasSHA2) |
870 | D.Diag(clang::diag::warn_target_unsupported_extension) |
871 | << "sha2" |
872 | << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix)); |
873 | if (HasAES) |
874 | D.Diag(clang::diag::warn_target_unsupported_extension) |
875 | << "aes" |
876 | << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix)); |
877 | // With -fno-integrated-as -mfpu=crypto-neon-fp-armv8 some assemblers such |
878 | // as the GNU assembler will permit the use of crypto instructions as the |
879 | // fpu will override the architecture. We keep the crypto feature in this |
880 | // case to preserve compatibility. In all other cases we remove the crypto |
881 | // feature. |
882 | if (!Args.hasArg(options::OPT_fno_integrated_as)) { |
883 | Features.push_back(x: "-sha2"); |
884 | Features.push_back(x: "-aes"); |
885 | } |
886 | } |
887 | } |
888 | |
889 | // Propagate frame-chain model selection |
890 | if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { |
891 | StringRef FrameChainOption = A->getValue(); |
892 | if (FrameChainOption.starts_with(Prefix: "aapcs")) |
893 | Features.push_back(x: "+aapcs-frame-chain"); |
894 | } |
895 | |
896 | // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. |
897 | if (Args.getLastArg(options::OPT_mcmse)) |
898 | Features.push_back(x: "+8msecext"); |
899 | |
900 | if (Arg *A = Args.getLastArg(options::OPT_mfix_cmse_cve_2021_35465, |
901 | options::OPT_mno_fix_cmse_cve_2021_35465)) { |
902 | if (!Args.getLastArg(options::OPT_mcmse)) |
903 | D.Diag(diag::err_opt_not_valid_without_opt) |
904 | << A->getOption().getName() << "-mcmse"; |
905 | |
906 | if (A->getOption().matches(options::OPT_mfix_cmse_cve_2021_35465)) |
907 | Features.push_back(x: "+fix-cmse-cve-2021-35465"); |
908 | else |
909 | Features.push_back(x: "-fix-cmse-cve-2021-35465"); |
910 | } |
911 | |
912 | // This also handles the -m(no-)fix-cortex-a72-1655431 arguments via aliases. |
913 | if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a57_aes_1742098, |
914 | options::OPT_mno_fix_cortex_a57_aes_1742098)) { |
915 | if (A->getOption().matches(options::OPT_mfix_cortex_a57_aes_1742098)) { |
916 | Features.push_back(x: "+fix-cortex-a57-aes-1742098"); |
917 | } else { |
918 | Features.push_back(x: "-fix-cortex-a57-aes-1742098"); |
919 | } |
920 | } |
921 | |
922 | // Look for the last occurrence of -mlong-calls or -mno-long-calls. If |
923 | // neither options are specified, see if we are compiling for kernel/kext and |
924 | // decide whether to pass "+long-calls" based on the OS and its version. |
925 | if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, |
926 | options::OPT_mno_long_calls)) { |
927 | if (A->getOption().matches(options::OPT_mlong_calls)) |
928 | Features.push_back(x: "+long-calls"); |
929 | } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(Major: 6)) && |
930 | !Triple.isWatchOS() && !Triple.isXROS()) { |
931 | Features.push_back(x: "+long-calls"); |
932 | } |
933 | |
934 | // Generate execute-only output (no data access to code sections). |
935 | // This only makes sense for the compiler, not for the assembler. |
936 | // It's not needed for multilib selection and may hide an unused |
937 | // argument diagnostic if the code is always run. |
938 | if (!ForAS && !ForMultilib) { |
939 | // Supported only on ARMv6T2 and ARMv7 and above. |
940 | // Cannot be combined with -mno-movt. |
941 | if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { |
942 | if (A->getOption().matches(options::OPT_mexecute_only)) { |
943 | if (getARMSubArchVersionNumber(Triple) < 7 && |
944 | llvm::ARM::parseArch(Arch: Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 && |
945 | llvm::ARM::parseArch(Arch: Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M) |
946 | D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); |
947 | else if (llvm::ARM::parseArch(Arch: Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) { |
948 | if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi, |
949 | options::OPT_fpic, options::OPT_fpie, |
950 | options::OPT_fPIC, options::OPT_fPIE)) |
951 | D.Diag(diag::err_opt_not_valid_with_opt_on_target) |
952 | << A->getAsString(Args) << PIArg->getAsString(Args) << Triple.getArchName(); |
953 | } else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) |
954 | D.Diag(diag::err_opt_not_valid_with_opt) |
955 | << A->getAsString(Args) << B->getAsString(Args); |
956 | Features.push_back(x: "+execute-only"); |
957 | } |
958 | } |
959 | } |
960 | |
961 | if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, |
962 | options::OPT_munaligned_access, |
963 | options::OPT_mstrict_align, |
964 | options::OPT_mno_strict_align)) { |
965 | // Kernel code has more strict alignment requirements. |
966 | if (KernelOrKext || |
967 | A->getOption().matches(options::OPT_mno_unaligned_access) || |
968 | A->getOption().matches(options::OPT_mstrict_align)) { |
969 | Features.push_back(x: "+strict-align"); |
970 | } else { |
971 | // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). |
972 | if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) |
973 | D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; |
974 | // v8M Baseline follows on from v6M, so doesn't support unaligned memory |
975 | // access either. |
976 | else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) |
977 | D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; |
978 | } |
979 | } else { |
980 | // Assume pre-ARMv6 doesn't support unaligned accesses. |
981 | // |
982 | // ARMv6 may or may not support unaligned accesses depending on the |
983 | // SCTLR.U bit, which is architecture-specific. We assume ARMv6 |
984 | // Darwin and NetBSD targets support unaligned accesses, and others don't. |
985 | // |
986 | // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit which |
987 | // raises an alignment fault on unaligned accesses. Assume ARMv7+ supports |
988 | // unaligned accesses, except ARMv6-M, and ARMv8-M without the Main |
989 | // Extension. This aligns with the default behavior of ARM's downstream |
990 | // versions of GCC and Clang. |
991 | // |
992 | // Users can change the default behavior via -m[no-]unaliged-access. |
993 | int VersionNum = getARMSubArchVersionNumber(Triple); |
994 | if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { |
995 | if (VersionNum < 6 || |
996 | Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) |
997 | Features.push_back(x: "+strict-align"); |
998 | } else if (Triple.getVendor() == llvm::Triple::Apple && |
999 | Triple.isOSBinFormatMachO()) { |
1000 | // Firmwares on Apple platforms are strict-align by default. |
1001 | Features.push_back(x: "+strict-align"); |
1002 | } else if (VersionNum < 7 || |
1003 | Triple.getSubArch() == |
1004 | llvm::Triple::SubArchType::ARMSubArch_v6m || |
1005 | Triple.getSubArch() == |
1006 | llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) { |
1007 | Features.push_back(x: "+strict-align"); |
1008 | } |
1009 | } |
1010 | |
1011 | // llvm does not support reserving registers in general. There is support |
1012 | // for reserving r9 on ARM though (defined as a platform-specific register |
1013 | // in ARM EABI). |
1014 | if (Args.hasArg(options::OPT_ffixed_r9)) |
1015 | Features.push_back(x: "+reserve-r9"); |
1016 | |
1017 | // The kext linker doesn't know how to deal with movw/movt. |
1018 | if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) |
1019 | Features.push_back(x: "+no-movt"); |
1020 | |
1021 | if (Args.hasArg(options::OPT_mno_neg_immediates)) |
1022 | Features.push_back(x: "+no-neg-immediates"); |
1023 | |
1024 | // Enable/disable straight line speculation hardening. |
1025 | if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { |
1026 | StringRef Scope = A->getValue(); |
1027 | bool EnableRetBr = false; |
1028 | bool EnableBlr = false; |
1029 | bool DisableComdat = false; |
1030 | if (Scope != "none") { |
1031 | SmallVector<StringRef, 4> Opts; |
1032 | Scope.split(A&: Opts, Separator: ","); |
1033 | for (auto Opt : Opts) { |
1034 | Opt = Opt.trim(); |
1035 | if (Opt == "all") { |
1036 | EnableBlr = true; |
1037 | EnableRetBr = true; |
1038 | continue; |
1039 | } |
1040 | if (Opt == "retbr") { |
1041 | EnableRetBr = true; |
1042 | continue; |
1043 | } |
1044 | if (Opt == "blr") { |
1045 | EnableBlr = true; |
1046 | continue; |
1047 | } |
1048 | if (Opt == "comdat") { |
1049 | DisableComdat = false; |
1050 | continue; |
1051 | } |
1052 | if (Opt == "nocomdat") { |
1053 | DisableComdat = true; |
1054 | continue; |
1055 | } |
1056 | D.Diag(diag::err_drv_unsupported_option_argument) |
1057 | << A->getSpelling() << Scope; |
1058 | break; |
1059 | } |
1060 | } |
1061 | |
1062 | if (EnableRetBr || EnableBlr) |
1063 | if (!(isARMAProfile(Triple) && getARMSubArchVersionNumber(Triple) >= 7)) |
1064 | D.Diag(diag::err_sls_hardening_arm_not_supported) |
1065 | << Scope << A->getAsString(Args); |
1066 | |
1067 | if (EnableRetBr) |
1068 | Features.push_back(x: "+harden-sls-retbr"); |
1069 | if (EnableBlr) |
1070 | Features.push_back(x: "+harden-sls-blr"); |
1071 | if (DisableComdat) { |
1072 | Features.push_back(x: "+harden-sls-nocomdat"); |
1073 | } |
1074 | } |
1075 | |
1076 | if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) |
1077 | Features.push_back(x: "+no-bti-at-return-twice"); |
1078 | |
1079 | checkARMFloatABI(D, Args, HasFPRegs); |
1080 | |
1081 | return FPUKind; |
1082 | } |
1083 | |
1084 | std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { |
1085 | std::string MArch; |
1086 | if (!Arch.empty()) |
1087 | MArch = std::string(Arch); |
1088 | else |
1089 | MArch = std::string(Triple.getArchName()); |
1090 | MArch = StringRef(MArch).split(Separator: "+").first.lower(); |
1091 | |
1092 | // Handle -march=native. |
1093 | if (MArch == "native") { |
1094 | std::string CPU = std::string(llvm::sys::getHostCPUName()); |
1095 | if (CPU != "generic") { |
1096 | // Translate the native cpu into the architecture suffix for that CPU. |
1097 | StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, Arch: MArch, Triple); |
1098 | // If there is no valid architecture suffix for this CPU we don't know how |
1099 | // to handle it, so return no architecture. |
1100 | if (Suffix.empty()) |
1101 | MArch = ""; |
1102 | else |
1103 | MArch = std::string("arm") + Suffix.str(); |
1104 | } |
1105 | } |
1106 | |
1107 | return MArch; |
1108 | } |
1109 | |
1110 | /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. |
1111 | StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { |
1112 | std::string MArch = getARMArch(Arch, Triple); |
1113 | // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch |
1114 | // here means an -march=native that we can't handle, so instead return no CPU. |
1115 | if (MArch.empty()) |
1116 | return StringRef(); |
1117 | |
1118 | // We need to return an empty string here on invalid MArch values as the |
1119 | // various places that call this function can't cope with a null result. |
1120 | return llvm::ARM::getARMCPUForArch(Triple, MArch); |
1121 | } |
1122 | |
1123 | /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. |
1124 | std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, |
1125 | const llvm::Triple &Triple) { |
1126 | // FIXME: Warn on inconsistent use of -mcpu and -march. |
1127 | // If we have -mcpu=, use that. |
1128 | if (!CPU.empty()) { |
1129 | std::string MCPU = StringRef(CPU).split(Separator: "+").first.lower(); |
1130 | // Handle -mcpu=native. |
1131 | if (MCPU == "native") |
1132 | return std::string(llvm::sys::getHostCPUName()); |
1133 | else |
1134 | return MCPU; |
1135 | } |
1136 | |
1137 | return std::string(getARMCPUForMArch(Arch, Triple)); |
1138 | } |
1139 | |
1140 | /// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a |
1141 | /// particular CPU (or Arch, if CPU is generic). This is needed to |
1142 | /// pass to functions like llvm::ARM::getDefaultFPU which need an |
1143 | /// ArchKind as well as a CPU name. |
1144 | llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, |
1145 | const llvm::Triple &Triple) { |
1146 | llvm::ARM::ArchKind ArchKind; |
1147 | if (CPU == "generic"|| CPU.empty()) { |
1148 | std::string ARMArch = tools::arm::getARMArch(Arch, Triple); |
1149 | ArchKind = llvm::ARM::parseArch(Arch: ARMArch); |
1150 | if (ArchKind == llvm::ARM::ArchKind::INVALID) |
1151 | // In case of generic Arch, i.e. "arm", |
1152 | // extract arch from default cpu of the Triple |
1153 | ArchKind = |
1154 | llvm::ARM::parseCPUArch(CPU: llvm::ARM::getARMCPUForArch(Triple, MArch: ARMArch)); |
1155 | } else { |
1156 | // FIXME: horrible hack to get around the fact that Cortex-A7 is only an |
1157 | // armv7k triple if it's actually been specified via "-arch armv7k". |
1158 | ArchKind = (Arch == "armv7k"|| Arch == "thumbv7k") |
1159 | ? llvm::ARM::ArchKind::ARMV7K |
1160 | : llvm::ARM::parseCPUArch(CPU); |
1161 | } |
1162 | return ArchKind; |
1163 | } |
1164 | |
1165 | /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular |
1166 | /// CPU (or Arch, if CPU is generic). |
1167 | // FIXME: This is redundant with -mcpu, why does LLVM use this. |
1168 | StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, |
1169 | const llvm::Triple &Triple) { |
1170 | llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple); |
1171 | if (ArchKind == llvm::ARM::ArchKind::INVALID) |
1172 | return ""; |
1173 | return llvm::ARM::getSubArch(AK: ArchKind); |
1174 | } |
1175 | |
1176 | void arm::appendBE8LinkFlag(const ArgList &Args, ArgStringList &CmdArgs, |
1177 | const llvm::Triple &Triple) { |
1178 | if (Args.hasArg(options::OPT_r)) |
1179 | return; |
1180 | |
1181 | // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker |
1182 | // to generate BE-8 executables. |
1183 | if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) |
1184 | CmdArgs.push_back(Elt: "--be8"); |
1185 | } |
1186 |
Definitions
- getARMSubArchVersionNumber
- isARMMProfile
- isARMBigEndian
- isARMAProfile
- isARMEABIBareMetal
- getARMArchCPUFromArgs
- getARMHWDivFeatures
- getARMFPUFeatures
- DecodeARMFeatures
- DecodeARMFeaturesFromCPU
- checkARMArchName
- checkARMCPUName
- checkARMFloatABI
- useAAPCSForMachO
- isHardTPSupported
- supportsThumb2Encoding
- getReadTPMode
- setArchNameInTriple
- setFloatABIInTriple
- getARMFloatABI
- getDefaultFloatABI
- getARMFloatABI
- hasIntegerMVE
- getARMTargetFeatures
- getARMArch
- getARMCPUForMArch
- getARMTargetCPU
- getLLVMArchKindForARM
- getLLVMArchSuffixForARM
Learn to use CMake with our Intro Training
Find out more