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/Driver.h" 11 #include "clang/Driver/DriverDiagnostic.h" 12 #include "clang/Driver/Options.h" 13 #include "llvm/Option/ArgList.h" 14 #include "llvm/Support/TargetParser.h" 15 #include "llvm/Support/Host.h" 16 17 using namespace clang::driver; 18 using namespace clang::driver::tools; 19 using namespace clang; 20 using namespace llvm::opt; 21 22 /// \returns true if the given triple can determine the default CPU type even 23 /// if -arch is not specified. 24 static 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. 31 std::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 // Handle CPU name is 'native'. 41 if (CPU == "native") 42 return std::string(llvm::sys::getHostCPUName()); 43 else if (CPU.size()) 44 return CPU; 45 46 // Make sure we pick the appropriate Apple CPU if -arch is used or when 47 // targetting a Darwin OS. 48 if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) 49 return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4" 50 : "apple-a7"; 51 52 return "generic"; 53 } 54 55 // Decode AArch64 features from string like +[no]featureA+[no]featureB+... 56 static bool DecodeAArch64Features(const Driver &D, StringRef text, 57 std::vector<StringRef> &Features, 58 llvm::AArch64::ArchKind ArchKind) { 59 SmallVector<StringRef, 8> Split; 60 text.split(Split, StringRef("+"), -1, false); 61 62 for (StringRef Feature : Split) { 63 StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature); 64 if (!FeatureName.empty()) 65 Features.push_back(FeatureName); 66 else if (Feature == "neon" || Feature == "noneon") 67 D.Diag(clang::diag::err_drv_no_neon_modifier); 68 else 69 return false; 70 71 // +sve implies +f32mm if the base architecture is v8.6A 72 // it isn't the case in general that sve implies both f64mm and f32mm 73 if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A) && Feature == "sve") 74 Features.push_back("+f32mm"); 75 } 76 return true; 77 } 78 79 // Check if the CPU name and feature modifiers in -mcpu are legal. If yes, 80 // decode CPU and feature. 81 static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, 82 std::vector<StringRef> &Features) { 83 std::pair<StringRef, StringRef> Split = Mcpu.split("+"); 84 CPU = Split.first; 85 llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A; 86 87 if (CPU == "native") 88 CPU = llvm::sys::getHostCPUName(); 89 90 if (CPU == "generic") { 91 Features.push_back("+neon"); 92 } else { 93 ArchKind = llvm::AArch64::parseCPUArch(CPU); 94 if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) 95 return false; 96 97 unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind); 98 if (!llvm::AArch64::getExtensionFeatures(Extension, Features)) 99 return false; 100 } 101 102 if (Split.second.size() && 103 !DecodeAArch64Features(D, Split.second, Features, ArchKind)) 104 return false; 105 106 return true; 107 } 108 109 static bool 110 getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, 111 const ArgList &Args, 112 std::vector<StringRef> &Features) { 113 std::string MarchLowerCase = March.lower(); 114 std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); 115 116 llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); 117 if (ArchKind == llvm::AArch64::ArchKind::INVALID || 118 !llvm::AArch64::getArchFeatures(ArchKind, Features) || 119 (Split.second.size() && 120 !DecodeAArch64Features(D, Split.second, Features, ArchKind))) 121 return false; 122 123 return true; 124 } 125 126 static bool 127 getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, 128 const ArgList &Args, 129 std::vector<StringRef> &Features) { 130 StringRef CPU; 131 std::string McpuLowerCase = Mcpu.lower(); 132 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) 133 return false; 134 135 return true; 136 } 137 138 static bool 139 getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, 140 const ArgList &Args, 141 std::vector<StringRef> &Features) { 142 std::string MtuneLowerCase = Mtune.lower(); 143 // Check CPU name is valid 144 std::vector<StringRef> MtuneFeatures; 145 StringRef Tune; 146 if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) 147 return false; 148 149 // Handle CPU name is 'native'. 150 if (MtuneLowerCase == "native") 151 MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); 152 if (MtuneLowerCase == "cyclone" || 153 StringRef(MtuneLowerCase).startswith("apple")) { 154 Features.push_back("+zcm"); 155 Features.push_back("+zcz"); 156 } 157 return true; 158 } 159 160 static bool 161 getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, 162 const ArgList &Args, 163 std::vector<StringRef> &Features) { 164 StringRef CPU; 165 std::vector<StringRef> DecodedFeature; 166 std::string McpuLowerCase = Mcpu.lower(); 167 if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) 168 return false; 169 170 return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features); 171 } 172 173 void aarch64::getAArch64TargetFeatures(const Driver &D, 174 const llvm::Triple &Triple, 175 const ArgList &Args, 176 std::vector<StringRef> &Features) { 177 Arg *A; 178 bool success = true; 179 // Enable NEON by default. 180 Features.push_back("+neon"); 181 if ((A = Args.getLastArg(options::OPT_march_EQ))) 182 success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); 183 else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) 184 success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features); 185 else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) 186 success = getAArch64ArchFeaturesFromMcpu( 187 D, getAArch64TargetCPU(Args, Triple, A), Args, Features); 188 189 if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) 190 success = 191 getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features); 192 else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) 193 success = 194 getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); 195 else if (success && 196 (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))) 197 success = getAArch64MicroArchFeaturesFromMcpu( 198 D, getAArch64TargetCPU(Args, Triple, A), Args, Features); 199 200 if (!success) 201 D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); 202 203 if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { 204 Features.push_back("-fp-armv8"); 205 Features.push_back("-crypto"); 206 Features.push_back("-neon"); 207 } 208 209 if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { 210 StringRef Mtp = A->getValue(); 211 if (Mtp == "el3") 212 Features.push_back("+tpidr-el3"); 213 else if (Mtp == "el2") 214 Features.push_back("+tpidr-el2"); 215 else if (Mtp == "el1") 216 Features.push_back("+tpidr-el1"); 217 else if (Mtp != "el0") 218 D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); 219 } 220 221 // Enable/disable straight line speculation hardening. 222 if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { 223 StringRef Scope = A->getValue(); 224 bool EnableRetBr = false; 225 bool EnableBlr = false; 226 if (Scope != "none" && Scope != "all") { 227 SmallVector<StringRef, 4> Opts; 228 Scope.split(Opts, ","); 229 for (auto Opt : Opts) { 230 Opt = Opt.trim(); 231 if (Opt == "retbr") { 232 EnableRetBr = true; 233 continue; 234 } 235 if (Opt == "blr") { 236 EnableBlr = true; 237 continue; 238 } 239 D.Diag(diag::err_invalid_sls_hardening) 240 << Scope << A->getAsString(Args); 241 break; 242 } 243 } else if (Scope == "all") { 244 EnableRetBr = true; 245 EnableBlr = true; 246 } 247 248 if (EnableRetBr) 249 Features.push_back("+harden-sls-retbr"); 250 if (EnableBlr) 251 Features.push_back("+harden-sls-blr"); 252 } 253 254 // En/disable crc 255 if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { 256 if (A->getOption().matches(options::OPT_mcrc)) 257 Features.push_back("+crc"); 258 else 259 Features.push_back("-crc"); 260 } 261 262 // Handle (arch-dependent) fp16fml/fullfp16 relationship. 263 // FIXME: this fp16fml option handling will be reimplemented after the 264 // TargetParser rewrite. 265 const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); 266 const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); 267 if (llvm::is_contained(Features, "+v8.4a")) { 268 const auto ItRFullFP16 = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); 269 if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { 270 // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. 271 // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. 272 if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) 273 Features.push_back("+fp16fml"); 274 } 275 else 276 goto fp16_fml_fallthrough; 277 } else { 278 fp16_fml_fallthrough: 279 // In both of these cases, putting the 'other' feature on the end of the vector will 280 // result in the same effect as placing it immediately after the current feature. 281 if (ItRNoFullFP16 < ItRFP16FML) 282 Features.push_back("-fp16fml"); 283 else if (ItRNoFullFP16 > ItRFP16FML) 284 Features.push_back("+fullfp16"); 285 } 286 287 // FIXME: this needs reimplementation too after the TargetParser rewrite 288 // 289 // Context sensitive meaning of Crypto: 290 // 1) For Arch >= ARMv8.4a: crypto = sm4 + sha3 + sha2 + aes 291 // 2) For Arch <= ARMv8.3a: crypto = sha2 + aes 292 const auto ItBegin = Features.begin(); 293 const auto ItEnd = Features.end(); 294 const auto ItRBegin = Features.rbegin(); 295 const auto ItREnd = Features.rend(); 296 const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto"); 297 const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto"); 298 const auto HasCrypto = ItRCrypto != ItREnd; 299 const auto HasNoCrypto = ItRNoCrypto != ItREnd; 300 const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin; 301 const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin; 302 303 bool NoCrypto = false; 304 if (HasCrypto && HasNoCrypto) { 305 if (PosNoCrypto < PosCrypto) 306 NoCrypto = true; 307 } 308 309 if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) { 310 if (HasCrypto && !NoCrypto) { 311 // Check if we have NOT disabled an algorithm with something like: 312 // +crypto, -algorithm 313 // And if "-algorithm" does not occur, we enable that crypto algorithm. 314 const bool HasSM4 = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd); 315 const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd); 316 const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); 317 const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); 318 if (HasSM4) 319 Features.push_back("+sm4"); 320 if (HasSHA3) 321 Features.push_back("+sha3"); 322 if (HasSHA2) 323 Features.push_back("+sha2"); 324 if (HasAES) 325 Features.push_back("+aes"); 326 } else if (HasNoCrypto) { 327 // Check if we have NOT enabled a crypto algorithm with something like: 328 // -crypto, +algorithm 329 // And if "+algorithm" does not occur, we disable that crypto algorithm. 330 const bool HasSM4 = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd); 331 const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd); 332 const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); 333 const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); 334 if (!HasSM4) 335 Features.push_back("-sm4"); 336 if (!HasSHA3) 337 Features.push_back("-sha3"); 338 if (!HasSHA2) 339 Features.push_back("-sha2"); 340 if (!HasAES) 341 Features.push_back("-aes"); 342 } 343 } else { 344 if (HasCrypto && !NoCrypto) { 345 const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); 346 const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); 347 if (HasSHA2) 348 Features.push_back("+sha2"); 349 if (HasAES) 350 Features.push_back("+aes"); 351 } else if (HasNoCrypto) { 352 const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); 353 const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); 354 const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd); 355 const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd); 356 const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd); 357 if (!HasSHA2) 358 Features.push_back("-sha2"); 359 if (!HasAES) 360 Features.push_back("-aes"); 361 if (HasV82a || HasV83a || HasV84a) { 362 Features.push_back("-sm4"); 363 Features.push_back("-sha3"); 364 } 365 } 366 } 367 368 auto V8_6Pos = llvm::find(Features, "+v8.6a"); 369 if (V8_6Pos != std::end(Features)) 370 V8_6Pos = Features.insert(std::next(V8_6Pos), {"+i8mm", "+bf16"}); 371 372 if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, 373 options::OPT_munaligned_access)) { 374 if (A->getOption().matches(options::OPT_mno_unaligned_access)) 375 Features.push_back("+strict-align"); 376 } else if (Triple.isOSOpenBSD()) 377 Features.push_back("+strict-align"); 378 379 if (Args.hasArg(options::OPT_ffixed_x1)) 380 Features.push_back("+reserve-x1"); 381 382 if (Args.hasArg(options::OPT_ffixed_x2)) 383 Features.push_back("+reserve-x2"); 384 385 if (Args.hasArg(options::OPT_ffixed_x3)) 386 Features.push_back("+reserve-x3"); 387 388 if (Args.hasArg(options::OPT_ffixed_x4)) 389 Features.push_back("+reserve-x4"); 390 391 if (Args.hasArg(options::OPT_ffixed_x5)) 392 Features.push_back("+reserve-x5"); 393 394 if (Args.hasArg(options::OPT_ffixed_x6)) 395 Features.push_back("+reserve-x6"); 396 397 if (Args.hasArg(options::OPT_ffixed_x7)) 398 Features.push_back("+reserve-x7"); 399 400 if (Args.hasArg(options::OPT_ffixed_x9)) 401 Features.push_back("+reserve-x9"); 402 403 if (Args.hasArg(options::OPT_ffixed_x10)) 404 Features.push_back("+reserve-x10"); 405 406 if (Args.hasArg(options::OPT_ffixed_x11)) 407 Features.push_back("+reserve-x11"); 408 409 if (Args.hasArg(options::OPT_ffixed_x12)) 410 Features.push_back("+reserve-x12"); 411 412 if (Args.hasArg(options::OPT_ffixed_x13)) 413 Features.push_back("+reserve-x13"); 414 415 if (Args.hasArg(options::OPT_ffixed_x14)) 416 Features.push_back("+reserve-x14"); 417 418 if (Args.hasArg(options::OPT_ffixed_x15)) 419 Features.push_back("+reserve-x15"); 420 421 if (Args.hasArg(options::OPT_ffixed_x18)) 422 Features.push_back("+reserve-x18"); 423 424 if (Args.hasArg(options::OPT_ffixed_x20)) 425 Features.push_back("+reserve-x20"); 426 427 if (Args.hasArg(options::OPT_ffixed_x21)) 428 Features.push_back("+reserve-x21"); 429 430 if (Args.hasArg(options::OPT_ffixed_x22)) 431 Features.push_back("+reserve-x22"); 432 433 if (Args.hasArg(options::OPT_ffixed_x23)) 434 Features.push_back("+reserve-x23"); 435 436 if (Args.hasArg(options::OPT_ffixed_x24)) 437 Features.push_back("+reserve-x24"); 438 439 if (Args.hasArg(options::OPT_ffixed_x25)) 440 Features.push_back("+reserve-x25"); 441 442 if (Args.hasArg(options::OPT_ffixed_x26)) 443 Features.push_back("+reserve-x26"); 444 445 if (Args.hasArg(options::OPT_ffixed_x27)) 446 Features.push_back("+reserve-x27"); 447 448 if (Args.hasArg(options::OPT_ffixed_x28)) 449 Features.push_back("+reserve-x28"); 450 451 if (Args.hasArg(options::OPT_ffixed_x30)) 452 Features.push_back("+reserve-x30"); 453 454 if (Args.hasArg(options::OPT_fcall_saved_x8)) 455 Features.push_back("+call-saved-x8"); 456 457 if (Args.hasArg(options::OPT_fcall_saved_x9)) 458 Features.push_back("+call-saved-x9"); 459 460 if (Args.hasArg(options::OPT_fcall_saved_x10)) 461 Features.push_back("+call-saved-x10"); 462 463 if (Args.hasArg(options::OPT_fcall_saved_x11)) 464 Features.push_back("+call-saved-x11"); 465 466 if (Args.hasArg(options::OPT_fcall_saved_x12)) 467 Features.push_back("+call-saved-x12"); 468 469 if (Args.hasArg(options::OPT_fcall_saved_x13)) 470 Features.push_back("+call-saved-x13"); 471 472 if (Args.hasArg(options::OPT_fcall_saved_x14)) 473 Features.push_back("+call-saved-x14"); 474 475 if (Args.hasArg(options::OPT_fcall_saved_x15)) 476 Features.push_back("+call-saved-x15"); 477 478 if (Args.hasArg(options::OPT_fcall_saved_x18)) 479 Features.push_back("+call-saved-x18"); 480 481 if (Args.hasArg(options::OPT_mno_neg_immediates)) 482 Features.push_back("+no-neg-immediates"); 483 } 484