1 //===--- AArch64.cpp - AArch64 (not ARM) 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 "AArch64.h"
10 #include "../CommonArgs.h"
11 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Driver/Options.h"
14 #include "llvm/Option/ArgList.h"
15 #include "llvm/TargetParser/AArch64TargetParser.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 /// \returns true if the given triple can determine the default CPU type even
24 /// if -arch is not specified.
isCPUDeterminedByTriple(const llvm::Triple & Triple)25 static bool isCPUDeterminedByTriple(const llvm::Triple &Triple) {
26 return Triple.isOSDarwin();
27 }
28
29 /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
30 /// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is
31 /// provided, or to nullptr otherwise.
getAArch64TargetCPU(const ArgList & Args,const llvm::Triple & Triple,Arg * & A)32 std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
33 const llvm::Triple &Triple, Arg *&A) {
34 std::string CPU;
35 // If we have -mcpu, use that.
36 if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
37 StringRef Mcpu = A->getValue();
38 CPU = Mcpu.split("+").first.lower();
39 }
40
41 CPU = llvm::AArch64::resolveCPUAlias(CPU);
42
43 // Handle CPU name is 'native'.
44 if (CPU == "native")
45 return std::string(llvm::sys::getHostCPUName());
46
47 if (CPU.size())
48 return CPU;
49
50 if (Triple.isTargetMachineMac() &&
51 Triple.getArch() == llvm::Triple::aarch64) {
52 // Apple Silicon macs default to M1 CPUs.
53 return "apple-m1";
54 }
55
56 if (Triple.isXROS()) {
57 // The xrOS simulator runs on M1 as well, it should have been covered above.
58 assert(!Triple.isSimulatorEnvironment() && "xrossim should be mac-like");
59 return "apple-a12";
60 }
61 // arm64e requires v8.3a and only runs on apple-a12 and later CPUs.
62 if (Triple.isArm64e())
63 return "apple-a12";
64
65 // Make sure we pick the appropriate Apple CPU when targetting a Darwin OS.
66 if (Triple.isOSDarwin())
67 return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4"
68 : "apple-a7";
69
70 return "generic";
71 }
72
73 // Decode AArch64 features from string like +[no]featureA+[no]featureB+...
DecodeAArch64Features(const Driver & D,StringRef text,llvm::AArch64::ExtensionSet & Extensions)74 static bool DecodeAArch64Features(const Driver &D, StringRef text,
75 llvm::AArch64::ExtensionSet &Extensions) {
76 SmallVector<StringRef, 8> Split;
77 text.split(Split, StringRef("+"), -1, false);
78
79 for (StringRef Feature : Split) {
80 if (Feature == "neon" || Feature == "noneon") {
81 D.Diag(clang::diag::err_drv_no_neon_modifier);
82 continue;
83 }
84 if (!Extensions.parseModifier(Feature))
85 return false;
86 }
87
88 return true;
89 }
90
91 // Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
92 // decode CPU and feature.
DecodeAArch64Mcpu(const Driver & D,StringRef Mcpu,StringRef & CPU,llvm::AArch64::ExtensionSet & Extensions)93 static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
94 llvm::AArch64::ExtensionSet &Extensions) {
95 std::pair<StringRef, StringRef> Split = Mcpu.split("+");
96 CPU = Split.first;
97
98 if (CPU == "native")
99 CPU = llvm::sys::getHostCPUName();
100
101 if (CPU == "generic") {
102 Extensions.enable(llvm::AArch64::AEK_SIMD);
103 } else {
104 const std::optional<llvm::AArch64::CpuInfo> CpuInfo =
105 llvm::AArch64::parseCpu(CPU);
106 if (!CpuInfo)
107 return false;
108
109 Extensions.addCPUDefaults(*CpuInfo);
110 }
111
112 if (Split.second.size() &&
113 !DecodeAArch64Features(D, Split.second, Extensions))
114 return false;
115
116 return true;
117 }
118
119 static bool
getAArch64ArchFeaturesFromMarch(const Driver & D,StringRef March,const ArgList & Args,llvm::AArch64::ExtensionSet & Extensions)120 getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
121 const ArgList &Args,
122 llvm::AArch64::ExtensionSet &Extensions) {
123 std::string MarchLowerCase = March.lower();
124 std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
125
126 const llvm::AArch64::ArchInfo *ArchInfo =
127 llvm::AArch64::parseArch(Split.first);
128 if (Split.first == "native")
129 ArchInfo = llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str());
130 if (!ArchInfo)
131 return false;
132
133 Extensions.addArchDefaults(*ArchInfo);
134
135 if ((Split.second.size() &&
136 !DecodeAArch64Features(D, Split.second, Extensions)))
137 return false;
138
139 return true;
140 }
141
142 static bool
getAArch64ArchFeaturesFromMcpu(const Driver & D,StringRef Mcpu,const ArgList & Args,llvm::AArch64::ExtensionSet & Extensions)143 getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
144 const ArgList &Args,
145 llvm::AArch64::ExtensionSet &Extensions) {
146 StringRef CPU;
147 std::string McpuLowerCase = Mcpu.lower();
148 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions))
149 return false;
150
151 return true;
152 }
153
154 static bool
getAArch64MicroArchFeaturesFromMtune(const Driver & D,StringRef Mtune,const ArgList & Args,std::vector<StringRef> & Features)155 getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
156 const ArgList &Args,
157 std::vector<StringRef> &Features) {
158 std::string MtuneLowerCase = Mtune.lower();
159 // Check CPU name is valid, but ignore any extensions on it.
160 llvm::AArch64::ExtensionSet Extensions;
161 StringRef Tune;
162 if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, Extensions))
163 return false;
164
165 // Handle CPU name is 'native'.
166 if (MtuneLowerCase == "native")
167 MtuneLowerCase = std::string(llvm::sys::getHostCPUName());
168 if (MtuneLowerCase == "cyclone" ||
169 StringRef(MtuneLowerCase).starts_with("apple")) {
170 Features.push_back("+zcm");
171 Features.push_back("+zcz");
172 }
173 return true;
174 }
175
176 static bool
getAArch64MicroArchFeaturesFromMcpu(const Driver & D,StringRef Mcpu,const ArgList & Args,std::vector<StringRef> & Features)177 getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
178 const ArgList &Args,
179 std::vector<StringRef> &Features) {
180 StringRef CPU;
181 // Check CPU name is valid, but ignore any extensions on it.
182 llvm::AArch64::ExtensionSet DecodedFeature;
183 std::string McpuLowerCase = Mcpu.lower();
184 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
185 return false;
186
187 return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
188 }
189
getAArch64TargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features,bool ForAS)190 void aarch64::getAArch64TargetFeatures(const Driver &D,
191 const llvm::Triple &Triple,
192 const ArgList &Args,
193 std::vector<StringRef> &Features,
194 bool ForAS) {
195 Arg *A;
196 bool success = true;
197 llvm::StringRef WaMArch;
198 llvm::AArch64::ExtensionSet Extensions;
199 if (ForAS)
200 for (const auto *A :
201 Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler))
202 for (StringRef Value : A->getValues())
203 if (Value.starts_with("-march="))
204 WaMArch = Value.substr(7);
205 // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or
206 // "-Xassembler -march" is detected. Otherwise it may return false
207 // and causes Clang to error out.
208 if (!WaMArch.empty())
209 success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Extensions);
210 else if ((A = Args.getLastArg(options::OPT_march_EQ)))
211 success =
212 getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions);
213 else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
214 success =
215 getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions);
216 else if (isCPUDeterminedByTriple(Triple))
217 success = getAArch64ArchFeaturesFromMcpu(
218 D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions);
219 else
220 // Default to 'A' profile if the architecture is not specified.
221 success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions);
222
223 if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
224 success =
225 getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
226 else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
227 success =
228 getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
229 else if (success && isCPUDeterminedByTriple(Triple))
230 success = getAArch64MicroArchFeaturesFromMcpu(
231 D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
232
233 if (!success) {
234 auto Diag = D.Diag(diag::err_drv_unsupported_option_argument);
235 // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value,
236 // while 'A' is uninitialized. Only dereference 'A' in the other case.
237 if (!WaMArch.empty())
238 Diag << "-march=" << WaMArch;
239 else
240 Diag << A->getSpelling() << A->getValue();
241 }
242
243 // -mgeneral-regs-only disables all floating-point features.
244 if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
245 Extensions.disable(llvm::AArch64::AEK_FP);
246 }
247
248 // En/disable crc
249 if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
250 if (A->getOption().matches(options::OPT_mcrc))
251 Extensions.enable(llvm::AArch64::AEK_CRC);
252 else
253 Extensions.disable(llvm::AArch64::AEK_CRC);
254 }
255
256 // At this point all hardware features are decided, so convert the extensions
257 // set to a feature list.
258 Extensions.toLLVMFeatureList(Features);
259
260 if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
261 StringRef Mtp = A->getValue();
262 if (Mtp == "el3" || Mtp == "tpidr_el3")
263 Features.push_back("+tpidr-el3");
264 else if (Mtp == "el2" || Mtp == "tpidr_el2")
265 Features.push_back("+tpidr-el2");
266 else if (Mtp == "el1" || Mtp == "tpidr_el1")
267 Features.push_back("+tpidr-el1");
268 else if (Mtp == "tpidrro_el0")
269 Features.push_back("+tpidrro-el0");
270 else if (Mtp != "el0" && Mtp != "tpidr_el0")
271 D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
272 }
273
274 // Enable/disable straight line speculation hardening.
275 if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
276 StringRef Scope = A->getValue();
277 bool EnableRetBr = false;
278 bool EnableBlr = false;
279 bool DisableComdat = false;
280 if (Scope != "none") {
281 SmallVector<StringRef, 4> Opts;
282 Scope.split(Opts, ",");
283 for (auto Opt : Opts) {
284 Opt = Opt.trim();
285 if (Opt == "all") {
286 EnableBlr = true;
287 EnableRetBr = true;
288 continue;
289 }
290 if (Opt == "retbr") {
291 EnableRetBr = true;
292 continue;
293 }
294 if (Opt == "blr") {
295 EnableBlr = true;
296 continue;
297 }
298 if (Opt == "comdat") {
299 DisableComdat = false;
300 continue;
301 }
302 if (Opt == "nocomdat") {
303 DisableComdat = true;
304 continue;
305 }
306 D.Diag(diag::err_drv_unsupported_option_argument)
307 << A->getSpelling() << Scope;
308 break;
309 }
310 }
311
312 if (EnableRetBr)
313 Features.push_back("+harden-sls-retbr");
314 if (EnableBlr)
315 Features.push_back("+harden-sls-blr");
316 if (DisableComdat) {
317 Features.push_back("+harden-sls-nocomdat");
318 }
319 }
320
321 if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
322 options::OPT_munaligned_access)) {
323 if (A->getOption().matches(options::OPT_mno_unaligned_access))
324 Features.push_back("+strict-align");
325 } else if (Triple.isOSOpenBSD())
326 Features.push_back("+strict-align");
327
328 if (Args.hasArg(options::OPT_ffixed_x1))
329 Features.push_back("+reserve-x1");
330
331 if (Args.hasArg(options::OPT_ffixed_x2))
332 Features.push_back("+reserve-x2");
333
334 if (Args.hasArg(options::OPT_ffixed_x3))
335 Features.push_back("+reserve-x3");
336
337 if (Args.hasArg(options::OPT_ffixed_x4))
338 Features.push_back("+reserve-x4");
339
340 if (Args.hasArg(options::OPT_ffixed_x5))
341 Features.push_back("+reserve-x5");
342
343 if (Args.hasArg(options::OPT_ffixed_x6))
344 Features.push_back("+reserve-x6");
345
346 if (Args.hasArg(options::OPT_ffixed_x7))
347 Features.push_back("+reserve-x7");
348
349 if (Args.hasArg(options::OPT_ffixed_x9))
350 Features.push_back("+reserve-x9");
351
352 if (Args.hasArg(options::OPT_ffixed_x10))
353 Features.push_back("+reserve-x10");
354
355 if (Args.hasArg(options::OPT_ffixed_x11))
356 Features.push_back("+reserve-x11");
357
358 if (Args.hasArg(options::OPT_ffixed_x12))
359 Features.push_back("+reserve-x12");
360
361 if (Args.hasArg(options::OPT_ffixed_x13))
362 Features.push_back("+reserve-x13");
363
364 if (Args.hasArg(options::OPT_ffixed_x14))
365 Features.push_back("+reserve-x14");
366
367 if (Args.hasArg(options::OPT_ffixed_x15))
368 Features.push_back("+reserve-x15");
369
370 if (Args.hasArg(options::OPT_ffixed_x18))
371 Features.push_back("+reserve-x18");
372
373 if (Args.hasArg(options::OPT_ffixed_x20))
374 Features.push_back("+reserve-x20");
375
376 if (Args.hasArg(options::OPT_ffixed_x21))
377 Features.push_back("+reserve-x21");
378
379 if (Args.hasArg(options::OPT_ffixed_x22))
380 Features.push_back("+reserve-x22");
381
382 if (Args.hasArg(options::OPT_ffixed_x23))
383 Features.push_back("+reserve-x23");
384
385 if (Args.hasArg(options::OPT_ffixed_x24))
386 Features.push_back("+reserve-x24");
387
388 if (Args.hasArg(options::OPT_ffixed_x25))
389 Features.push_back("+reserve-x25");
390
391 if (Args.hasArg(options::OPT_ffixed_x26))
392 Features.push_back("+reserve-x26");
393
394 if (Args.hasArg(options::OPT_ffixed_x27))
395 Features.push_back("+reserve-x27");
396
397 if (Args.hasArg(options::OPT_ffixed_x28))
398 Features.push_back("+reserve-x28");
399
400 if (Args.hasArg(options::OPT_ffixed_x30))
401 Features.push_back("+reserve-x30");
402
403 if (Args.hasArg(options::OPT_fcall_saved_x8))
404 Features.push_back("+call-saved-x8");
405
406 if (Args.hasArg(options::OPT_fcall_saved_x9))
407 Features.push_back("+call-saved-x9");
408
409 if (Args.hasArg(options::OPT_fcall_saved_x10))
410 Features.push_back("+call-saved-x10");
411
412 if (Args.hasArg(options::OPT_fcall_saved_x11))
413 Features.push_back("+call-saved-x11");
414
415 if (Args.hasArg(options::OPT_fcall_saved_x12))
416 Features.push_back("+call-saved-x12");
417
418 if (Args.hasArg(options::OPT_fcall_saved_x13))
419 Features.push_back("+call-saved-x13");
420
421 if (Args.hasArg(options::OPT_fcall_saved_x14))
422 Features.push_back("+call-saved-x14");
423
424 if (Args.hasArg(options::OPT_fcall_saved_x15))
425 Features.push_back("+call-saved-x15");
426
427 if (Args.hasArg(options::OPT_fcall_saved_x18))
428 Features.push_back("+call-saved-x18");
429
430 if (Args.hasArg(options::OPT_mno_neg_immediates))
431 Features.push_back("+no-neg-immediates");
432
433 if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
434 options::OPT_mno_fix_cortex_a53_835769)) {
435 if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
436 Features.push_back("+fix-cortex-a53-835769");
437 else
438 Features.push_back("-fix-cortex-a53-835769");
439 } else if (Triple.isAndroid() || Triple.isOHOSFamily()) {
440 // Enabled A53 errata (835769) workaround by default on android
441 Features.push_back("+fix-cortex-a53-835769");
442 } else if (Triple.isOSFuchsia()) {
443 std::string CPU = getCPUName(D, Args, Triple);
444 if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
445 Features.push_back("+fix-cortex-a53-835769");
446 }
447
448 if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
449 Features.push_back("+no-bti-at-return-twice");
450 }
451