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