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. 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. 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+... 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. 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 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 115 static bool 116 getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, 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 138 static bool getAArch64ArchFeaturesFromMcpu( 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 156 static bool 157 getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, 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 181 static bool 182 getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, 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 195 void aarch64::getAArch64TargetFeatures(const Driver &D, 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)) 222 success = getAArch64ArchFeaturesFromMcpu( 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)) 235 success = getAArch64MicroArchFeaturesFromMcpu( 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") { 286 SmallVector<StringRef, 4> Opts; 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 459 void 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 } 479