1 //===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===// 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 a target parser to recognise ARM hardware features 11 // such as FPU/CPU/ARCH/extensions and specific support such as HWDIV. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/Support/ARMTargetParser.h" 16 #include "llvm/ADT/StringSwitch.h" 17 #include <cctype> 18 19 using namespace llvm; 20 21 static StringRef getHWDivSynonym(StringRef HWDiv) { 22 return StringSwitch<StringRef>(HWDiv) 23 .Case("thumb,arm", "arm,thumb") 24 .Default(HWDiv); 25 } 26 27 // Allows partial match, ex. "v7a" matches "armv7a". 28 ARM::ArchKind ARM::parseArch(StringRef Arch) { 29 Arch = getCanonicalArchName(Arch); 30 StringRef Syn = getArchSynonym(Arch); 31 for (const auto A : ARCHNames) { 32 if (A.getName().endswith(Syn)) 33 return A.ID; 34 } 35 return ArchKind::INVALID; 36 } 37 38 // Version number (ex. v7 = 7). 39 unsigned ARM::parseArchVersion(StringRef Arch) { 40 Arch = getCanonicalArchName(Arch); 41 switch (parseArch(Arch)) { 42 case ArchKind::ARMV2: 43 case ArchKind::ARMV2A: 44 return 2; 45 case ArchKind::ARMV3: 46 case ArchKind::ARMV3M: 47 return 3; 48 case ArchKind::ARMV4: 49 case ArchKind::ARMV4T: 50 return 4; 51 case ArchKind::ARMV5T: 52 case ArchKind::ARMV5TE: 53 case ArchKind::IWMMXT: 54 case ArchKind::IWMMXT2: 55 case ArchKind::XSCALE: 56 case ArchKind::ARMV5TEJ: 57 return 5; 58 case ArchKind::ARMV6: 59 case ArchKind::ARMV6K: 60 case ArchKind::ARMV6T2: 61 case ArchKind::ARMV6KZ: 62 case ArchKind::ARMV6M: 63 return 6; 64 case ArchKind::ARMV7A: 65 case ArchKind::ARMV7VE: 66 case ArchKind::ARMV7R: 67 case ArchKind::ARMV7M: 68 case ArchKind::ARMV7S: 69 case ArchKind::ARMV7EM: 70 case ArchKind::ARMV7K: 71 return 7; 72 case ArchKind::ARMV8A: 73 case ArchKind::ARMV8_1A: 74 case ArchKind::ARMV8_2A: 75 case ArchKind::ARMV8_3A: 76 case ArchKind::ARMV8_4A: 77 case ArchKind::ARMV8_5A: 78 case ArchKind::ARMV8R: 79 case ArchKind::ARMV8MBaseline: 80 case ArchKind::ARMV8MMainline: 81 return 8; 82 case ArchKind::INVALID: 83 return 0; 84 } 85 llvm_unreachable("Unhandled architecture"); 86 } 87 88 // Profile A/R/M 89 ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { 90 Arch = getCanonicalArchName(Arch); 91 switch (parseArch(Arch)) { 92 case ArchKind::ARMV6M: 93 case ArchKind::ARMV7M: 94 case ArchKind::ARMV7EM: 95 case ArchKind::ARMV8MMainline: 96 case ArchKind::ARMV8MBaseline: 97 return ProfileKind::M; 98 case ArchKind::ARMV7R: 99 case ArchKind::ARMV8R: 100 return ProfileKind::R; 101 case ArchKind::ARMV7A: 102 case ArchKind::ARMV7VE: 103 case ArchKind::ARMV7K: 104 case ArchKind::ARMV8A: 105 case ArchKind::ARMV8_1A: 106 case ArchKind::ARMV8_2A: 107 case ArchKind::ARMV8_3A: 108 case ArchKind::ARMV8_4A: 109 case ArchKind::ARMV8_5A: 110 return ProfileKind::A; 111 case ArchKind::ARMV2: 112 case ArchKind::ARMV2A: 113 case ArchKind::ARMV3: 114 case ArchKind::ARMV3M: 115 case ArchKind::ARMV4: 116 case ArchKind::ARMV4T: 117 case ArchKind::ARMV5T: 118 case ArchKind::ARMV5TE: 119 case ArchKind::ARMV5TEJ: 120 case ArchKind::ARMV6: 121 case ArchKind::ARMV6K: 122 case ArchKind::ARMV6T2: 123 case ArchKind::ARMV6KZ: 124 case ArchKind::ARMV7S: 125 case ArchKind::IWMMXT: 126 case ArchKind::IWMMXT2: 127 case ArchKind::XSCALE: 128 case ArchKind::INVALID: 129 return ProfileKind::INVALID; 130 } 131 llvm_unreachable("Unhandled architecture"); 132 } 133 134 StringRef ARM::getArchSynonym(StringRef Arch) { 135 return StringSwitch<StringRef>(Arch) 136 .Case("v5", "v5t") 137 .Case("v5e", "v5te") 138 .Case("v6j", "v6") 139 .Case("v6hl", "v6k") 140 .Cases("v6m", "v6sm", "v6s-m", "v6-m") 141 .Cases("v6z", "v6zk", "v6kz") 142 .Cases("v7", "v7a", "v7hl", "v7l", "v7-a") 143 .Case("v7r", "v7-r") 144 .Case("v7m", "v7-m") 145 .Case("v7em", "v7e-m") 146 .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a") 147 .Case("v8.1a", "v8.1-a") 148 .Case("v8.2a", "v8.2-a") 149 .Case("v8.3a", "v8.3-a") 150 .Case("v8.4a", "v8.4-a") 151 .Case("v8.5a", "v8.5-a") 152 .Case("v8r", "v8-r") 153 .Case("v8m.base", "v8-m.base") 154 .Case("v8m.main", "v8-m.main") 155 .Default(Arch); 156 } 157 158 bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) { 159 160 if (FPUKind >= FK_LAST || FPUKind == FK_INVALID) 161 return false; 162 163 // fp-only-sp and d16 subtarget features are independent of each other, so we 164 // must enable/disable both. 165 switch (FPUNames[FPUKind].Restriction) { 166 case FPURestriction::SP_D16: 167 Features.push_back("+fp-only-sp"); 168 Features.push_back("+d16"); 169 break; 170 case FPURestriction::D16: 171 Features.push_back("-fp-only-sp"); 172 Features.push_back("+d16"); 173 break; 174 case FPURestriction::None: 175 Features.push_back("-fp-only-sp"); 176 Features.push_back("-d16"); 177 break; 178 } 179 180 // FPU version subtarget features are inclusive of lower-numbered ones, so 181 // enable the one corresponding to this version and disable all that are 182 // higher. We also have to make sure to disable fp16 when vfp4 is disabled, 183 // as +vfp4 implies +fp16 but -vfp4 does not imply -fp16. 184 switch (FPUNames[FPUKind].FPUVer) { 185 case FPUVersion::VFPV5: 186 Features.push_back("+fp-armv8"); 187 break; 188 case FPUVersion::VFPV4: 189 Features.push_back("+vfp4"); 190 Features.push_back("-fp-armv8"); 191 break; 192 case FPUVersion::VFPV3_FP16: 193 Features.push_back("+vfp3"); 194 Features.push_back("+fp16"); 195 Features.push_back("-vfp4"); 196 Features.push_back("-fp-armv8"); 197 break; 198 case FPUVersion::VFPV3: 199 Features.push_back("+vfp3"); 200 Features.push_back("-fp16"); 201 Features.push_back("-vfp4"); 202 Features.push_back("-fp-armv8"); 203 break; 204 case FPUVersion::VFPV2: 205 Features.push_back("+vfp2"); 206 Features.push_back("-vfp3"); 207 Features.push_back("-fp16"); 208 Features.push_back("-vfp4"); 209 Features.push_back("-fp-armv8"); 210 break; 211 case FPUVersion::NONE: 212 Features.push_back("-vfp2"); 213 Features.push_back("-vfp3"); 214 Features.push_back("-fp16"); 215 Features.push_back("-vfp4"); 216 Features.push_back("-fp-armv8"); 217 break; 218 } 219 220 // crypto includes neon, so we handle this similarly to FPU version. 221 switch (FPUNames[FPUKind].NeonSupport) { 222 case NeonSupportLevel::Crypto: 223 Features.push_back("+neon"); 224 Features.push_back("+crypto"); 225 break; 226 case NeonSupportLevel::Neon: 227 Features.push_back("+neon"); 228 Features.push_back("-crypto"); 229 break; 230 case NeonSupportLevel::None: 231 Features.push_back("-neon"); 232 Features.push_back("-crypto"); 233 break; 234 } 235 236 return true; 237 } 238 239 // Little/Big endian 240 ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { 241 if (Arch.startswith("armeb") || Arch.startswith("thumbeb") || 242 Arch.startswith("aarch64_be")) 243 return EndianKind::BIG; 244 245 if (Arch.startswith("arm") || Arch.startswith("thumb")) { 246 if (Arch.endswith("eb")) 247 return EndianKind::BIG; 248 else 249 return EndianKind::LITTLE; 250 } 251 252 if (Arch.startswith("aarch64")) 253 return EndianKind::LITTLE; 254 255 return EndianKind::INVALID; 256 } 257 258 // ARM, Thumb, AArch64 259 ARM::ISAKind ARM::parseArchISA(StringRef Arch) { 260 return StringSwitch<ISAKind>(Arch) 261 .StartsWith("aarch64", ISAKind::AARCH64) 262 .StartsWith("arm64", ISAKind::AARCH64) 263 .StartsWith("thumb", ISAKind::THUMB) 264 .StartsWith("arm", ISAKind::ARM) 265 .Default(ISAKind::INVALID); 266 } 267 268 unsigned ARM::parseFPU(StringRef FPU) { 269 StringRef Syn = getFPUSynonym(FPU); 270 for (const auto F : FPUNames) { 271 if (Syn == F.getName()) 272 return F.ID; 273 } 274 return FK_INVALID; 275 } 276 277 ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) { 278 if (FPUKind >= FK_LAST) 279 return NeonSupportLevel::None; 280 return FPUNames[FPUKind].NeonSupport; 281 } 282 283 // MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but 284 // (iwmmxt|xscale)(eb)? is also permitted. If the former, return 285 // "v.+", if the latter, return unmodified string, minus 'eb'. 286 // If invalid, return empty string. 287 StringRef ARM::getCanonicalArchName(StringRef Arch) { 288 size_t offset = StringRef::npos; 289 StringRef A = Arch; 290 StringRef Error = ""; 291 292 // Begins with "arm" / "thumb", move past it. 293 if (A.startswith("arm64")) 294 offset = 5; 295 else if (A.startswith("arm")) 296 offset = 3; 297 else if (A.startswith("thumb")) 298 offset = 5; 299 else if (A.startswith("aarch64")) { 300 offset = 7; 301 // AArch64 uses "_be", not "eb" suffix. 302 if (A.find("eb") != StringRef::npos) 303 return Error; 304 if (A.substr(offset, 3) == "_be") 305 offset += 3; 306 } 307 308 // Ex. "armebv7", move past the "eb". 309 if (offset != StringRef::npos && A.substr(offset, 2) == "eb") 310 offset += 2; 311 // Or, if it ends with eb ("armv7eb"), chop it off. 312 else if (A.endswith("eb")) 313 A = A.substr(0, A.size() - 2); 314 // Trim the head 315 if (offset != StringRef::npos) 316 A = A.substr(offset); 317 318 // Empty string means offset reached the end, which means it's valid. 319 if (A.empty()) 320 return Arch; 321 322 // Only match non-marketing names 323 if (offset != StringRef::npos) { 324 // Must start with 'vN'. 325 if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1]))) 326 return Error; 327 // Can't have an extra 'eb'. 328 if (A.find("eb") != StringRef::npos) 329 return Error; 330 } 331 332 // Arch will either be a 'v' name (v7a) or a marketing name (xscale). 333 return A; 334 } 335 336 StringRef ARM::getFPUSynonym(StringRef FPU) { 337 return StringSwitch<StringRef>(FPU) 338 .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported 339 .Case("vfp2", "vfpv2") 340 .Case("vfp3", "vfpv3") 341 .Case("vfp4", "vfpv4") 342 .Case("vfp3-d16", "vfpv3-d16") 343 .Case("vfp4-d16", "vfpv4-d16") 344 .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16") 345 .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16") 346 .Case("fp5-sp-d16", "fpv5-sp-d16") 347 .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16") 348 // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3. 349 .Case("neon-vfpv3", "neon") 350 .Default(FPU); 351 } 352 353 StringRef ARM::getFPUName(unsigned FPUKind) { 354 if (FPUKind >= FK_LAST) 355 return StringRef(); 356 return FPUNames[FPUKind].getName(); 357 } 358 359 ARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) { 360 if (FPUKind >= FK_LAST) 361 return FPUVersion::NONE; 362 return FPUNames[FPUKind].FPUVer; 363 } 364 365 ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) { 366 if (FPUKind >= FK_LAST) 367 return FPURestriction::None; 368 return FPUNames[FPUKind].Restriction; 369 } 370 371 unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) { 372 if (CPU == "generic") 373 return ARM::ARCHNames[static_cast<unsigned>(AK)].DefaultFPU; 374 375 return StringSwitch<unsigned>(CPU) 376 #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 377 .Case(NAME, DEFAULT_FPU) 378 #include "llvm/Support/ARMTargetParser.def" 379 .Default(ARM::FK_INVALID); 380 } 381 382 unsigned ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) { 383 if (CPU == "generic") 384 return ARM::ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions; 385 386 return StringSwitch<unsigned>(CPU) 387 #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 388 .Case(NAME, \ 389 ARCHNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \ 390 DEFAULT_EXT) 391 #include "llvm/Support/ARMTargetParser.def" 392 .Default(ARM::AEK_INVALID); 393 } 394 395 bool ARM::getHWDivFeatures(unsigned HWDivKind, 396 std::vector<StringRef> &Features) { 397 398 if (HWDivKind == AEK_INVALID) 399 return false; 400 401 if (HWDivKind & AEK_HWDIVARM) 402 Features.push_back("+hwdiv-arm"); 403 else 404 Features.push_back("-hwdiv-arm"); 405 406 if (HWDivKind & AEK_HWDIVTHUMB) 407 Features.push_back("+hwdiv"); 408 else 409 Features.push_back("-hwdiv"); 410 411 return true; 412 } 413 414 bool ARM::getExtensionFeatures(unsigned Extensions, 415 std::vector<StringRef> &Features) { 416 417 if (Extensions == AEK_INVALID) 418 return false; 419 420 if (Extensions & AEK_CRC) 421 Features.push_back("+crc"); 422 else 423 Features.push_back("-crc"); 424 425 if (Extensions & AEK_DSP) 426 Features.push_back("+dsp"); 427 else 428 Features.push_back("-dsp"); 429 430 if (Extensions & AEK_FP16FML) 431 Features.push_back("+fp16fml"); 432 else 433 Features.push_back("-fp16fml"); 434 435 if (Extensions & AEK_RAS) 436 Features.push_back("+ras"); 437 else 438 Features.push_back("-ras"); 439 440 if (Extensions & AEK_DOTPROD) 441 Features.push_back("+dotprod"); 442 else 443 Features.push_back("-dotprod"); 444 445 return getHWDivFeatures(Extensions, Features); 446 } 447 448 StringRef ARM::getArchName(ARM::ArchKind AK) { 449 return ARCHNames[static_cast<unsigned>(AK)].getName(); 450 } 451 452 StringRef ARM::getCPUAttr(ARM::ArchKind AK) { 453 return ARCHNames[static_cast<unsigned>(AK)].getCPUAttr(); 454 } 455 456 StringRef ARM::getSubArch(ARM::ArchKind AK) { 457 return ARCHNames[static_cast<unsigned>(AK)].getSubArch(); 458 } 459 460 unsigned ARM::getArchAttr(ARM::ArchKind AK) { 461 return ARCHNames[static_cast<unsigned>(AK)].ArchAttr; 462 } 463 464 StringRef ARM::getArchExtName(unsigned ArchExtKind) { 465 for (const auto AE : ARCHExtNames) { 466 if (ArchExtKind == AE.ID) 467 return AE.getName(); 468 } 469 return StringRef(); 470 } 471 472 StringRef ARM::getArchExtFeature(StringRef ArchExt) { 473 if (ArchExt.startswith("no")) { 474 StringRef ArchExtBase(ArchExt.substr(2)); 475 for (const auto AE : ARCHExtNames) { 476 if (AE.NegFeature && ArchExtBase == AE.getName()) 477 return StringRef(AE.NegFeature); 478 } 479 } 480 for (const auto AE : ARCHExtNames) { 481 if (AE.Feature && ArchExt == AE.getName()) 482 return StringRef(AE.Feature); 483 } 484 485 return StringRef(); 486 } 487 488 StringRef ARM::getHWDivName(unsigned HWDivKind) { 489 for (const auto D : HWDivNames) { 490 if (HWDivKind == D.ID) 491 return D.getName(); 492 } 493 return StringRef(); 494 } 495 496 StringRef ARM::getDefaultCPU(StringRef Arch) { 497 ArchKind AK = parseArch(Arch); 498 if (AK == ArchKind::INVALID) 499 return StringRef(); 500 501 // Look for multiple AKs to find the default for pair AK+Name. 502 for (const auto CPU : CPUNames) { 503 if (CPU.ArchID == AK && CPU.Default) 504 return CPU.getName(); 505 } 506 507 // If we can't find a default then target the architecture instead 508 return "generic"; 509 } 510 511 unsigned ARM::parseHWDiv(StringRef HWDiv) { 512 StringRef Syn = getHWDivSynonym(HWDiv); 513 for (const auto D : HWDivNames) { 514 if (Syn == D.getName()) 515 return D.ID; 516 } 517 return AEK_INVALID; 518 } 519 520 unsigned ARM::parseArchExt(StringRef ArchExt) { 521 for (const auto A : ARCHExtNames) { 522 if (ArchExt == A.getName()) 523 return A.ID; 524 } 525 return AEK_INVALID; 526 } 527 528 ARM::ArchKind ARM::parseCPUArch(StringRef CPU) { 529 for (const auto C : CPUNames) { 530 if (CPU == C.getName()) 531 return C.ArchID; 532 } 533 return ArchKind::INVALID; 534 } 535 536 void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 537 for (const CpuNames<ArchKind> &Arch : CPUNames) { 538 if (Arch.ArchID != ArchKind::INVALID) 539 Values.push_back(Arch.getName()); 540 } 541 } 542 543 StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { 544 StringRef ArchName = 545 CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU)); 546 547 if (TT.isOSBinFormatMachO()) { 548 if (TT.getEnvironment() == Triple::EABI || 549 TT.getOS() == Triple::UnknownOS || 550 parseArchProfile(ArchName) == ProfileKind::M) 551 return "aapcs"; 552 if (TT.isWatchABI()) 553 return "aapcs16"; 554 return "apcs-gnu"; 555 } else if (TT.isOSWindows()) 556 // FIXME: this is invalid for WindowsCE. 557 return "aapcs"; 558 559 // Select the default based on the platform. 560 switch (TT.getEnvironment()) { 561 case Triple::Android: 562 case Triple::GNUEABI: 563 case Triple::GNUEABIHF: 564 case Triple::MuslEABI: 565 case Triple::MuslEABIHF: 566 return "aapcs-linux"; 567 case Triple::EABIHF: 568 case Triple::EABI: 569 return "aapcs"; 570 default: 571 if (TT.isOSNetBSD()) 572 return "apcs-gnu"; 573 if (TT.isOSOpenBSD()) 574 return "aapcs-linux"; 575 return "aapcs"; 576 } 577 } 578