483 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "AArch64.h"10#include "clang/Driver/CommonArgs.h"11#include "clang/Driver/Driver.h"12#include "clang/Options/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 even23/// 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 are29/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is30/// 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) {94 SmallVector<StringRef, 8> Split;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 bool134getAArch64ArchFeaturesFromMarch(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 156static bool getAArch64ArchFeaturesFromMcpu(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 bool175getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,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 bool186getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,187 const ArgList &Args,188 std::vector<StringRef> &Features) {189 return getAArch64MicroArchFeaturesFromMtune(D, Mcpu, Args, Features);190}191 192void aarch64::getAArch64TargetFeatures(const Driver &D,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=" or208 // "-Xassembler -march" is detected. Otherwise it may return false209 // 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))219 success = getAArch64ArchFeaturesFromMcpu(220 D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions, Features);221 else222 // 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(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))232 success = getAArch64MicroArchFeaturesFromMcpu(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 else242 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 crc251 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 else255 Extensions.disable(llvm::AArch64::AEK_CRC);256 }257 258 // At this point all hardware features are decided, so convert the extensions259 // 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") {283 SmallVector<StringRef, 4> Opts;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 unused335 // 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 else455 Features.push_back("-fix-cortex-a53-835769");456 } else if (Triple.isAndroid() || Triple.isOHOSFamily()) {457 // Enabled A53 errata (835769) workaround by default on android458 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 469/// Is the triple {aarch64.aarch64_be}-none-elf?470bool aarch64::isAArch64BareMetal(const llvm::Triple &Triple) {471 if (Triple.getArch() != llvm::Triple::aarch64 &&472 Triple.getArch() != llvm::Triple::aarch64_be)473 return false;474 475 if (Triple.getVendor() != llvm::Triple::UnknownVendor)476 return false;477 478 if (Triple.getOS() != llvm::Triple::UnknownOS)479 return false;480 481 return Triple.getEnvironmentName() == "elf";482}483