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