1bdd1243dSDimitry Andric //===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // This file implements a target parser to recognise ARM hardware features 10bdd1243dSDimitry Andric // such as FPU/CPU/ARCH/extensions and specific support such as HWDIV. 11bdd1243dSDimitry Andric // 12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 13bdd1243dSDimitry Andric 14bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParser.h" 15bdd1243dSDimitry Andric #include "llvm/ADT/StringSwitch.h" 165f757f3fSDimitry Andric #include "llvm/Support/Format.h" 175f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h" 18bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParserCommon.h" 19bdd1243dSDimitry Andric #include "llvm/TargetParser/Triple.h" 20bdd1243dSDimitry Andric #include <cctype> 21bdd1243dSDimitry Andric 22bdd1243dSDimitry Andric using namespace llvm; 23bdd1243dSDimitry Andric 24bdd1243dSDimitry Andric static StringRef getHWDivSynonym(StringRef HWDiv) { 25bdd1243dSDimitry Andric return StringSwitch<StringRef>(HWDiv) 26bdd1243dSDimitry Andric .Case("thumb,arm", "arm,thumb") 27bdd1243dSDimitry Andric .Default(HWDiv); 28bdd1243dSDimitry Andric } 29bdd1243dSDimitry Andric 30bdd1243dSDimitry Andric // Allows partial match, ex. "v7a" matches "armv7a". 31bdd1243dSDimitry Andric ARM::ArchKind ARM::parseArch(StringRef Arch) { 32bdd1243dSDimitry Andric Arch = getCanonicalArchName(Arch); 33bdd1243dSDimitry Andric StringRef Syn = getArchSynonym(Arch); 34bdd1243dSDimitry Andric for (const auto &A : ARMArchNames) { 355f757f3fSDimitry Andric if (A.Name.ends_with(Syn)) 36bdd1243dSDimitry Andric return A.ID; 37bdd1243dSDimitry Andric } 38bdd1243dSDimitry Andric return ArchKind::INVALID; 39bdd1243dSDimitry Andric } 40bdd1243dSDimitry Andric 41bdd1243dSDimitry Andric // Version number (ex. v7 = 7). 42bdd1243dSDimitry Andric unsigned ARM::parseArchVersion(StringRef Arch) { 43bdd1243dSDimitry Andric Arch = getCanonicalArchName(Arch); 44bdd1243dSDimitry Andric switch (parseArch(Arch)) { 45bdd1243dSDimitry Andric case ArchKind::ARMV4: 46bdd1243dSDimitry Andric case ArchKind::ARMV4T: 47bdd1243dSDimitry Andric return 4; 48bdd1243dSDimitry Andric case ArchKind::ARMV5T: 49bdd1243dSDimitry Andric case ArchKind::ARMV5TE: 50bdd1243dSDimitry Andric case ArchKind::IWMMXT: 51bdd1243dSDimitry Andric case ArchKind::IWMMXT2: 52bdd1243dSDimitry Andric case ArchKind::XSCALE: 53bdd1243dSDimitry Andric case ArchKind::ARMV5TEJ: 54bdd1243dSDimitry Andric return 5; 55bdd1243dSDimitry Andric case ArchKind::ARMV6: 56bdd1243dSDimitry Andric case ArchKind::ARMV6K: 57bdd1243dSDimitry Andric case ArchKind::ARMV6T2: 58bdd1243dSDimitry Andric case ArchKind::ARMV6KZ: 59bdd1243dSDimitry Andric case ArchKind::ARMV6M: 60bdd1243dSDimitry Andric return 6; 61bdd1243dSDimitry Andric case ArchKind::ARMV7A: 62bdd1243dSDimitry Andric case ArchKind::ARMV7VE: 63bdd1243dSDimitry Andric case ArchKind::ARMV7R: 64bdd1243dSDimitry Andric case ArchKind::ARMV7M: 65bdd1243dSDimitry Andric case ArchKind::ARMV7S: 66bdd1243dSDimitry Andric case ArchKind::ARMV7EM: 67bdd1243dSDimitry Andric case ArchKind::ARMV7K: 68bdd1243dSDimitry Andric return 7; 69bdd1243dSDimitry Andric case ArchKind::ARMV8A: 70bdd1243dSDimitry Andric case ArchKind::ARMV8_1A: 71bdd1243dSDimitry Andric case ArchKind::ARMV8_2A: 72bdd1243dSDimitry Andric case ArchKind::ARMV8_3A: 73bdd1243dSDimitry Andric case ArchKind::ARMV8_4A: 74bdd1243dSDimitry Andric case ArchKind::ARMV8_5A: 75bdd1243dSDimitry Andric case ArchKind::ARMV8_6A: 76bdd1243dSDimitry Andric case ArchKind::ARMV8_7A: 77bdd1243dSDimitry Andric case ArchKind::ARMV8_8A: 78bdd1243dSDimitry Andric case ArchKind::ARMV8_9A: 79bdd1243dSDimitry Andric case ArchKind::ARMV8R: 80bdd1243dSDimitry Andric case ArchKind::ARMV8MBaseline: 81bdd1243dSDimitry Andric case ArchKind::ARMV8MMainline: 82bdd1243dSDimitry Andric case ArchKind::ARMV8_1MMainline: 83bdd1243dSDimitry Andric return 8; 84bdd1243dSDimitry Andric case ArchKind::ARMV9A: 85bdd1243dSDimitry Andric case ArchKind::ARMV9_1A: 86bdd1243dSDimitry Andric case ArchKind::ARMV9_2A: 87bdd1243dSDimitry Andric case ArchKind::ARMV9_3A: 88bdd1243dSDimitry Andric case ArchKind::ARMV9_4A: 89bdd1243dSDimitry Andric return 9; 90bdd1243dSDimitry Andric case ArchKind::INVALID: 91bdd1243dSDimitry Andric return 0; 92bdd1243dSDimitry Andric } 93bdd1243dSDimitry Andric llvm_unreachable("Unhandled architecture"); 94bdd1243dSDimitry Andric } 95bdd1243dSDimitry Andric 96bdd1243dSDimitry Andric static ARM::ProfileKind getProfileKind(ARM::ArchKind AK) { 97bdd1243dSDimitry Andric switch (AK) { 98bdd1243dSDimitry Andric case ARM::ArchKind::ARMV6M: 99bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7M: 100bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7EM: 101bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8MMainline: 102bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8MBaseline: 103bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_1MMainline: 104bdd1243dSDimitry Andric return ARM::ProfileKind::M; 105bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7R: 106bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8R: 107bdd1243dSDimitry Andric return ARM::ProfileKind::R; 108bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7A: 109bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7VE: 110bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7K: 111bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8A: 112bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_1A: 113bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_2A: 114bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_3A: 115bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_4A: 116bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_5A: 117bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_6A: 118bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_7A: 119bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_8A: 120bdd1243dSDimitry Andric case ARM::ArchKind::ARMV8_9A: 121bdd1243dSDimitry Andric case ARM::ArchKind::ARMV9A: 122bdd1243dSDimitry Andric case ARM::ArchKind::ARMV9_1A: 123bdd1243dSDimitry Andric case ARM::ArchKind::ARMV9_2A: 124bdd1243dSDimitry Andric case ARM::ArchKind::ARMV9_3A: 125bdd1243dSDimitry Andric case ARM::ArchKind::ARMV9_4A: 126bdd1243dSDimitry Andric return ARM::ProfileKind::A; 127bdd1243dSDimitry Andric case ARM::ArchKind::ARMV4: 128bdd1243dSDimitry Andric case ARM::ArchKind::ARMV4T: 129bdd1243dSDimitry Andric case ARM::ArchKind::ARMV5T: 130bdd1243dSDimitry Andric case ARM::ArchKind::ARMV5TE: 131bdd1243dSDimitry Andric case ARM::ArchKind::ARMV5TEJ: 132bdd1243dSDimitry Andric case ARM::ArchKind::ARMV6: 133bdd1243dSDimitry Andric case ARM::ArchKind::ARMV6K: 134bdd1243dSDimitry Andric case ARM::ArchKind::ARMV6T2: 135bdd1243dSDimitry Andric case ARM::ArchKind::ARMV6KZ: 136bdd1243dSDimitry Andric case ARM::ArchKind::ARMV7S: 137bdd1243dSDimitry Andric case ARM::ArchKind::IWMMXT: 138bdd1243dSDimitry Andric case ARM::ArchKind::IWMMXT2: 139bdd1243dSDimitry Andric case ARM::ArchKind::XSCALE: 140bdd1243dSDimitry Andric case ARM::ArchKind::INVALID: 141bdd1243dSDimitry Andric return ARM::ProfileKind::INVALID; 142bdd1243dSDimitry Andric } 143bdd1243dSDimitry Andric llvm_unreachable("Unhandled architecture"); 144bdd1243dSDimitry Andric } 145bdd1243dSDimitry Andric 146bdd1243dSDimitry Andric // Profile A/R/M 147bdd1243dSDimitry Andric ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { 148bdd1243dSDimitry Andric Arch = getCanonicalArchName(Arch); 149bdd1243dSDimitry Andric return getProfileKind(parseArch(Arch)); 150bdd1243dSDimitry Andric } 151bdd1243dSDimitry Andric 15206c3fb27SDimitry Andric bool ARM::getFPUFeatures(ARM::FPUKind FPUKind, 15306c3fb27SDimitry Andric std::vector<StringRef> &Features) { 154bdd1243dSDimitry Andric 155bdd1243dSDimitry Andric if (FPUKind >= FK_LAST || FPUKind == FK_INVALID) 156bdd1243dSDimitry Andric return false; 157bdd1243dSDimitry Andric 158bdd1243dSDimitry Andric static const struct FPUFeatureNameInfo { 159bdd1243dSDimitry Andric const char *PlusName, *MinusName; 160bdd1243dSDimitry Andric FPUVersion MinVersion; 161bdd1243dSDimitry Andric FPURestriction MaxRestriction; 162bdd1243dSDimitry Andric } FPUFeatureInfoList[] = { 163bdd1243dSDimitry Andric // We have to specify the + and - versions of the name in full so 164bdd1243dSDimitry Andric // that we can return them as static StringRefs. 165bdd1243dSDimitry Andric // 166bdd1243dSDimitry Andric // Also, the SubtargetFeatures ending in just "sp" are listed here 167bdd1243dSDimitry Andric // under FPURestriction::None, which is the only FPURestriction in 168bdd1243dSDimitry Andric // which they would be valid (since FPURestriction::SP doesn't 169bdd1243dSDimitry Andric // exist). 170bdd1243dSDimitry Andric {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16}, 171bdd1243dSDimitry Andric {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16}, 172bdd1243dSDimitry Andric {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None}, 173bdd1243dSDimitry Andric {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16}, 174bdd1243dSDimitry Andric {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16}, 175bdd1243dSDimitry Andric {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None}, 176bdd1243dSDimitry Andric {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16}, 177bdd1243dSDimitry Andric {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None}, 178bdd1243dSDimitry Andric {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16}, 179bdd1243dSDimitry Andric {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16}, 180bdd1243dSDimitry Andric {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None}, 181bdd1243dSDimitry Andric {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None}, 182bdd1243dSDimitry Andric {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16}, 183bdd1243dSDimitry Andric {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16}, 184bdd1243dSDimitry Andric {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None}, 185bdd1243dSDimitry Andric {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16}, 186bdd1243dSDimitry Andric {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16}, 187bdd1243dSDimitry Andric {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None}, 188bdd1243dSDimitry Andric }; 189bdd1243dSDimitry Andric 190bdd1243dSDimitry Andric for (const auto &Info: FPUFeatureInfoList) { 191bdd1243dSDimitry Andric if (FPUNames[FPUKind].FPUVer >= Info.MinVersion && 192bdd1243dSDimitry Andric FPUNames[FPUKind].Restriction <= Info.MaxRestriction) 193bdd1243dSDimitry Andric Features.push_back(Info.PlusName); 194bdd1243dSDimitry Andric else 195bdd1243dSDimitry Andric Features.push_back(Info.MinusName); 196bdd1243dSDimitry Andric } 197bdd1243dSDimitry Andric 198bdd1243dSDimitry Andric static const struct NeonFeatureNameInfo { 199bdd1243dSDimitry Andric const char *PlusName, *MinusName; 200bdd1243dSDimitry Andric NeonSupportLevel MinSupportLevel; 201bdd1243dSDimitry Andric } NeonFeatureInfoList[] = { 202bdd1243dSDimitry Andric {"+neon", "-neon", NeonSupportLevel::Neon}, 203bdd1243dSDimitry Andric {"+sha2", "-sha2", NeonSupportLevel::Crypto}, 204bdd1243dSDimitry Andric {"+aes", "-aes", NeonSupportLevel::Crypto}, 205bdd1243dSDimitry Andric }; 206bdd1243dSDimitry Andric 207bdd1243dSDimitry Andric for (const auto &Info: NeonFeatureInfoList) { 208bdd1243dSDimitry Andric if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel) 209bdd1243dSDimitry Andric Features.push_back(Info.PlusName); 210bdd1243dSDimitry Andric else 211bdd1243dSDimitry Andric Features.push_back(Info.MinusName); 212bdd1243dSDimitry Andric } 213bdd1243dSDimitry Andric 214bdd1243dSDimitry Andric return true; 215bdd1243dSDimitry Andric } 216bdd1243dSDimitry Andric 21706c3fb27SDimitry Andric ARM::FPUKind ARM::parseFPU(StringRef FPU) { 218bdd1243dSDimitry Andric StringRef Syn = getFPUSynonym(FPU); 219bdd1243dSDimitry Andric for (const auto &F : FPUNames) { 220bdd1243dSDimitry Andric if (Syn == F.Name) 221bdd1243dSDimitry Andric return F.ID; 222bdd1243dSDimitry Andric } 223bdd1243dSDimitry Andric return FK_INVALID; 224bdd1243dSDimitry Andric } 225bdd1243dSDimitry Andric 22606c3fb27SDimitry Andric ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(ARM::FPUKind FPUKind) { 227bdd1243dSDimitry Andric if (FPUKind >= FK_LAST) 228bdd1243dSDimitry Andric return NeonSupportLevel::None; 229bdd1243dSDimitry Andric return FPUNames[FPUKind].NeonSupport; 230bdd1243dSDimitry Andric } 231bdd1243dSDimitry Andric 232bdd1243dSDimitry Andric StringRef ARM::getFPUSynonym(StringRef FPU) { 233bdd1243dSDimitry Andric return StringSwitch<StringRef>(FPU) 234bdd1243dSDimitry Andric .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported 235bdd1243dSDimitry Andric .Case("vfp2", "vfpv2") 236bdd1243dSDimitry Andric .Case("vfp3", "vfpv3") 237bdd1243dSDimitry Andric .Case("vfp4", "vfpv4") 238bdd1243dSDimitry Andric .Case("vfp3-d16", "vfpv3-d16") 239bdd1243dSDimitry Andric .Case("vfp4-d16", "vfpv4-d16") 240bdd1243dSDimitry Andric .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16") 241bdd1243dSDimitry Andric .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16") 242bdd1243dSDimitry Andric .Case("fp5-sp-d16", "fpv5-sp-d16") 243bdd1243dSDimitry Andric .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16") 244bdd1243dSDimitry Andric // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3. 245bdd1243dSDimitry Andric .Case("neon-vfpv3", "neon") 246bdd1243dSDimitry Andric .Default(FPU); 247bdd1243dSDimitry Andric } 248bdd1243dSDimitry Andric 24906c3fb27SDimitry Andric StringRef ARM::getFPUName(ARM::FPUKind FPUKind) { 250bdd1243dSDimitry Andric if (FPUKind >= FK_LAST) 251bdd1243dSDimitry Andric return StringRef(); 252bdd1243dSDimitry Andric return FPUNames[FPUKind].Name; 253bdd1243dSDimitry Andric } 254bdd1243dSDimitry Andric 25506c3fb27SDimitry Andric ARM::FPUVersion ARM::getFPUVersion(ARM::FPUKind FPUKind) { 256bdd1243dSDimitry Andric if (FPUKind >= FK_LAST) 257bdd1243dSDimitry Andric return FPUVersion::NONE; 258bdd1243dSDimitry Andric return FPUNames[FPUKind].FPUVer; 259bdd1243dSDimitry Andric } 260bdd1243dSDimitry Andric 26106c3fb27SDimitry Andric ARM::FPURestriction ARM::getFPURestriction(ARM::FPUKind FPUKind) { 262bdd1243dSDimitry Andric if (FPUKind >= FK_LAST) 263bdd1243dSDimitry Andric return FPURestriction::None; 264bdd1243dSDimitry Andric return FPUNames[FPUKind].Restriction; 265bdd1243dSDimitry Andric } 266bdd1243dSDimitry Andric 26706c3fb27SDimitry Andric ARM::FPUKind ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) { 268bdd1243dSDimitry Andric if (CPU == "generic") 269bdd1243dSDimitry Andric return ARM::ARMArchNames[static_cast<unsigned>(AK)].DefaultFPU; 270bdd1243dSDimitry Andric 27106c3fb27SDimitry Andric return StringSwitch<ARM::FPUKind>(CPU) 272bdd1243dSDimitry Andric #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 273bdd1243dSDimitry Andric .Case(NAME, DEFAULT_FPU) 274bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParser.def" 275bdd1243dSDimitry Andric .Default(ARM::FK_INVALID); 276bdd1243dSDimitry Andric } 277bdd1243dSDimitry Andric 278bdd1243dSDimitry Andric uint64_t ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) { 279bdd1243dSDimitry Andric if (CPU == "generic") 280bdd1243dSDimitry Andric return ARM::ARMArchNames[static_cast<unsigned>(AK)].ArchBaseExtensions; 281bdd1243dSDimitry Andric 282bdd1243dSDimitry Andric return StringSwitch<uint64_t>(CPU) 283bdd1243dSDimitry Andric #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 284bdd1243dSDimitry Andric .Case(NAME, \ 285bdd1243dSDimitry Andric ARMArchNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \ 286bdd1243dSDimitry Andric DEFAULT_EXT) 287bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParser.def" 288bdd1243dSDimitry Andric .Default(ARM::AEK_INVALID); 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric 291bdd1243dSDimitry Andric bool ARM::getHWDivFeatures(uint64_t HWDivKind, 292bdd1243dSDimitry Andric std::vector<StringRef> &Features) { 293bdd1243dSDimitry Andric 294bdd1243dSDimitry Andric if (HWDivKind == AEK_INVALID) 295bdd1243dSDimitry Andric return false; 296bdd1243dSDimitry Andric 297bdd1243dSDimitry Andric if (HWDivKind & AEK_HWDIVARM) 298bdd1243dSDimitry Andric Features.push_back("+hwdiv-arm"); 299bdd1243dSDimitry Andric else 300bdd1243dSDimitry Andric Features.push_back("-hwdiv-arm"); 301bdd1243dSDimitry Andric 302bdd1243dSDimitry Andric if (HWDivKind & AEK_HWDIVTHUMB) 303bdd1243dSDimitry Andric Features.push_back("+hwdiv"); 304bdd1243dSDimitry Andric else 305bdd1243dSDimitry Andric Features.push_back("-hwdiv"); 306bdd1243dSDimitry Andric 307bdd1243dSDimitry Andric return true; 308bdd1243dSDimitry Andric } 309bdd1243dSDimitry Andric 310bdd1243dSDimitry Andric bool ARM::getExtensionFeatures(uint64_t Extensions, 311bdd1243dSDimitry Andric std::vector<StringRef> &Features) { 312bdd1243dSDimitry Andric 313bdd1243dSDimitry Andric if (Extensions == AEK_INVALID) 314bdd1243dSDimitry Andric return false; 315bdd1243dSDimitry Andric 316bdd1243dSDimitry Andric for (const auto &AE : ARCHExtNames) { 317bdd1243dSDimitry Andric if ((Extensions & AE.ID) == AE.ID && !AE.Feature.empty()) 318bdd1243dSDimitry Andric Features.push_back(AE.Feature); 319bdd1243dSDimitry Andric else if (!AE.NegFeature.empty()) 320bdd1243dSDimitry Andric Features.push_back(AE.NegFeature); 321bdd1243dSDimitry Andric } 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric return getHWDivFeatures(Extensions, Features); 324bdd1243dSDimitry Andric } 325bdd1243dSDimitry Andric 326bdd1243dSDimitry Andric StringRef ARM::getArchName(ARM::ArchKind AK) { 327bdd1243dSDimitry Andric return ARMArchNames[static_cast<unsigned>(AK)].Name; 328bdd1243dSDimitry Andric } 329bdd1243dSDimitry Andric 330bdd1243dSDimitry Andric StringRef ARM::getCPUAttr(ARM::ArchKind AK) { 331bdd1243dSDimitry Andric return ARMArchNames[static_cast<unsigned>(AK)].CPUAttr; 332bdd1243dSDimitry Andric } 333bdd1243dSDimitry Andric 334bdd1243dSDimitry Andric StringRef ARM::getSubArch(ARM::ArchKind AK) { 335bdd1243dSDimitry Andric return ARMArchNames[static_cast<unsigned>(AK)].getSubArch(); 336bdd1243dSDimitry Andric } 337bdd1243dSDimitry Andric 338bdd1243dSDimitry Andric unsigned ARM::getArchAttr(ARM::ArchKind AK) { 339bdd1243dSDimitry Andric return ARMArchNames[static_cast<unsigned>(AK)].ArchAttr; 340bdd1243dSDimitry Andric } 341bdd1243dSDimitry Andric 342bdd1243dSDimitry Andric StringRef ARM::getArchExtName(uint64_t ArchExtKind) { 343bdd1243dSDimitry Andric for (const auto &AE : ARCHExtNames) { 344bdd1243dSDimitry Andric if (ArchExtKind == AE.ID) 345bdd1243dSDimitry Andric return AE.Name; 346bdd1243dSDimitry Andric } 347bdd1243dSDimitry Andric return StringRef(); 348bdd1243dSDimitry Andric } 349bdd1243dSDimitry Andric 350bdd1243dSDimitry Andric static bool stripNegationPrefix(StringRef &Name) { 351*647cbc5dSDimitry Andric return Name.consume_front("no"); 352bdd1243dSDimitry Andric } 353bdd1243dSDimitry Andric 354bdd1243dSDimitry Andric StringRef ARM::getArchExtFeature(StringRef ArchExt) { 355bdd1243dSDimitry Andric bool Negated = stripNegationPrefix(ArchExt); 356bdd1243dSDimitry Andric for (const auto &AE : ARCHExtNames) { 357bdd1243dSDimitry Andric if (!AE.Feature.empty() && ArchExt == AE.Name) 358bdd1243dSDimitry Andric return StringRef(Negated ? AE.NegFeature : AE.Feature); 359bdd1243dSDimitry Andric } 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric return StringRef(); 362bdd1243dSDimitry Andric } 363bdd1243dSDimitry Andric 36406c3fb27SDimitry Andric static ARM::FPUKind findDoublePrecisionFPU(ARM::FPUKind InputFPUKind) { 3655f757f3fSDimitry Andric if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE) 3665f757f3fSDimitry Andric return ARM::FK_INVALID; 3675f757f3fSDimitry Andric 368bdd1243dSDimitry Andric const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind]; 369bdd1243dSDimitry Andric 370bdd1243dSDimitry Andric // If the input FPU already supports double-precision, then there 371bdd1243dSDimitry Andric // isn't any different FPU we can return here. 3725f757f3fSDimitry Andric if (ARM::isDoublePrecision(InputFPU.Restriction)) 3735f757f3fSDimitry Andric return InputFPUKind; 374bdd1243dSDimitry Andric 375bdd1243dSDimitry Andric // Otherwise, look for an FPU entry with all the same fields, except 3765f757f3fSDimitry Andric // that it supports double precision. 377bdd1243dSDimitry Andric for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) { 378bdd1243dSDimitry Andric if (CandidateFPU.FPUVer == InputFPU.FPUVer && 379bdd1243dSDimitry Andric CandidateFPU.NeonSupport == InputFPU.NeonSupport && 3805f757f3fSDimitry Andric ARM::has32Regs(CandidateFPU.Restriction) == 3815f757f3fSDimitry Andric ARM::has32Regs(InputFPU.Restriction) && 3825f757f3fSDimitry Andric ARM::isDoublePrecision(CandidateFPU.Restriction)) { 3835f757f3fSDimitry Andric return CandidateFPU.ID; 3845f757f3fSDimitry Andric } 3855f757f3fSDimitry Andric } 3865f757f3fSDimitry Andric 3875f757f3fSDimitry Andric // nothing found 3885f757f3fSDimitry Andric return ARM::FK_INVALID; 3895f757f3fSDimitry Andric } 3905f757f3fSDimitry Andric 3915f757f3fSDimitry Andric static ARM::FPUKind findSinglePrecisionFPU(ARM::FPUKind InputFPUKind) { 3925f757f3fSDimitry Andric if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE) 3935f757f3fSDimitry Andric return ARM::FK_INVALID; 3945f757f3fSDimitry Andric 3955f757f3fSDimitry Andric const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind]; 3965f757f3fSDimitry Andric 3975f757f3fSDimitry Andric // If the input FPU already is single-precision only, then there 3985f757f3fSDimitry Andric // isn't any different FPU we can return here. 3995f757f3fSDimitry Andric if (!ARM::isDoublePrecision(InputFPU.Restriction)) 4005f757f3fSDimitry Andric return InputFPUKind; 4015f757f3fSDimitry Andric 4025f757f3fSDimitry Andric // Otherwise, look for an FPU entry with all the same fields, except 4035f757f3fSDimitry Andric // that it does not support double precision. 4045f757f3fSDimitry Andric for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) { 4055f757f3fSDimitry Andric if (CandidateFPU.FPUVer == InputFPU.FPUVer && 4065f757f3fSDimitry Andric CandidateFPU.NeonSupport == InputFPU.NeonSupport && 4075f757f3fSDimitry Andric ARM::has32Regs(CandidateFPU.Restriction) == 4085f757f3fSDimitry Andric ARM::has32Regs(InputFPU.Restriction) && 4095f757f3fSDimitry Andric !ARM::isDoublePrecision(CandidateFPU.Restriction)) { 410bdd1243dSDimitry Andric return CandidateFPU.ID; 411bdd1243dSDimitry Andric } 412bdd1243dSDimitry Andric } 413bdd1243dSDimitry Andric 414bdd1243dSDimitry Andric // nothing found 415bdd1243dSDimitry Andric return ARM::FK_INVALID; 416bdd1243dSDimitry Andric } 417bdd1243dSDimitry Andric 418bdd1243dSDimitry Andric bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, 419bdd1243dSDimitry Andric StringRef ArchExt, 420bdd1243dSDimitry Andric std::vector<StringRef> &Features, 42106c3fb27SDimitry Andric ARM::FPUKind &ArgFPUKind) { 422bdd1243dSDimitry Andric 423bdd1243dSDimitry Andric size_t StartingNumFeatures = Features.size(); 424bdd1243dSDimitry Andric const bool Negated = stripNegationPrefix(ArchExt); 425bdd1243dSDimitry Andric uint64_t ID = parseArchExt(ArchExt); 426bdd1243dSDimitry Andric 427bdd1243dSDimitry Andric if (ID == AEK_INVALID) 428bdd1243dSDimitry Andric return false; 429bdd1243dSDimitry Andric 430bdd1243dSDimitry Andric for (const auto &AE : ARCHExtNames) { 431bdd1243dSDimitry Andric if (Negated) { 432bdd1243dSDimitry Andric if ((AE.ID & ID) == ID && !AE.NegFeature.empty()) 433bdd1243dSDimitry Andric Features.push_back(AE.NegFeature); 434bdd1243dSDimitry Andric } else { 435bdd1243dSDimitry Andric if ((AE.ID & ID) == AE.ID && !AE.Feature.empty()) 436bdd1243dSDimitry Andric Features.push_back(AE.Feature); 437bdd1243dSDimitry Andric } 438bdd1243dSDimitry Andric } 439bdd1243dSDimitry Andric 440bdd1243dSDimitry Andric if (CPU == "") 441bdd1243dSDimitry Andric CPU = "generic"; 442bdd1243dSDimitry Andric 443bdd1243dSDimitry Andric if (ArchExt == "fp" || ArchExt == "fp.dp") { 4445f757f3fSDimitry Andric const ARM::FPUKind DefaultFPU = getDefaultFPU(CPU, AK); 44506c3fb27SDimitry Andric ARM::FPUKind FPUKind; 446bdd1243dSDimitry Andric if (ArchExt == "fp.dp") { 4475f757f3fSDimitry Andric const bool IsDP = ArgFPUKind != ARM::FK_INVALID && 4485f757f3fSDimitry Andric ArgFPUKind != ARM::FK_NONE && 4495f757f3fSDimitry Andric isDoublePrecision(getFPURestriction(ArgFPUKind)); 450bdd1243dSDimitry Andric if (Negated) { 4515f757f3fSDimitry Andric /* If there is no FPU selected yet, we still need to set ArgFPUKind, as 4525f757f3fSDimitry Andric * leaving it as FK_INVALID, would cause default FPU to be selected 4535f757f3fSDimitry Andric * later and that could be double precision one. */ 4545f757f3fSDimitry Andric if (ArgFPUKind != ARM::FK_INVALID && !IsDP) 455bdd1243dSDimitry Andric return true; 4565f757f3fSDimitry Andric FPUKind = findSinglePrecisionFPU(DefaultFPU); 4575f757f3fSDimitry Andric if (FPUKind == ARM::FK_INVALID) 4585f757f3fSDimitry Andric FPUKind = ARM::FK_NONE; 4595f757f3fSDimitry Andric } else { 4605f757f3fSDimitry Andric if (IsDP) 4615f757f3fSDimitry Andric return true; 4625f757f3fSDimitry Andric FPUKind = findDoublePrecisionFPU(DefaultFPU); 4635f757f3fSDimitry Andric if (FPUKind == ARM::FK_INVALID) 4645f757f3fSDimitry Andric return false; 465bdd1243dSDimitry Andric } 466bdd1243dSDimitry Andric } else if (Negated) { 467bdd1243dSDimitry Andric FPUKind = ARM::FK_NONE; 468bdd1243dSDimitry Andric } else { 4695f757f3fSDimitry Andric FPUKind = DefaultFPU; 470bdd1243dSDimitry Andric } 47106c3fb27SDimitry Andric ArgFPUKind = FPUKind; 4725f757f3fSDimitry Andric return true; 473bdd1243dSDimitry Andric } 474bdd1243dSDimitry Andric return StartingNumFeatures != Features.size(); 475bdd1243dSDimitry Andric } 476bdd1243dSDimitry Andric 477bdd1243dSDimitry Andric ARM::ArchKind ARM::convertV9toV8(ARM::ArchKind AK) { 478bdd1243dSDimitry Andric if (getProfileKind(AK) != ProfileKind::A) 479bdd1243dSDimitry Andric return ARM::ArchKind::INVALID; 480bdd1243dSDimitry Andric if (AK < ARM::ArchKind::ARMV9A || AK > ARM::ArchKind::ARMV9_3A) 481bdd1243dSDimitry Andric return ARM::ArchKind::INVALID; 482bdd1243dSDimitry Andric unsigned AK_v8 = static_cast<unsigned>(ARM::ArchKind::ARMV8_5A); 483bdd1243dSDimitry Andric AK_v8 += static_cast<unsigned>(AK) - 484bdd1243dSDimitry Andric static_cast<unsigned>(ARM::ArchKind::ARMV9A); 485bdd1243dSDimitry Andric return static_cast<ARM::ArchKind>(AK_v8); 486bdd1243dSDimitry Andric } 487bdd1243dSDimitry Andric 488bdd1243dSDimitry Andric StringRef ARM::getDefaultCPU(StringRef Arch) { 489bdd1243dSDimitry Andric ArchKind AK = parseArch(Arch); 490bdd1243dSDimitry Andric if (AK == ArchKind::INVALID) 491bdd1243dSDimitry Andric return StringRef(); 492bdd1243dSDimitry Andric 493bdd1243dSDimitry Andric // Look for multiple AKs to find the default for pair AK+Name. 494bdd1243dSDimitry Andric for (const auto &CPU : CPUNames) { 495bdd1243dSDimitry Andric if (CPU.ArchID == AK && CPU.Default) 496bdd1243dSDimitry Andric return CPU.Name; 497bdd1243dSDimitry Andric } 498bdd1243dSDimitry Andric 499bdd1243dSDimitry Andric // If we can't find a default then target the architecture instead 500bdd1243dSDimitry Andric return "generic"; 501bdd1243dSDimitry Andric } 502bdd1243dSDimitry Andric 503bdd1243dSDimitry Andric uint64_t ARM::parseHWDiv(StringRef HWDiv) { 504bdd1243dSDimitry Andric StringRef Syn = getHWDivSynonym(HWDiv); 505bdd1243dSDimitry Andric for (const auto &D : HWDivNames) { 506bdd1243dSDimitry Andric if (Syn == D.Name) 507bdd1243dSDimitry Andric return D.ID; 508bdd1243dSDimitry Andric } 509bdd1243dSDimitry Andric return AEK_INVALID; 510bdd1243dSDimitry Andric } 511bdd1243dSDimitry Andric 512bdd1243dSDimitry Andric uint64_t ARM::parseArchExt(StringRef ArchExt) { 513bdd1243dSDimitry Andric for (const auto &A : ARCHExtNames) { 514bdd1243dSDimitry Andric if (ArchExt == A.Name) 515bdd1243dSDimitry Andric return A.ID; 516bdd1243dSDimitry Andric } 517bdd1243dSDimitry Andric return AEK_INVALID; 518bdd1243dSDimitry Andric } 519bdd1243dSDimitry Andric 520bdd1243dSDimitry Andric ARM::ArchKind ARM::parseCPUArch(StringRef CPU) { 521bdd1243dSDimitry Andric for (const auto &C : CPUNames) { 522bdd1243dSDimitry Andric if (CPU == C.Name) 523bdd1243dSDimitry Andric return C.ArchID; 524bdd1243dSDimitry Andric } 525bdd1243dSDimitry Andric return ArchKind::INVALID; 526bdd1243dSDimitry Andric } 527bdd1243dSDimitry Andric 528bdd1243dSDimitry Andric void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 529bdd1243dSDimitry Andric for (const auto &Arch : CPUNames) { 530bdd1243dSDimitry Andric if (Arch.ArchID != ArchKind::INVALID) 531bdd1243dSDimitry Andric Values.push_back(Arch.Name); 532bdd1243dSDimitry Andric } 533bdd1243dSDimitry Andric } 534bdd1243dSDimitry Andric 535bdd1243dSDimitry Andric StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { 536bdd1243dSDimitry Andric StringRef ArchName = 537bdd1243dSDimitry Andric CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU)); 538bdd1243dSDimitry Andric 539bdd1243dSDimitry Andric if (TT.isOSBinFormatMachO()) { 540bdd1243dSDimitry Andric if (TT.getEnvironment() == Triple::EABI || 541bdd1243dSDimitry Andric TT.getOS() == Triple::UnknownOS || 542bdd1243dSDimitry Andric parseArchProfile(ArchName) == ProfileKind::M) 543bdd1243dSDimitry Andric return "aapcs"; 544bdd1243dSDimitry Andric if (TT.isWatchABI()) 545bdd1243dSDimitry Andric return "aapcs16"; 546bdd1243dSDimitry Andric return "apcs-gnu"; 547bdd1243dSDimitry Andric } else if (TT.isOSWindows()) 548bdd1243dSDimitry Andric // FIXME: this is invalid for WindowsCE. 549bdd1243dSDimitry Andric return "aapcs"; 550bdd1243dSDimitry Andric 551bdd1243dSDimitry Andric // Select the default based on the platform. 552bdd1243dSDimitry Andric switch (TT.getEnvironment()) { 553bdd1243dSDimitry Andric case Triple::Android: 554bdd1243dSDimitry Andric case Triple::GNUEABI: 555bdd1243dSDimitry Andric case Triple::GNUEABIHF: 556bdd1243dSDimitry Andric case Triple::MuslEABI: 557bdd1243dSDimitry Andric case Triple::MuslEABIHF: 5585f757f3fSDimitry Andric case Triple::OpenHOS: 559bdd1243dSDimitry Andric return "aapcs-linux"; 560bdd1243dSDimitry Andric case Triple::EABIHF: 561bdd1243dSDimitry Andric case Triple::EABI: 562bdd1243dSDimitry Andric return "aapcs"; 563bdd1243dSDimitry Andric default: 564bdd1243dSDimitry Andric if (TT.isOSNetBSD()) 565bdd1243dSDimitry Andric return "apcs-gnu"; 5665f757f3fSDimitry Andric if (TT.isOSFreeBSD() || TT.isOSOpenBSD() || TT.isOSHaiku() || 5675f757f3fSDimitry Andric TT.isOHOSFamily()) 568bdd1243dSDimitry Andric return "aapcs-linux"; 569bdd1243dSDimitry Andric return "aapcs"; 570bdd1243dSDimitry Andric } 571bdd1243dSDimitry Andric } 572bdd1243dSDimitry Andric 573bdd1243dSDimitry Andric StringRef ARM::getARMCPUForArch(const llvm::Triple &Triple, StringRef MArch) { 574bdd1243dSDimitry Andric if (MArch.empty()) 575bdd1243dSDimitry Andric MArch = Triple.getArchName(); 576bdd1243dSDimitry Andric MArch = llvm::ARM::getCanonicalArchName(MArch); 577bdd1243dSDimitry Andric 578bdd1243dSDimitry Andric // Some defaults are forced. 579bdd1243dSDimitry Andric switch (Triple.getOS()) { 580bdd1243dSDimitry Andric case llvm::Triple::FreeBSD: 581bdd1243dSDimitry Andric case llvm::Triple::NetBSD: 582bdd1243dSDimitry Andric case llvm::Triple::OpenBSD: 5835f757f3fSDimitry Andric case llvm::Triple::Haiku: 584bdd1243dSDimitry Andric if (!MArch.empty() && MArch == "v6") 585bdd1243dSDimitry Andric return "arm1176jzf-s"; 586bdd1243dSDimitry Andric if (!MArch.empty() && MArch == "v7") 587bdd1243dSDimitry Andric return "cortex-a8"; 588bdd1243dSDimitry Andric break; 589bdd1243dSDimitry Andric case llvm::Triple::Win32: 590bdd1243dSDimitry Andric // FIXME: this is invalid for WindowsCE 591bdd1243dSDimitry Andric if (llvm::ARM::parseArchVersion(MArch) <= 7) 592bdd1243dSDimitry Andric return "cortex-a9"; 593bdd1243dSDimitry Andric break; 594bdd1243dSDimitry Andric case llvm::Triple::IOS: 595bdd1243dSDimitry Andric case llvm::Triple::MacOSX: 596bdd1243dSDimitry Andric case llvm::Triple::TvOS: 597bdd1243dSDimitry Andric case llvm::Triple::WatchOS: 598bdd1243dSDimitry Andric case llvm::Triple::DriverKit: 599bdd1243dSDimitry Andric if (MArch == "v7k") 600bdd1243dSDimitry Andric return "cortex-a7"; 601bdd1243dSDimitry Andric break; 602bdd1243dSDimitry Andric default: 603bdd1243dSDimitry Andric break; 604bdd1243dSDimitry Andric } 605bdd1243dSDimitry Andric 606bdd1243dSDimitry Andric if (MArch.empty()) 607bdd1243dSDimitry Andric return StringRef(); 608bdd1243dSDimitry Andric 609bdd1243dSDimitry Andric StringRef CPU = llvm::ARM::getDefaultCPU(MArch); 610bdd1243dSDimitry Andric if (!CPU.empty() && !CPU.equals("invalid")) 611bdd1243dSDimitry Andric return CPU; 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric // If no specific architecture version is requested, return the minimum CPU 614bdd1243dSDimitry Andric // required by the OS and environment. 615bdd1243dSDimitry Andric switch (Triple.getOS()) { 6165f757f3fSDimitry Andric case llvm::Triple::Haiku: 6175f757f3fSDimitry Andric return "arm1176jzf-s"; 618bdd1243dSDimitry Andric case llvm::Triple::NetBSD: 619bdd1243dSDimitry Andric switch (Triple.getEnvironment()) { 620bdd1243dSDimitry Andric case llvm::Triple::EABI: 621bdd1243dSDimitry Andric case llvm::Triple::EABIHF: 622bdd1243dSDimitry Andric case llvm::Triple::GNUEABI: 623bdd1243dSDimitry Andric case llvm::Triple::GNUEABIHF: 624bdd1243dSDimitry Andric return "arm926ej-s"; 625bdd1243dSDimitry Andric default: 626bdd1243dSDimitry Andric return "strongarm"; 627bdd1243dSDimitry Andric } 628bdd1243dSDimitry Andric case llvm::Triple::NaCl: 629bdd1243dSDimitry Andric case llvm::Triple::OpenBSD: 630bdd1243dSDimitry Andric return "cortex-a8"; 631bdd1243dSDimitry Andric default: 632bdd1243dSDimitry Andric switch (Triple.getEnvironment()) { 633bdd1243dSDimitry Andric case llvm::Triple::EABIHF: 634bdd1243dSDimitry Andric case llvm::Triple::GNUEABIHF: 635bdd1243dSDimitry Andric case llvm::Triple::MuslEABIHF: 636bdd1243dSDimitry Andric return "arm1176jzf-s"; 637bdd1243dSDimitry Andric default: 638bdd1243dSDimitry Andric return "arm7tdmi"; 639bdd1243dSDimitry Andric } 640bdd1243dSDimitry Andric } 641bdd1243dSDimitry Andric 642bdd1243dSDimitry Andric llvm_unreachable("invalid arch name"); 643bdd1243dSDimitry Andric } 6445f757f3fSDimitry Andric 6455f757f3fSDimitry Andric void ARM::PrintSupportedExtensions(StringMap<StringRef> DescMap) { 6465f757f3fSDimitry Andric outs() << "All available -march extensions for ARM\n\n" 6475f757f3fSDimitry Andric << " " << left_justify("Name", 20) 6485f757f3fSDimitry Andric << (DescMap.empty() ? "\n" : "Description\n"); 6495f757f3fSDimitry Andric for (const auto &Ext : ARCHExtNames) { 6505f757f3fSDimitry Andric // Extensions without a feature cannot be used with -march. 6515f757f3fSDimitry Andric if (!Ext.Feature.empty()) { 6525f757f3fSDimitry Andric std::string Description = DescMap[Ext.Name].str(); 6535f757f3fSDimitry Andric outs() << " " 6545f757f3fSDimitry Andric << format(Description.empty() ? "%s\n" : "%-20s%s\n", 6555f757f3fSDimitry Andric Ext.Name.str().c_str(), Description.c_str()); 6565f757f3fSDimitry Andric } 6575f757f3fSDimitry Andric } 6585f757f3fSDimitry Andric } 659