1 //===--- AArch64.cpp - Implement AArch64 target feature support -----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements AArch64 TargetInfo objects. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "AArch64.h" 15 #include "clang/Basic/TargetBuiltins.h" 16 #include "clang/Basic/TargetInfo.h" 17 #include "llvm/ADT/ArrayRef.h" 18 #include "llvm/ADT/StringExtras.h" 19 20 using namespace clang; 21 using namespace clang::targets; 22 23 const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { 24 #define BUILTIN(ID, TYPE, ATTRS) \ 25 {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, 26 #include "clang/Basic/BuiltinsNEON.def" 27 28 #define BUILTIN(ID, TYPE, ATTRS) \ 29 {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, 30 #define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ 31 {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, 32 #include "clang/Basic/BuiltinsAArch64.def" 33 }; 34 35 AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, 36 const TargetOptions &Opts) 37 : TargetInfo(Triple), ABI("aapcs") { 38 if (getTriple().getOS() == llvm::Triple::NetBSD || 39 getTriple().getOS() == llvm::Triple::OpenBSD) { 40 // NetBSD apparently prefers consistency across ARM targets to 41 // consistency across 64-bit targets. 42 Int64Type = SignedLongLong; 43 IntMaxType = SignedLongLong; 44 } else { 45 if (!getTriple().isOSDarwin()) 46 WCharType = UnsignedInt; 47 48 Int64Type = SignedLong; 49 IntMaxType = SignedLong; 50 } 51 52 // All AArch64 implementations support ARMv8 FP, which makes half a legal type. 53 HasLegalHalfType = true; 54 55 LongWidth = LongAlign = PointerWidth = PointerAlign = 64; 56 MaxVectorAlign = 128; 57 MaxAtomicInlineWidth = 128; 58 MaxAtomicPromoteWidth = 128; 59 60 LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; 61 LongDoubleFormat = &llvm::APFloat::IEEEquad(); 62 63 // Make __builtin_ms_va_list available. 64 HasBuiltinMSVaList = true; 65 66 // {} in inline assembly are neon specifiers, not assembly variant 67 // specifiers. 68 NoAsmVariants = true; 69 70 // AAPCS gives rules for bitfields. 7.1.7 says: "The container type 71 // contributes to the alignment of the containing aggregate in the same way 72 // a plain (non bit-field) member of that type would, without exception for 73 // zero-sized or anonymous bit-fields." 74 assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); 75 UseZeroLengthBitfieldAlignment = true; 76 77 // AArch64 targets default to using the ARM C++ ABI. 78 TheCXXABI.set(TargetCXXABI::GenericAArch64); 79 80 if (Triple.getOS() == llvm::Triple::Linux) 81 this->MCountName = "\01_mcount"; 82 else if (Triple.getOS() == llvm::Triple::UnknownOS) 83 this->MCountName = 84 Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount"; 85 } 86 87 StringRef AArch64TargetInfo::getABI() const { return ABI; } 88 89 bool AArch64TargetInfo::setABI(const std::string &Name) { 90 if (Name != "aapcs" && Name != "darwinpcs") 91 return false; 92 93 ABI = Name; 94 return true; 95 } 96 97 bool AArch64TargetInfo::isValidCPUName(StringRef Name) const { 98 return Name == "generic" || 99 llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID; 100 } 101 102 bool AArch64TargetInfo::setCPU(const std::string &Name) { 103 return isValidCPUName(Name); 104 } 105 106 void AArch64TargetInfo::fillValidCPUList( 107 SmallVectorImpl<StringRef> &Values) const { 108 llvm::AArch64::fillValidCPUArchList(Values); 109 } 110 111 void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, 112 MacroBuilder &Builder) const { 113 Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); 114 } 115 116 void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, 117 MacroBuilder &Builder) const { 118 // Also include the ARMv8.1 defines 119 getTargetDefinesARMV81A(Opts, Builder); 120 } 121 122 void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, 123 MacroBuilder &Builder) const { 124 // Target identification. 125 Builder.defineMacro("__aarch64__"); 126 // For bare-metal none-eabi. 127 if (getTriple().getOS() == llvm::Triple::UnknownOS && 128 (getTriple().getEnvironment() == llvm::Triple::EABI || 129 getTriple().getEnvironment() == llvm::Triple::EABIHF)) 130 Builder.defineMacro("__ELF__"); 131 132 // Target properties. 133 if (!getTriple().isOSWindows()) { 134 Builder.defineMacro("_LP64"); 135 Builder.defineMacro("__LP64__"); 136 } 137 138 // ACLE predefines. Many can only have one possible value on v8 AArch64. 139 Builder.defineMacro("__ARM_ACLE", "200"); 140 Builder.defineMacro("__ARM_ARCH", "8"); 141 Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); 142 143 Builder.defineMacro("__ARM_64BIT_STATE", "1"); 144 Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); 145 Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); 146 147 Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); 148 Builder.defineMacro("__ARM_FEATURE_FMA", "1"); 149 Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); 150 Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE 151 Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility 152 Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); 153 Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); 154 155 Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); 156 157 // 0xe implies support for half, single and double precision operations. 158 Builder.defineMacro("__ARM_FP", "0xE"); 159 160 // PCS specifies this for SysV variants, which is all we support. Other ABIs 161 // may choose __ARM_FP16_FORMAT_ALTERNATIVE. 162 Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); 163 Builder.defineMacro("__ARM_FP16_ARGS", "1"); 164 165 if (Opts.UnsafeFPMath) 166 Builder.defineMacro("__ARM_FP_FAST", "1"); 167 168 Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", 169 Twine(Opts.WCharSize ? Opts.WCharSize : 4)); 170 171 Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); 172 173 if (FPU & NeonMode) { 174 Builder.defineMacro("__ARM_NEON", "1"); 175 // 64-bit NEON supports half, single and double precision operations. 176 Builder.defineMacro("__ARM_NEON_FP", "0xE"); 177 } 178 179 if (FPU & SveMode) 180 Builder.defineMacro("__ARM_FEATURE_SVE", "1"); 181 182 if (CRC) 183 Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); 184 185 if (Crypto) 186 Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); 187 188 if (Unaligned) 189 Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); 190 191 if ((FPU & NeonMode) && HasFullFP16) 192 Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); 193 if (HasFullFP16) 194 Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1"); 195 196 switch (ArchKind) { 197 default: 198 break; 199 case llvm::AArch64::ArchKind::ARMV8_1A: 200 getTargetDefinesARMV81A(Opts, Builder); 201 break; 202 case llvm::AArch64::ArchKind::ARMV8_2A: 203 getTargetDefinesARMV82A(Opts, Builder); 204 break; 205 } 206 207 // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. 208 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 209 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 210 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 211 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 212 } 213 214 ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const { 215 return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - 216 Builtin::FirstTSBuiltin); 217 } 218 219 bool AArch64TargetInfo::hasFeature(StringRef Feature) const { 220 return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || 221 (Feature == "neon" && (FPU & NeonMode)) || 222 (Feature == "sve" && (FPU & SveMode)); 223 } 224 225 bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 226 DiagnosticsEngine &Diags) { 227 FPU = FPUMode; 228 CRC = 0; 229 Crypto = 0; 230 Unaligned = 1; 231 HasFullFP16 = 0; 232 ArchKind = llvm::AArch64::ArchKind::ARMV8A; 233 234 for (const auto &Feature : Features) { 235 if (Feature == "+neon") 236 FPU |= NeonMode; 237 if (Feature == "+sve") 238 FPU |= SveMode; 239 if (Feature == "+crc") 240 CRC = 1; 241 if (Feature == "+crypto") 242 Crypto = 1; 243 if (Feature == "+strict-align") 244 Unaligned = 0; 245 if (Feature == "+v8.1a") 246 ArchKind = llvm::AArch64::ArchKind::ARMV8_1A; 247 if (Feature == "+v8.2a") 248 ArchKind = llvm::AArch64::ArchKind::ARMV8_2A; 249 if (Feature == "+fullfp16") 250 HasFullFP16 = 1; 251 } 252 253 setDataLayout(); 254 255 return true; 256 } 257 258 TargetInfo::CallingConvCheckResult 259 AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { 260 switch (CC) { 261 case CC_C: 262 case CC_Swift: 263 case CC_PreserveMost: 264 case CC_PreserveAll: 265 case CC_OpenCLKernel: 266 case CC_Win64: 267 return CCCR_OK; 268 default: 269 return CCCR_Warning; 270 } 271 } 272 273 bool AArch64TargetInfo::isCLZForZeroUndef() const { return false; } 274 275 TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const { 276 return TargetInfo::AArch64ABIBuiltinVaList; 277 } 278 279 const char *const AArch64TargetInfo::GCCRegNames[] = { 280 // 32-bit Integer registers 281 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", 282 "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", 283 "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", 284 285 // 64-bit Integer registers 286 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", 287 "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", 288 "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", 289 290 // 32-bit floating point regsisters 291 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", 292 "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", 293 "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", 294 295 // 64-bit floating point regsisters 296 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", 297 "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", 298 "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", 299 300 // Vector registers 301 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", 302 "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", 303 "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" 304 }; 305 306 ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { 307 return llvm::makeArrayRef(GCCRegNames); 308 } 309 310 const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { 311 {{"w31"}, "wsp"}, {{"x29"}, "fp"}, {{"x30"}, "lr"}, {{"x31"}, "sp"}, 312 // The S/D/Q and W/X registers overlap, but aren't really aliases; we 313 // don't want to substitute one of these for a different-sized one. 314 }; 315 316 ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const { 317 return llvm::makeArrayRef(GCCRegAliases); 318 } 319 320 bool AArch64TargetInfo::validateAsmConstraint( 321 const char *&Name, TargetInfo::ConstraintInfo &Info) const { 322 switch (*Name) { 323 default: 324 return false; 325 case 'w': // Floating point and SIMD registers (V0-V31) 326 Info.setAllowsRegister(); 327 return true; 328 case 'I': // Constant that can be used with an ADD instruction 329 case 'J': // Constant that can be used with a SUB instruction 330 case 'K': // Constant that can be used with a 32-bit logical instruction 331 case 'L': // Constant that can be used with a 64-bit logical instruction 332 case 'M': // Constant that can be used as a 32-bit MOV immediate 333 case 'N': // Constant that can be used as a 64-bit MOV immediate 334 case 'Y': // Floating point constant zero 335 case 'Z': // Integer constant zero 336 return true; 337 case 'Q': // A memory reference with base register and no offset 338 Info.setAllowsMemory(); 339 return true; 340 case 'S': // A symbolic address 341 Info.setAllowsRegister(); 342 return true; 343 case 'U': 344 // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. 345 // Utf: A memory address suitable for ldp/stp in TF mode. 346 // Usa: An absolute symbolic address. 347 // Ush: The high part (bits 32:12) of a pc-relative symbolic address. 348 llvm_unreachable("FIXME: Unimplemented support for U* constraints."); 349 case 'z': // Zero register, wzr or xzr 350 Info.setAllowsRegister(); 351 return true; 352 case 'x': // Floating point and SIMD registers (V0-V15) 353 Info.setAllowsRegister(); 354 return true; 355 } 356 return false; 357 } 358 359 bool AArch64TargetInfo::validateConstraintModifier( 360 StringRef Constraint, char Modifier, unsigned Size, 361 std::string &SuggestedModifier) const { 362 // Strip off constraint modifiers. 363 while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') 364 Constraint = Constraint.substr(1); 365 366 switch (Constraint[0]) { 367 default: 368 return true; 369 case 'z': 370 case 'r': { 371 switch (Modifier) { 372 case 'x': 373 case 'w': 374 // For now assume that the person knows what they're 375 // doing with the modifier. 376 return true; 377 default: 378 // By default an 'r' constraint will be in the 'x' 379 // registers. 380 if (Size == 64) 381 return true; 382 383 SuggestedModifier = "w"; 384 return false; 385 } 386 } 387 } 388 } 389 390 const char *AArch64TargetInfo::getClobbers() const { return ""; } 391 392 int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { 393 if (RegNo == 0) 394 return 0; 395 if (RegNo == 1) 396 return 1; 397 return -1; 398 } 399 400 AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple, 401 const TargetOptions &Opts) 402 : AArch64TargetInfo(Triple, Opts) {} 403 404 void AArch64leTargetInfo::setDataLayout() { 405 if (getTriple().isOSBinFormatMachO()) 406 resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); 407 else 408 resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); 409 } 410 411 void AArch64leTargetInfo::getTargetDefines(const LangOptions &Opts, 412 MacroBuilder &Builder) const { 413 Builder.defineMacro("__AARCH64EL__"); 414 AArch64TargetInfo::getTargetDefines(Opts, Builder); 415 } 416 417 AArch64beTargetInfo::AArch64beTargetInfo(const llvm::Triple &Triple, 418 const TargetOptions &Opts) 419 : AArch64TargetInfo(Triple, Opts) {} 420 421 void AArch64beTargetInfo::getTargetDefines(const LangOptions &Opts, 422 MacroBuilder &Builder) const { 423 Builder.defineMacro("__AARCH64EB__"); 424 Builder.defineMacro("__AARCH_BIG_ENDIAN"); 425 Builder.defineMacro("__ARM_BIG_ENDIAN"); 426 AArch64TargetInfo::getTargetDefines(Opts, Builder); 427 } 428 429 void AArch64beTargetInfo::setDataLayout() { 430 assert(!getTriple().isOSBinFormatMachO()); 431 resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); 432 } 433 434 WindowsARM64TargetInfo::WindowsARM64TargetInfo(const llvm::Triple &Triple, 435 const TargetOptions &Opts) 436 : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) { 437 438 // This is an LLP64 platform. 439 // int:4, long:4, long long:8, long double:8. 440 IntWidth = IntAlign = 32; 441 LongWidth = LongAlign = 32; 442 DoubleAlign = LongLongAlign = 64; 443 LongDoubleWidth = LongDoubleAlign = 64; 444 LongDoubleFormat = &llvm::APFloat::IEEEdouble(); 445 IntMaxType = SignedLongLong; 446 Int64Type = SignedLongLong; 447 SizeType = UnsignedLongLong; 448 PtrDiffType = SignedLongLong; 449 IntPtrType = SignedLongLong; 450 } 451 452 void WindowsARM64TargetInfo::setDataLayout() { 453 resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"); 454 } 455 456 TargetInfo::BuiltinVaListKind 457 WindowsARM64TargetInfo::getBuiltinVaListKind() const { 458 return TargetInfo::CharPtrBuiltinVaList; 459 } 460 461 TargetInfo::CallingConvCheckResult 462 WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { 463 switch (CC) { 464 case CC_X86StdCall: 465 case CC_X86ThisCall: 466 case CC_X86FastCall: 467 case CC_X86VectorCall: 468 return CCCR_Ignore; 469 case CC_C: 470 case CC_OpenCLKernel: 471 case CC_PreserveMost: 472 case CC_PreserveAll: 473 case CC_Win64: 474 return CCCR_OK; 475 default: 476 return CCCR_Warning; 477 } 478 } 479 480 MicrosoftARM64TargetInfo::MicrosoftARM64TargetInfo(const llvm::Triple &Triple, 481 const TargetOptions &Opts) 482 : WindowsARM64TargetInfo(Triple, Opts) { 483 TheCXXABI.set(TargetCXXABI::Microsoft); 484 } 485 486 void MicrosoftARM64TargetInfo::getVisualStudioDefines( 487 const LangOptions &Opts, MacroBuilder &Builder) const { 488 WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, Builder); 489 Builder.defineMacro("_M_ARM64", "1"); 490 } 491 492 void MicrosoftARM64TargetInfo::getTargetDefines(const LangOptions &Opts, 493 MacroBuilder &Builder) const { 494 WindowsTargetInfo::getTargetDefines(Opts, Builder); 495 getVisualStudioDefines(Opts, Builder); 496 } 497 498 MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple, 499 const TargetOptions &Opts) 500 : WindowsARM64TargetInfo(Triple, Opts) { 501 TheCXXABI.set(TargetCXXABI::GenericAArch64); 502 } 503 504 DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple, 505 const TargetOptions &Opts) 506 : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) { 507 Int64Type = SignedLongLong; 508 UseSignedCharForObjCBool = false; 509 510 LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; 511 LongDoubleFormat = &llvm::APFloat::IEEEdouble(); 512 513 TheCXXABI.set(TargetCXXABI::iOS64); 514 } 515 516 void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts, 517 const llvm::Triple &Triple, 518 MacroBuilder &Builder) const { 519 Builder.defineMacro("__AARCH64_SIMD__"); 520 Builder.defineMacro("__ARM64_ARCH_8__"); 521 Builder.defineMacro("__ARM_NEON__"); 522 Builder.defineMacro("__LITTLE_ENDIAN__"); 523 Builder.defineMacro("__REGISTER_PREFIX__", ""); 524 Builder.defineMacro("__arm64", "1"); 525 Builder.defineMacro("__arm64__", "1"); 526 527 getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); 528 } 529 530 TargetInfo::BuiltinVaListKind 531 DarwinAArch64TargetInfo::getBuiltinVaListKind() const { 532 return TargetInfo::CharPtrBuiltinVaList; 533 } 534 535 // 64-bit RenderScript is aarch64 536 RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple, 537 const TargetOptions &Opts) 538 : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), 539 Triple.getOSName(), 540 Triple.getEnvironmentName()), 541 Opts) { 542 IsRenderScriptTarget = true; 543 } 544 545 void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts, 546 MacroBuilder &Builder) const { 547 Builder.defineMacro("__RENDERSCRIPT__"); 548 AArch64leTargetInfo::getTargetDefines(Opts, Builder); 549 } 550