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