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