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