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