clang 20.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"
10#include "../CommonArgs.h"
11#include "clang/Driver/Driver.h"
14#include "llvm/Option/ArgList.h"
15#include "llvm/TargetParser/AArch64TargetParser.h"
16#include "llvm/TargetParser/Host.h"
17
18using namespace clang::driver;
19using namespace clang::driver::tools;
20using namespace clang;
21using namespace llvm::opt;
22
23/// \returns true if the given triple can determine the default CPU type even
24/// if -arch is not specified.
25static 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.
32std::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+...
74static bool DecodeAArch64Features(const Driver &D, StringRef text,
75 llvm::AArch64::ExtensionSet &Extensions) {
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.
93static 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 const std::optional<llvm::AArch64::CpuInfo> CpuInfo =
102 llvm::AArch64::parseCpu(CPU);
103 if (!CpuInfo)
104 return false;
105
106 Extensions.addCPUDefaults(*CpuInfo);
107
108 if (Split.second.size() &&
109 !DecodeAArch64Features(D, Split.second, Extensions))
110 return false;
111
112 return true;
113}
114
115static bool
117 const ArgList &Args,
118 llvm::AArch64::ExtensionSet &Extensions) {
119 std::string MarchLowerCase = March.lower();
120 std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
121
122 const llvm::AArch64::ArchInfo *ArchInfo =
123 llvm::AArch64::parseArch(Split.first);
124 if (Split.first == "native")
125 ArchInfo = llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str());
126 if (!ArchInfo)
127 return false;
128
129 Extensions.addArchDefaults(*ArchInfo);
130
131 if ((Split.second.size() &&
132 !DecodeAArch64Features(D, Split.second, Extensions)))
133 return false;
134
135 return true;
136}
137
139 const Driver &D, StringRef Mcpu, const ArgList &Args,
140 llvm::AArch64::ExtensionSet &Extensions, std::vector<StringRef> &Features) {
141 StringRef CPU;
142 std::string McpuLowerCase = Mcpu.lower();
143 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions))
144 return false;
145
146 if (Mcpu == "native") {
147 llvm::StringMap<bool> HostFeatures = llvm::sys::getHostCPUFeatures();
148 for (auto &[Feature, Enabled] : HostFeatures) {
149 Features.push_back(Args.MakeArgString((Enabled ? "+" : "-") + Feature));
150 }
151 }
152
153 return true;
154}
155
156static bool
158 const ArgList &Args,
159 std::vector<StringRef> &Features) {
160 std::string MtuneLowerCase = Mtune.lower();
161 // Check CPU name is valid, but ignore any extensions on it.
162 llvm::AArch64::ExtensionSet Extensions;
163 StringRef Tune;
164 if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, Extensions))
165 return false;
166
167 // Handle CPU name is 'native'.
168 if (MtuneLowerCase == "native")
169 MtuneLowerCase = std::string(llvm::sys::getHostCPUName());
170
171 // 'cyclone' and later have zero-cycle register moves and zeroing.
172 if (MtuneLowerCase == "cyclone" ||
173 StringRef(MtuneLowerCase).starts_with("apple")) {
174 Features.push_back("+zcm");
175 Features.push_back("+zcz");
176 }
177
178 return true;
179}
180
181static bool
183 const ArgList &Args,
184 std::vector<StringRef> &Features) {
185 StringRef CPU;
186 // Check CPU name is valid, but ignore any extensions on it.
187 llvm::AArch64::ExtensionSet DecodedFeature;
188 std::string McpuLowerCase = Mcpu.lower();
189 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
190 return false;
191
192 return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
193}
194
196 const llvm::Triple &Triple,
197 const ArgList &Args,
198 std::vector<StringRef> &Features,
199 bool ForAS) {
200 Arg *A;
201 bool success = true;
202 llvm::StringRef WaMArch;
203 llvm::AArch64::ExtensionSet Extensions;
204 if (ForAS)
205 for (const auto *A :
206 Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler))
207 for (StringRef Value : A->getValues())
208 if (Value.starts_with("-march="))
209 WaMArch = Value.substr(7);
210 // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or
211 // "-Xassembler -march" is detected. Otherwise it may return false
212 // and causes Clang to error out.
213 if (!WaMArch.empty())
214 success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Extensions);
215 else if ((A = Args.getLastArg(options::OPT_march_EQ)))
216 success =
217 getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions);
218 else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
219 success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions,
220 Features);
221 else if (isCPUDeterminedByTriple(Triple))
223 D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions, Features);
224 else
225 // Default to 'A' profile if the architecture is not specified.
226 success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions);
227
228 if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
229 success =
230 getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
231 else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
232 success =
233 getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
234 else if (success && isCPUDeterminedByTriple(Triple))
236 D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
237
238 if (!success) {
239 auto Diag = D.Diag(diag::err_drv_unsupported_option_argument);
240 // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value,
241 // while 'A' is uninitialized. Only dereference 'A' in the other case.
242 if (!WaMArch.empty())
243 Diag << "-march=" << WaMArch;
244 else
245 Diag << A->getSpelling() << A->getValue();
246 }
247
248 // -mgeneral-regs-only disables all floating-point features.
249 if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
250 Extensions.disable(llvm::AArch64::AEK_FP);
251 }
252
253 // En/disable crc
254 if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
255 if (A->getOption().matches(options::OPT_mcrc))
256 Extensions.enable(llvm::AArch64::AEK_CRC);
257 else
258 Extensions.disable(llvm::AArch64::AEK_CRC);
259 }
260
261 // At this point all hardware features are decided, so convert the extensions
262 // set to a feature list.
263 Extensions.toLLVMFeatureList(Features);
264
265 if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
266 StringRef Mtp = A->getValue();
267 if (Mtp == "el3" || Mtp == "tpidr_el3")
268 Features.push_back("+tpidr-el3");
269 else if (Mtp == "el2" || Mtp == "tpidr_el2")
270 Features.push_back("+tpidr-el2");
271 else if (Mtp == "el1" || Mtp == "tpidr_el1")
272 Features.push_back("+tpidr-el1");
273 else if (Mtp == "tpidrro_el0")
274 Features.push_back("+tpidrro-el0");
275 else if (Mtp != "el0" && Mtp != "tpidr_el0")
276 D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
277 }
278
279 // Enable/disable straight line speculation hardening.
280 if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
281 StringRef Scope = A->getValue();
282 bool EnableRetBr = false;
283 bool EnableBlr = false;
284 bool DisableComdat = false;
285 if (Scope != "none") {
287 Scope.split(Opts, ",");
288 for (auto Opt : Opts) {
289 Opt = Opt.trim();
290 if (Opt == "all") {
291 EnableBlr = true;
292 EnableRetBr = true;
293 continue;
294 }
295 if (Opt == "retbr") {
296 EnableRetBr = true;
297 continue;
298 }
299 if (Opt == "blr") {
300 EnableBlr = true;
301 continue;
302 }
303 if (Opt == "comdat") {
304 DisableComdat = false;
305 continue;
306 }
307 if (Opt == "nocomdat") {
308 DisableComdat = true;
309 continue;
310 }
311 D.Diag(diag::err_drv_unsupported_option_argument)
312 << A->getSpelling() << Scope;
313 break;
314 }
315 }
316
317 if (EnableRetBr)
318 Features.push_back("+harden-sls-retbr");
319 if (EnableBlr)
320 Features.push_back("+harden-sls-blr");
321 if (DisableComdat) {
322 Features.push_back("+harden-sls-nocomdat");
323 }
324 }
325
326 if (Arg *A = Args.getLastArg(
327 options::OPT_mstrict_align, options::OPT_mno_strict_align,
328 options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) {
329 if (A->getOption().matches(options::OPT_mstrict_align) ||
330 A->getOption().matches(options::OPT_mno_unaligned_access))
331 Features.push_back("+strict-align");
332 } else if (Triple.isOSOpenBSD())
333 Features.push_back("+strict-align");
334
335 if (Args.hasArg(options::OPT_ffixed_x1))
336 Features.push_back("+reserve-x1");
337
338 if (Args.hasArg(options::OPT_ffixed_x2))
339 Features.push_back("+reserve-x2");
340
341 if (Args.hasArg(options::OPT_ffixed_x3))
342 Features.push_back("+reserve-x3");
343
344 if (Args.hasArg(options::OPT_ffixed_x4))
345 Features.push_back("+reserve-x4");
346
347 if (Args.hasArg(options::OPT_ffixed_x5))
348 Features.push_back("+reserve-x5");
349
350 if (Args.hasArg(options::OPT_ffixed_x6))
351 Features.push_back("+reserve-x6");
352
353 if (Args.hasArg(options::OPT_ffixed_x7))
354 Features.push_back("+reserve-x7");
355
356 if (Args.hasArg(options::OPT_ffixed_x9))
357 Features.push_back("+reserve-x9");
358
359 if (Args.hasArg(options::OPT_ffixed_x10))
360 Features.push_back("+reserve-x10");
361
362 if (Args.hasArg(options::OPT_ffixed_x11))
363 Features.push_back("+reserve-x11");
364
365 if (Args.hasArg(options::OPT_ffixed_x12))
366 Features.push_back("+reserve-x12");
367
368 if (Args.hasArg(options::OPT_ffixed_x13))
369 Features.push_back("+reserve-x13");
370
371 if (Args.hasArg(options::OPT_ffixed_x14))
372 Features.push_back("+reserve-x14");
373
374 if (Args.hasArg(options::OPT_ffixed_x15))
375 Features.push_back("+reserve-x15");
376
377 if (Args.hasArg(options::OPT_ffixed_x18))
378 Features.push_back("+reserve-x18");
379
380 if (Args.hasArg(options::OPT_ffixed_x20))
381 Features.push_back("+reserve-x20");
382
383 if (Args.hasArg(options::OPT_ffixed_x21))
384 Features.push_back("+reserve-x21");
385
386 if (Args.hasArg(options::OPT_ffixed_x22))
387 Features.push_back("+reserve-x22");
388
389 if (Args.hasArg(options::OPT_ffixed_x23))
390 Features.push_back("+reserve-x23");
391
392 if (Args.hasArg(options::OPT_ffixed_x24))
393 Features.push_back("+reserve-x24");
394
395 if (Args.hasArg(options::OPT_ffixed_x25))
396 Features.push_back("+reserve-x25");
397
398 if (Args.hasArg(options::OPT_ffixed_x26))
399 Features.push_back("+reserve-x26");
400
401 if (Args.hasArg(options::OPT_ffixed_x27))
402 Features.push_back("+reserve-x27");
403
404 if (Args.hasArg(options::OPT_ffixed_x28))
405 Features.push_back("+reserve-x28");
406
407 if (Args.hasArg(options::OPT_mlr_for_calls_only))
408 Features.push_back("+reserve-lr-for-ra");
409
410 if (Args.hasArg(options::OPT_fcall_saved_x8))
411 Features.push_back("+call-saved-x8");
412
413 if (Args.hasArg(options::OPT_fcall_saved_x9))
414 Features.push_back("+call-saved-x9");
415
416 if (Args.hasArg(options::OPT_fcall_saved_x10))
417 Features.push_back("+call-saved-x10");
418
419 if (Args.hasArg(options::OPT_fcall_saved_x11))
420 Features.push_back("+call-saved-x11");
421
422 if (Args.hasArg(options::OPT_fcall_saved_x12))
423 Features.push_back("+call-saved-x12");
424
425 if (Args.hasArg(options::OPT_fcall_saved_x13))
426 Features.push_back("+call-saved-x13");
427
428 if (Args.hasArg(options::OPT_fcall_saved_x14))
429 Features.push_back("+call-saved-x14");
430
431 if (Args.hasArg(options::OPT_fcall_saved_x15))
432 Features.push_back("+call-saved-x15");
433
434 if (Args.hasArg(options::OPT_fcall_saved_x18))
435 Features.push_back("+call-saved-x18");
436
437 if (Args.hasArg(options::OPT_mno_neg_immediates))
438 Features.push_back("+no-neg-immediates");
439
440 if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
441 options::OPT_mno_fix_cortex_a53_835769)) {
442 if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
443 Features.push_back("+fix-cortex-a53-835769");
444 else
445 Features.push_back("-fix-cortex-a53-835769");
446 } else if (Triple.isAndroid() || Triple.isOHOSFamily()) {
447 // Enabled A53 errata (835769) workaround by default on android
448 Features.push_back("+fix-cortex-a53-835769");
449 } else if (Triple.isOSFuchsia()) {
450 std::string CPU = getCPUName(D, Args, Triple);
451 if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
452 Features.push_back("+fix-cortex-a53-835769");
453 }
454
455 if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
456 Features.push_back("+no-bti-at-return-twice");
457}
458
459void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args,
460 llvm::Triple &Triple) {
461 Arg *ABIArg = Args.getLastArg(options::OPT_mabi_EQ);
462 bool HasPAuthABI =
463 ABIArg ? (StringRef(ABIArg->getValue()) == "pauthtest") : false;
464
465 switch (Triple.getEnvironment()) {
466 case llvm::Triple::UnknownEnvironment:
467 if (HasPAuthABI)
468 Triple.setEnvironment(llvm::Triple::PAuthTest);
469 break;
470 case llvm::Triple::PAuthTest:
471 break;
472 default:
473 if (HasPAuthABI)
474 D.Diag(diag::err_drv_unsupported_opt_for_target)
475 << ABIArg->getAsString(Args) << Triple.getTriple();
476 break;
477 }
478}
const Decl * D
static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, llvm::AArch64::ExtensionSet &Extensions)
Definition: AArch64.cpp:116
static bool getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, llvm::AArch64::ExtensionSet &Extensions, std::vector< StringRef > &Features)
Definition: AArch64.cpp:138
static bool getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector< StringRef > &Features)
Definition: AArch64.cpp:182
static bool getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector< StringRef > &Features)
Definition: AArch64.cpp:157
static bool DecodeAArch64Features(const Driver &D, StringRef text, llvm::AArch64::ExtensionSet &Extensions)
Definition: AArch64.cpp:74
static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, llvm::AArch64::ExtensionSet &Extensions)
Definition: AArch64.cpp:93
static bool isCPUDeterminedByTriple(const llvm::Triple &Triple)
Definition: AArch64.cpp:25
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:77
void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< llvm::StringRef > &Features, bool ForAS)
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.