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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/Driver/ToolChains/Arch/AArch64.cpp