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