diff options
Diffstat (limited to 'llvm/lib/TargetParser')
| -rw-r--r-- | llvm/lib/TargetParser/AArch64TargetParser.cpp | 159 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/ARMTargetParser.cpp | 599 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/ARMTargetParserCommon.cpp | 181 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/CSKYTargetParser.cpp | 181 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/Host.cpp | 1869 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/LoongArchTargetParser.cpp | 49 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/RISCVTargetParser.cpp | 104 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/TargetParser.cpp | 253 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/Triple.cpp | 1923 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/Unix/Host.inc | 87 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/Windows/Host.inc | 35 | ||||
| -rw-r--r-- | llvm/lib/TargetParser/X86TargetParser.cpp | 744 |
12 files changed, 6184 insertions, 0 deletions
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp new file mode 100644 index 000000000000..41d5c2544f29 --- /dev/null +++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp @@ -0,0 +1,159 @@ +//===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise AArch64 hardware features +// such as FPU/CPU/ARCH and extension names. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/TargetParser/Triple.h" +#include <cctype> + +using namespace llvm; + +static unsigned checkArchVersion(llvm::StringRef Arch) { + if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) + return (Arch[1] - 48); + return 0; +} + +uint64_t AArch64::getDefaultExtensions(StringRef CPU, + const AArch64::ArchInfo &AI) { + if (CPU == "generic") + return AI.DefaultExts; + + // Note: this now takes cpu aliases into account + const CpuInfo &Cpu = parseCpu(CPU); + return Cpu.Arch.DefaultExts | Cpu.DefaultExtensions; +} + +void AArch64::getFeatureOption(StringRef Name, std::string &Feature) { + for (const auto &E : llvm::AArch64::Extensions) { + if (Name == E.Name) { + Feature = E.Feature; + return; + } + } + Feature = Name.str(); +} + +const AArch64::ArchInfo &AArch64::getArchForCpu(StringRef CPU) { + if (CPU == "generic") + return ARMV8A; + + // Note: this now takes cpu aliases into account + const CpuInfo &Cpu = parseCpu(CPU); + return Cpu.Arch; +} + +const AArch64::ArchInfo &AArch64::ArchInfo::findBySubArch(StringRef SubArch) { + for (const auto *A : AArch64::ArchInfos) + if (A->getSubArch() == SubArch) + return *A; + return AArch64::INVALID; +} + +uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { + uint64_t FeaturesMask = 0; + for (const StringRef &FeatureStr : FeatureStrs) { + for (const auto &E : llvm::AArch64::Extensions) + if (FeatureStr == E.Name) { + FeaturesMask |= (1ULL << E.CPUFeature); + break; + } + } + return FeaturesMask; +} + +bool AArch64::getExtensionFeatures(uint64_t InputExts, + std::vector<StringRef> &Features) { + if (InputExts == AArch64::AEK_INVALID) + return false; + + for (const auto &E : Extensions) + /* INVALID and NONE have no feature name. */ + if ((InputExts & E.ID) && !E.Feature.empty()) + Features.push_back(E.Feature); + + return true; +} + +StringRef AArch64::resolveCPUAlias(StringRef Name) { + for (const auto &A : CpuAliases) + if (A.Alias == Name) + return A.Name; + return Name; +} + +StringRef AArch64::getArchExtFeature(StringRef ArchExt) { + if (ArchExt.startswith("no")) { + StringRef ArchExtBase(ArchExt.substr(2)); + for (const auto &AE : Extensions) { + if (!AE.NegFeature.empty() && ArchExtBase == AE.Name) + return AE.NegFeature; + } + } + + for (const auto &AE : Extensions) + if (!AE.Feature.empty() && ArchExt == AE.Name) + return AE.Feature; + return StringRef(); +} + +void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { + for (const auto &C : CpuInfos) + if (C.Arch != INVALID) + Values.push_back(C.Name); + + for (const auto &Alias : CpuAliases) + Values.push_back(Alias.Alias); +} + +bool AArch64::isX18ReservedByDefault(const Triple &TT) { + return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || + TT.isOSWindows(); +} + +// Allows partial match, ex. "v8a" matches "armv8a". +const AArch64::ArchInfo &AArch64::parseArch(StringRef Arch) { + Arch = llvm::ARM::getCanonicalArchName(Arch); + if (checkArchVersion(Arch) < 8) + return AArch64::INVALID; + + StringRef Syn = llvm::ARM::getArchSynonym(Arch); + for (const auto *A : ArchInfos) { + if (A->Name.endswith(Syn)) + return *A; + } + return AArch64::INVALID; +} + +AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) { + for (const auto &A : Extensions) { + if (ArchExt == A.Name) + return static_cast<ArchExtKind>(A.ID); + } + return AArch64::AEK_INVALID; +} + +const AArch64::CpuInfo &AArch64::parseCpu(StringRef Name) { + // Resolve aliases first. + Name = resolveCPUAlias(Name); + + // Then find the CPU name. + for (const auto &C : CpuInfos) + if (Name == C.Name) + return C; + + // "generic" returns invalid. + assert(Name != "invalid" && "Unexpected recursion."); + return parseCpu("invalid"); +} diff --git a/llvm/lib/TargetParser/ARMTargetParser.cpp b/llvm/lib/TargetParser/ARMTargetParser.cpp new file mode 100644 index 000000000000..af98ecb122d6 --- /dev/null +++ b/llvm/lib/TargetParser/ARMTargetParser.cpp @@ -0,0 +1,599 @@ +//===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise ARM hardware features +// such as FPU/CPU/ARCH/extensions and specific support such as HWDIV. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/TargetParser/Triple.h" +#include <cctype> + +using namespace llvm; + +static StringRef getHWDivSynonym(StringRef HWDiv) { + return StringSwitch<StringRef>(HWDiv) + .Case("thumb,arm", "arm,thumb") + .Default(HWDiv); +} + +// Allows partial match, ex. "v7a" matches "armv7a". +ARM::ArchKind ARM::parseArch(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + StringRef Syn = getArchSynonym(Arch); + for (const auto &A : ARMArchNames) { + if (A.Name.endswith(Syn)) + return A.ID; + } + return ArchKind::INVALID; +} + +// Version number (ex. v7 = 7). +unsigned ARM::parseArchVersion(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + switch (parseArch(Arch)) { + case ArchKind::ARMV4: + case ArchKind::ARMV4T: + return 4; + case ArchKind::ARMV5T: + case ArchKind::ARMV5TE: + case ArchKind::IWMMXT: + case ArchKind::IWMMXT2: + case ArchKind::XSCALE: + case ArchKind::ARMV5TEJ: + return 5; + case ArchKind::ARMV6: + case ArchKind::ARMV6K: + case ArchKind::ARMV6T2: + case ArchKind::ARMV6KZ: + case ArchKind::ARMV6M: + return 6; + case ArchKind::ARMV7A: + case ArchKind::ARMV7VE: + case ArchKind::ARMV7R: + case ArchKind::ARMV7M: + case ArchKind::ARMV7S: + case ArchKind::ARMV7EM: + case ArchKind::ARMV7K: + return 7; + case ArchKind::ARMV8A: + case ArchKind::ARMV8_1A: + case ArchKind::ARMV8_2A: + case ArchKind::ARMV8_3A: + case ArchKind::ARMV8_4A: + case ArchKind::ARMV8_5A: + case ArchKind::ARMV8_6A: + case ArchKind::ARMV8_7A: + case ArchKind::ARMV8_8A: + case ArchKind::ARMV8_9A: + case ArchKind::ARMV8R: + case ArchKind::ARMV8MBaseline: + case ArchKind::ARMV8MMainline: + case ArchKind::ARMV8_1MMainline: + return 8; + case ArchKind::ARMV9A: + case ArchKind::ARMV9_1A: + case ArchKind::ARMV9_2A: + case ArchKind::ARMV9_3A: + case ArchKind::ARMV9_4A: + return 9; + case ArchKind::INVALID: + return 0; + } + llvm_unreachable("Unhandled architecture"); +} + +static ARM::ProfileKind getProfileKind(ARM::ArchKind AK) { + switch (AK) { + case ARM::ArchKind::ARMV6M: + case ARM::ArchKind::ARMV7M: + case ARM::ArchKind::ARMV7EM: + case ARM::ArchKind::ARMV8MMainline: + case ARM::ArchKind::ARMV8MBaseline: + case ARM::ArchKind::ARMV8_1MMainline: + return ARM::ProfileKind::M; + case ARM::ArchKind::ARMV7R: + case ARM::ArchKind::ARMV8R: + return ARM::ProfileKind::R; + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7VE: + case ARM::ArchKind::ARMV7K: + case ARM::ArchKind::ARMV8A: + case ARM::ArchKind::ARMV8_1A: + case ARM::ArchKind::ARMV8_2A: + case ARM::ArchKind::ARMV8_3A: + case ARM::ArchKind::ARMV8_4A: + case ARM::ArchKind::ARMV8_5A: + case ARM::ArchKind::ARMV8_6A: + case ARM::ArchKind::ARMV8_7A: + case ARM::ArchKind::ARMV8_8A: + case ARM::ArchKind::ARMV8_9A: + case ARM::ArchKind::ARMV9A: + case ARM::ArchKind::ARMV9_1A: + case ARM::ArchKind::ARMV9_2A: + case ARM::ArchKind::ARMV9_3A: + case ARM::ArchKind::ARMV9_4A: + return ARM::ProfileKind::A; + case ARM::ArchKind::ARMV4: + case ARM::ArchKind::ARMV4T: + case ARM::ArchKind::ARMV5T: + case ARM::ArchKind::ARMV5TE: + case ARM::ArchKind::ARMV5TEJ: + case ARM::ArchKind::ARMV6: + case ARM::ArchKind::ARMV6K: + case ARM::ArchKind::ARMV6T2: + case ARM::ArchKind::ARMV6KZ: + case ARM::ArchKind::ARMV7S: + case ARM::ArchKind::IWMMXT: + case ARM::ArchKind::IWMMXT2: + case ARM::ArchKind::XSCALE: + case ARM::ArchKind::INVALID: + return ARM::ProfileKind::INVALID; + } + llvm_unreachable("Unhandled architecture"); +} + +// Profile A/R/M +ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + return getProfileKind(parseArch(Arch)); +} + +bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) { + + if (FPUKind >= FK_LAST || FPUKind == FK_INVALID) + return false; + + static const struct FPUFeatureNameInfo { + const char *PlusName, *MinusName; + FPUVersion MinVersion; + FPURestriction MaxRestriction; + } FPUFeatureInfoList[] = { + // We have to specify the + and - versions of the name in full so + // that we can return them as static StringRefs. + // + // Also, the SubtargetFeatures ending in just "sp" are listed here + // under FPURestriction::None, which is the only FPURestriction in + // which they would be valid (since FPURestriction::SP doesn't + // exist). + {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16}, + {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16}, + {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None}, + {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16}, + {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16}, + {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None}, + {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16}, + {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None}, + {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16}, + {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16}, + {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None}, + {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None}, + {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16}, + {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16}, + {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None}, + {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16}, + {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16}, + {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None}, + }; + + for (const auto &Info: FPUFeatureInfoList) { + if (FPUNames[FPUKind].FPUVer >= Info.MinVersion && + FPUNames[FPUKind].Restriction <= Info.MaxRestriction) + Features.push_back(Info.PlusName); + else + Features.push_back(Info.MinusName); + } + + static const struct NeonFeatureNameInfo { + const char *PlusName, *MinusName; + NeonSupportLevel MinSupportLevel; + } NeonFeatureInfoList[] = { + {"+neon", "-neon", NeonSupportLevel::Neon}, + {"+sha2", "-sha2", NeonSupportLevel::Crypto}, + {"+aes", "-aes", NeonSupportLevel::Crypto}, + }; + + for (const auto &Info: NeonFeatureInfoList) { + if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel) + Features.push_back(Info.PlusName); + else + Features.push_back(Info.MinusName); + } + + return true; +} + +unsigned ARM::parseFPU(StringRef FPU) { + StringRef Syn = getFPUSynonym(FPU); + for (const auto &F : FPUNames) { + if (Syn == F.Name) + return F.ID; + } + return FK_INVALID; +} + +ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return NeonSupportLevel::None; + return FPUNames[FPUKind].NeonSupport; +} + +StringRef ARM::getFPUSynonym(StringRef FPU) { + return StringSwitch<StringRef>(FPU) + .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported + .Case("vfp2", "vfpv2") + .Case("vfp3", "vfpv3") + .Case("vfp4", "vfpv4") + .Case("vfp3-d16", "vfpv3-d16") + .Case("vfp4-d16", "vfpv4-d16") + .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16") + .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16") + .Case("fp5-sp-d16", "fpv5-sp-d16") + .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16") + // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3. + .Case("neon-vfpv3", "neon") + .Default(FPU); +} + +StringRef ARM::getFPUName(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return StringRef(); + return FPUNames[FPUKind].Name; +} + +ARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return FPUVersion::NONE; + return FPUNames[FPUKind].FPUVer; +} + +ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return FPURestriction::None; + return FPUNames[FPUKind].Restriction; +} + +unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) { + if (CPU == "generic") + return ARM::ARMArchNames[static_cast<unsigned>(AK)].DefaultFPU; + + return StringSwitch<unsigned>(CPU) +#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, DEFAULT_FPU) +#include "llvm/TargetParser/ARMTargetParser.def" + .Default(ARM::FK_INVALID); +} + +uint64_t ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) { + if (CPU == "generic") + return ARM::ARMArchNames[static_cast<unsigned>(AK)].ArchBaseExtensions; + + return StringSwitch<uint64_t>(CPU) +#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, \ + ARMArchNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \ + DEFAULT_EXT) +#include "llvm/TargetParser/ARMTargetParser.def" + .Default(ARM::AEK_INVALID); +} + +bool ARM::getHWDivFeatures(uint64_t HWDivKind, + std::vector<StringRef> &Features) { + + if (HWDivKind == AEK_INVALID) + return false; + + if (HWDivKind & AEK_HWDIVARM) + Features.push_back("+hwdiv-arm"); + else + Features.push_back("-hwdiv-arm"); + + if (HWDivKind & AEK_HWDIVTHUMB) + Features.push_back("+hwdiv"); + else + Features.push_back("-hwdiv"); + + return true; +} + +bool ARM::getExtensionFeatures(uint64_t Extensions, + std::vector<StringRef> &Features) { + + if (Extensions == AEK_INVALID) + return false; + + for (const auto &AE : ARCHExtNames) { + if ((Extensions & AE.ID) == AE.ID && !AE.Feature.empty()) + Features.push_back(AE.Feature); + else if (!AE.NegFeature.empty()) + Features.push_back(AE.NegFeature); + } + + return getHWDivFeatures(Extensions, Features); +} + +StringRef ARM::getArchName(ARM::ArchKind AK) { + return ARMArchNames[static_cast<unsigned>(AK)].Name; +} + +StringRef ARM::getCPUAttr(ARM::ArchKind AK) { + return ARMArchNames[static_cast<unsigned>(AK)].CPUAttr; +} + +StringRef ARM::getSubArch(ARM::ArchKind AK) { + return ARMArchNames[static_cast<unsigned>(AK)].getSubArch(); +} + +unsigned ARM::getArchAttr(ARM::ArchKind AK) { + return ARMArchNames[static_cast<unsigned>(AK)].ArchAttr; +} + +StringRef ARM::getArchExtName(uint64_t ArchExtKind) { + for (const auto &AE : ARCHExtNames) { + if (ArchExtKind == AE.ID) + return AE.Name; + } + return StringRef(); +} + +static bool stripNegationPrefix(StringRef &Name) { + if (Name.startswith("no")) { + Name = Name.substr(2); + return true; + } + return false; +} + +StringRef ARM::getArchExtFeature(StringRef ArchExt) { + bool Negated = stripNegationPrefix(ArchExt); + for (const auto &AE : ARCHExtNames) { + if (!AE.Feature.empty() && ArchExt == AE.Name) + return StringRef(Negated ? AE.NegFeature : AE.Feature); + } + + return StringRef(); +} + +static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) { + const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind]; + + // If the input FPU already supports double-precision, then there + // isn't any different FPU we can return here. + // + // The current available FPURestriction values are None (no + // restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs + // and single precision only); there's no value representing + // SP restriction without D16. So this test just means 'is it + // SP only?'. + if (InputFPU.Restriction != ARM::FPURestriction::SP_D16) + return ARM::FK_INVALID; + + // Otherwise, look for an FPU entry with all the same fields, except + // that SP_D16 has been replaced with just D16, representing adding + // double precision and not changing anything else. + for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) { + if (CandidateFPU.FPUVer == InputFPU.FPUVer && + CandidateFPU.NeonSupport == InputFPU.NeonSupport && + CandidateFPU.Restriction == ARM::FPURestriction::D16) { + return CandidateFPU.ID; + } + } + + // nothing found + return ARM::FK_INVALID; +} + +bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, + StringRef ArchExt, + std::vector<StringRef> &Features, + unsigned &ArgFPUID) { + + size_t StartingNumFeatures = Features.size(); + const bool Negated = stripNegationPrefix(ArchExt); + uint64_t ID = parseArchExt(ArchExt); + + if (ID == AEK_INVALID) + return false; + + for (const auto &AE : ARCHExtNames) { + if (Negated) { + if ((AE.ID & ID) == ID && !AE.NegFeature.empty()) + Features.push_back(AE.NegFeature); + } else { + if ((AE.ID & ID) == AE.ID && !AE.Feature.empty()) + Features.push_back(AE.Feature); + } + } + + if (CPU == "") + CPU = "generic"; + + if (ArchExt == "fp" || ArchExt == "fp.dp") { + unsigned FPUKind; + if (ArchExt == "fp.dp") { + if (Negated) { + Features.push_back("-fp64"); + return true; + } + FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK)); + } else if (Negated) { + FPUKind = ARM::FK_NONE; + } else { + FPUKind = getDefaultFPU(CPU, AK); + } + ArgFPUID = FPUKind; + return ARM::getFPUFeatures(FPUKind, Features); + } + return StartingNumFeatures != Features.size(); +} + +ARM::ArchKind ARM::convertV9toV8(ARM::ArchKind AK) { + if (getProfileKind(AK) != ProfileKind::A) + return ARM::ArchKind::INVALID; + if (AK < ARM::ArchKind::ARMV9A || AK > ARM::ArchKind::ARMV9_3A) + return ARM::ArchKind::INVALID; + unsigned AK_v8 = static_cast<unsigned>(ARM::ArchKind::ARMV8_5A); + AK_v8 += static_cast<unsigned>(AK) - + static_cast<unsigned>(ARM::ArchKind::ARMV9A); + return static_cast<ARM::ArchKind>(AK_v8); +} + +StringRef ARM::getDefaultCPU(StringRef Arch) { + ArchKind AK = parseArch(Arch); + if (AK == ArchKind::INVALID) + return StringRef(); + + // Look for multiple AKs to find the default for pair AK+Name. + for (const auto &CPU : CPUNames) { + if (CPU.ArchID == AK && CPU.Default) + return CPU.Name; + } + + // If we can't find a default then target the architecture instead + return "generic"; +} + +uint64_t ARM::parseHWDiv(StringRef HWDiv) { + StringRef Syn = getHWDivSynonym(HWDiv); + for (const auto &D : HWDivNames) { + if (Syn == D.Name) + return D.ID; + } + return AEK_INVALID; +} + +uint64_t ARM::parseArchExt(StringRef ArchExt) { + for (const auto &A : ARCHExtNames) { + if (ArchExt == A.Name) + return A.ID; + } + return AEK_INVALID; +} + +ARM::ArchKind ARM::parseCPUArch(StringRef CPU) { + for (const auto &C : CPUNames) { + if (CPU == C.Name) + return C.ArchID; + } + return ArchKind::INVALID; +} + +void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { + for (const auto &Arch : CPUNames) { + if (Arch.ArchID != ArchKind::INVALID) + Values.push_back(Arch.Name); + } +} + +StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { + StringRef ArchName = + CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU)); + + if (TT.isOSBinFormatMachO()) { + if (TT.getEnvironment() == Triple::EABI || + TT.getOS() == Triple::UnknownOS || + parseArchProfile(ArchName) == ProfileKind::M) + return "aapcs"; + if (TT.isWatchABI()) + return "aapcs16"; + return "apcs-gnu"; + } else if (TT.isOSWindows()) + // FIXME: this is invalid for WindowsCE. + return "aapcs"; + + // Select the default based on the platform. + switch (TT.getEnvironment()) { + case Triple::Android: + case Triple::GNUEABI: + case Triple::GNUEABIHF: + case Triple::MuslEABI: + case Triple::MuslEABIHF: + return "aapcs-linux"; + case Triple::EABIHF: + case Triple::EABI: + return "aapcs"; + default: + if (TT.isOSNetBSD()) + return "apcs-gnu"; + if (TT.isOSOpenBSD()) + return "aapcs-linux"; + return "aapcs"; + } +} + +StringRef ARM::getARMCPUForArch(const llvm::Triple &Triple, StringRef MArch) { + if (MArch.empty()) + MArch = Triple.getArchName(); + MArch = llvm::ARM::getCanonicalArchName(MArch); + + // Some defaults are forced. + switch (Triple.getOS()) { + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: + if (!MArch.empty() && MArch == "v6") + return "arm1176jzf-s"; + if (!MArch.empty() && MArch == "v7") + return "cortex-a8"; + break; + case llvm::Triple::Win32: + // FIXME: this is invalid for WindowsCE + if (llvm::ARM::parseArchVersion(MArch) <= 7) + return "cortex-a9"; + break; + case llvm::Triple::IOS: + case llvm::Triple::MacOSX: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + case llvm::Triple::DriverKit: + if (MArch == "v7k") + return "cortex-a7"; + break; + default: + break; + } + + if (MArch.empty()) + return StringRef(); + + StringRef CPU = llvm::ARM::getDefaultCPU(MArch); + if (!CPU.empty() && !CPU.equals("invalid")) + return CPU; + + // If no specific architecture version is requested, return the minimum CPU + // required by the OS and environment. + switch (Triple.getOS()) { + case llvm::Triple::NetBSD: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABI: + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIHF: + return "arm926ej-s"; + default: + return "strongarm"; + } + case llvm::Triple::NaCl: + case llvm::Triple::OpenBSD: + return "cortex-a8"; + default: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABIHF: + return "arm1176jzf-s"; + default: + return "arm7tdmi"; + } + } + + llvm_unreachable("invalid arch name"); +} diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp new file mode 100644 index 000000000000..ba517d6cf1bc --- /dev/null +++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp @@ -0,0 +1,181 @@ +//===---------------- ARMTargetParserCommon ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Code that is common to ARMTargetParser and AArch64TargetParser. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace llvm; + +StringRef ARM::getArchSynonym(StringRef Arch) { + return StringSwitch<StringRef>(Arch) + .Case("v5", "v5t") + .Case("v5e", "v5te") + .Case("v6j", "v6") + .Case("v6hl", "v6k") + .Cases("v6m", "v6sm", "v6s-m", "v6-m") + .Cases("v6z", "v6zk", "v6kz") + .Cases("v7", "v7a", "v7hl", "v7l", "v7-a") + .Case("v7r", "v7-r") + .Case("v7m", "v7-m") + .Case("v7em", "v7e-m") + .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a") + .Case("v8.1a", "v8.1-a") + .Case("v8.2a", "v8.2-a") + .Case("v8.3a", "v8.3-a") + .Case("v8.4a", "v8.4-a") + .Case("v8.5a", "v8.5-a") + .Case("v8.6a", "v8.6-a") + .Case("v8.7a", "v8.7-a") + .Case("v8.8a", "v8.8-a") + .Case("v8.9a", "v8.9-a") + .Case("v8r", "v8-r") + .Cases("v9", "v9a", "v9-a") + .Case("v9.1a", "v9.1-a") + .Case("v9.2a", "v9.2-a") + .Case("v9.3a", "v9.3-a") + .Case("v9.4a", "v9.4-a") + .Case("v8m.base", "v8-m.base") + .Case("v8m.main", "v8-m.main") + .Case("v8.1m.main", "v8.1-m.main") + .Default(Arch); +} + +StringRef ARM::getCanonicalArchName(StringRef Arch) { + size_t offset = StringRef::npos; + StringRef A = Arch; + StringRef Error = ""; + + // Begins with "arm" / "thumb", move past it. + if (A.startswith("arm64_32")) + offset = 8; + else if (A.startswith("arm64e")) + offset = 6; + else if (A.startswith("arm64")) + offset = 5; + else if (A.startswith("aarch64_32")) + offset = 10; + else if (A.startswith("arm")) + offset = 3; + else if (A.startswith("thumb")) + offset = 5; + else if (A.startswith("aarch64")) { + offset = 7; + // AArch64 uses "_be", not "eb" suffix. + if (A.contains("eb")) + return Error; + if (A.substr(offset, 3) == "_be") + offset += 3; + } + + // Ex. "armebv7", move past the "eb". + if (offset != StringRef::npos && A.substr(offset, 2) == "eb") + offset += 2; + // Or, if it ends with eb ("armv7eb"), chop it off. + else if (A.endswith("eb")) + A = A.substr(0, A.size() - 2); + // Trim the head + if (offset != StringRef::npos) + A = A.substr(offset); + + // Empty string means offset reached the end, which means it's valid. + if (A.empty()) + return Arch; + + // Only match non-marketing names + if (offset != StringRef::npos) { + // Must start with 'vN'. + if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1]))) + return Error; + // Can't have an extra 'eb'. + if (A.contains("eb")) + return Error; + } + + // Arch will either be a 'v' name (v7a) or a marketing name (xscale). + return A; +} + +ARM::ISAKind ARM::parseArchISA(StringRef Arch) { + return StringSwitch<ISAKind>(Arch) + .StartsWith("aarch64", ISAKind::AARCH64) + .StartsWith("arm64", ISAKind::AARCH64) + .StartsWith("thumb", ISAKind::THUMB) + .StartsWith("arm", ISAKind::ARM) + .Default(ISAKind::INVALID); +} + +ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { + if (Arch.startswith("armeb") || Arch.startswith("thumbeb") || + Arch.startswith("aarch64_be")) + return EndianKind::BIG; + + if (Arch.startswith("arm") || Arch.startswith("thumb")) { + if (Arch.endswith("eb")) + return EndianKind::BIG; + else + return EndianKind::LITTLE; + } + + if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32")) + return EndianKind::LITTLE; + + return EndianKind::INVALID; +} + +// Parse a branch protection specification, which has the form +// standard | none | [bti,pac-ret[+b-key,+leaf]*] +// Returns true on success, with individual elements of the specification +// returned in `PBP`. Returns false in error, with `Err` containing +// an erroneous part of the spec. +bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, + StringRef &Err) { + PBP = {"none", "a_key", false}; + if (Spec == "none") + return true; // defaults are ok + + if (Spec == "standard") { + PBP.Scope = "non-leaf"; + PBP.BranchTargetEnforcement = true; + return true; + } + + SmallVector<StringRef, 4> Opts; + Spec.split(Opts, "+"); + for (int I = 0, E = Opts.size(); I != E; ++I) { + StringRef Opt = Opts[I].trim(); + if (Opt == "bti") { + PBP.BranchTargetEnforcement = true; + continue; + } + if (Opt == "pac-ret") { + PBP.Scope = "non-leaf"; + for (; I + 1 != E; ++I) { + StringRef PACOpt = Opts[I + 1].trim(); + if (PACOpt == "leaf") + PBP.Scope = "all"; + else if (PACOpt == "b-key") + PBP.Key = "b_key"; + else + break; + } + continue; + } + if (Opt == "") + Err = "<empty>"; + else + Err = Opt; + return false; + } + + return true; +} diff --git a/llvm/lib/TargetParser/CSKYTargetParser.cpp b/llvm/lib/TargetParser/CSKYTargetParser.cpp new file mode 100644 index 000000000000..493f253cd716 --- /dev/null +++ b/llvm/lib/TargetParser/CSKYTargetParser.cpp @@ -0,0 +1,181 @@ +//===-- TargetParser - Parser for target features ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise CSKY hardware features +// such as CPU/ARCH names. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/CSKYTargetParser.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace llvm; + +bool CSKY::getFPUFeatures(CSKYFPUKind CSKYFPUKind, + std::vector<StringRef> &Features) { + + if (CSKYFPUKind >= FK_LAST || CSKYFPUKind == FK_INVALID) + return false; + + switch (CSKYFPUKind) { + case FK_AUTO: + Features.push_back("+fpuv2_sf"); + Features.push_back("+fpuv2_df"); + Features.push_back("+fdivdu"); + break; + case FK_FPV2: + Features.push_back("+fpuv2_sf"); + Features.push_back("+fpuv2_df"); + break; + case FK_FPV2_DIVD: + Features.push_back("+fpuv2_sf"); + Features.push_back("+fpuv2_df"); + Features.push_back("+fdivdu"); + break; + case FK_FPV2_SF: + Features.push_back("+fpuv2_sf"); + break; + case FK_FPV3: + Features.push_back("+fpuv3_hf"); + Features.push_back("+fpuv3_hi"); + Features.push_back("+fpuv3_sf"); + Features.push_back("+fpuv3_df"); + break; + case FK_FPV3_HF: + Features.push_back("+fpuv3_hf"); + Features.push_back("+fpuv3_hi"); + break; + case FK_FPV3_HSF: + Features.push_back("+fpuv3_hf"); + Features.push_back("+fpuv3_hi"); + Features.push_back("+fpuv3_sf"); + break; + case FK_FPV3_SDF: + Features.push_back("+fpuv3_sf"); + Features.push_back("+fpuv3_df"); + break; + default: + llvm_unreachable("Unknown FPU Kind"); + return false; + } + + return true; +} + +// ======================================================= // +// Information by ID +// ======================================================= // + +StringRef CSKY::getArchName(ArchKind AK) { + return ARCHNames[static_cast<unsigned>(AK)].getName(); +} + +// The default cpu's name is same as arch name. +StringRef CSKY::getDefaultCPU(StringRef Arch) { + ArchKind AK = parseArch(Arch); + if (AK == CSKY::ArchKind::INVALID) + return StringRef(); + + return Arch; +} + +// ======================================================= // +// Parsers +// ======================================================= // +CSKY::ArchKind CSKY::parseArch(StringRef Arch) { + for (const auto A : ARCHNames) { + if (A.getName() == Arch) + return A.ID; + } + + return CSKY::ArchKind::INVALID; +} + +CSKY::ArchKind CSKY::parseCPUArch(StringRef CPU) { + for (const auto C : CPUNames) { + if (CPU == C.getName()) + return C.ArchID; + } + + return CSKY::ArchKind::INVALID; +} + +uint64_t CSKY::parseArchExt(StringRef ArchExt) { + for (const auto &A : CSKYARCHExtNames) { + if (ArchExt == A.getName()) + return A.ID; + } + return AEK_INVALID; +} + +void CSKY::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { + for (const CpuNames<CSKY::ArchKind> &Arch : CPUNames) { + if (Arch.ArchID != CSKY::ArchKind::INVALID) + Values.push_back(Arch.getName()); + } +} + +StringRef CSKY::getFPUName(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return StringRef(); + return FPUNames[FPUKind].getName(); +} + +CSKY::FPUVersion CSKY::getFPUVersion(unsigned FPUKind) { + if (FPUKind >= FK_LAST) + return FPUVersion::NONE; + return FPUNames[FPUKind].FPUVer; +} + +uint64_t CSKY::getDefaultExtensions(StringRef CPU) { + return StringSwitch<uint64_t>(CPU) +#define CSKY_CPU_NAME(NAME, ID, DEFAULT_EXT) \ + .Case(NAME, ARCHNames[static_cast<unsigned>(ArchKind::ID)].archBaseExt | \ + DEFAULT_EXT) +#include "llvm/TargetParser/CSKYTargetParser.def" + .Default(CSKY::AEK_INVALID); +} + +StringRef CSKY::getArchExtName(uint64_t ArchExtKind) { + for (const auto &AE : CSKYARCHExtNames) + if (ArchExtKind == AE.ID) + return AE.getName(); + return StringRef(); +} + +static bool stripNegationPrefix(StringRef &Name) { + if (Name.startswith("no")) { + Name = Name.substr(2); + return true; + } + return false; +} + +StringRef CSKY::getArchExtFeature(StringRef ArchExt) { + bool Negated = stripNegationPrefix(ArchExt); + for (const auto &AE : CSKYARCHExtNames) { + if (AE.Feature && ArchExt == AE.getName()) + return StringRef(Negated ? AE.NegFeature : AE.Feature); + } + + return StringRef(); +} + +bool CSKY::getExtensionFeatures(uint64_t Extensions, + std::vector<StringRef> &Features) { + if (Extensions == CSKY::AEK_INVALID) + return false; + + for (const auto &AE : CSKYARCHExtNames) { + if ((Extensions & AE.ID) == AE.ID && AE.Feature) + Features.push_back(AE.Feature); + } + + return true; +} diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp new file mode 100644 index 000000000000..80ebe0fa57d4 --- /dev/null +++ b/llvm/lib/TargetParser/Host.cpp @@ -0,0 +1,1869 @@ +//===-- Host.cpp - Implement OS Host Detection ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system Host detection. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/Host.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" +#include "llvm/TargetParser/X86TargetParser.h" +#include <string.h> + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Host.inc" +#include <sched.h> +#endif +#ifdef _WIN32 +#include "Windows/Host.inc" +#endif +#ifdef _MSC_VER +#include <intrin.h> +#endif +#ifdef __MVS__ +#include "llvm/Support/BCD.h" +#endif +#if defined(__APPLE__) +#include <mach/host_info.h> +#include <mach/mach.h> +#include <mach/mach_host.h> +#include <mach/machine.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#endif +#ifdef _AIX +#include <sys/systemcfg.h> +#endif +#if defined(__sun__) && defined(__svr4__) +#include <kstat.h> +#endif + +#define DEBUG_TYPE "host-detection" + +//===----------------------------------------------------------------------===// +// +// Implementations of the CPU detection routines +// +//===----------------------------------------------------------------------===// + +using namespace llvm; + +static std::unique_ptr<llvm::MemoryBuffer> + LLVM_ATTRIBUTE_UNUSED getProcCpuinfoContent() { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo"); + if (std::error_code EC = Text.getError()) { + llvm::errs() << "Can't read " + << "/proc/cpuinfo: " << EC.message() << "\n"; + return nullptr; + } + return std::move(*Text); +} + +StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) { + // Access to the Processor Version Register (PVR) on PowerPC is privileged, + // and so we must use an operating-system interface to determine the current + // processor type. On Linux, this is exposed through the /proc/cpuinfo file. + const char *generic = "generic"; + + // The cpu line is second (after the 'processor: 0' line), so if this + // buffer is too small then something has changed (or is wrong). + StringRef::const_iterator CPUInfoStart = ProcCpuinfoContent.begin(); + StringRef::const_iterator CPUInfoEnd = ProcCpuinfoContent.end(); + + StringRef::const_iterator CIP = CPUInfoStart; + + StringRef::const_iterator CPUStart = nullptr; + size_t CPULen = 0; + + // We need to find the first line which starts with cpu, spaces, and a colon. + // After the colon, there may be some additional spaces and then the cpu type. + while (CIP < CPUInfoEnd && CPUStart == nullptr) { + if (CIP < CPUInfoEnd && *CIP == '\n') + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == 'c') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'p') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'u') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == ':') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd) { + CPUStart = CIP; + while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && + *CIP != ',' && *CIP != '\n')) + ++CIP; + CPULen = CIP - CPUStart; + } + } + } + } + } + + if (CPUStart == nullptr) + while (CIP < CPUInfoEnd && *CIP != '\n') + ++CIP; + } + + if (CPUStart == nullptr) + return generic; + + return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) + .Case("604e", "604e") + .Case("604", "604") + .Case("7400", "7400") + .Case("7410", "7400") + .Case("7447", "7400") + .Case("7455", "7450") + .Case("G4", "g4") + .Case("POWER4", "970") + .Case("PPC970FX", "970") + .Case("PPC970MP", "970") + .Case("G5", "g5") + .Case("POWER5", "g5") + .Case("A2", "a2") + .Case("POWER6", "pwr6") + .Case("POWER7", "pwr7") + .Case("POWER8", "pwr8") + .Case("POWER8E", "pwr8") + .Case("POWER8NVL", "pwr8") + .Case("POWER9", "pwr9") + .Case("POWER10", "pwr10") + // FIXME: If we get a simulator or machine with the capabilities of + // mcpu=future, we should revisit this and add the name reported by the + // simulator/machine. + .Default(generic); +} + +StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { + // The cpuid register on arm is not accessible from user space. On Linux, + // it is exposed through the /proc/cpuinfo file. + + // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line + // in all cases. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU implementer line. + StringRef Implementer; + StringRef Hardware; + StringRef Part; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("CPU implementer")) + Implementer = Lines[I].substr(15).ltrim("\t :"); + if (Lines[I].startswith("Hardware")) + Hardware = Lines[I].substr(8).ltrim("\t :"); + if (Lines[I].startswith("CPU part")) + Part = Lines[I].substr(8).ltrim("\t :"); + } + + if (Implementer == "0x41") { // ARM Ltd. + // MSM8992/8994 may give cpu part for the core that the kernel is running on, + // which is undeterministic and wrong. Always return cortex-a53 for these SoC. + if (Hardware.endswith("MSM8994") || Hardware.endswith("MSM8996")) + return "cortex-a53"; + + + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + // This corresponds to the Main ID Register in Technical Reference Manuals. + // and is used in programs like sys-utils + return StringSwitch<const char *>(Part) + .Case("0x926", "arm926ej-s") + .Case("0xb02", "mpcore") + .Case("0xb36", "arm1136j-s") + .Case("0xb56", "arm1156t2-s") + .Case("0xb76", "arm1176jz-s") + .Case("0xc08", "cortex-a8") + .Case("0xc09", "cortex-a9") + .Case("0xc0f", "cortex-a15") + .Case("0xc20", "cortex-m0") + .Case("0xc23", "cortex-m3") + .Case("0xc24", "cortex-m4") + .Case("0xd22", "cortex-m55") + .Case("0xd02", "cortex-a34") + .Case("0xd04", "cortex-a35") + .Case("0xd03", "cortex-a53") + .Case("0xd05", "cortex-a55") + .Case("0xd46", "cortex-a510") + .Case("0xd07", "cortex-a57") + .Case("0xd08", "cortex-a72") + .Case("0xd09", "cortex-a73") + .Case("0xd0a", "cortex-a75") + .Case("0xd0b", "cortex-a76") + .Case("0xd0d", "cortex-a77") + .Case("0xd41", "cortex-a78") + .Case("0xd47", "cortex-a710") + .Case("0xd4d", "cortex-a715") + .Case("0xd44", "cortex-x1") + .Case("0xd4c", "cortex-x1c") + .Case("0xd48", "cortex-x2") + .Case("0xd4e", "cortex-x3") + .Case("0xd0c", "neoverse-n1") + .Case("0xd49", "neoverse-n2") + .Case("0xd40", "neoverse-v1") + .Case("0xd4f", "neoverse-v2") + .Default("generic"); + } + + if (Implementer == "0x42" || Implementer == "0x43") { // Broadcom | Cavium. + return StringSwitch<const char *>(Part) + .Case("0x516", "thunderx2t99") + .Case("0x0516", "thunderx2t99") + .Case("0xaf", "thunderx2t99") + .Case("0x0af", "thunderx2t99") + .Case("0xa1", "thunderxt88") + .Case("0x0a1", "thunderxt88") + .Default("generic"); + } + + if (Implementer == "0x46") { // Fujitsu Ltd. + return StringSwitch<const char *>(Part) + .Case("0x001", "a64fx") + .Default("generic"); + } + + if (Implementer == "0x4e") { // NVIDIA Corporation + return StringSwitch<const char *>(Part) + .Case("0x004", "carmel") + .Default("generic"); + } + + if (Implementer == "0x48") // HiSilicon Technologies, Inc. + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Part) + .Case("0xd01", "tsv110") + .Default("generic"); + + if (Implementer == "0x51") // Qualcomm Technologies, Inc. + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Part) + .Case("0x06f", "krait") // APQ8064 + .Case("0x201", "kryo") + .Case("0x205", "kryo") + .Case("0x211", "kryo") + .Case("0x800", "cortex-a73") // Kryo 2xx Gold + .Case("0x801", "cortex-a73") // Kryo 2xx Silver + .Case("0x802", "cortex-a75") // Kryo 3xx Gold + .Case("0x803", "cortex-a75") // Kryo 3xx Silver + .Case("0x804", "cortex-a76") // Kryo 4xx Gold + .Case("0x805", "cortex-a76") // Kryo 4xx/5xx Silver + .Case("0xc00", "falkor") + .Case("0xc01", "saphira") + .Default("generic"); + if (Implementer == "0x53") { // Samsung Electronics Co., Ltd. + // The Exynos chips have a convoluted ID scheme that doesn't seem to follow + // any predictive pattern across variants and parts. + unsigned Variant = 0, Part = 0; + + // Look for the CPU variant line, whose value is a 1 digit hexadecimal + // number, corresponding to the Variant bits in the CP15/C0 register. + for (auto I : Lines) + if (I.consume_front("CPU variant")) + I.ltrim("\t :").getAsInteger(0, Variant); + + // Look for the CPU part line, whose value is a 3 digit hexadecimal + // number, corresponding to the PartNum bits in the CP15/C0 register. + for (auto I : Lines) + if (I.consume_front("CPU part")) + I.ltrim("\t :").getAsInteger(0, Part); + + unsigned Exynos = (Variant << 12) | Part; + switch (Exynos) { + default: + // Default by falling through to Exynos M3. + [[fallthrough]]; + case 0x1002: + return "exynos-m3"; + case 0x1003: + return "exynos-m4"; + } + } + + if (Implementer == "0xc0") { // Ampere Computing + return StringSwitch<const char *>(Part) + .Case("0xac3", "ampere1") + .Case("0xac4", "ampere1a") + .Default("generic"); + } + + return "generic"; +} + +namespace { +StringRef getCPUNameFromS390Model(unsigned int Id, bool HaveVectorSupport) { + switch (Id) { + case 2064: // z900 not supported by LLVM + case 2066: + case 2084: // z990 not supported by LLVM + case 2086: + case 2094: // z9-109 not supported by LLVM + case 2096: + return "generic"; + case 2097: + case 2098: + return "z10"; + case 2817: + case 2818: + return "z196"; + case 2827: + case 2828: + return "zEC12"; + case 2964: + case 2965: + return HaveVectorSupport? "z13" : "zEC12"; + case 3906: + case 3907: + return HaveVectorSupport? "z14" : "zEC12"; + case 8561: + case 8562: + return HaveVectorSupport? "z15" : "zEC12"; + case 3931: + case 3932: + default: + return HaveVectorSupport? "z16" : "zEC12"; + } +} +} // end anonymous namespace + +StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { + // STIDP is a privileged operation, so use /proc/cpuinfo instead. + + // The "processor 0:" line comes after a fair amount of other information, + // including a cache breakdown, but this should be plenty. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU features. + SmallVector<StringRef, 32> CPUFeatures; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("features")) { + size_t Pos = Lines[I].find(':'); + if (Pos != StringRef::npos) { + Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); + break; + } + } + + // We need to check for the presence of vector support independently of + // the machine type, since we may only use the vector register set when + // supported by the kernel (and hypervisor). + bool HaveVectorSupport = false; + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + if (CPUFeatures[I] == "vx") + HaveVectorSupport = true; + } + + // Now check the processor machine type. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("processor ")) { + size_t Pos = Lines[I].find("machine = "); + if (Pos != StringRef::npos) { + Pos += sizeof("machine = ") - 1; + unsigned int Id; + if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) + return getCPUNameFromS390Model(Id, HaveVectorSupport); + } + break; + } + } + + return "generic"; +} + +StringRef sys::detail::getHostCPUNameForRISCV(StringRef ProcCpuinfoContent) { + // There are 24 lines in /proc/cpuinfo + SmallVector<StringRef> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for uarch line to determine cpu name + StringRef UArch; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("uarch")) { + UArch = Lines[I].substr(5).ltrim("\t :"); + break; + } + } + + return StringSwitch<const char *>(UArch) + .Case("sifive,u74-mc", "sifive-u74") + .Case("sifive,bullet0", "sifive-u74") + .Default("generic"); +} + +StringRef sys::detail::getHostCPUNameForBPF() { +#if !defined(__linux__) || !defined(__x86_64__) + return "generic"; +#else + uint8_t v3_insns[40] __attribute__ ((aligned (8))) = + /* BPF_MOV64_IMM(BPF_REG_0, 0) */ + { 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_2, 1) */ + 0xb7, 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_JMP32_REG(BPF_JLT, BPF_REG_0, BPF_REG_2, 1) */ + 0xae, 0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_0, 1) */ + 0xb7, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_EXIT_INSN() */ + 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + uint8_t v2_insns[40] __attribute__ ((aligned (8))) = + /* BPF_MOV64_IMM(BPF_REG_0, 0) */ + { 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_2, 1) */ + 0xb7, 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_JMP_REG(BPF_JLT, BPF_REG_0, BPF_REG_2, 1) */ + 0xad, 0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_0, 1) */ + 0xb7, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_EXIT_INSN() */ + 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + struct bpf_prog_load_attr { + uint32_t prog_type; + uint32_t insn_cnt; + uint64_t insns; + uint64_t license; + uint32_t log_level; + uint32_t log_size; + uint64_t log_buf; + uint32_t kern_version; + uint32_t prog_flags; + } attr = {}; + attr.prog_type = 1; /* BPF_PROG_TYPE_SOCKET_FILTER */ + attr.insn_cnt = 5; + attr.insns = (uint64_t)v3_insns; + attr.license = (uint64_t)"DUMMY"; + + int fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, + sizeof(attr)); + if (fd >= 0) { + close(fd); + return "v3"; + } + + /* Clear the whole attr in case its content changed by syscall. */ + memset(&attr, 0, sizeof(attr)); + attr.prog_type = 1; /* BPF_PROG_TYPE_SOCKET_FILTER */ + attr.insn_cnt = 5; + attr.insns = (uint64_t)v2_insns; + attr.license = (uint64_t)"DUMMY"; + fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, sizeof(attr)); + if (fd >= 0) { + close(fd); + return "v2"; + } + return "v1"; +#endif +} + +#if defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64__) || defined(_M_X64) + +// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). +// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID +// support. Consequently, for i386, the presence of CPUID is checked first +// via the corresponding eflags bit. +// Removal of cpuid.h header motivated by PR30384 +// Header cpuid.h and method __get_cpuid_max are not used in llvm, clang, openmp +// or test-suite, but are used in external projects e.g. libstdcxx +static bool isCpuIdSupported() { +#if defined(__GNUC__) || defined(__clang__) +#if defined(__i386__) + int __cpuid_supported; + __asm__(" pushfl\n" + " popl %%eax\n" + " movl %%eax,%%ecx\n" + " xorl $0x00200000,%%eax\n" + " pushl %%eax\n" + " popfl\n" + " pushfl\n" + " popl %%eax\n" + " movl $0,%0\n" + " cmpl %%eax,%%ecx\n" + " je 1f\n" + " movl $1,%0\n" + "1:" + : "=r"(__cpuid_supported) + : + : "eax", "ecx"); + if (!__cpuid_supported) + return false; +#endif + return true; +#endif + return true; +} + +/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in +/// the specified arguments. If we can't run cpuid on the host, return true. +static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, + unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. + // FIXME: should we save this for Clang? + __asm__("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); + return false; +#elif defined(__i386__) + __asm__("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); + return false; +#else + return true; +#endif +#elif defined(_MSC_VER) + // The MSVC intrinsic is portable across x86 and x64. + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; +#else + return true; +#endif +} + +namespace llvm { +namespace sys { +namespace detail { +namespace x86 { + +VendorSignatures getVendorSignature(unsigned *MaxLeaf) { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + if (MaxLeaf == nullptr) + MaxLeaf = &EAX; + else + *MaxLeaf = 0; + + if (!isCpuIdSupported()) + return VendorSignatures::UNKNOWN; + + if (getX86CpuIDAndInfo(0, MaxLeaf, &EBX, &ECX, &EDX) || *MaxLeaf < 1) + return VendorSignatures::UNKNOWN; + + // "Genu ineI ntel" + if (EBX == 0x756e6547 && EDX == 0x49656e69 && ECX == 0x6c65746e) + return VendorSignatures::GENUINE_INTEL; + + // "Auth enti cAMD" + if (EBX == 0x68747541 && EDX == 0x69746e65 && ECX == 0x444d4163) + return VendorSignatures::AUTHENTIC_AMD; + + return VendorSignatures::UNKNOWN; +} + +} // namespace x86 +} // namespace detail +} // namespace sys +} // namespace llvm + +using namespace llvm::sys::detail::x86; + +/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return +/// the 4 values in the specified arguments. If we can't run cpuid on the host, +/// return true. +static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, + unsigned *rEAX, unsigned *rEBX, unsigned *rECX, + unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. + // FIXME: should we save this for Clang? + __asm__("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); + return false; +#elif defined(__i386__) + __asm__("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); + return false; +#else + return true; +#endif +#elif defined(_MSC_VER) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; +#else + return true; +#endif +} + +// Read control register 0 (XCR0). Used to detect features such as AVX. +static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) + // Check xgetbv; this uses a .byte sequence instead of the instruction + // directly because older assemblers do not include support for xgetbv and + // there is no easy way to conditionally compile based on the assembler used. + __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); + return false; +#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) + unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); + *rEAX = Result; + *rEDX = Result >> 32; + return false; +#else + return true; +#endif +} + +static void detectX86FamilyModel(unsigned EAX, unsigned *Family, + unsigned *Model) { + *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (*Family == 6 || *Family == 0xf) { + if (*Family == 0xf) + // Examine extended family ID if family ID is F. + *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + +static StringRef +getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, + const unsigned *Features, + unsigned *Type, unsigned *Subtype) { + auto testFeature = [&](unsigned F) { + return (Features[F / 32] & (1U << (F % 32))) != 0; + }; + + StringRef CPU; + + switch (Family) { + case 3: + CPU = "i386"; + break; + case 4: + CPU = "i486"; + break; + case 5: + if (testFeature(X86::FEATURE_MMX)) { + CPU = "pentium-mmx"; + break; + } + CPU = "pentium"; + break; + case 6: + switch (Model) { + case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + // processor, Intel Core 2 Quad processor, Intel Core 2 Quad + // mobile processor, Intel Core 2 Extreme processor, Intel + // Pentium Dual-Core processor, Intel Xeon processor, model + // 0Fh. All processors are manufactured using the 65 nm process. + case 0x16: // Intel Celeron processor model 16h. All processors are + // manufactured using the 65 nm process + CPU = "core2"; + *Type = X86::INTEL_CORE2; + break; + case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model + // 17h. All processors are manufactured using the 45 nm process. + // + // 45nm: Penryn , Wolfdale, Yorkfield (XE) + case 0x1d: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + CPU = "penryn"; + *Type = X86::INTEL_CORE2; + break; + case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 45 nm process. + case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + // As found in a Summer 2010 model iMac. + case 0x1f: + case 0x2e: // Nehalem EX + CPU = "nehalem"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_NEHALEM; + break; + case 0x25: // Intel Core i7, laptop version. + case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 32 nm process. + case 0x2f: // Westmere EX + CPU = "westmere"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_WESTMERE; + break; + case 0x2a: // Intel Core i7 processor. All processors are manufactured + // using the 32 nm process. + case 0x2d: + CPU = "sandybridge"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SANDYBRIDGE; + break; + case 0x3a: + case 0x3e: // Ivy Bridge EP + CPU = "ivybridge"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_IVYBRIDGE; + break; + + // Haswell: + case 0x3c: + case 0x3f: + case 0x45: + case 0x46: + CPU = "haswell"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_HASWELL; + break; + + // Broadwell: + case 0x3d: + case 0x47: + case 0x4f: + case 0x56: + CPU = "broadwell"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_BROADWELL; + break; + + // Skylake: + case 0x4e: // Skylake mobile + case 0x5e: // Skylake desktop + case 0x8e: // Kaby Lake mobile + case 0x9e: // Kaby Lake desktop + case 0xa5: // Comet Lake-H/S + case 0xa6: // Comet Lake-U + CPU = "skylake"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SKYLAKE; + break; + + // Rocketlake: + case 0xa7: + CPU = "rocketlake"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ROCKETLAKE; + break; + + // Skylake Xeon: + case 0x55: + *Type = X86::INTEL_COREI7; + if (testFeature(X86::FEATURE_AVX512BF16)) { + CPU = "cooperlake"; + *Subtype = X86::INTEL_COREI7_COOPERLAKE; + } else if (testFeature(X86::FEATURE_AVX512VNNI)) { + CPU = "cascadelake"; + *Subtype = X86::INTEL_COREI7_CASCADELAKE; + } else { + CPU = "skylake-avx512"; + *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512; + } + break; + + // Cannonlake: + case 0x66: + CPU = "cannonlake"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_CANNONLAKE; + break; + + // Icelake: + case 0x7d: + case 0x7e: + CPU = "icelake-client"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT; + break; + + // Tigerlake: + case 0x8c: + case 0x8d: + CPU = "tigerlake"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_TIGERLAKE; + break; + + // Alderlake: + case 0x97: + case 0x9a: + // Raptorlake: + case 0xb7: + // Meteorlake: + case 0xaa: + case 0xac: + CPU = "alderlake"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ALDERLAKE; + break; + + // Graniterapids: + case 0xae: + case 0xad: + CPU = "graniterapids"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_GRANITERAPIDS; + break; + + // Icelake Xeon: + case 0x6a: + case 0x6c: + CPU = "icelake-server"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ICELAKE_SERVER; + break; + + // Emerald Rapids: + case 0xcf: + // Sapphire Rapids: + case 0x8f: + CPU = "sapphirerapids"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SAPPHIRERAPIDS; + break; + + case 0x1c: // Most 45 nm Intel Atom processors + case 0x26: // 45 nm Atom Lincroft + case 0x27: // 32 nm Atom Medfield + case 0x35: // 32 nm Atom Midview + case 0x36: // 32 nm Atom Midview + CPU = "bonnell"; + *Type = X86::INTEL_BONNELL; + break; + + // Atom Silvermont codes from the Intel software optimization guide. + case 0x37: + case 0x4a: + case 0x4d: + case 0x5a: + case 0x5d: + case 0x4c: // really airmont + CPU = "silvermont"; + *Type = X86::INTEL_SILVERMONT; + break; + // Goldmont: + case 0x5c: // Apollo Lake + case 0x5f: // Denverton + CPU = "goldmont"; + *Type = X86::INTEL_GOLDMONT; + break; + case 0x7a: + CPU = "goldmont-plus"; + *Type = X86::INTEL_GOLDMONT_PLUS; + break; + case 0x86: + CPU = "tremont"; + *Type = X86::INTEL_TREMONT; + break; + + // Sierraforest: + case 0xaf: + CPU = "sierraforest"; + *Type = X86::INTEL_SIERRAFOREST; + break; + + // Grandridge: + case 0xb6: + CPU = "grandridge"; + *Type = X86::INTEL_GRANDRIDGE; + break; + + // Xeon Phi (Knights Landing + Knights Mill): + case 0x57: + CPU = "knl"; + *Type = X86::INTEL_KNL; + break; + case 0x85: + CPU = "knm"; + *Type = X86::INTEL_KNM; + break; + + default: // Unknown family 6 CPU, try to guess. + // Don't both with Type/Subtype here, they aren't used by the caller. + // They're used above to keep the code in sync with compiler-rt. + // TODO detect tigerlake host from model + if (testFeature(X86::FEATURE_AVX512VP2INTERSECT)) { + CPU = "tigerlake"; + } else if (testFeature(X86::FEATURE_AVX512VBMI2)) { + CPU = "icelake-client"; + } else if (testFeature(X86::FEATURE_AVX512VBMI)) { + CPU = "cannonlake"; + } else if (testFeature(X86::FEATURE_AVX512BF16)) { + CPU = "cooperlake"; + } else if (testFeature(X86::FEATURE_AVX512VNNI)) { + CPU = "cascadelake"; + } else if (testFeature(X86::FEATURE_AVX512VL)) { + CPU = "skylake-avx512"; + } else if (testFeature(X86::FEATURE_AVX512ER)) { + CPU = "knl"; + } else if (testFeature(X86::FEATURE_CLFLUSHOPT)) { + if (testFeature(X86::FEATURE_SHA)) + CPU = "goldmont"; + else + CPU = "skylake"; + } else if (testFeature(X86::FEATURE_ADX)) { + CPU = "broadwell"; + } else if (testFeature(X86::FEATURE_AVX2)) { + CPU = "haswell"; + } else if (testFeature(X86::FEATURE_AVX)) { + CPU = "sandybridge"; + } else if (testFeature(X86::FEATURE_SSE4_2)) { + if (testFeature(X86::FEATURE_MOVBE)) + CPU = "silvermont"; + else + CPU = "nehalem"; + } else if (testFeature(X86::FEATURE_SSE4_1)) { + CPU = "penryn"; + } else if (testFeature(X86::FEATURE_SSSE3)) { + if (testFeature(X86::FEATURE_MOVBE)) + CPU = "bonnell"; + else + CPU = "core2"; + } else if (testFeature(X86::FEATURE_64BIT)) { + CPU = "core2"; + } else if (testFeature(X86::FEATURE_SSE3)) { + CPU = "yonah"; + } else if (testFeature(X86::FEATURE_SSE2)) { + CPU = "pentium-m"; + } else if (testFeature(X86::FEATURE_SSE)) { + CPU = "pentium3"; + } else if (testFeature(X86::FEATURE_MMX)) { + CPU = "pentium2"; + } else { + CPU = "pentiumpro"; + } + break; + } + break; + case 15: { + if (testFeature(X86::FEATURE_64BIT)) { + CPU = "nocona"; + break; + } + if (testFeature(X86::FEATURE_SSE3)) { + CPU = "prescott"; + break; + } + CPU = "pentium4"; + break; + } + default: + break; // Unknown. + } + + return CPU; +} + +static StringRef +getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, + const unsigned *Features, + unsigned *Type, unsigned *Subtype) { + auto testFeature = [&](unsigned F) { + return (Features[F / 32] & (1U << (F % 32))) != 0; + }; + + StringRef CPU; + + switch (Family) { + case 4: + CPU = "i486"; + break; + case 5: + CPU = "pentium"; + switch (Model) { + case 6: + case 7: + CPU = "k6"; + break; + case 8: + CPU = "k6-2"; + break; + case 9: + case 13: + CPU = "k6-3"; + break; + case 10: + CPU = "geode"; + break; + } + break; + case 6: + if (testFeature(X86::FEATURE_SSE)) { + CPU = "athlon-xp"; + break; + } + CPU = "athlon"; + break; + case 15: + if (testFeature(X86::FEATURE_SSE3)) { + CPU = "k8-sse3"; + break; + } + CPU = "k8"; + break; + case 16: + CPU = "amdfam10"; + *Type = X86::AMDFAM10H; // "amdfam10" + switch (Model) { + case 2: + *Subtype = X86::AMDFAM10H_BARCELONA; + break; + case 4: + *Subtype = X86::AMDFAM10H_SHANGHAI; + break; + case 8: + *Subtype = X86::AMDFAM10H_ISTANBUL; + break; + } + break; + case 20: + CPU = "btver1"; + *Type = X86::AMD_BTVER1; + break; + case 21: + CPU = "bdver1"; + *Type = X86::AMDFAM15H; + if (Model >= 0x60 && Model <= 0x7f) { + CPU = "bdver4"; + *Subtype = X86::AMDFAM15H_BDVER4; + break; // 60h-7Fh: Excavator + } + if (Model >= 0x30 && Model <= 0x3f) { + CPU = "bdver3"; + *Subtype = X86::AMDFAM15H_BDVER3; + break; // 30h-3Fh: Steamroller + } + if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { + CPU = "bdver2"; + *Subtype = X86::AMDFAM15H_BDVER2; + break; // 02h, 10h-1Fh: Piledriver + } + if (Model <= 0x0f) { + *Subtype = X86::AMDFAM15H_BDVER1; + break; // 00h-0Fh: Bulldozer + } + break; + case 22: + CPU = "btver2"; + *Type = X86::AMD_BTVER2; + break; + case 23: + CPU = "znver1"; + *Type = X86::AMDFAM17H; + if ((Model >= 0x30 && Model <= 0x3f) || Model == 0x71) { + CPU = "znver2"; + *Subtype = X86::AMDFAM17H_ZNVER2; + break; // 30h-3fh, 71h: Zen2 + } + if (Model <= 0x0f) { + *Subtype = X86::AMDFAM17H_ZNVER1; + break; // 00h-0Fh: Zen1 + } + break; + case 25: + CPU = "znver3"; + *Type = X86::AMDFAM19H; + if (Model <= 0x0f || (Model >= 0x20 && Model <= 0x5f)) { + // Family 19h Models 00h-0Fh - Zen3 + // Family 19h Models 20h-2Fh - Zen3 + // Family 19h Models 30h-3Fh - Zen3 + // Family 19h Models 40h-4Fh - Zen3+ + // Family 19h Models 50h-5Fh - Zen3+ + *Subtype = X86::AMDFAM19H_ZNVER3; + break; + } + if ((Model >= 0x10 && Model <= 0x1f) || + (Model >= 0x60 && Model <= 0x74) || + (Model >= 0x78 && Model <= 0x7b) || + (Model >= 0xA0 && Model <= 0xAf)) { + CPU = "znver4"; + *Subtype = X86::AMDFAM19H_ZNVER4; + break; // "znver4" + } + break; // family 19h + default: + break; // Unknown AMD CPU. + } + + return CPU; +} + +static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, + unsigned *Features) { + unsigned EAX, EBX; + + auto setFeature = [&](unsigned F) { + Features[F / 32] |= 1U << (F % 32); + }; + + if ((EDX >> 15) & 1) + setFeature(X86::FEATURE_CMOV); + if ((EDX >> 23) & 1) + setFeature(X86::FEATURE_MMX); + if ((EDX >> 25) & 1) + setFeature(X86::FEATURE_SSE); + if ((EDX >> 26) & 1) + setFeature(X86::FEATURE_SSE2); + + if ((ECX >> 0) & 1) + setFeature(X86::FEATURE_SSE3); + if ((ECX >> 1) & 1) + setFeature(X86::FEATURE_PCLMUL); + if ((ECX >> 9) & 1) + setFeature(X86::FEATURE_SSSE3); + if ((ECX >> 12) & 1) + setFeature(X86::FEATURE_FMA); + if ((ECX >> 19) & 1) + setFeature(X86::FEATURE_SSE4_1); + if ((ECX >> 20) & 1) { + setFeature(X86::FEATURE_SSE4_2); + setFeature(X86::FEATURE_CRC32); + } + if ((ECX >> 23) & 1) + setFeature(X86::FEATURE_POPCNT); + if ((ECX >> 25) & 1) + setFeature(X86::FEATURE_AES); + + if ((ECX >> 22) & 1) + setFeature(X86::FEATURE_MOVBE); + + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && + ((EAX & 0x6) == 0x6); +#if defined(__APPLE__) + // Darwin lazily saves the AVX512 context on first use: trust that the OS will + // save the AVX512 context if we use AVX512 instructions, even the bit is not + // set right now. + bool HasAVX512Save = true; +#else + // AVX512 requires additional context to be saved by the OS. + bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); +#endif + + if (HasAVX) + setFeature(X86::FEATURE_AVX); + + bool HasLeaf7 = + MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + + if (HasLeaf7 && ((EBX >> 3) & 1)) + setFeature(X86::FEATURE_BMI); + if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) + setFeature(X86::FEATURE_AVX2); + if (HasLeaf7 && ((EBX >> 8) & 1)) + setFeature(X86::FEATURE_BMI2); + if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512F); + if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512DQ); + if (HasLeaf7 && ((EBX >> 19) & 1)) + setFeature(X86::FEATURE_ADX); + if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512IFMA); + if (HasLeaf7 && ((EBX >> 23) & 1)) + setFeature(X86::FEATURE_CLFLUSHOPT); + if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512PF); + if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512ER); + if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512CD); + if (HasLeaf7 && ((EBX >> 29) & 1)) + setFeature(X86::FEATURE_SHA); + if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512BW); + if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VL); + + if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VBMI); + if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VBMI2); + if (HasLeaf7 && ((ECX >> 8) & 1)) + setFeature(X86::FEATURE_GFNI); + if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX) + setFeature(X86::FEATURE_VPCLMULQDQ); + if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VNNI); + if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512BITALG); + if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VPOPCNTDQ); + + if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX5124VNNIW); + if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX5124FMAPS); + if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512VP2INTERSECT); + + bool HasLeaf7Subleaf1 = + MaxLeaf >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save) + setFeature(X86::FEATURE_AVX512BF16); + + unsigned MaxExtLevel; + getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + + bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && + !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + if (HasExtLeaf1 && ((ECX >> 6) & 1)) + setFeature(X86::FEATURE_SSE4_A); + if (HasExtLeaf1 && ((ECX >> 11) & 1)) + setFeature(X86::FEATURE_XOP); + if (HasExtLeaf1 && ((ECX >> 16) & 1)) + setFeature(X86::FEATURE_FMA4); + + if (HasExtLeaf1 && ((EDX >> 29) & 1)) + setFeature(X86::FEATURE_64BIT); +} + +StringRef sys::getHostCPUName() { + unsigned MaxLeaf = 0; + const VendorSignatures Vendor = getVendorSignature(&MaxLeaf); + if (Vendor == VendorSignatures::UNKNOWN) + return "generic"; + + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX); + + unsigned Family = 0, Model = 0; + unsigned Features[(X86::CPU_FEATURE_MAX + 31) / 32] = {0}; + detectX86FamilyModel(EAX, &Family, &Model); + getAvailableFeatures(ECX, EDX, MaxLeaf, Features); + + // These aren't consumed in this file, but we try to keep some source code the + // same or similar to compiler-rt. + unsigned Type = 0; + unsigned Subtype = 0; + + StringRef CPU; + + if (Vendor == VendorSignatures::GENUINE_INTEL) { + CPU = getIntelProcessorTypeAndSubtype(Family, Model, Features, &Type, + &Subtype); + } else if (Vendor == VendorSignatures::AUTHENTIC_AMD) { + CPU = getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, + &Subtype); + } + + if (!CPU.empty()) + return CPU; + + return "generic"; +} + +#elif defined(__APPLE__) && defined(__powerpc__) +StringRef sys::getHostCPUName() { + host_basic_info_data_t hostInfo; + mach_msg_type_number_t infoCount; + + infoCount = HOST_BASIC_INFO_COUNT; + mach_port_t hostPort = mach_host_self(); + host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&hostInfo, + &infoCount); + mach_port_deallocate(mach_task_self(), hostPort); + + if (hostInfo.cpu_type != CPU_TYPE_POWERPC) + return "generic"; + + switch (hostInfo.cpu_subtype) { + case CPU_SUBTYPE_POWERPC_601: + return "601"; + case CPU_SUBTYPE_POWERPC_602: + return "602"; + case CPU_SUBTYPE_POWERPC_603: + return "603"; + case CPU_SUBTYPE_POWERPC_603e: + return "603e"; + case CPU_SUBTYPE_POWERPC_603ev: + return "603ev"; + case CPU_SUBTYPE_POWERPC_604: + return "604"; + case CPU_SUBTYPE_POWERPC_604e: + return "604e"; + case CPU_SUBTYPE_POWERPC_620: + return "620"; + case CPU_SUBTYPE_POWERPC_750: + return "750"; + case CPU_SUBTYPE_POWERPC_7400: + return "7400"; + case CPU_SUBTYPE_POWERPC_7450: + return "7450"; + case CPU_SUBTYPE_POWERPC_970: + return "970"; + default:; + } + + return "generic"; +} +#elif defined(__linux__) && defined(__powerpc__) +StringRef sys::getHostCPUName() { + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + StringRef Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForPowerPC(Content); +} +#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) +StringRef sys::getHostCPUName() { + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + StringRef Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForARM(Content); +} +#elif defined(__linux__) && defined(__s390x__) +StringRef sys::getHostCPUName() { + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + StringRef Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForS390x(Content); +} +#elif defined(__MVS__) +StringRef sys::getHostCPUName() { + // Get pointer to Communications Vector Table (CVT). + // The pointer is located at offset 16 of the Prefixed Save Area (PSA). + // It is stored as 31 bit pointer and will be zero-extended to 64 bit. + int *StartToCVTOffset = reinterpret_cast<int *>(0x10); + // Since its stored as a 31-bit pointer, get the 4 bytes from the start + // of address. + int ReadValue = *StartToCVTOffset; + // Explicitly clear the high order bit. + ReadValue = (ReadValue & 0x7FFFFFFF); + char *CVT = reinterpret_cast<char *>(ReadValue); + // The model number is located in the CVT prefix at offset -6 and stored as + // signless packed decimal. + uint16_t Id = *(uint16_t *)&CVT[-6]; + // Convert number to integer. + Id = decodePackedBCD<uint16_t>(Id, false); + // Check for vector support. It's stored in field CVTFLAG5 (offset 244), + // bit CVTVEF (X'80'). The facilities list is part of the PSA but the vector + // extension can only be used if bit CVTVEF is on. + bool HaveVectorSupport = CVT[244] & 0x80; + return getCPUNameFromS390Model(Id, HaveVectorSupport); +} +#elif defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) +#define CPUFAMILY_ARM_SWIFT 0x1e2d6381 +#define CPUFAMILY_ARM_CYCLONE 0x37a09642 +#define CPUFAMILY_ARM_TYPHOON 0x2c91a47e +#define CPUFAMILY_ARM_TWISTER 0x92fb37c8 +#define CPUFAMILY_ARM_HURRICANE 0x67ceee93 +#define CPUFAMILY_ARM_MONSOON_MISTRAL 0xe81e7ef6 +#define CPUFAMILY_ARM_VORTEX_TEMPEST 0x07d34b9f +#define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504d2 +#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1b588bb3 + +StringRef sys::getHostCPUName() { + uint32_t Family; + size_t Length = sizeof(Family); + sysctlbyname("hw.cpufamily", &Family, &Length, NULL, 0); + + switch (Family) { + case CPUFAMILY_ARM_SWIFT: + return "swift"; + case CPUFAMILY_ARM_CYCLONE: + return "apple-a7"; + case CPUFAMILY_ARM_TYPHOON: + return "apple-a8"; + case CPUFAMILY_ARM_TWISTER: + return "apple-a9"; + case CPUFAMILY_ARM_HURRICANE: + return "apple-a10"; + case CPUFAMILY_ARM_MONSOON_MISTRAL: + return "apple-a11"; + case CPUFAMILY_ARM_VORTEX_TEMPEST: + return "apple-a12"; + case CPUFAMILY_ARM_LIGHTNING_THUNDER: + return "apple-a13"; + case CPUFAMILY_ARM_FIRESTORM_ICESTORM: + return "apple-m1"; + default: + // Default to the newest CPU we know about. + return "apple-m1"; + } +} +#elif defined(_AIX) +StringRef sys::getHostCPUName() { + switch (_system_configuration.implementation) { + case POWER_4: + if (_system_configuration.version == PV_4_3) + return "970"; + return "pwr4"; + case POWER_5: + if (_system_configuration.version == PV_5) + return "pwr5"; + return "pwr5x"; + case POWER_6: + if (_system_configuration.version == PV_6_Compat) + return "pwr6"; + return "pwr6x"; + case POWER_7: + return "pwr7"; + case POWER_8: + return "pwr8"; + case POWER_9: + return "pwr9"; +// TODO: simplify this once the macro is available in all OS levels. +#ifdef POWER_10 + case POWER_10: +#else + case 0x40000: +#endif + return "pwr10"; + default: + return "generic"; + } +} +#elif defined(__riscv) +StringRef sys::getHostCPUName() { +#if defined(__linux__) + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + StringRef Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForRISCV(Content); +#else +#if __riscv_xlen == 64 + return "generic-rv64"; +#elif __riscv_xlen == 32 + return "generic-rv32"; +#else +#error "Unhandled value of __riscv_xlen" +#endif +#endif +} +#elif defined(__sparc__) +#if defined(__linux__) +StringRef sys::detail::getHostCPUNameForSPARC(StringRef ProcCpuinfoContent) { + SmallVector<StringRef> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for cpu line to determine cpu name + StringRef Cpu; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("cpu")) { + Cpu = Lines[I].substr(5).ltrim("\t :"); + break; + } + } + + return StringSwitch<const char *>(Cpu) + .StartsWith("SuperSparc", "supersparc") + .StartsWith("HyperSparc", "hypersparc") + .StartsWith("SpitFire", "ultrasparc") + .StartsWith("BlackBird", "ultrasparc") + .StartsWith("Sabre", " ultrasparc") + .StartsWith("Hummingbird", "ultrasparc") + .StartsWith("Cheetah", "ultrasparc3") + .StartsWith("Jalapeno", "ultrasparc3") + .StartsWith("Jaguar", "ultrasparc3") + .StartsWith("Panther", "ultrasparc3") + .StartsWith("Serrano", "ultrasparc3") + .StartsWith("UltraSparc T1", "niagara") + .StartsWith("UltraSparc T2", "niagara2") + .StartsWith("UltraSparc T3", "niagara3") + .StartsWith("UltraSparc T4", "niagara4") + .StartsWith("UltraSparc T5", "niagara4") + .StartsWith("LEON", "leon3") + // niagara7/m8 not supported by LLVM yet. + .StartsWith("SPARC-M7", "niagara4" /* "niagara7" */) + .StartsWith("SPARC-S7", "niagara4" /* "niagara7" */) + .StartsWith("SPARC-M8", "niagara4" /* "m8" */) + .Default("generic"); +} +#endif + +StringRef sys::getHostCPUName() { +#if defined(__linux__) + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + StringRef Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForSPARC(Content); +#elif defined(__sun__) && defined(__svr4__) + char *buf = NULL; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *brand = NULL; + + kc = kstat_open(); + if (kc != NULL) { + ksp = kstat_lookup(kc, const_cast<char *>("cpu_info"), -1, NULL); + if (ksp != NULL && kstat_read(kc, ksp, NULL) != -1 && + ksp->ks_type == KSTAT_TYPE_NAMED) + brand = + (kstat_named_t *)kstat_data_lookup(ksp, const_cast<char *>("brand")); + if (brand != NULL && brand->data_type == KSTAT_DATA_STRING) + buf = KSTAT_NAMED_STR_PTR(brand); + } + kstat_close(kc); + + return StringSwitch<const char *>(buf) + .Case("TMS390S10", "supersparc") // Texas Instruments microSPARC I + .Case("TMS390Z50", "supersparc") // Texas Instruments SuperSPARC I + .Case("TMS390Z55", + "supersparc") // Texas Instruments SuperSPARC I with SuperCache + .Case("MB86904", "supersparc") // Fujitsu microSPARC II + .Case("MB86907", "supersparc") // Fujitsu TurboSPARC + .Case("RT623", "hypersparc") // Ross hyperSPARC + .Case("RT625", "hypersparc") + .Case("RT626", "hypersparc") + .Case("UltraSPARC-I", "ultrasparc") + .Case("UltraSPARC-II", "ultrasparc") + .Case("UltraSPARC-IIe", "ultrasparc") + .Case("UltraSPARC-IIi", "ultrasparc") + .Case("SPARC64-III", "ultrasparc") + .Case("SPARC64-IV", "ultrasparc") + .Case("UltraSPARC-III", "ultrasparc3") + .Case("UltraSPARC-III+", "ultrasparc3") + .Case("UltraSPARC-IIIi", "ultrasparc3") + .Case("UltraSPARC-IIIi+", "ultrasparc3") + .Case("UltraSPARC-IV", "ultrasparc3") + .Case("UltraSPARC-IV+", "ultrasparc3") + .Case("SPARC64-V", "ultrasparc3") + .Case("SPARC64-VI", "ultrasparc3") + .Case("SPARC64-VII", "ultrasparc3") + .Case("UltraSPARC-T1", "niagara") + .Case("UltraSPARC-T2", "niagara2") + .Case("UltraSPARC-T2", "niagara2") + .Case("UltraSPARC-T2+", "niagara2") + .Case("SPARC-T3", "niagara3") + .Case("SPARC-T4", "niagara4") + .Case("SPARC-T5", "niagara4") + // niagara7/m8 not supported by LLVM yet. + .Case("SPARC-M7", "niagara4" /* "niagara7" */) + .Case("SPARC-S7", "niagara4" /* "niagara7" */) + .Case("SPARC-M8", "niagara4" /* "m8" */) + .Default("generic"); +#else + return "generic"; +#endif +} +#else +StringRef sys::getHostCPUName() { return "generic"; } +namespace llvm { +namespace sys { +namespace detail { +namespace x86 { + +VendorSignatures getVendorSignature(unsigned *MaxLeaf) { + return VendorSignatures::UNKNOWN; +} + +} // namespace x86 +} // namespace detail +} // namespace sys +} // namespace llvm +#endif + +#if defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64__) || defined(_M_X64) +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + unsigned MaxLevel; + + if (getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX) || MaxLevel < 1) + return false; + + getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); + + Features["cx8"] = (EDX >> 8) & 1; + Features["cmov"] = (EDX >> 15) & 1; + Features["mmx"] = (EDX >> 23) & 1; + Features["fxsr"] = (EDX >> 24) & 1; + Features["sse"] = (EDX >> 25) & 1; + Features["sse2"] = (EDX >> 26) & 1; + + Features["sse3"] = (ECX >> 0) & 1; + Features["pclmul"] = (ECX >> 1) & 1; + Features["ssse3"] = (ECX >> 9) & 1; + Features["cx16"] = (ECX >> 13) & 1; + Features["sse4.1"] = (ECX >> 19) & 1; + Features["sse4.2"] = (ECX >> 20) & 1; + Features["crc32"] = Features["sse4.2"]; + Features["movbe"] = (ECX >> 22) & 1; + Features["popcnt"] = (ECX >> 23) & 1; + Features["aes"] = (ECX >> 25) & 1; + Features["rdrnd"] = (ECX >> 30) & 1; + + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX); + bool HasAVXSave = HasXSave && ((ECX >> 28) & 1) && ((EAX & 0x6) == 0x6); +#if defined(__APPLE__) + // Darwin lazily saves the AVX512 context on first use: trust that the OS will + // save the AVX512 context if we use AVX512 instructions, even the bit is not + // set right now. + bool HasAVX512Save = true; +#else + // AVX512 requires additional context to be saved by the OS. + bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); +#endif + // AMX requires additional context to be saved by the OS. + const unsigned AMXBits = (1 << 17) | (1 << 18); + bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits); + + Features["avx"] = HasAVXSave; + Features["fma"] = ((ECX >> 12) & 1) && HasAVXSave; + // Only enable XSAVE if OS has enabled support for saving YMM state. + Features["xsave"] = ((ECX >> 26) & 1) && HasAVXSave; + Features["f16c"] = ((ECX >> 29) & 1) && HasAVXSave; + + unsigned MaxExtLevel; + getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + + bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && + !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features["sahf"] = HasExtLeaf1 && ((ECX >> 0) & 1); + Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); + Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); + Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); + Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; + Features["lwp"] = HasExtLeaf1 && ((ECX >> 15) & 1); + Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; + Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); + Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); + + Features["64bit"] = HasExtLeaf1 && ((EDX >> 29) & 1); + + // Miscellaneous memory related features, detected by + // using the 0x80000008 leaf of the CPUID instruction + bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && + !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); + Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); + Features["rdpru"] = HasExtLeaf8 && ((EBX >> 4) & 1); + Features["wbnoinvd"] = HasExtLeaf8 && ((EBX >> 9) & 1); + + bool HasLeaf7 = + MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + + Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); + Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); + Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); + // AVX2 is only supported if we have the OS save support from AVX. + Features["avx2"] = HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave; + Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); + Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); + Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); + // AVX512 is only supported if the OS supports the context save for it. + Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; + Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save; + Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); + Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); + Features["avx512ifma"] = HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save; + Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); + Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); + Features["avx512pf"] = HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save; + Features["avx512er"] = HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save; + Features["avx512cd"] = HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save; + Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); + Features["avx512bw"] = HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save; + Features["avx512vl"] = HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save; + + Features["prefetchwt1"] = HasLeaf7 && ((ECX >> 0) & 1); + Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; + Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + Features["waitpkg"] = HasLeaf7 && ((ECX >> 5) & 1); + Features["avx512vbmi2"] = HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save; + Features["shstk"] = HasLeaf7 && ((ECX >> 7) & 1); + Features["gfni"] = HasLeaf7 && ((ECX >> 8) & 1); + Features["vaes"] = HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave; + Features["vpclmulqdq"] = HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave; + Features["avx512vnni"] = HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save; + Features["avx512bitalg"] = HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save; + Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; + Features["rdpid"] = HasLeaf7 && ((ECX >> 22) & 1); + Features["kl"] = HasLeaf7 && ((ECX >> 23) & 1); // key locker + Features["cldemote"] = HasLeaf7 && ((ECX >> 25) & 1); + Features["movdiri"] = HasLeaf7 && ((ECX >> 27) & 1); + Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1); + Features["enqcmd"] = HasLeaf7 && ((ECX >> 29) & 1); + + Features["uintr"] = HasLeaf7 && ((EDX >> 5) & 1); + Features["avx512vp2intersect"] = + HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save; + Features["serialize"] = HasLeaf7 && ((EDX >> 14) & 1); + Features["tsxldtrk"] = HasLeaf7 && ((EDX >> 16) & 1); + // There are two CPUID leafs which information associated with the pconfig + // instruction: + // EAX=0x7, ECX=0x0 indicates the availability of the instruction (via the 18th + // bit of EDX), while the EAX=0x1b leaf returns information on the + // availability of specific pconfig leafs. + // The target feature here only refers to the the first of these two. + // Users might need to check for the availability of specific pconfig + // leaves using cpuid, since that information is ignored while + // detecting features using the "-march=native" flag. + // For more info, see X86 ISA docs. + Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1); + Features["amx-bf16"] = HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave; + Features["avx512fp16"] = HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save; + Features["amx-tile"] = HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave; + Features["amx-int8"] = HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave; + bool HasLeaf7Subleaf1 = + MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); + Features["raoint"] = HasLeaf7Subleaf1 && ((EAX >> 3) & 1); + Features["avxvnni"] = HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave; + Features["avx512bf16"] = HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save; + Features["amx-fp16"] = HasLeaf7Subleaf1 && ((EAX >> 21) & 1) && HasAMXSave; + Features["cmpccxadd"] = HasLeaf7Subleaf1 && ((EAX >> 7) & 1); + Features["hreset"] = HasLeaf7Subleaf1 && ((EAX >> 22) & 1); + Features["avxifma"] = HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave; + Features["avxvnniint8"] = HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave; + Features["avxneconvert"] = HasLeaf7Subleaf1 && ((EDX >> 5) & 1) && HasAVXSave; + Features["prefetchi"] = HasLeaf7Subleaf1 && ((EDX >> 14) & 1); + + bool HasLeafD = MaxLevel >= 0xd && + !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); + + // Only enable XSAVE if OS has enabled support for saving YMM state. + Features["xsaveopt"] = HasLeafD && ((EAX >> 0) & 1) && HasAVXSave; + Features["xsavec"] = HasLeafD && ((EAX >> 1) & 1) && HasAVXSave; + Features["xsaves"] = HasLeafD && ((EAX >> 3) & 1) && HasAVXSave; + + bool HasLeaf14 = MaxLevel >= 0x14 && + !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX); + + Features["ptwrite"] = HasLeaf14 && ((EBX >> 4) & 1); + + bool HasLeaf19 = + MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX); + Features["widekl"] = HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1); + + return true; +} +#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + if (!P) + return false; + + SmallVector<StringRef, 32> Lines; + P->getBuffer().split(Lines, "\n"); + + SmallVector<StringRef, 32> CPUFeatures; + + // Look for the CPU features. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("Features")) { + Lines[I].split(CPUFeatures, ' '); + break; + } + +#if defined(__aarch64__) + // Keep track of which crypto features we have seen + enum { CAP_AES = 0x1, CAP_PMULL = 0x2, CAP_SHA1 = 0x4, CAP_SHA2 = 0x8 }; + uint32_t crypto = 0; +#endif + + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I]) +#if defined(__aarch64__) + .Case("asimd", "neon") + .Case("fp", "fp-armv8") + .Case("crc32", "crc") + .Case("atomics", "lse") + .Case("sve", "sve") + .Case("sve2", "sve2") +#else + .Case("half", "fp16") + .Case("neon", "neon") + .Case("vfpv3", "vfp3") + .Case("vfpv3d16", "vfp3d16") + .Case("vfpv4", "vfp4") + .Case("idiva", "hwdiv-arm") + .Case("idivt", "hwdiv") +#endif + .Default(""); + +#if defined(__aarch64__) + // We need to check crypto separately since we need all of the crypto + // extensions to enable the subtarget feature + if (CPUFeatures[I] == "aes") + crypto |= CAP_AES; + else if (CPUFeatures[I] == "pmull") + crypto |= CAP_PMULL; + else if (CPUFeatures[I] == "sha1") + crypto |= CAP_SHA1; + else if (CPUFeatures[I] == "sha2") + crypto |= CAP_SHA2; +#endif + + if (LLVMFeatureStr != "") + Features[LLVMFeatureStr] = true; + } + +#if defined(__aarch64__) + // If we have all crypto bits we can add the feature + if (crypto == (CAP_AES | CAP_PMULL | CAP_SHA1 | CAP_SHA2)) + Features["crypto"] = true; +#endif + + return true; +} +#elif defined(_WIN32) && (defined(__aarch64__) || defined(_M_ARM64)) +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { + if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) + Features["neon"] = true; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) + Features["crc"] = true; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) + Features["crypto"] = true; + + return true; +} +#else +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return false; } +#endif + +std::string sys::getProcessTriple() { + std::string TargetTripleString = updateTripleOSVersion(LLVM_HOST_TRIPLE); + Triple PT(Triple::normalize(TargetTripleString)); + + if (sizeof(void *) == 8 && PT.isArch32Bit()) + PT = PT.get64BitArchVariant(); + if (sizeof(void *) == 4 && PT.isArch64Bit()) + PT = PT.get32BitArchVariant(); + + return PT.str(); +} + +void sys::printDefaultTargetAndDetectedCPU(raw_ostream &OS) { +#if LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO + std::string CPU = std::string(sys::getHostCPUName()); + if (CPU == "generic") + CPU = "(unknown)"; + OS << " Default target: " << sys::getDefaultTargetTriple() << '\n' + << " Host CPU: " << CPU << '\n'; +#endif +} diff --git a/llvm/lib/TargetParser/LoongArchTargetParser.cpp b/llvm/lib/TargetParser/LoongArchTargetParser.cpp new file mode 100644 index 000000000000..faa8c314fc00 --- /dev/null +++ b/llvm/lib/TargetParser/LoongArchTargetParser.cpp @@ -0,0 +1,49 @@ +//==-- LoongArch64TargetParser - Parser for LoongArch64 features --*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise LoongArch hardware features +// such as CPU/ARCH and extension names. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/LoongArchTargetParser.h" + +using namespace llvm; +using namespace llvm::LoongArch; + +const FeatureInfo AllFeatures[] = { +#define LOONGARCH_FEATURE(NAME, KIND) {NAME, KIND}, +#include "llvm/TargetParser/LoongArchTargetParser.def" +}; + +const ArchInfo AllArchs[] = { +#define LOONGARCH_ARCH(NAME, KIND, FEATURES) \ + {NAME, LoongArch::ArchKind::KIND, FEATURES}, +#include "llvm/TargetParser/LoongArchTargetParser.def" +}; + +LoongArch::ArchKind LoongArch::parseArch(StringRef Arch) { + for (const auto A : AllArchs) + if (A.Name == Arch) + return A.Kind; + + return LoongArch::ArchKind::AK_INVALID; +} + +bool LoongArch::getArchFeatures(StringRef Arch, + std::vector<StringRef> &Features) { + for (const auto A : AllArchs) { + if (A.Name == Arch) { + for (const auto F : AllFeatures) + if ((A.Features & F.Kind) == F.Kind && F.Kind != FK_INVALID) + Features.push_back(F.Name); + return true; + } + } + return false; +} diff --git a/llvm/lib/TargetParser/RISCVTargetParser.cpp b/llvm/lib/TargetParser/RISCVTargetParser.cpp new file mode 100644 index 000000000000..89cd5c082d72 --- /dev/null +++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp @@ -0,0 +1,104 @@ +//===-- RISCVTargetParser.cpp - Parser for target features ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise hardware features +// FOR RISC-V CPUS. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/RISCVTargetParser.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" + +namespace llvm { +namespace RISCV { + +struct CPUInfo { + StringLiteral Name; + CPUKind Kind; + StringLiteral DefaultMarch; + bool isInvalid() const { return DefaultMarch.empty(); } + bool is64Bit() const { return DefaultMarch.starts_with("rv64"); } +}; + +constexpr CPUInfo RISCVCPUInfo[] = { +#define PROC(ENUM, NAME, DEFAULT_MARCH) \ + {NAME, CK_##ENUM, DEFAULT_MARCH}, +#include "llvm/TargetParser/RISCVTargetParserDef.inc" +}; + +bool checkCPUKind(CPUKind Kind, bool IsRV64) { + if (Kind == CK_INVALID) + return false; + return RISCVCPUInfo[static_cast<unsigned>(Kind)].is64Bit() == IsRV64; +} + +bool checkTuneCPUKind(CPUKind Kind, bool IsRV64) { + if (Kind == CK_INVALID) + return false; +#define TUNE_PROC(ENUM, NAME) \ + if (Kind == CK_##ENUM) \ + return true; +#include "llvm/TargetParser/RISCVTargetParserDef.inc" + return RISCVCPUInfo[static_cast<unsigned>(Kind)].is64Bit() == IsRV64; +} + +CPUKind parseCPUKind(StringRef CPU) { + return llvm::StringSwitch<CPUKind>(CPU) +#define PROC(ENUM, NAME, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) +#include "llvm/TargetParser/RISCVTargetParserDef.inc" + .Default(CK_INVALID); +} + +CPUKind parseTuneCPUKind(StringRef TuneCPU, bool IsRV64) { + return llvm::StringSwitch<CPUKind>(TuneCPU) +#define PROC(ENUM, NAME, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) +#define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM) +#include "llvm/TargetParser/RISCVTargetParserDef.inc" + .Default(CK_INVALID); +} + +StringRef getMArchFromMcpu(StringRef CPU) { + CPUKind Kind = parseCPUKind(CPU); + return RISCVCPUInfo[static_cast<unsigned>(Kind)].DefaultMarch; +} + +void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { + for (const auto &C : RISCVCPUInfo) { + if (C.Kind != CK_INVALID && IsRV64 == C.is64Bit()) + Values.emplace_back(C.Name); + } +} + +void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { + for (const auto &C : RISCVCPUInfo) { + if (C.Kind != CK_INVALID && IsRV64 == C.is64Bit()) + Values.emplace_back(C.Name); + } +#define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME)); +#include "llvm/TargetParser/RISCVTargetParserDef.inc" +} + +// Get all features except standard extension feature +bool getCPUFeaturesExceptStdExt(CPUKind Kind, + std::vector<StringRef> &Features) { + const CPUInfo &Info = RISCVCPUInfo[static_cast<unsigned>(Kind)]; + + if (Info.isInvalid()) + return false; + + if (Info.is64Bit()) + Features.push_back("+64bit"); + else + Features.push_back("-64bit"); + + return true; +} + +} // namespace RISCV +} // namespace llvm diff --git a/llvm/lib/TargetParser/TargetParser.cpp b/llvm/lib/TargetParser/TargetParser.cpp new file mode 100644 index 000000000000..e9fccef0433e --- /dev/null +++ b/llvm/lib/TargetParser/TargetParser.cpp @@ -0,0 +1,253 @@ +//===-- TargetParser - Parser for target features ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise hardware features such as +// FPU/CPU/ARCH names as well as specific support such as HDIV, etc. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/TargetParser.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TargetParser/Triple.h" + +using namespace llvm; +using namespace AMDGPU; + +namespace { + +struct GPUInfo { + StringLiteral Name; + StringLiteral CanonicalName; + AMDGPU::GPUKind Kind; + unsigned Features; +}; + +constexpr GPUInfo R600GPUs[] = { + // Name Canonical Kind Features + // Name + {{"r600"}, {"r600"}, GK_R600, FEATURE_NONE }, + {{"rv630"}, {"r600"}, GK_R600, FEATURE_NONE }, + {{"rv635"}, {"r600"}, GK_R600, FEATURE_NONE }, + {{"r630"}, {"r630"}, GK_R630, FEATURE_NONE }, + {{"rs780"}, {"rs880"}, GK_RS880, FEATURE_NONE }, + {{"rs880"}, {"rs880"}, GK_RS880, FEATURE_NONE }, + {{"rv610"}, {"rs880"}, GK_RS880, FEATURE_NONE }, + {{"rv620"}, {"rs880"}, GK_RS880, FEATURE_NONE }, + {{"rv670"}, {"rv670"}, GK_RV670, FEATURE_NONE }, + {{"rv710"}, {"rv710"}, GK_RV710, FEATURE_NONE }, + {{"rv730"}, {"rv730"}, GK_RV730, FEATURE_NONE }, + {{"rv740"}, {"rv770"}, GK_RV770, FEATURE_NONE }, + {{"rv770"}, {"rv770"}, GK_RV770, FEATURE_NONE }, + {{"cedar"}, {"cedar"}, GK_CEDAR, FEATURE_NONE }, + {{"palm"}, {"cedar"}, GK_CEDAR, FEATURE_NONE }, + {{"cypress"}, {"cypress"}, GK_CYPRESS, FEATURE_FMA }, + {{"hemlock"}, {"cypress"}, GK_CYPRESS, FEATURE_FMA }, + {{"juniper"}, {"juniper"}, GK_JUNIPER, FEATURE_NONE }, + {{"redwood"}, {"redwood"}, GK_REDWOOD, FEATURE_NONE }, + {{"sumo"}, {"sumo"}, GK_SUMO, FEATURE_NONE }, + {{"sumo2"}, {"sumo"}, GK_SUMO, FEATURE_NONE }, + {{"barts"}, {"barts"}, GK_BARTS, FEATURE_NONE }, + {{"caicos"}, {"caicos"}, GK_CAICOS, FEATURE_NONE }, + {{"aruba"}, {"cayman"}, GK_CAYMAN, FEATURE_FMA }, + {{"cayman"}, {"cayman"}, GK_CAYMAN, FEATURE_FMA }, + {{"turks"}, {"turks"}, GK_TURKS, FEATURE_NONE } +}; + +// This table should be sorted by the value of GPUKind +// Don't bother listing the implicitly true features +constexpr GPUInfo AMDGCNGPUs[] = { + // Name Canonical Kind Features + // Name + {{"gfx600"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32}, + {{"tahiti"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32}, + {{"gfx601"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, + {{"pitcairn"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, + {{"verde"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, + {{"gfx602"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, + {{"hainan"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, + {{"oland"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, + {{"gfx700"}, {"gfx700"}, GK_GFX700, FEATURE_NONE}, + {{"kaveri"}, {"gfx700"}, GK_GFX700, FEATURE_NONE}, + {{"gfx701"}, {"gfx701"}, GK_GFX701, FEATURE_FAST_FMA_F32}, + {{"hawaii"}, {"gfx701"}, GK_GFX701, FEATURE_FAST_FMA_F32}, + {{"gfx702"}, {"gfx702"}, GK_GFX702, FEATURE_FAST_FMA_F32}, + {{"gfx703"}, {"gfx703"}, GK_GFX703, FEATURE_NONE}, + {{"kabini"}, {"gfx703"}, GK_GFX703, FEATURE_NONE}, + {{"mullins"}, {"gfx703"}, GK_GFX703, FEATURE_NONE}, + {{"gfx704"}, {"gfx704"}, GK_GFX704, FEATURE_NONE}, + {{"bonaire"}, {"gfx704"}, GK_GFX704, FEATURE_NONE}, + {{"gfx705"}, {"gfx705"}, GK_GFX705, FEATURE_NONE}, + {{"gfx801"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"carrizo"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx802"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, + {{"iceland"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, + {{"tonga"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, + {{"gfx803"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, + {{"fiji"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, + {{"polaris10"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, + {{"polaris11"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, + {{"gfx805"}, {"gfx805"}, GK_GFX805, FEATURE_FAST_DENORMAL_F32}, + {{"tongapro"}, {"gfx805"}, GK_GFX805, FEATURE_FAST_DENORMAL_F32}, + {{"gfx810"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"stoney"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx900"}, {"gfx900"}, GK_GFX900, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx902"}, {"gfx902"}, GK_GFX902, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx904"}, {"gfx904"}, GK_GFX904, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx906"}, {"gfx906"}, GK_GFX906, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx908"}, {"gfx908"}, GK_GFX908, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx909"}, {"gfx909"}, GK_GFX909, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx90a"}, {"gfx90a"}, GK_GFX90A, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx90c"}, {"gfx90c"}, GK_GFX90C, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx940"}, {"gfx940"}, GK_GFX940, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx1010"}, {"gfx1010"}, GK_GFX1010, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1012"}, {"gfx1012"}, GK_GFX1012, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1013"}, {"gfx1013"}, GK_GFX1013, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1030"}, {"gfx1030"}, GK_GFX1030, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1031"}, {"gfx1031"}, GK_GFX1031, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1032"}, {"gfx1032"}, GK_GFX1032, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1033"}, {"gfx1033"}, GK_GFX1033, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1034"}, {"gfx1034"}, GK_GFX1034, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1035"}, {"gfx1035"}, GK_GFX1035, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1036"}, {"gfx1036"}, GK_GFX1036, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1100"}, {"gfx1100"}, GK_GFX1100, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1101"}, {"gfx1101"}, GK_GFX1101, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1102"}, {"gfx1102"}, GK_GFX1102, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1103"}, {"gfx1103"}, GK_GFX1103, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, +}; + +const GPUInfo *getArchEntry(AMDGPU::GPUKind AK, ArrayRef<GPUInfo> Table) { + GPUInfo Search = { {""}, {""}, AK, AMDGPU::FEATURE_NONE }; + + auto I = + llvm::lower_bound(Table, Search, [](const GPUInfo &A, const GPUInfo &B) { + return A.Kind < B.Kind; + }); + + if (I == Table.end()) + return nullptr; + return I; +} + +} // namespace + +StringRef llvm::AMDGPU::getArchNameAMDGCN(GPUKind AK) { + if (const auto *Entry = getArchEntry(AK, AMDGCNGPUs)) + return Entry->CanonicalName; + return ""; +} + +StringRef llvm::AMDGPU::getArchNameR600(GPUKind AK) { + if (const auto *Entry = getArchEntry(AK, R600GPUs)) + return Entry->CanonicalName; + return ""; +} + +AMDGPU::GPUKind llvm::AMDGPU::parseArchAMDGCN(StringRef CPU) { + for (const auto &C : AMDGCNGPUs) { + if (CPU == C.Name) + return C.Kind; + } + + return AMDGPU::GPUKind::GK_NONE; +} + +AMDGPU::GPUKind llvm::AMDGPU::parseArchR600(StringRef CPU) { + for (const auto &C : R600GPUs) { + if (CPU == C.Name) + return C.Kind; + } + + return AMDGPU::GPUKind::GK_NONE; +} + +unsigned AMDGPU::getArchAttrAMDGCN(GPUKind AK) { + if (const auto *Entry = getArchEntry(AK, AMDGCNGPUs)) + return Entry->Features; + return FEATURE_NONE; +} + +unsigned AMDGPU::getArchAttrR600(GPUKind AK) { + if (const auto *Entry = getArchEntry(AK, R600GPUs)) + return Entry->Features; + return FEATURE_NONE; +} + +void AMDGPU::fillValidArchListAMDGCN(SmallVectorImpl<StringRef> &Values) { + // XXX: Should this only report unique canonical names? + for (const auto &C : AMDGCNGPUs) + Values.push_back(C.Name); +} + +void AMDGPU::fillValidArchListR600(SmallVectorImpl<StringRef> &Values) { + for (const auto &C : R600GPUs) + Values.push_back(C.Name); +} + +AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) { + AMDGPU::GPUKind AK = parseArchAMDGCN(GPU); + if (AK == AMDGPU::GPUKind::GK_NONE) { + if (GPU == "generic-hsa") + return {7, 0, 0}; + if (GPU == "generic") + return {6, 0, 0}; + return {0, 0, 0}; + } + + switch (AK) { + case GK_GFX600: return {6, 0, 0}; + case GK_GFX601: return {6, 0, 1}; + case GK_GFX602: return {6, 0, 2}; + case GK_GFX700: return {7, 0, 0}; + case GK_GFX701: return {7, 0, 1}; + case GK_GFX702: return {7, 0, 2}; + case GK_GFX703: return {7, 0, 3}; + case GK_GFX704: return {7, 0, 4}; + case GK_GFX705: return {7, 0, 5}; + case GK_GFX801: return {8, 0, 1}; + case GK_GFX802: return {8, 0, 2}; + case GK_GFX803: return {8, 0, 3}; + case GK_GFX805: return {8, 0, 5}; + case GK_GFX810: return {8, 1, 0}; + case GK_GFX900: return {9, 0, 0}; + case GK_GFX902: return {9, 0, 2}; + case GK_GFX904: return {9, 0, 4}; + case GK_GFX906: return {9, 0, 6}; + case GK_GFX908: return {9, 0, 8}; + case GK_GFX909: return {9, 0, 9}; + case GK_GFX90A: return {9, 0, 10}; + case GK_GFX90C: return {9, 0, 12}; + case GK_GFX940: return {9, 4, 0}; + case GK_GFX1010: return {10, 1, 0}; + case GK_GFX1011: return {10, 1, 1}; + case GK_GFX1012: return {10, 1, 2}; + case GK_GFX1013: return {10, 1, 3}; + case GK_GFX1030: return {10, 3, 0}; + case GK_GFX1031: return {10, 3, 1}; + case GK_GFX1032: return {10, 3, 2}; + case GK_GFX1033: return {10, 3, 3}; + case GK_GFX1034: return {10, 3, 4}; + case GK_GFX1035: return {10, 3, 5}; + case GK_GFX1036: return {10, 3, 6}; + case GK_GFX1100: return {11, 0, 0}; + case GK_GFX1101: return {11, 0, 1}; + case GK_GFX1102: return {11, 0, 2}; + case GK_GFX1103: return {11, 0, 3}; + default: return {0, 0, 0}; + } +} + +StringRef AMDGPU::getCanonicalArchName(const Triple &T, StringRef Arch) { + assert(T.isAMDGPU()); + auto ProcKind = T.isAMDGCN() ? parseArchAMDGCN(Arch) : parseArchR600(Arch); + if (ProcKind == GK_NONE) + return StringRef(); + + return T.isAMDGCN() ? getArchNameAMDGCN(ProcKind) : getArchNameR600(ProcKind); +} diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp new file mode 100644 index 000000000000..a68035989a93 --- /dev/null +++ b/llvm/lib/TargetParser/Triple.cpp @@ -0,0 +1,1923 @@ +//===--- Triple.cpp - Target triple helper class --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/Triple.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/TargetParser/Host.h" +#include <cassert> +#include <cstring> +using namespace llvm; + +StringRef Triple::getArchTypeName(ArchType Kind) { + switch (Kind) { + case UnknownArch: return "unknown"; + + case aarch64: return "aarch64"; + case aarch64_32: return "aarch64_32"; + case aarch64_be: return "aarch64_be"; + case amdgcn: return "amdgcn"; + case amdil64: return "amdil64"; + case amdil: return "amdil"; + case arc: return "arc"; + case arm: return "arm"; + case armeb: return "armeb"; + case avr: return "avr"; + case bpfeb: return "bpfeb"; + case bpfel: return "bpfel"; + case csky: return "csky"; + case dxil: return "dxil"; + case hexagon: return "hexagon"; + case hsail64: return "hsail64"; + case hsail: return "hsail"; + case kalimba: return "kalimba"; + case lanai: return "lanai"; + case le32: return "le32"; + case le64: return "le64"; + case loongarch32: return "loongarch32"; + case loongarch64: return "loongarch64"; + case m68k: return "m68k"; + case mips64: return "mips64"; + case mips64el: return "mips64el"; + case mips: return "mips"; + case mipsel: return "mipsel"; + case msp430: return "msp430"; + case nvptx64: return "nvptx64"; + case nvptx: return "nvptx"; + case ppc64: return "powerpc64"; + case ppc64le: return "powerpc64le"; + case ppc: return "powerpc"; + case ppcle: return "powerpcle"; + case r600: return "r600"; + case renderscript32: return "renderscript32"; + case renderscript64: return "renderscript64"; + case riscv32: return "riscv32"; + case riscv64: return "riscv64"; + case shave: return "shave"; + case sparc: return "sparc"; + case sparcel: return "sparcel"; + case sparcv9: return "sparcv9"; + case spir64: return "spir64"; + case spir: return "spir"; + case spirv32: return "spirv32"; + case spirv64: return "spirv64"; + case systemz: return "s390x"; + case tce: return "tce"; + case tcele: return "tcele"; + case thumb: return "thumb"; + case thumbeb: return "thumbeb"; + case ve: return "ve"; + case wasm32: return "wasm32"; + case wasm64: return "wasm64"; + case x86: return "i386"; + case x86_64: return "x86_64"; + case xcore: return "xcore"; + case xtensa: return "xtensa"; + } + + llvm_unreachable("Invalid ArchType!"); +} + +StringRef Triple::getArchTypePrefix(ArchType Kind) { + switch (Kind) { + default: + return StringRef(); + + case aarch64: + case aarch64_be: + case aarch64_32: return "aarch64"; + + case arc: return "arc"; + + case arm: + case armeb: + case thumb: + case thumbeb: return "arm"; + + case avr: return "avr"; + + case ppc64: + case ppc64le: + case ppc: + case ppcle: return "ppc"; + + case m68k: return "m68k"; + + case mips: + case mipsel: + case mips64: + case mips64el: return "mips"; + + case hexagon: return "hexagon"; + + case amdgcn: return "amdgcn"; + case r600: return "r600"; + + case bpfel: + case bpfeb: return "bpf"; + + case sparcv9: + case sparcel: + case sparc: return "sparc"; + + case systemz: return "s390"; + + case x86: + case x86_64: return "x86"; + + case xcore: return "xcore"; + + // NVPTX intrinsics are namespaced under nvvm. + case nvptx: return "nvvm"; + case nvptx64: return "nvvm"; + + case le32: return "le32"; + case le64: return "le64"; + + case amdil: + case amdil64: return "amdil"; + + case hsail: + case hsail64: return "hsail"; + + case spir: + case spir64: return "spir"; + + case spirv32: + case spirv64: return "spirv"; + + case kalimba: return "kalimba"; + case lanai: return "lanai"; + case shave: return "shave"; + case wasm32: + case wasm64: return "wasm"; + + case riscv32: + case riscv64: return "riscv"; + + case ve: return "ve"; + case csky: return "csky"; + + case loongarch32: + case loongarch64: return "loongarch"; + + case dxil: return "dx"; + + case xtensa: return "xtensa"; + } +} + +StringRef Triple::getVendorTypeName(VendorType Kind) { + switch (Kind) { + case UnknownVendor: return "unknown"; + + case AMD: return "amd"; + case Apple: return "apple"; + case CSR: return "csr"; + case Freescale: return "fsl"; + case IBM: return "ibm"; + case ImaginationTechnologies: return "img"; + case Mesa: return "mesa"; + case MipsTechnologies: return "mti"; + case Myriad: return "myriad"; + case NVIDIA: return "nvidia"; + case OpenEmbedded: return "oe"; + case PC: return "pc"; + case SCEI: return "scei"; + case SUSE: return "suse"; + } + + llvm_unreachable("Invalid VendorType!"); +} + +StringRef Triple::getOSTypeName(OSType Kind) { + switch (Kind) { + case UnknownOS: return "unknown"; + + case AIX: return "aix"; + case AMDHSA: return "amdhsa"; + case AMDPAL: return "amdpal"; + case Ananas: return "ananas"; + case CUDA: return "cuda"; + case CloudABI: return "cloudabi"; + case Contiki: return "contiki"; + case Darwin: return "darwin"; + case DragonFly: return "dragonfly"; + case DriverKit: return "driverkit"; + case ELFIAMCU: return "elfiamcu"; + case Emscripten: return "emscripten"; + case FreeBSD: return "freebsd"; + case Fuchsia: return "fuchsia"; + case Haiku: return "haiku"; + case HermitCore: return "hermit"; + case Hurd: return "hurd"; + case IOS: return "ios"; + case KFreeBSD: return "kfreebsd"; + case Linux: return "linux"; + case Lv2: return "lv2"; + case MacOSX: return "macosx"; + case Mesa3D: return "mesa3d"; + case Minix: return "minix"; + case NVCL: return "nvcl"; + case NaCl: return "nacl"; + case NetBSD: return "netbsd"; + case OpenBSD: return "openbsd"; + case PS4: return "ps4"; + case PS5: return "ps5"; + case RTEMS: return "rtems"; + case Solaris: return "solaris"; + case TvOS: return "tvos"; + case WASI: return "wasi"; + case WatchOS: return "watchos"; + case Win32: return "windows"; + case ZOS: return "zos"; + case ShaderModel: return "shadermodel"; + } + + llvm_unreachable("Invalid OSType"); +} + +StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { + switch (Kind) { + case UnknownEnvironment: return "unknown"; + case Android: return "android"; + case CODE16: return "code16"; + case CoreCLR: return "coreclr"; + case Cygnus: return "cygnus"; + case EABI: return "eabi"; + case EABIHF: return "eabihf"; + case GNU: return "gnu"; + case GNUABI64: return "gnuabi64"; + case GNUABIN32: return "gnuabin32"; + case GNUEABI: return "gnueabi"; + case GNUEABIHF: return "gnueabihf"; + case GNUF32: return "gnuf32"; + case GNUF64: return "gnuf64"; + case GNUSF: return "gnusf"; + case GNUX32: return "gnux32"; + case GNUILP32: return "gnu_ilp32"; + case Itanium: return "itanium"; + case MSVC: return "msvc"; + case MacABI: return "macabi"; + case Musl: return "musl"; + case MuslEABI: return "musleabi"; + case MuslEABIHF: return "musleabihf"; + case MuslX32: return "muslx32"; + case Simulator: return "simulator"; + case Pixel: return "pixel"; + case Vertex: return "vertex"; + case Geometry: return "geometry"; + case Hull: return "hull"; + case Domain: return "domain"; + case Compute: return "compute"; + case Library: return "library"; + case RayGeneration: return "raygeneration"; + case Intersection: return "intersection"; + case AnyHit: return "anyhit"; + case ClosestHit: return "closesthit"; + case Miss: return "miss"; + case Callable: return "callable"; + case Mesh: return "mesh"; + case Amplification: return "amplification"; + } + + llvm_unreachable("Invalid EnvironmentType!"); +} + +static Triple::ArchType parseBPFArch(StringRef ArchName) { + if (ArchName.equals("bpf")) { + if (sys::IsLittleEndianHost) + return Triple::bpfel; + else + return Triple::bpfeb; + } else if (ArchName.equals("bpf_be") || ArchName.equals("bpfeb")) { + return Triple::bpfeb; + } else if (ArchName.equals("bpf_le") || ArchName.equals("bpfel")) { + return Triple::bpfel; + } else { + return Triple::UnknownArch; + } +} + +Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { + Triple::ArchType BPFArch(parseBPFArch(Name)); + return StringSwitch<Triple::ArchType>(Name) + .Case("aarch64", aarch64) + .Case("aarch64_be", aarch64_be) + .Case("aarch64_32", aarch64_32) + .Case("arc", arc) + .Case("arm64", aarch64) // "arm64" is an alias for "aarch64" + .Case("arm64_32", aarch64_32) + .Case("arm", arm) + .Case("armeb", armeb) + .Case("avr", avr) + .StartsWith("bpf", BPFArch) + .Case("m68k", m68k) + .Case("mips", mips) + .Case("mipsel", mipsel) + .Case("mips64", mips64) + .Case("mips64el", mips64el) + .Case("msp430", msp430) + .Case("ppc64", ppc64) + .Case("ppc32", ppc) + .Case("ppc", ppc) + .Case("ppc32le", ppcle) + .Case("ppcle", ppcle) + .Case("ppc64le", ppc64le) + .Case("r600", r600) + .Case("amdgcn", amdgcn) + .Case("riscv32", riscv32) + .Case("riscv64", riscv64) + .Case("hexagon", hexagon) + .Case("sparc", sparc) + .Case("sparcel", sparcel) + .Case("sparcv9", sparcv9) + .Case("s390x", systemz) + .Case("systemz", systemz) + .Case("tce", tce) + .Case("tcele", tcele) + .Case("thumb", thumb) + .Case("thumbeb", thumbeb) + .Case("x86", x86) + .Case("i386", x86) + .Case("x86-64", x86_64) + .Case("xcore", xcore) + .Case("nvptx", nvptx) + .Case("nvptx64", nvptx64) + .Case("le32", le32) + .Case("le64", le64) + .Case("amdil", amdil) + .Case("amdil64", amdil64) + .Case("hsail", hsail) + .Case("hsail64", hsail64) + .Case("spir", spir) + .Case("spir64", spir64) + .Case("spirv32", spirv32) + .Case("spirv64", spirv64) + .Case("kalimba", kalimba) + .Case("lanai", lanai) + .Case("shave", shave) + .Case("wasm32", wasm32) + .Case("wasm64", wasm64) + .Case("renderscript32", renderscript32) + .Case("renderscript64", renderscript64) + .Case("ve", ve) + .Case("csky", csky) + .Case("loongarch32", loongarch32) + .Case("loongarch64", loongarch64) + .Case("dxil", dxil) + .Case("xtensa", xtensa) + .Default(UnknownArch); +} + +static Triple::ArchType parseARMArch(StringRef ArchName) { + ARM::ISAKind ISA = ARM::parseArchISA(ArchName); + ARM::EndianKind ENDIAN = ARM::parseArchEndian(ArchName); + + Triple::ArchType arch = Triple::UnknownArch; + switch (ENDIAN) { + case ARM::EndianKind::LITTLE: { + switch (ISA) { + case ARM::ISAKind::ARM: + arch = Triple::arm; + break; + case ARM::ISAKind::THUMB: + arch = Triple::thumb; + break; + case ARM::ISAKind::AARCH64: + arch = Triple::aarch64; + break; + case ARM::ISAKind::INVALID: + break; + } + break; + } + case ARM::EndianKind::BIG: { + switch (ISA) { + case ARM::ISAKind::ARM: + arch = Triple::armeb; + break; + case ARM::ISAKind::THUMB: + arch = Triple::thumbeb; + break; + case ARM::ISAKind::AARCH64: + arch = Triple::aarch64_be; + break; + case ARM::ISAKind::INVALID: + break; + } + break; + } + case ARM::EndianKind::INVALID: { + break; + } + } + + ArchName = ARM::getCanonicalArchName(ArchName); + if (ArchName.empty()) + return Triple::UnknownArch; + + // Thumb only exists in v4+ + if (ISA == ARM::ISAKind::THUMB && + (ArchName.startswith("v2") || ArchName.startswith("v3"))) + return Triple::UnknownArch; + + // Thumb only for v6m + ARM::ProfileKind Profile = ARM::parseArchProfile(ArchName); + unsigned Version = ARM::parseArchVersion(ArchName); + if (Profile == ARM::ProfileKind::M && Version == 6) { + if (ENDIAN == ARM::EndianKind::BIG) + return Triple::thumbeb; + else + return Triple::thumb; + } + + return arch; +} + +static Triple::ArchType parseArch(StringRef ArchName) { + auto AT = StringSwitch<Triple::ArchType>(ArchName) + .Cases("i386", "i486", "i586", "i686", Triple::x86) + // FIXME: Do we need to support these? + .Cases("i786", "i886", "i986", Triple::x86) + .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64) + .Cases("powerpc", "powerpcspe", "ppc", "ppc32", Triple::ppc) + .Cases("powerpcle", "ppcle", "ppc32le", Triple::ppcle) + .Cases("powerpc64", "ppu", "ppc64", Triple::ppc64) + .Cases("powerpc64le", "ppc64le", Triple::ppc64le) + .Case("xscale", Triple::arm) + .Case("xscaleeb", Triple::armeb) + .Case("aarch64", Triple::aarch64) + .Case("aarch64_be", Triple::aarch64_be) + .Case("aarch64_32", Triple::aarch64_32) + .Case("arc", Triple::arc) + .Case("arm64", Triple::aarch64) + .Case("arm64_32", Triple::aarch64_32) + .Case("arm64e", Triple::aarch64) + .Case("arm64ec", Triple::aarch64) + .Case("arm", Triple::arm) + .Case("armeb", Triple::armeb) + .Case("thumb", Triple::thumb) + .Case("thumbeb", Triple::thumbeb) + .Case("avr", Triple::avr) + .Case("m68k", Triple::m68k) + .Case("msp430", Triple::msp430) + .Cases("mips", "mipseb", "mipsallegrex", "mipsisa32r6", + "mipsr6", Triple::mips) + .Cases("mipsel", "mipsallegrexel", "mipsisa32r6el", "mipsr6el", + Triple::mipsel) + .Cases("mips64", "mips64eb", "mipsn32", "mipsisa64r6", + "mips64r6", "mipsn32r6", Triple::mips64) + .Cases("mips64el", "mipsn32el", "mipsisa64r6el", "mips64r6el", + "mipsn32r6el", Triple::mips64el) + .Case("r600", Triple::r600) + .Case("amdgcn", Triple::amdgcn) + .Case("riscv32", Triple::riscv32) + .Case("riscv64", Triple::riscv64) + .Case("hexagon", Triple::hexagon) + .Cases("s390x", "systemz", Triple::systemz) + .Case("sparc", Triple::sparc) + .Case("sparcel", Triple::sparcel) + .Cases("sparcv9", "sparc64", Triple::sparcv9) + .Case("tce", Triple::tce) + .Case("tcele", Triple::tcele) + .Case("xcore", Triple::xcore) + .Case("nvptx", Triple::nvptx) + .Case("nvptx64", Triple::nvptx64) + .Case("le32", Triple::le32) + .Case("le64", Triple::le64) + .Case("amdil", Triple::amdil) + .Case("amdil64", Triple::amdil64) + .Case("hsail", Triple::hsail) + .Case("hsail64", Triple::hsail64) + .Case("spir", Triple::spir) + .Case("spir64", Triple::spir64) + .Cases("spirv32", "spirv32v1.0", "spirv32v1.1", "spirv32v1.2", + "spirv32v1.3", "spirv32v1.4", "spirv32v1.5", Triple::spirv32) + .Cases("spirv64", "spirv64v1.0", "spirv64v1.1", "spirv64v1.2", + "spirv64v1.3", "spirv64v1.4", "spirv64v1.5", Triple::spirv64) + .StartsWith("kalimba", Triple::kalimba) + .Case("lanai", Triple::lanai) + .Case("renderscript32", Triple::renderscript32) + .Case("renderscript64", Triple::renderscript64) + .Case("shave", Triple::shave) + .Case("ve", Triple::ve) + .Case("wasm32", Triple::wasm32) + .Case("wasm64", Triple::wasm64) + .Case("csky", Triple::csky) + .Case("loongarch32", Triple::loongarch32) + .Case("loongarch64", Triple::loongarch64) + .Case("dxil", Triple::dxil) + .Case("xtensa", Triple::xtensa) + .Default(Triple::UnknownArch); + + // Some architectures require special parsing logic just to compute the + // ArchType result. + if (AT == Triple::UnknownArch) { + if (ArchName.startswith("arm") || ArchName.startswith("thumb") || + ArchName.startswith("aarch64")) + return parseARMArch(ArchName); + if (ArchName.startswith("bpf")) + return parseBPFArch(ArchName); + } + + return AT; +} + +static Triple::VendorType parseVendor(StringRef VendorName) { + return StringSwitch<Triple::VendorType>(VendorName) + .Case("apple", Triple::Apple) + .Case("pc", Triple::PC) + .Case("scei", Triple::SCEI) + .Case("sie", Triple::SCEI) + .Case("fsl", Triple::Freescale) + .Case("ibm", Triple::IBM) + .Case("img", Triple::ImaginationTechnologies) + .Case("mti", Triple::MipsTechnologies) + .Case("nvidia", Triple::NVIDIA) + .Case("csr", Triple::CSR) + .Case("myriad", Triple::Myriad) + .Case("amd", Triple::AMD) + .Case("mesa", Triple::Mesa) + .Case("suse", Triple::SUSE) + .Case("oe", Triple::OpenEmbedded) + .Default(Triple::UnknownVendor); +} + +static Triple::OSType parseOS(StringRef OSName) { + return StringSwitch<Triple::OSType>(OSName) + .StartsWith("ananas", Triple::Ananas) + .StartsWith("cloudabi", Triple::CloudABI) + .StartsWith("darwin", Triple::Darwin) + .StartsWith("dragonfly", Triple::DragonFly) + .StartsWith("freebsd", Triple::FreeBSD) + .StartsWith("fuchsia", Triple::Fuchsia) + .StartsWith("ios", Triple::IOS) + .StartsWith("kfreebsd", Triple::KFreeBSD) + .StartsWith("linux", Triple::Linux) + .StartsWith("lv2", Triple::Lv2) + .StartsWith("macos", Triple::MacOSX) + .StartsWith("netbsd", Triple::NetBSD) + .StartsWith("openbsd", Triple::OpenBSD) + .StartsWith("solaris", Triple::Solaris) + .StartsWith("win32", Triple::Win32) + .StartsWith("windows", Triple::Win32) + .StartsWith("zos", Triple::ZOS) + .StartsWith("haiku", Triple::Haiku) + .StartsWith("minix", Triple::Minix) + .StartsWith("rtems", Triple::RTEMS) + .StartsWith("nacl", Triple::NaCl) + .StartsWith("aix", Triple::AIX) + .StartsWith("cuda", Triple::CUDA) + .StartsWith("nvcl", Triple::NVCL) + .StartsWith("amdhsa", Triple::AMDHSA) + .StartsWith("ps4", Triple::PS4) + .StartsWith("ps5", Triple::PS5) + .StartsWith("elfiamcu", Triple::ELFIAMCU) + .StartsWith("tvos", Triple::TvOS) + .StartsWith("watchos", Triple::WatchOS) + .StartsWith("driverkit", Triple::DriverKit) + .StartsWith("mesa3d", Triple::Mesa3D) + .StartsWith("contiki", Triple::Contiki) + .StartsWith("amdpal", Triple::AMDPAL) + .StartsWith("hermit", Triple::HermitCore) + .StartsWith("hurd", Triple::Hurd) + .StartsWith("wasi", Triple::WASI) + .StartsWith("emscripten", Triple::Emscripten) + .StartsWith("shadermodel", Triple::ShaderModel) + .Default(Triple::UnknownOS); +} + +static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { + return StringSwitch<Triple::EnvironmentType>(EnvironmentName) + .StartsWith("eabihf", Triple::EABIHF) + .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabin32", Triple::GNUABIN32) + .StartsWith("gnuabi64", Triple::GNUABI64) + .StartsWith("gnueabihf", Triple::GNUEABIHF) + .StartsWith("gnueabi", Triple::GNUEABI) + .StartsWith("gnuf32", Triple::GNUF32) + .StartsWith("gnuf64", Triple::GNUF64) + .StartsWith("gnusf", Triple::GNUSF) + .StartsWith("gnux32", Triple::GNUX32) + .StartsWith("gnu_ilp32", Triple::GNUILP32) + .StartsWith("code16", Triple::CODE16) + .StartsWith("gnu", Triple::GNU) + .StartsWith("android", Triple::Android) + .StartsWith("musleabihf", Triple::MuslEABIHF) + .StartsWith("musleabi", Triple::MuslEABI) + .StartsWith("muslx32", Triple::MuslX32) + .StartsWith("musl", Triple::Musl) + .StartsWith("msvc", Triple::MSVC) + .StartsWith("itanium", Triple::Itanium) + .StartsWith("cygnus", Triple::Cygnus) + .StartsWith("coreclr", Triple::CoreCLR) + .StartsWith("simulator", Triple::Simulator) + .StartsWith("macabi", Triple::MacABI) + .StartsWith("pixel", Triple::Pixel) + .StartsWith("vertex", Triple::Vertex) + .StartsWith("geometry", Triple::Geometry) + .StartsWith("hull", Triple::Hull) + .StartsWith("domain", Triple::Domain) + .StartsWith("compute", Triple::Compute) + .StartsWith("library", Triple::Library) + .StartsWith("raygeneration", Triple::RayGeneration) + .StartsWith("intersection", Triple::Intersection) + .StartsWith("anyhit", Triple::AnyHit) + .StartsWith("closesthit", Triple::ClosestHit) + .StartsWith("miss", Triple::Miss) + .StartsWith("callable", Triple::Callable) + .StartsWith("mesh", Triple::Mesh) + .StartsWith("amplification", Triple::Amplification) + .Default(Triple::UnknownEnvironment); +} + +static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { + return StringSwitch<Triple::ObjectFormatType>(EnvironmentName) + // "xcoff" must come before "coff" because of the order-dependendent + // pattern matching. + .EndsWith("xcoff", Triple::XCOFF) + .EndsWith("coff", Triple::COFF) + .EndsWith("elf", Triple::ELF) + .EndsWith("goff", Triple::GOFF) + .EndsWith("macho", Triple::MachO) + .EndsWith("wasm", Triple::Wasm) + .EndsWith("spirv", Triple::SPIRV) + .Default(Triple::UnknownObjectFormat); +} + +static Triple::SubArchType parseSubArch(StringRef SubArchName) { + if (SubArchName.startswith("mips") && + (SubArchName.endswith("r6el") || SubArchName.endswith("r6"))) + return Triple::MipsSubArch_r6; + + if (SubArchName == "powerpcspe") + return Triple::PPCSubArch_spe; + + if (SubArchName == "arm64e") + return Triple::AArch64SubArch_arm64e; + + if (SubArchName == "arm64ec") + return Triple::AArch64SubArch_arm64ec; + + if (SubArchName.startswith("spirv")) + return StringSwitch<Triple::SubArchType>(SubArchName) + .EndsWith("v1.0", Triple::SPIRVSubArch_v10) + .EndsWith("v1.1", Triple::SPIRVSubArch_v11) + .EndsWith("v1.2", Triple::SPIRVSubArch_v12) + .EndsWith("v1.3", Triple::SPIRVSubArch_v13) + .EndsWith("v1.4", Triple::SPIRVSubArch_v14) + .EndsWith("v1.5", Triple::SPIRVSubArch_v15) + .Default(Triple::NoSubArch); + + StringRef ARMSubArch = ARM::getCanonicalArchName(SubArchName); + + // For now, this is the small part. Early return. + if (ARMSubArch.empty()) + return StringSwitch<Triple::SubArchType>(SubArchName) + .EndsWith("kalimba3", Triple::KalimbaSubArch_v3) + .EndsWith("kalimba4", Triple::KalimbaSubArch_v4) + .EndsWith("kalimba5", Triple::KalimbaSubArch_v5) + .Default(Triple::NoSubArch); + + // ARM sub arch. + switch(ARM::parseArch(ARMSubArch)) { + case ARM::ArchKind::ARMV4: + return Triple::NoSubArch; + case ARM::ArchKind::ARMV4T: + return Triple::ARMSubArch_v4t; + case ARM::ArchKind::ARMV5T: + return Triple::ARMSubArch_v5; + case ARM::ArchKind::ARMV5TE: + case ARM::ArchKind::IWMMXT: + case ARM::ArchKind::IWMMXT2: + case ARM::ArchKind::XSCALE: + case ARM::ArchKind::ARMV5TEJ: + return Triple::ARMSubArch_v5te; + case ARM::ArchKind::ARMV6: + return Triple::ARMSubArch_v6; + case ARM::ArchKind::ARMV6K: + case ARM::ArchKind::ARMV6KZ: + return Triple::ARMSubArch_v6k; + case ARM::ArchKind::ARMV6T2: + return Triple::ARMSubArch_v6t2; + case ARM::ArchKind::ARMV6M: + return Triple::ARMSubArch_v6m; + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7R: + return Triple::ARMSubArch_v7; + case ARM::ArchKind::ARMV7VE: + return Triple::ARMSubArch_v7ve; + case ARM::ArchKind::ARMV7K: + return Triple::ARMSubArch_v7k; + case ARM::ArchKind::ARMV7M: + return Triple::ARMSubArch_v7m; + case ARM::ArchKind::ARMV7S: + return Triple::ARMSubArch_v7s; + case ARM::ArchKind::ARMV7EM: + return Triple::ARMSubArch_v7em; + case ARM::ArchKind::ARMV8A: + return Triple::ARMSubArch_v8; + case ARM::ArchKind::ARMV8_1A: + return Triple::ARMSubArch_v8_1a; + case ARM::ArchKind::ARMV8_2A: + return Triple::ARMSubArch_v8_2a; + case ARM::ArchKind::ARMV8_3A: + return Triple::ARMSubArch_v8_3a; + case ARM::ArchKind::ARMV8_4A: + return Triple::ARMSubArch_v8_4a; + case ARM::ArchKind::ARMV8_5A: + return Triple::ARMSubArch_v8_5a; + case ARM::ArchKind::ARMV8_6A: + return Triple::ARMSubArch_v8_6a; + case ARM::ArchKind::ARMV8_7A: + return Triple::ARMSubArch_v8_7a; + case ARM::ArchKind::ARMV8_8A: + return Triple::ARMSubArch_v8_8a; + case ARM::ArchKind::ARMV8_9A: + return Triple::ARMSubArch_v8_9a; + case ARM::ArchKind::ARMV9A: + return Triple::ARMSubArch_v9; + case ARM::ArchKind::ARMV9_1A: + return Triple::ARMSubArch_v9_1a; + case ARM::ArchKind::ARMV9_2A: + return Triple::ARMSubArch_v9_2a; + case ARM::ArchKind::ARMV9_3A: + return Triple::ARMSubArch_v9_3a; + case ARM::ArchKind::ARMV9_4A: + return Triple::ARMSubArch_v9_4a; + case ARM::ArchKind::ARMV8R: + return Triple::ARMSubArch_v8r; + case ARM::ArchKind::ARMV8MBaseline: + return Triple::ARMSubArch_v8m_baseline; + case ARM::ArchKind::ARMV8MMainline: + return Triple::ARMSubArch_v8m_mainline; + case ARM::ArchKind::ARMV8_1MMainline: + return Triple::ARMSubArch_v8_1m_mainline; + default: + return Triple::NoSubArch; + } +} + +static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) { + switch (Kind) { + case Triple::UnknownObjectFormat: + return ""; + case Triple::COFF: + return "coff"; + case Triple::ELF: + return "elf"; + case Triple::GOFF: + return "goff"; + case Triple::MachO: + return "macho"; + case Triple::Wasm: + return "wasm"; + case Triple::XCOFF: + return "xcoff"; + case Triple::DXContainer: + return "dxcontainer"; + case Triple::SPIRV: + return "spirv"; + } + llvm_unreachable("unknown object format type"); +} + +static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { + switch (T.getArch()) { + case Triple::UnknownArch: + case Triple::aarch64: + case Triple::aarch64_32: + case Triple::arm: + case Triple::thumb: + case Triple::x86: + case Triple::x86_64: + if (T.isOSDarwin()) + return Triple::MachO; + else if (T.isOSWindows()) + return Triple::COFF; + return Triple::ELF; + + case Triple::aarch64_be: + case Triple::amdgcn: + case Triple::amdil64: + case Triple::amdil: + case Triple::arc: + case Triple::armeb: + case Triple::avr: + case Triple::bpfeb: + case Triple::bpfel: + case Triple::csky: + case Triple::hexagon: + case Triple::hsail64: + case Triple::hsail: + case Triple::kalimba: + case Triple::lanai: + case Triple::le32: + case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: + case Triple::m68k: + case Triple::mips64: + case Triple::mips64el: + case Triple::mips: + case Triple::mipsel: + case Triple::msp430: + case Triple::nvptx64: + case Triple::nvptx: + case Triple::ppc64le: + case Triple::ppcle: + case Triple::r600: + case Triple::renderscript32: + case Triple::renderscript64: + case Triple::riscv32: + case Triple::riscv64: + case Triple::shave: + case Triple::sparc: + case Triple::sparcel: + case Triple::sparcv9: + case Triple::spir64: + case Triple::spir: + case Triple::tce: + case Triple::tcele: + case Triple::thumbeb: + case Triple::ve: + case Triple::xcore: + case Triple::xtensa: + return Triple::ELF; + + case Triple::ppc64: + case Triple::ppc: + if (T.isOSAIX()) + return Triple::XCOFF; + return Triple::ELF; + + case Triple::systemz: + if (T.isOSzOS()) + return Triple::GOFF; + return Triple::ELF; + + case Triple::wasm32: + case Triple::wasm64: + return Triple::Wasm; + + case Triple::spirv32: + case Triple::spirv64: + return Triple::SPIRV; + + case Triple::dxil: + return Triple::DXContainer; + } + llvm_unreachable("unknown architecture"); +} + +/// Construct a triple from the string representation provided. +/// +/// This stores the string representation and parses the various pieces into +/// enum members. +Triple::Triple(const Twine &Str) + : Data(Str.str()), Arch(UnknownArch), SubArch(NoSubArch), + Vendor(UnknownVendor), OS(UnknownOS), Environment(UnknownEnvironment), + ObjectFormat(UnknownObjectFormat) { + // Do minimal parsing by hand here. + SmallVector<StringRef, 4> Components; + StringRef(Data).split(Components, '-', /*MaxSplit*/ 3); + if (Components.size() > 0) { + Arch = parseArch(Components[0]); + SubArch = parseSubArch(Components[0]); + if (Components.size() > 1) { + Vendor = parseVendor(Components[1]); + if (Components.size() > 2) { + OS = parseOS(Components[2]); + if (Components.size() > 3) { + Environment = parseEnvironment(Components[3]); + ObjectFormat = parseFormat(Components[3]); + } + } + } else { + Environment = + StringSwitch<Triple::EnvironmentType>(Components[0]) + .StartsWith("mipsn32", Triple::GNUABIN32) + .StartsWith("mips64", Triple::GNUABI64) + .StartsWith("mipsisa64", Triple::GNUABI64) + .StartsWith("mipsisa32", Triple::GNU) + .Cases("mips", "mipsel", "mipsr6", "mipsr6el", Triple::GNU) + .Default(UnknownEnvironment); + } + } + if (ObjectFormat == UnknownObjectFormat) + ObjectFormat = getDefaultFormat(*this); +} + +/// Construct a triple from string representations of the architecture, +/// vendor, and OS. +/// +/// This joins each argument into a canonical string representation and parses +/// them into enum members. It leaves the environment unknown and omits it from +/// the string representation. +Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr) + : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr).str()), + Arch(parseArch(ArchStr.str())), + SubArch(parseSubArch(ArchStr.str())), + Vendor(parseVendor(VendorStr.str())), + OS(parseOS(OSStr.str())), + Environment(), ObjectFormat(Triple::UnknownObjectFormat) { + ObjectFormat = getDefaultFormat(*this); +} + +/// Construct a triple from string representations of the architecture, +/// vendor, OS, and environment. +/// +/// This joins each argument into a canonical string representation and parses +/// them into enum members. +Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr, + const Twine &EnvironmentStr) + : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr + Twine('-') + + EnvironmentStr).str()), + Arch(parseArch(ArchStr.str())), + SubArch(parseSubArch(ArchStr.str())), + Vendor(parseVendor(VendorStr.str())), + OS(parseOS(OSStr.str())), + Environment(parseEnvironment(EnvironmentStr.str())), + ObjectFormat(parseFormat(EnvironmentStr.str())) { + if (ObjectFormat == Triple::UnknownObjectFormat) + ObjectFormat = getDefaultFormat(*this); +} + +std::string Triple::normalize(StringRef Str) { + bool IsMinGW32 = false; + bool IsCygwin = false; + + // Parse into components. + SmallVector<StringRef, 4> Components; + Str.split(Components, '-'); + + // If the first component corresponds to a known architecture, preferentially + // use it for the architecture. If the second component corresponds to a + // known vendor, preferentially use it for the vendor, etc. This avoids silly + // component movement when a component parses as (eg) both a valid arch and a + // valid os. + ArchType Arch = UnknownArch; + if (Components.size() > 0) + Arch = parseArch(Components[0]); + VendorType Vendor = UnknownVendor; + if (Components.size() > 1) + Vendor = parseVendor(Components[1]); + OSType OS = UnknownOS; + if (Components.size() > 2) { + OS = parseOS(Components[2]); + IsCygwin = Components[2].startswith("cygwin"); + IsMinGW32 = Components[2].startswith("mingw"); + } + EnvironmentType Environment = UnknownEnvironment; + if (Components.size() > 3) + Environment = parseEnvironment(Components[3]); + ObjectFormatType ObjectFormat = UnknownObjectFormat; + if (Components.size() > 4) + ObjectFormat = parseFormat(Components[4]); + + // Note which components are already in their final position. These will not + // be moved. + bool Found[4]; + Found[0] = Arch != UnknownArch; + Found[1] = Vendor != UnknownVendor; + Found[2] = OS != UnknownOS; + Found[3] = Environment != UnknownEnvironment; + + // If they are not there already, permute the components into their canonical + // positions by seeing if they parse as a valid architecture, and if so moving + // the component to the architecture position etc. + for (unsigned Pos = 0; Pos != std::size(Found); ++Pos) { + if (Found[Pos]) + continue; // Already in the canonical position. + + for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { + // Do not reparse any components that already matched. + if (Idx < std::size(Found) && Found[Idx]) + continue; + + // Does this component parse as valid for the target position? + bool Valid = false; + StringRef Comp = Components[Idx]; + switch (Pos) { + default: llvm_unreachable("unexpected component type!"); + case 0: + Arch = parseArch(Comp); + Valid = Arch != UnknownArch; + break; + case 1: + Vendor = parseVendor(Comp); + Valid = Vendor != UnknownVendor; + break; + case 2: + OS = parseOS(Comp); + IsCygwin = Comp.startswith("cygwin"); + IsMinGW32 = Comp.startswith("mingw"); + Valid = OS != UnknownOS || IsCygwin || IsMinGW32; + break; + case 3: + Environment = parseEnvironment(Comp); + Valid = Environment != UnknownEnvironment; + if (!Valid) { + ObjectFormat = parseFormat(Comp); + Valid = ObjectFormat != UnknownObjectFormat; + } + break; + } + if (!Valid) + continue; // Nope, try the next component. + + // Move the component to the target position, pushing any non-fixed + // components that are in the way to the right. This tends to give + // good results in the common cases of a forgotten vendor component + // or a wrongly positioned environment. + if (Pos < Idx) { + // Insert left, pushing the existing components to the right. For + // example, a-b-i386 -> i386-a-b when moving i386 to the front. + StringRef CurrentComponent(""); // The empty component. + // Replace the component we are moving with an empty component. + std::swap(CurrentComponent, Components[Idx]); + // Insert the component being moved at Pos, displacing any existing + // components to the right. + for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { + // Skip over any fixed components. + while (i < std::size(Found) && Found[i]) + ++i; + // Place the component at the new position, getting the component + // that was at this position - it will be moved right. + std::swap(CurrentComponent, Components[i]); + } + } else if (Pos > Idx) { + // Push right by inserting empty components until the component at Idx + // reaches the target position Pos. For example, pc-a -> -pc-a when + // moving pc to the second position. + do { + // Insert one empty component at Idx. + StringRef CurrentComponent(""); // The empty component. + for (unsigned i = Idx; i < Components.size();) { + // Place the component at the new position, getting the component + // that was at this position - it will be moved right. + std::swap(CurrentComponent, Components[i]); + // If it was placed on top of an empty component then we are done. + if (CurrentComponent.empty()) + break; + // Advance to the next component, skipping any fixed components. + while (++i < std::size(Found) && Found[i]) + ; + } + // The last component was pushed off the end - append it. + if (!CurrentComponent.empty()) + Components.push_back(CurrentComponent); + + // Advance Idx to the component's new position. + while (++Idx < std::size(Found) && Found[Idx]) + ; + } while (Idx < Pos); // Add more until the final position is reached. + } + assert(Pos < Components.size() && Components[Pos] == Comp && + "Component moved wrong!"); + Found[Pos] = true; + break; + } + } + + // Replace empty components with "unknown" value. + for (StringRef &C : Components) + if (C.empty()) + C = "unknown"; + + // Special case logic goes here. At this point Arch, Vendor and OS have the + // correct values for the computed components. + std::string NormalizedEnvironment; + if (Environment == Triple::Android && Components[3].startswith("androideabi")) { + StringRef AndroidVersion = Components[3].drop_front(strlen("androideabi")); + if (AndroidVersion.empty()) { + Components[3] = "android"; + } else { + NormalizedEnvironment = Twine("android", AndroidVersion).str(); + Components[3] = NormalizedEnvironment; + } + } + + // SUSE uses "gnueabi" to mean "gnueabihf" + if (Vendor == Triple::SUSE && Environment == llvm::Triple::GNUEABI) + Components[3] = "gnueabihf"; + + if (OS == Triple::Win32) { + Components.resize(4); + Components[2] = "windows"; + if (Environment == UnknownEnvironment) { + if (ObjectFormat == UnknownObjectFormat || ObjectFormat == Triple::COFF) + Components[3] = "msvc"; + else + Components[3] = getObjectFormatTypeName(ObjectFormat); + } + } else if (IsMinGW32) { + Components.resize(4); + Components[2] = "windows"; + Components[3] = "gnu"; + } else if (IsCygwin) { + Components.resize(4); + Components[2] = "windows"; + Components[3] = "cygnus"; + } + if (IsMinGW32 || IsCygwin || + (OS == Triple::Win32 && Environment != UnknownEnvironment)) { + if (ObjectFormat != UnknownObjectFormat && ObjectFormat != Triple::COFF) { + Components.resize(5); + Components[4] = getObjectFormatTypeName(ObjectFormat); + } + } + + // Stick the corrected components back together to form the normalized string. + return join(Components, "-"); +} + +StringRef Triple::getArchName() const { + return StringRef(Data).split('-').first; // Isolate first component +} + +StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) const { + switch (Kind) { + case Triple::mips: + if (SubArch == MipsSubArch_r6) + return "mipsisa32r6"; + break; + case Triple::mipsel: + if (SubArch == MipsSubArch_r6) + return "mipsisa32r6el"; + break; + case Triple::mips64: + if (SubArch == MipsSubArch_r6) + return "mipsisa64r6"; + break; + case Triple::mips64el: + if (SubArch == MipsSubArch_r6) + return "mipsisa64r6el"; + break; + case Triple::aarch64: + if (SubArch == AArch64SubArch_arm64ec) + return "arm64ec"; + break; + default: + break; + } + return getArchTypeName(Kind); +} + +StringRef Triple::getVendorName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + return Tmp.split('-').first; // Isolate second component +} + +StringRef Triple::getOSName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + Tmp = Tmp.split('-').second; // Strip second component + return Tmp.split('-').first; // Isolate third component +} + +StringRef Triple::getEnvironmentName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + Tmp = Tmp.split('-').second; // Strip second component + return Tmp.split('-').second; // Strip third component +} + +StringRef Triple::getOSAndEnvironmentName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + return Tmp.split('-').second; // Strip second component +} + +static VersionTuple parseVersionFromName(StringRef Name) { + VersionTuple Version; + Version.tryParse(Name); + return Version.withoutBuild(); +} + +VersionTuple Triple::getEnvironmentVersion() const { + StringRef EnvironmentName = getEnvironmentName(); + StringRef EnvironmentTypeName = getEnvironmentTypeName(getEnvironment()); + if (EnvironmentName.startswith(EnvironmentTypeName)) + EnvironmentName = EnvironmentName.substr(EnvironmentTypeName.size()); + + return parseVersionFromName(EnvironmentName); +} + +VersionTuple Triple::getOSVersion() const { + StringRef OSName = getOSName(); + // Assume that the OS portion of the triple starts with the canonical name. + StringRef OSTypeName = getOSTypeName(getOS()); + if (OSName.startswith(OSTypeName)) + OSName = OSName.substr(OSTypeName.size()); + else if (getOS() == MacOSX) + OSName.consume_front("macos"); + + return parseVersionFromName(OSName); +} + +bool Triple::getMacOSXVersion(VersionTuple &Version) const { + Version = getOSVersion(); + + switch (getOS()) { + default: llvm_unreachable("unexpected OS for Darwin triple"); + case Darwin: + // Default to darwin8, i.e., MacOSX 10.4. + if (Version.getMajor() == 0) + Version = VersionTuple(8); + // Darwin version numbers are skewed from OS X versions. + if (Version.getMajor() < 4) { + return false; + } + if (Version.getMajor() <= 19) { + Version = VersionTuple(10, Version.getMajor() - 4); + } else { + // darwin20+ corresponds to macOS 11+. + Version = VersionTuple(11 + Version.getMajor() - 20); + } + break; + case MacOSX: + // Default to 10.4. + if (Version.getMajor() == 0) { + Version = VersionTuple(10, 4); + } else if (Version.getMajor() < 10) { + return false; + } + break; + case IOS: + case TvOS: + case WatchOS: + // Ignore the version from the triple. This is only handled because the + // the clang driver combines OS X and IOS support into a common Darwin + // toolchain that wants to know the OS X version number even when targeting + // IOS. + Version = VersionTuple(10, 4); + break; + case DriverKit: + llvm_unreachable("OSX version isn't relevant for DriverKit"); + } + return true; +} + +VersionTuple Triple::getiOSVersion() const { + switch (getOS()) { + default: llvm_unreachable("unexpected OS for Darwin triple"); + case Darwin: + case MacOSX: + // Ignore the version from the triple. This is only handled because the + // the clang driver combines OS X and IOS support into a common Darwin + // toolchain that wants to know the iOS version number even when targeting + // OS X. + return VersionTuple(5); + case IOS: + case TvOS: { + VersionTuple Version = getOSVersion(); + // Default to 5.0 (or 7.0 for arm64). + if (Version.getMajor() == 0) + return (getArch() == aarch64) ? VersionTuple(7) : VersionTuple(5); + return Version; + } + case WatchOS: + llvm_unreachable("conflicting triple info"); + case DriverKit: + llvm_unreachable("DriverKit doesn't have an iOS version"); + } +} + +VersionTuple Triple::getWatchOSVersion() const { + switch (getOS()) { + default: llvm_unreachable("unexpected OS for Darwin triple"); + case Darwin: + case MacOSX: + // Ignore the version from the triple. This is only handled because the + // the clang driver combines OS X and IOS support into a common Darwin + // toolchain that wants to know the iOS version number even when targeting + // OS X. + return VersionTuple(2); + case WatchOS: { + VersionTuple Version = getOSVersion(); + if (Version.getMajor() == 0) + return VersionTuple(2); + return Version; + } + case IOS: + llvm_unreachable("conflicting triple info"); + case DriverKit: + llvm_unreachable("DriverKit doesn't have a WatchOS version"); + } +} + +VersionTuple Triple::getDriverKitVersion() const { + switch (getOS()) { + default: + llvm_unreachable("unexpected OS for Darwin triple"); + case DriverKit: + VersionTuple Version = getOSVersion(); + if (Version.getMajor() == 0) + return Version.withMajorReplaced(19); + return Version; + } +} + +void Triple::setTriple(const Twine &Str) { + *this = Triple(Str); +} + +void Triple::setArch(ArchType Kind, SubArchType SubArch) { + setArchName(getArchName(Kind, SubArch)); +} + +void Triple::setVendor(VendorType Kind) { + setVendorName(getVendorTypeName(Kind)); +} + +void Triple::setOS(OSType Kind) { + setOSName(getOSTypeName(Kind)); +} + +void Triple::setEnvironment(EnvironmentType Kind) { + if (ObjectFormat == getDefaultFormat(*this)) + return setEnvironmentName(getEnvironmentTypeName(Kind)); + + setEnvironmentName((getEnvironmentTypeName(Kind) + Twine("-") + + getObjectFormatTypeName(ObjectFormat)).str()); +} + +void Triple::setObjectFormat(ObjectFormatType Kind) { + if (Environment == UnknownEnvironment) + return setEnvironmentName(getObjectFormatTypeName(Kind)); + + setEnvironmentName((getEnvironmentTypeName(Environment) + Twine("-") + + getObjectFormatTypeName(Kind)).str()); +} + +void Triple::setArchName(StringRef Str) { + // Work around a miscompilation bug for Twines in gcc 4.0.3. + SmallString<64> Triple; + Triple += Str; + Triple += "-"; + Triple += getVendorName(); + Triple += "-"; + Triple += getOSAndEnvironmentName(); + setTriple(Triple); +} + +void Triple::setVendorName(StringRef Str) { + setTriple(getArchName() + "-" + Str + "-" + getOSAndEnvironmentName()); +} + +void Triple::setOSName(StringRef Str) { + if (hasEnvironment()) + setTriple(getArchName() + "-" + getVendorName() + "-" + Str + + "-" + getEnvironmentName()); + else + setTriple(getArchName() + "-" + getVendorName() + "-" + Str); +} + +void Triple::setEnvironmentName(StringRef Str) { + setTriple(getArchName() + "-" + getVendorName() + "-" + getOSName() + + "-" + Str); +} + +void Triple::setOSAndEnvironmentName(StringRef Str) { + setTriple(getArchName() + "-" + getVendorName() + "-" + Str); +} + +static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { + switch (Arch) { + case llvm::Triple::UnknownArch: + return 0; + + case llvm::Triple::avr: + case llvm::Triple::msp430: + return 16; + + case llvm::Triple::aarch64_32: + case llvm::Triple::amdil: + case llvm::Triple::arc: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::csky: + case llvm::Triple::dxil: + case llvm::Triple::hexagon: + case llvm::Triple::hsail: + case llvm::Triple::kalimba: + case llvm::Triple::lanai: + case llvm::Triple::le32: + case llvm::Triple::loongarch32: + case llvm::Triple::m68k: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::nvptx: + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::r600: + case llvm::Triple::renderscript32: + case llvm::Triple::riscv32: + case llvm::Triple::shave: + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::spir: + case llvm::Triple::spirv32: + case llvm::Triple::tce: + case llvm::Triple::tcele: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::wasm32: + case llvm::Triple::x86: + case llvm::Triple::xcore: + case llvm::Triple::xtensa: + return 32; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::amdgcn: + case llvm::Triple::amdil64: + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + case llvm::Triple::hsail64: + case llvm::Triple::le64: + case llvm::Triple::loongarch64: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::nvptx64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::renderscript64: + case llvm::Triple::riscv64: + case llvm::Triple::sparcv9: + case llvm::Triple::spir64: + case llvm::Triple::spirv64: + case llvm::Triple::systemz: + case llvm::Triple::ve: + case llvm::Triple::wasm64: + case llvm::Triple::x86_64: + return 64; + } + llvm_unreachable("Invalid architecture value"); +} + +bool Triple::isArch64Bit() const { + return getArchPointerBitWidth(getArch()) == 64; +} + +bool Triple::isArch32Bit() const { + return getArchPointerBitWidth(getArch()) == 32; +} + +bool Triple::isArch16Bit() const { + return getArchPointerBitWidth(getArch()) == 16; +} + +Triple Triple::get32BitArchVariant() const { + Triple T(*this); + switch (getArch()) { + case Triple::UnknownArch: + case Triple::amdgcn: + case Triple::avr: + case Triple::bpfeb: + case Triple::bpfel: + case Triple::msp430: + case Triple::systemz: + case Triple::ve: + T.setArch(UnknownArch); + break; + + case Triple::aarch64_32: + case Triple::amdil: + case Triple::arc: + case Triple::arm: + case Triple::armeb: + case Triple::csky: + case Triple::dxil: + case Triple::hexagon: + case Triple::hsail: + case Triple::kalimba: + case Triple::lanai: + case Triple::le32: + case Triple::loongarch32: + case Triple::m68k: + case Triple::mips: + case Triple::mipsel: + case Triple::nvptx: + case Triple::ppc: + case Triple::ppcle: + case Triple::r600: + case Triple::renderscript32: + case Triple::riscv32: + case Triple::shave: + case Triple::sparc: + case Triple::sparcel: + case Triple::spir: + case Triple::spirv32: + case Triple::tce: + case Triple::tcele: + case Triple::thumb: + case Triple::thumbeb: + case Triple::wasm32: + case Triple::x86: + case Triple::xcore: + case Triple::xtensa: + // Already 32-bit. + break; + + case Triple::aarch64: T.setArch(Triple::arm); break; + case Triple::aarch64_be: T.setArch(Triple::armeb); break; + case Triple::amdil64: T.setArch(Triple::amdil); break; + case Triple::hsail64: T.setArch(Triple::hsail); break; + case Triple::le64: T.setArch(Triple::le32); break; + case Triple::loongarch64: T.setArch(Triple::loongarch32); break; + case Triple::mips64: + T.setArch(Triple::mips, getSubArch()); + break; + case Triple::mips64el: + T.setArch(Triple::mipsel, getSubArch()); + break; + case Triple::nvptx64: T.setArch(Triple::nvptx); break; + case Triple::ppc64: T.setArch(Triple::ppc); break; + case Triple::ppc64le: T.setArch(Triple::ppcle); break; + case Triple::renderscript64: T.setArch(Triple::renderscript32); break; + case Triple::riscv64: T.setArch(Triple::riscv32); break; + case Triple::sparcv9: T.setArch(Triple::sparc); break; + case Triple::spir64: T.setArch(Triple::spir); break; + case Triple::spirv64: + T.setArch(Triple::spirv32, getSubArch()); + break; + case Triple::wasm64: T.setArch(Triple::wasm32); break; + case Triple::x86_64: T.setArch(Triple::x86); break; + } + return T; +} + +Triple Triple::get64BitArchVariant() const { + Triple T(*this); + switch (getArch()) { + case Triple::UnknownArch: + case Triple::arc: + case Triple::avr: + case Triple::csky: + case Triple::dxil: + case Triple::hexagon: + case Triple::kalimba: + case Triple::lanai: + case Triple::m68k: + case Triple::msp430: + case Triple::r600: + case Triple::shave: + case Triple::sparcel: + case Triple::tce: + case Triple::tcele: + case Triple::xcore: + case Triple::xtensa: + T.setArch(UnknownArch); + break; + + case Triple::aarch64: + case Triple::aarch64_be: + case Triple::amdgcn: + case Triple::amdil64: + case Triple::bpfeb: + case Triple::bpfel: + case Triple::hsail64: + case Triple::le64: + case Triple::loongarch64: + case Triple::mips64: + case Triple::mips64el: + case Triple::nvptx64: + case Triple::ppc64: + case Triple::ppc64le: + case Triple::renderscript64: + case Triple::riscv64: + case Triple::sparcv9: + case Triple::spir64: + case Triple::spirv64: + case Triple::systemz: + case Triple::ve: + case Triple::wasm64: + case Triple::x86_64: + // Already 64-bit. + break; + + case Triple::aarch64_32: T.setArch(Triple::aarch64); break; + case Triple::amdil: T.setArch(Triple::amdil64); break; + case Triple::arm: T.setArch(Triple::aarch64); break; + case Triple::armeb: T.setArch(Triple::aarch64_be); break; + case Triple::hsail: T.setArch(Triple::hsail64); break; + case Triple::le32: T.setArch(Triple::le64); break; + case Triple::loongarch32: T.setArch(Triple::loongarch64); break; + case Triple::mips: + T.setArch(Triple::mips64, getSubArch()); + break; + case Triple::mipsel: + T.setArch(Triple::mips64el, getSubArch()); + break; + case Triple::nvptx: T.setArch(Triple::nvptx64); break; + case Triple::ppc: T.setArch(Triple::ppc64); break; + case Triple::ppcle: T.setArch(Triple::ppc64le); break; + case Triple::renderscript32: T.setArch(Triple::renderscript64); break; + case Triple::riscv32: T.setArch(Triple::riscv64); break; + case Triple::sparc: T.setArch(Triple::sparcv9); break; + case Triple::spir: T.setArch(Triple::spir64); break; + case Triple::spirv32: + T.setArch(Triple::spirv64, getSubArch()); + break; + case Triple::thumb: T.setArch(Triple::aarch64); break; + case Triple::thumbeb: T.setArch(Triple::aarch64_be); break; + case Triple::wasm32: T.setArch(Triple::wasm64); break; + case Triple::x86: T.setArch(Triple::x86_64); break; + } + return T; +} + +Triple Triple::getBigEndianArchVariant() const { + Triple T(*this); + // Already big endian. + if (!isLittleEndian()) + return T; + switch (getArch()) { + case Triple::UnknownArch: + case Triple::amdgcn: + case Triple::amdil64: + case Triple::amdil: + case Triple::avr: + case Triple::dxil: + case Triple::hexagon: + case Triple::hsail64: + case Triple::hsail: + case Triple::kalimba: + case Triple::le32: + case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: + case Triple::msp430: + case Triple::nvptx64: + case Triple::nvptx: + case Triple::r600: + case Triple::renderscript32: + case Triple::renderscript64: + case Triple::riscv32: + case Triple::riscv64: + case Triple::shave: + case Triple::spir64: + case Triple::spir: + case Triple::spirv32: + case Triple::spirv64: + case Triple::wasm32: + case Triple::wasm64: + case Triple::x86: + case Triple::x86_64: + case Triple::xcore: + case Triple::ve: + case Triple::csky: + case Triple::xtensa: + + // ARM is intentionally unsupported here, changing the architecture would + // drop any arch suffixes. + case Triple::arm: + case Triple::thumb: + T.setArch(UnknownArch); + break; + + case Triple::aarch64: T.setArch(Triple::aarch64_be); break; + case Triple::bpfel: T.setArch(Triple::bpfeb); break; + case Triple::mips64el: + T.setArch(Triple::mips64, getSubArch()); + break; + case Triple::mipsel: + T.setArch(Triple::mips, getSubArch()); + break; + case Triple::ppcle: T.setArch(Triple::ppc); break; + case Triple::ppc64le: T.setArch(Triple::ppc64); break; + case Triple::sparcel: T.setArch(Triple::sparc); break; + case Triple::tcele: T.setArch(Triple::tce); break; + default: + llvm_unreachable("getBigEndianArchVariant: unknown triple."); + } + return T; +} + +Triple Triple::getLittleEndianArchVariant() const { + Triple T(*this); + if (isLittleEndian()) + return T; + + switch (getArch()) { + case Triple::UnknownArch: + case Triple::lanai: + case Triple::sparcv9: + case Triple::systemz: + case Triple::m68k: + + // ARM is intentionally unsupported here, changing the architecture would + // drop any arch suffixes. + case Triple::armeb: + case Triple::thumbeb: + T.setArch(UnknownArch); + break; + + case Triple::aarch64_be: T.setArch(Triple::aarch64); break; + case Triple::bpfeb: T.setArch(Triple::bpfel); break; + case Triple::mips64: + T.setArch(Triple::mips64el, getSubArch()); + break; + case Triple::mips: + T.setArch(Triple::mipsel, getSubArch()); + break; + case Triple::ppc: T.setArch(Triple::ppcle); break; + case Triple::ppc64: T.setArch(Triple::ppc64le); break; + case Triple::sparc: T.setArch(Triple::sparcel); break; + case Triple::tce: T.setArch(Triple::tcele); break; + default: + llvm_unreachable("getLittleEndianArchVariant: unknown triple."); + } + return T; +} + +bool Triple::isLittleEndian() const { + switch (getArch()) { + case Triple::aarch64: + case Triple::aarch64_32: + case Triple::amdgcn: + case Triple::amdil64: + case Triple::amdil: + case Triple::arm: + case Triple::avr: + case Triple::bpfel: + case Triple::csky: + case Triple::dxil: + case Triple::hexagon: + case Triple::hsail64: + case Triple::hsail: + case Triple::kalimba: + case Triple::le32: + case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: + case Triple::mips64el: + case Triple::mipsel: + case Triple::msp430: + case Triple::nvptx64: + case Triple::nvptx: + case Triple::ppcle: + case Triple::ppc64le: + case Triple::r600: + case Triple::renderscript32: + case Triple::renderscript64: + case Triple::riscv32: + case Triple::riscv64: + case Triple::shave: + case Triple::sparcel: + case Triple::spir64: + case Triple::spir: + case Triple::spirv32: + case Triple::spirv64: + case Triple::tcele: + case Triple::thumb: + case Triple::ve: + case Triple::wasm32: + case Triple::wasm64: + case Triple::x86: + case Triple::x86_64: + case Triple::xcore: + case Triple::xtensa: + return true; + default: + return false; + } +} + +bool Triple::isCompatibleWith(const Triple &Other) const { + // ARM and Thumb triples are compatible, if subarch, vendor and OS match. + if ((getArch() == Triple::thumb && Other.getArch() == Triple::arm) || + (getArch() == Triple::arm && Other.getArch() == Triple::thumb) || + (getArch() == Triple::thumbeb && Other.getArch() == Triple::armeb) || + (getArch() == Triple::armeb && Other.getArch() == Triple::thumbeb)) { + if (getVendor() == Triple::Apple) + return getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS(); + else + return getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS() && + getEnvironment() == Other.getEnvironment() && + getObjectFormat() == Other.getObjectFormat(); + } + + // If vendor is apple, ignore the version number. + if (getVendor() == Triple::Apple) + return getArch() == Other.getArch() && getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS(); + + return *this == Other; +} + +std::string Triple::merge(const Triple &Other) const { + // If vendor is apple, pick the triple with the larger version number. + if (getVendor() == Triple::Apple) + if (Other.isOSVersionLT(*this)) + return str(); + + return Other.str(); +} + +bool Triple::isMacOSXVersionLT(unsigned Major, unsigned Minor, + unsigned Micro) const { + assert(isMacOSX() && "Not an OS X triple!"); + + // If this is OS X, expect a sane version number. + if (getOS() == Triple::MacOSX) + return isOSVersionLT(Major, Minor, Micro); + + // Otherwise, compare to the "Darwin" number. + if (Major == 10) { + return isOSVersionLT(Minor + 4, Micro, 0); + } else { + assert(Major >= 11 && "Unexpected major version"); + return isOSVersionLT(Major - 11 + 20, Minor, Micro); + } +} + +VersionTuple Triple::getMinimumSupportedOSVersion() const { + if (getVendor() != Triple::Apple || getArch() != Triple::aarch64) + return VersionTuple(); + switch (getOS()) { + case Triple::MacOSX: + // ARM64 slice is supported starting from macOS 11.0+. + return VersionTuple(11, 0, 0); + case Triple::IOS: + // ARM64 slice is supported starting from Mac Catalyst 14 (macOS 11). + // ARM64 simulators are supported for iOS 14+. + if (isMacCatalystEnvironment() || isSimulatorEnvironment()) + return VersionTuple(14, 0, 0); + // ARM64e slice is supported starting from iOS 14. + if (isArm64e()) + return VersionTuple(14, 0, 0); + break; + case Triple::TvOS: + // ARM64 simulators are supported for tvOS 14+. + if (isSimulatorEnvironment()) + return VersionTuple(14, 0, 0); + break; + case Triple::WatchOS: + // ARM64 simulators are supported for watchOS 7+. + if (isSimulatorEnvironment()) + return VersionTuple(7, 0, 0); + break; + case Triple::DriverKit: + return VersionTuple(20, 0, 0); + default: + break; + } + return VersionTuple(); +} + +VersionTuple Triple::getCanonicalVersionForOS(OSType OSKind, + const VersionTuple &Version) { + switch (OSKind) { + case MacOSX: + // macOS 10.16 is canonicalized to macOS 11. + if (Version == VersionTuple(10, 16)) + return VersionTuple(11, 0); + [[fallthrough]]; + default: + return Version; + } +} + +// HLSL triple environment orders are relied on in the front end +static_assert(Triple::Vertex - Triple::Pixel == 1, + "incorrect HLSL stage order"); +static_assert(Triple::Geometry - Triple::Pixel == 2, + "incorrect HLSL stage order"); +static_assert(Triple::Hull - Triple::Pixel == 3, + "incorrect HLSL stage order"); +static_assert(Triple::Domain - Triple::Pixel == 4, + "incorrect HLSL stage order"); +static_assert(Triple::Compute - Triple::Pixel == 5, + "incorrect HLSL stage order"); +static_assert(Triple::Library - Triple::Pixel == 6, + "incorrect HLSL stage order"); +static_assert(Triple::RayGeneration - Triple::Pixel == 7, + "incorrect HLSL stage order"); +static_assert(Triple::Intersection - Triple::Pixel == 8, + "incorrect HLSL stage order"); +static_assert(Triple::AnyHit - Triple::Pixel == 9, + "incorrect HLSL stage order"); +static_assert(Triple::ClosestHit - Triple::Pixel == 10, + "incorrect HLSL stage order"); +static_assert(Triple::Miss - Triple::Pixel == 11, + "incorrect HLSL stage order"); +static_assert(Triple::Callable - Triple::Pixel == 12, + "incorrect HLSL stage order"); +static_assert(Triple::Mesh - Triple::Pixel == 13, + "incorrect HLSL stage order"); +static_assert(Triple::Amplification - Triple::Pixel == 14, + "incorrect HLSL stage order"); diff --git a/llvm/lib/TargetParser/Unix/Host.inc b/llvm/lib/TargetParser/Unix/Host.inc new file mode 100644 index 000000000000..a33fe6fff893 --- /dev/null +++ b/llvm/lib/TargetParser/Unix/Host.inc @@ -0,0 +1,87 @@ +//===- llvm/TargetParser/Unix/Host.inc --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Host support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include <cctype> +#include <string> +#include <sys/utsname.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +using namespace llvm; + +static std::string getOSVersion() { + struct utsname info; + + if (uname(&info)) + return ""; + + return info.release; +} + +static std::string updateTripleOSVersion(std::string TargetTripleString) { + // On darwin, we want to update the version to match that of the target. + std::string::size_type DarwinDashIdx = TargetTripleString.find("-darwin"); + if (DarwinDashIdx != std::string::npos) { + TargetTripleString.resize(DarwinDashIdx + strlen("-darwin")); + TargetTripleString += getOSVersion(); + return TargetTripleString; + } + std::string::size_type MacOSDashIdx = TargetTripleString.find("-macos"); + if (MacOSDashIdx != std::string::npos) { + TargetTripleString.resize(MacOSDashIdx); + // Reset the OS to darwin as the OS version from `uname` doesn't use the + // macOS version scheme. + TargetTripleString += "-darwin"; + TargetTripleString += getOSVersion(); + } + // On AIX, the AIX version and release should be that of the current host + // unless if the version has already been specified. + if (Triple(LLVM_HOST_TRIPLE).getOS() == Triple::AIX) { + Triple TT(TargetTripleString); + if (TT.getOS() == Triple::AIX && !TT.getOSMajorVersion()) { + struct utsname name; + if (uname(&name) != -1) { + std::string NewOSName = std::string(Triple::getOSTypeName(Triple::AIX)); + NewOSName += name.version; + NewOSName += '.'; + NewOSName += name.release; + NewOSName += ".0.0"; + TT.setOSName(NewOSName); + return TT.str(); + } + } + } + return TargetTripleString; +} + +std::string sys::getDefaultTargetTriple() { + std::string TargetTripleString = + updateTripleOSVersion(LLVM_DEFAULT_TARGET_TRIPLE); + + // Override the default target with an environment variable named by + // LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + TargetTripleString = EnvTriple; +#endif + + return TargetTripleString; +} diff --git a/llvm/lib/TargetParser/Windows/Host.inc b/llvm/lib/TargetParser/Windows/Host.inc new file mode 100644 index 000000000000..487d69bcc7a4 --- /dev/null +++ b/llvm/lib/TargetParser/Windows/Host.inc @@ -0,0 +1,35 @@ +//===- llvm/TargetParser/Win32/Host.inc -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Host support. +// +//===----------------------------------------------------------------------===// + +// We need to include config.h here because LLVM_DEFAULT_TARGET_TRIPLE is not +// defined in llvm-config.h if it is unset. +#include "llvm/Config/config.h" +#include "llvm/Support/Windows/WindowsSupport.h" +#include <cstdio> +#include <string> + +using namespace llvm; + +static std::string updateTripleOSVersion(std::string Triple) { return Triple; } + +std::string sys::getDefaultTargetTriple() { + const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; + + // Override the default target with an environment variable named by + // LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + Triple = EnvTriple; +#endif + + return Triple; +} diff --git a/llvm/lib/TargetParser/X86TargetParser.cpp b/llvm/lib/TargetParser/X86TargetParser.cpp new file mode 100644 index 000000000000..20770a49f5c6 --- /dev/null +++ b/llvm/lib/TargetParser/X86TargetParser.cpp @@ -0,0 +1,744 @@ +//===-- X86TargetParser - Parser for X86 features ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise X86 hardware features. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TargetParser/X86TargetParser.h" +#include "llvm/ADT/StringSwitch.h" +#include <numeric> + +using namespace llvm; +using namespace llvm::X86; + +namespace { + +/// Container class for CPU features. +/// This is a constexpr reimplementation of a subset of std::bitset. It would be +/// nice to use std::bitset directly, but it doesn't support constant +/// initialization. +class FeatureBitset { + static constexpr unsigned NUM_FEATURE_WORDS = + (X86::CPU_FEATURE_MAX + 31) / 32; + + // This cannot be a std::array, operator[] is not constexpr until C++17. + uint32_t Bits[NUM_FEATURE_WORDS] = {}; + +public: + constexpr FeatureBitset() = default; + constexpr FeatureBitset(std::initializer_list<unsigned> Init) { + for (auto I : Init) + set(I); + } + + bool any() const { + return llvm::any_of(Bits, [](uint64_t V) { return V != 0; }); + } + + constexpr FeatureBitset &set(unsigned I) { + // GCC <6.2 crashes if this is written in a single statement. + uint32_t NewBits = Bits[I / 32] | (uint32_t(1) << (I % 32)); + Bits[I / 32] = NewBits; + return *this; + } + + constexpr bool operator[](unsigned I) const { + uint32_t Mask = uint32_t(1) << (I % 32); + return (Bits[I / 32] & Mask) != 0; + } + + constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) { + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) { + // GCC <6.2 crashes if this is written in a single statement. + uint32_t NewBits = Bits[I] & RHS.Bits[I]; + Bits[I] = NewBits; + } + return *this; + } + + constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) { + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) { + // GCC <6.2 crashes if this is written in a single statement. + uint32_t NewBits = Bits[I] | RHS.Bits[I]; + Bits[I] = NewBits; + } + return *this; + } + + // gcc 5.3 miscompiles this if we try to write this using operator&=. + constexpr FeatureBitset operator&(const FeatureBitset &RHS) const { + FeatureBitset Result; + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) + Result.Bits[I] = Bits[I] & RHS.Bits[I]; + return Result; + } + + // gcc 5.3 miscompiles this if we try to write this using operator&=. + constexpr FeatureBitset operator|(const FeatureBitset &RHS) const { + FeatureBitset Result; + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) + Result.Bits[I] = Bits[I] | RHS.Bits[I]; + return Result; + } + + constexpr FeatureBitset operator~() const { + FeatureBitset Result; + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) + Result.Bits[I] = ~Bits[I]; + return Result; + } + + constexpr bool operator!=(const FeatureBitset &RHS) const { + for (unsigned I = 0, E = std::size(Bits); I != E; ++I) + if (Bits[I] != RHS.Bits[I]) + return true; + return false; + } +}; + +struct ProcInfo { + StringLiteral Name; + X86::CPUKind Kind; + unsigned KeyFeature; + FeatureBitset Features; +}; + +struct FeatureInfo { + StringLiteral Name; + FeatureBitset ImpliedFeatures; +}; + +} // end anonymous namespace + +#define X86_FEATURE(ENUM, STRING) \ + constexpr FeatureBitset Feature##ENUM = {X86::FEATURE_##ENUM}; +#include "llvm/TargetParser/X86TargetParser.def" + +// Pentium with MMX. +constexpr FeatureBitset FeaturesPentiumMMX = + FeatureX87 | FeatureCMPXCHG8B | FeatureMMX; + +// Pentium 2 and 3. +constexpr FeatureBitset FeaturesPentium2 = + FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | FeatureFXSR; +constexpr FeatureBitset FeaturesPentium3 = FeaturesPentium2 | FeatureSSE; + +// Pentium 4 CPUs +constexpr FeatureBitset FeaturesPentium4 = FeaturesPentium3 | FeatureSSE2; +constexpr FeatureBitset FeaturesPrescott = FeaturesPentium4 | FeatureSSE3; +constexpr FeatureBitset FeaturesNocona = + FeaturesPrescott | Feature64BIT | FeatureCMPXCHG16B; + +// Basic 64-bit capable CPU. +constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT; +constexpr FeatureBitset FeaturesX86_64_V2 = FeaturesX86_64 | FeatureSAHF | + FeaturePOPCNT | FeatureCRC32 | + FeatureSSE4_2 | FeatureCMPXCHG16B; +constexpr FeatureBitset FeaturesX86_64_V3 = + FeaturesX86_64_V2 | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureF16C | + FeatureFMA | FeatureLZCNT | FeatureMOVBE | FeatureXSAVE; +constexpr FeatureBitset FeaturesX86_64_V4 = FeaturesX86_64_V3 | + FeatureAVX512BW | FeatureAVX512CD | + FeatureAVX512DQ | FeatureAVX512VL; + +// Intel Core CPUs +constexpr FeatureBitset FeaturesCore2 = + FeaturesNocona | FeatureSAHF | FeatureSSSE3; +constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1; +constexpr FeatureBitset FeaturesNehalem = + FeaturesPenryn | FeaturePOPCNT | FeatureCRC32 | FeatureSSE4_2; +constexpr FeatureBitset FeaturesWestmere = FeaturesNehalem | FeaturePCLMUL; +constexpr FeatureBitset FeaturesSandyBridge = + FeaturesWestmere | FeatureAVX | FeatureXSAVE | FeatureXSAVEOPT; +constexpr FeatureBitset FeaturesIvyBridge = + FeaturesSandyBridge | FeatureF16C | FeatureFSGSBASE | FeatureRDRND; +constexpr FeatureBitset FeaturesHaswell = + FeaturesIvyBridge | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureFMA | + FeatureINVPCID | FeatureLZCNT | FeatureMOVBE; +constexpr FeatureBitset FeaturesBroadwell = + FeaturesHaswell | FeatureADX | FeaturePRFCHW | FeatureRDSEED; + +// Intel Knights Landing and Knights Mill +// Knights Landing has feature parity with Broadwell. +constexpr FeatureBitset FeaturesKNL = + FeaturesBroadwell | FeatureAES | FeatureAVX512F | FeatureAVX512CD | + FeatureAVX512ER | FeatureAVX512PF | FeaturePREFETCHWT1; +constexpr FeatureBitset FeaturesKNM = FeaturesKNL | FeatureAVX512VPOPCNTDQ; + +// Intel Skylake processors. +constexpr FeatureBitset FeaturesSkylakeClient = + FeaturesBroadwell | FeatureAES | FeatureCLFLUSHOPT | FeatureXSAVEC | + FeatureXSAVES | FeatureSGX; +// SkylakeServer inherits all SkylakeClient features except SGX. +// FIXME: That doesn't match gcc. +constexpr FeatureBitset FeaturesSkylakeServer = + (FeaturesSkylakeClient & ~FeatureSGX) | FeatureAVX512F | FeatureAVX512CD | + FeatureAVX512DQ | FeatureAVX512BW | FeatureAVX512VL | FeatureCLWB | + FeaturePKU; +constexpr FeatureBitset FeaturesCascadeLake = + FeaturesSkylakeServer | FeatureAVX512VNNI; +constexpr FeatureBitset FeaturesCooperLake = + FeaturesCascadeLake | FeatureAVX512BF16; + +// Intel 10nm processors. +constexpr FeatureBitset FeaturesCannonlake = + FeaturesSkylakeClient | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ | + FeatureAVX512BW | FeatureAVX512VL | FeatureAVX512IFMA | FeatureAVX512VBMI | + FeaturePKU | FeatureSHA; +constexpr FeatureBitset FeaturesICLClient = + FeaturesCannonlake | FeatureAVX512BITALG | FeatureAVX512VBMI2 | + FeatureAVX512VNNI | FeatureAVX512VPOPCNTDQ | FeatureGFNI | FeatureRDPID | + FeatureVAES | FeatureVPCLMULQDQ; +constexpr FeatureBitset FeaturesRocketlake = FeaturesICLClient & ~FeatureSGX; +constexpr FeatureBitset FeaturesICLServer = + FeaturesICLClient | FeatureCLWB | FeaturePCONFIG | FeatureWBNOINVD; +constexpr FeatureBitset FeaturesTigerlake = + FeaturesICLClient | FeatureAVX512VP2INTERSECT | FeatureMOVDIR64B | + FeatureCLWB | FeatureMOVDIRI | FeatureSHSTK | FeatureKL | FeatureWIDEKL; +constexpr FeatureBitset FeaturesSapphireRapids = + FeaturesICLServer | FeatureAMX_BF16 | FeatureAMX_INT8 | FeatureAMX_TILE | + FeatureAVX512BF16 | FeatureAVX512FP16 | FeatureAVXVNNI | FeatureCLDEMOTE | + FeatureENQCMD | FeatureMOVDIR64B | FeatureMOVDIRI | FeaturePTWRITE | + FeatureSERIALIZE | FeatureSHSTK | FeatureTSXLDTRK | FeatureUINTR | + FeatureWAITPKG; +constexpr FeatureBitset FeaturesGraniteRapids = + FeaturesSapphireRapids | FeatureAMX_FP16 | FeaturePREFETCHI; + +// Intel Atom processors. +// Bonnell has feature parity with Core2 and adds MOVBE. +constexpr FeatureBitset FeaturesBonnell = FeaturesCore2 | FeatureMOVBE; +// Silvermont has parity with Westmere and Bonnell plus PRFCHW and RDRND. +constexpr FeatureBitset FeaturesSilvermont = + FeaturesBonnell | FeaturesWestmere | FeaturePRFCHW | FeatureRDRND; +constexpr FeatureBitset FeaturesGoldmont = + FeaturesSilvermont | FeatureAES | FeatureCLFLUSHOPT | FeatureFSGSBASE | + FeatureRDSEED | FeatureSHA | FeatureXSAVE | FeatureXSAVEC | + FeatureXSAVEOPT | FeatureXSAVES; +constexpr FeatureBitset FeaturesGoldmontPlus = + FeaturesGoldmont | FeaturePTWRITE | FeatureRDPID | FeatureSGX; +constexpr FeatureBitset FeaturesTremont = + FeaturesGoldmontPlus | FeatureCLWB | FeatureGFNI; +constexpr FeatureBitset FeaturesAlderlake = + FeaturesTremont | FeatureADX | FeatureBMI | FeatureBMI2 | FeatureF16C | + FeatureFMA | FeatureINVPCID | FeatureLZCNT | FeaturePCONFIG | FeaturePKU | + FeatureSERIALIZE | FeatureSHSTK | FeatureVAES | FeatureVPCLMULQDQ | + FeatureCLDEMOTE | FeatureMOVDIR64B | FeatureMOVDIRI | FeatureWAITPKG | + FeatureAVXVNNI | FeatureHRESET | FeatureWIDEKL; +constexpr FeatureBitset FeaturesSierraforest = + FeaturesAlderlake | FeatureCMPCCXADD | FeatureAVXIFMA | + FeatureAVXNECONVERT | FeatureAVXVNNIINT8; +constexpr FeatureBitset FeaturesGrandridge = + FeaturesSierraforest | FeatureRAOINT; + +// Geode Processor. +constexpr FeatureBitset FeaturesGeode = + FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA; + +// K6 processor. +constexpr FeatureBitset FeaturesK6 = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX; + +// K7 and K8 architecture processors. +constexpr FeatureBitset FeaturesAthlon = + FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA; +constexpr FeatureBitset FeaturesAthlonXP = + FeaturesAthlon | FeatureFXSR | FeatureSSE; +constexpr FeatureBitset FeaturesK8 = + FeaturesAthlonXP | FeatureSSE2 | Feature64BIT; +constexpr FeatureBitset FeaturesK8SSE3 = FeaturesK8 | FeatureSSE3; +constexpr FeatureBitset FeaturesAMDFAM10 = + FeaturesK8SSE3 | FeatureCMPXCHG16B | FeatureLZCNT | FeaturePOPCNT | + FeaturePRFCHW | FeatureSAHF | FeatureSSE4_A; + +// Bobcat architecture processors. +constexpr FeatureBitset FeaturesBTVER1 = + FeatureX87 | FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT | + FeatureFXSR | FeatureLZCNT | FeatureMMX | FeaturePOPCNT | FeaturePRFCHW | + FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_A | + FeatureSAHF; +constexpr FeatureBitset FeaturesBTVER2 = + FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureCRC32 | + FeatureF16C | FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT; + +// AMD Bulldozer architecture processors. +constexpr FeatureBitset FeaturesBDVER1 = + FeatureX87 | FeatureAES | FeatureAVX | FeatureCMPXCHG8B | + FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT | FeatureFMA4 | + FeatureFXSR | FeatureLWP | FeatureLZCNT | FeatureMMX | FeaturePCLMUL | + FeaturePOPCNT | FeaturePRFCHW | FeatureSAHF | FeatureSSE | FeatureSSE2 | + FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A | + FeatureXOP | FeatureXSAVE; +constexpr FeatureBitset FeaturesBDVER2 = + FeaturesBDVER1 | FeatureBMI | FeatureFMA | FeatureF16C | FeatureTBM; +constexpr FeatureBitset FeaturesBDVER3 = + FeaturesBDVER2 | FeatureFSGSBASE | FeatureXSAVEOPT; +constexpr FeatureBitset FeaturesBDVER4 = FeaturesBDVER3 | FeatureAVX2 | + FeatureBMI2 | FeatureMOVBE | + FeatureMWAITX | FeatureRDRND; + +// AMD Zen architecture processors. +constexpr FeatureBitset FeaturesZNVER1 = + FeatureX87 | FeatureADX | FeatureAES | FeatureAVX | FeatureAVX2 | + FeatureBMI | FeatureBMI2 | FeatureCLFLUSHOPT | FeatureCLZERO | + FeatureCMPXCHG8B | FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT | + FeatureF16C | FeatureFMA | FeatureFSGSBASE | FeatureFXSR | FeatureLZCNT | + FeatureMMX | FeatureMOVBE | FeatureMWAITX | FeaturePCLMUL | FeaturePOPCNT | + FeaturePRFCHW | FeatureRDRND | FeatureRDSEED | FeatureSAHF | FeatureSHA | + FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 | + FeatureSSE4_2 | FeatureSSE4_A | FeatureXSAVE | FeatureXSAVEC | + FeatureXSAVEOPT | FeatureXSAVES; +constexpr FeatureBitset FeaturesZNVER2 = FeaturesZNVER1 | FeatureCLWB | + FeatureRDPID | FeatureRDPRU | + FeatureWBNOINVD; +static constexpr FeatureBitset FeaturesZNVER3 = FeaturesZNVER2 | + FeatureINVPCID | FeaturePKU | + FeatureVAES | FeatureVPCLMULQDQ; +static constexpr FeatureBitset FeaturesZNVER4 = + FeaturesZNVER3 | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ | + FeatureAVX512BW | FeatureAVX512VL | FeatureAVX512IFMA | FeatureAVX512VBMI | + FeatureAVX512VBMI2 | FeatureAVX512VNNI | FeatureAVX512BITALG | + FeatureAVX512VPOPCNTDQ | FeatureAVX512BF16 | FeatureGFNI | + FeatureSHSTK; + +constexpr ProcInfo Processors[] = { + // Empty processor. Include X87 and CMPXCHG8 for backwards compatibility. + { {""}, CK_None, ~0U, FeatureX87 | FeatureCMPXCHG8B }, + // i386-generation processors. + { {"i386"}, CK_i386, ~0U, FeatureX87 }, + // i486-generation processors. + { {"i486"}, CK_i486, ~0U, FeatureX87 }, + { {"winchip-c6"}, CK_WinChipC6, ~0U, FeaturesPentiumMMX }, + { {"winchip2"}, CK_WinChip2, ~0U, FeaturesPentiumMMX | Feature3DNOW }, + { {"c3"}, CK_C3, ~0U, FeaturesPentiumMMX | Feature3DNOW }, + // i586-generation processors, P5 microarchitecture based. + { {"i586"}, CK_i586, ~0U, FeatureX87 | FeatureCMPXCHG8B }, + { {"pentium"}, CK_Pentium, ~0U, FeatureX87 | FeatureCMPXCHG8B }, + { {"pentium-mmx"}, CK_PentiumMMX, ~0U, FeaturesPentiumMMX }, + // i686-generation processors, P6 / Pentium M microarchitecture based. + { {"pentiumpro"}, CK_PentiumPro, ~0U, FeatureX87 | FeatureCMPXCHG8B }, + { {"i686"}, CK_i686, ~0U, FeatureX87 | FeatureCMPXCHG8B }, + { {"pentium2"}, CK_Pentium2, ~0U, FeaturesPentium2 }, + { {"pentium3"}, CK_Pentium3, ~0U, FeaturesPentium3 }, + { {"pentium3m"}, CK_Pentium3, ~0U, FeaturesPentium3 }, + { {"pentium-m"}, CK_PentiumM, ~0U, FeaturesPentium4 }, + { {"c3-2"}, CK_C3_2, ~0U, FeaturesPentium3 }, + { {"yonah"}, CK_Yonah, ~0U, FeaturesPrescott }, + // Netburst microarchitecture based processors. + { {"pentium4"}, CK_Pentium4, ~0U, FeaturesPentium4 }, + { {"pentium4m"}, CK_Pentium4, ~0U, FeaturesPentium4 }, + { {"prescott"}, CK_Prescott, ~0U, FeaturesPrescott }, + { {"nocona"}, CK_Nocona, ~0U, FeaturesNocona }, + // Core microarchitecture based processors. + { {"core2"}, CK_Core2, FEATURE_SSSE3, FeaturesCore2 }, + { {"penryn"}, CK_Penryn, ~0U, FeaturesPenryn }, + // Atom processors + { {"bonnell"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell }, + { {"atom"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell }, + { {"silvermont"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont }, + { {"slm"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont }, + { {"goldmont"}, CK_Goldmont, FEATURE_SSE4_2, FeaturesGoldmont }, + { {"goldmont-plus"}, CK_GoldmontPlus, FEATURE_SSE4_2, FeaturesGoldmontPlus }, + { {"tremont"}, CK_Tremont, FEATURE_SSE4_2, FeaturesTremont }, + // Nehalem microarchitecture based processors. + { {"nehalem"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem }, + { {"corei7"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem }, + // Westmere microarchitecture based processors. + { {"westmere"}, CK_Westmere, FEATURE_PCLMUL, FeaturesWestmere }, + // Sandy Bridge microarchitecture based processors. + { {"sandybridge"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge }, + { {"corei7-avx"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge }, + // Ivy Bridge microarchitecture based processors. + { {"ivybridge"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge }, + { {"core-avx-i"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge }, + // Haswell microarchitecture based processors. + { {"haswell"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell }, + { {"core-avx2"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell }, + // Broadwell microarchitecture based processors. + { {"broadwell"}, CK_Broadwell, FEATURE_AVX2, FeaturesBroadwell }, + // Skylake client microarchitecture based processors. + { {"skylake"}, CK_SkylakeClient, FEATURE_AVX2, FeaturesSkylakeClient }, + // Skylake server microarchitecture based processors. + { {"skylake-avx512"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer }, + { {"skx"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer }, + // Cascadelake Server microarchitecture based processors. + { {"cascadelake"}, CK_Cascadelake, FEATURE_AVX512VNNI, FeaturesCascadeLake }, + // Cooperlake Server microarchitecture based processors. + { {"cooperlake"}, CK_Cooperlake, FEATURE_AVX512BF16, FeaturesCooperLake }, + // Cannonlake client microarchitecture based processors. + { {"cannonlake"}, CK_Cannonlake, FEATURE_AVX512VBMI, FeaturesCannonlake }, + // Icelake client microarchitecture based processors. + { {"icelake-client"}, CK_IcelakeClient, FEATURE_AVX512VBMI2, FeaturesICLClient }, + // Rocketlake microarchitecture based processors. + { {"rocketlake"}, CK_Rocketlake, FEATURE_AVX512VBMI2, FeaturesRocketlake }, + // Icelake server microarchitecture based processors. + { {"icelake-server"}, CK_IcelakeServer, FEATURE_AVX512VBMI2, FeaturesICLServer }, + // Tigerlake microarchitecture based processors. + { {"tigerlake"}, CK_Tigerlake, FEATURE_AVX512VP2INTERSECT, FeaturesTigerlake }, + // Sapphire Rapids microarchitecture based processors. + { {"sapphirerapids"}, CK_SapphireRapids, FEATURE_AVX512BF16, FeaturesSapphireRapids }, + // Alderlake microarchitecture based processors. + { {"alderlake"}, CK_Alderlake, FEATURE_AVX2, FeaturesAlderlake }, + // Raptorlake microarchitecture based processors. + { {"raptorlake"}, CK_Raptorlake, FEATURE_AVX2, FeaturesAlderlake }, + // Meteorlake microarchitecture based processors. + { {"meteorlake"}, CK_Meteorlake, FEATURE_AVX2, FeaturesAlderlake }, + // Sierraforest microarchitecture based processors. + { {"sierraforest"}, CK_Sierraforest, FEATURE_AVX2, FeaturesSierraforest }, + // Grandridge microarchitecture based processors. + { {"grandridge"}, CK_Grandridge, FEATURE_AVX2, FeaturesGrandridge }, + // Granite Rapids microarchitecture based processors. + { {"graniterapids"}, CK_Graniterapids, FEATURE_AVX512BF16, FeaturesGraniteRapids }, + // Emerald Rapids microarchitecture based processors. + { {"emeraldrapids"}, CK_Emeraldrapids, FEATURE_AVX512BF16, FeaturesSapphireRapids }, + // Knights Landing processor. + { {"knl"}, CK_KNL, FEATURE_AVX512F, FeaturesKNL }, + // Knights Mill processor. + { {"knm"}, CK_KNM, FEATURE_AVX5124FMAPS, FeaturesKNM }, + // Lakemont microarchitecture based processors. + { {"lakemont"}, CK_Lakemont, ~0U, FeatureCMPXCHG8B }, + // K6 architecture processors. + { {"k6"}, CK_K6, ~0U, FeaturesK6 }, + { {"k6-2"}, CK_K6_2, ~0U, FeaturesK6 | Feature3DNOW }, + { {"k6-3"}, CK_K6_3, ~0U, FeaturesK6 | Feature3DNOW }, + // K7 architecture processors. + { {"athlon"}, CK_Athlon, ~0U, FeaturesAthlon }, + { {"athlon-tbird"}, CK_Athlon, ~0U, FeaturesAthlon }, + { {"athlon-xp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP }, + { {"athlon-mp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP }, + { {"athlon-4"}, CK_AthlonXP, ~0U, FeaturesAthlonXP }, + // K8 architecture processors. + { {"k8"}, CK_K8, ~0U, FeaturesK8 }, + { {"athlon64"}, CK_K8, ~0U, FeaturesK8 }, + { {"athlon-fx"}, CK_K8, ~0U, FeaturesK8 }, + { {"opteron"}, CK_K8, ~0U, FeaturesK8 }, + { {"k8-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 }, + { {"athlon64-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 }, + { {"opteron-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 }, + { {"amdfam10"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 }, + { {"barcelona"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 }, + // Bobcat architecture processors. + { {"btver1"}, CK_BTVER1, FEATURE_SSE4_A, FeaturesBTVER1 }, + { {"btver2"}, CK_BTVER2, FEATURE_BMI, FeaturesBTVER2 }, + // Bulldozer architecture processors. + { {"bdver1"}, CK_BDVER1, FEATURE_XOP, FeaturesBDVER1 }, + { {"bdver2"}, CK_BDVER2, FEATURE_FMA, FeaturesBDVER2 }, + { {"bdver3"}, CK_BDVER3, FEATURE_FMA, FeaturesBDVER3 }, + { {"bdver4"}, CK_BDVER4, FEATURE_AVX2, FeaturesBDVER4 }, + // Zen architecture processors. + { {"znver1"}, CK_ZNVER1, FEATURE_AVX2, FeaturesZNVER1 }, + { {"znver2"}, CK_ZNVER2, FEATURE_AVX2, FeaturesZNVER2 }, + { {"znver3"}, CK_ZNVER3, FEATURE_AVX2, FeaturesZNVER3 }, + { {"znver4"}, CK_ZNVER4, FEATURE_AVX512VBMI2, FeaturesZNVER4 }, + // Generic 64-bit processor. + { {"x86-64"}, CK_x86_64, ~0U, FeaturesX86_64 }, + { {"x86-64-v2"}, CK_x86_64_v2, ~0U, FeaturesX86_64_V2 }, + { {"x86-64-v3"}, CK_x86_64_v3, ~0U, FeaturesX86_64_V3 }, + { {"x86-64-v4"}, CK_x86_64_v4, ~0U, FeaturesX86_64_V4 }, + // Geode processors. + { {"geode"}, CK_Geode, ~0U, FeaturesGeode }, +}; + +constexpr const char *NoTuneList[] = {"x86-64-v2", "x86-64-v3", "x86-64-v4"}; + +X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) { + for (const auto &P : Processors) + if (P.Name == CPU && (P.Features[FEATURE_64BIT] || !Only64Bit)) + return P.Kind; + + return CK_None; +} + +X86::CPUKind llvm::X86::parseTuneCPU(StringRef CPU, bool Only64Bit) { + if (llvm::is_contained(NoTuneList, CPU)) + return CK_None; + return parseArchX86(CPU, Only64Bit); +} + +void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, + bool Only64Bit) { + for (const auto &P : Processors) + if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit)) + Values.emplace_back(P.Name); +} + +void llvm::X86::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values, + bool Only64Bit) { + for (const ProcInfo &P : Processors) + if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit) && + !llvm::is_contained(NoTuneList, P.Name)) + Values.emplace_back(P.Name); +} + +ProcessorFeatures llvm::X86::getKeyFeature(X86::CPUKind Kind) { + // FIXME: Can we avoid a linear search here? The table might be sorted by + // CPUKind so we could binary search? + for (const auto &P : Processors) { + if (P.Kind == Kind) { + assert(P.KeyFeature != ~0U && "Processor does not have a key feature."); + return static_cast<ProcessorFeatures>(P.KeyFeature); + } + } + + llvm_unreachable("Unable to find CPU kind!"); +} + +// Features with no dependencies. +constexpr FeatureBitset ImpliedFeatures64BIT = {}; +constexpr FeatureBitset ImpliedFeaturesADX = {}; +constexpr FeatureBitset ImpliedFeaturesBMI = {}; +constexpr FeatureBitset ImpliedFeaturesBMI2 = {}; +constexpr FeatureBitset ImpliedFeaturesCLDEMOTE = {}; +constexpr FeatureBitset ImpliedFeaturesCLFLUSHOPT = {}; +constexpr FeatureBitset ImpliedFeaturesCLWB = {}; +constexpr FeatureBitset ImpliedFeaturesCLZERO = {}; +constexpr FeatureBitset ImpliedFeaturesCMOV = {}; +constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {}; +constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {}; +constexpr FeatureBitset ImpliedFeaturesCRC32 = {}; +constexpr FeatureBitset ImpliedFeaturesENQCMD = {}; +constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {}; +constexpr FeatureBitset ImpliedFeaturesFXSR = {}; +constexpr FeatureBitset ImpliedFeaturesINVPCID = {}; +constexpr FeatureBitset ImpliedFeaturesLWP = {}; +constexpr FeatureBitset ImpliedFeaturesLZCNT = {}; +constexpr FeatureBitset ImpliedFeaturesMWAITX = {}; +constexpr FeatureBitset ImpliedFeaturesMOVBE = {}; +constexpr FeatureBitset ImpliedFeaturesMOVDIR64B = {}; +constexpr FeatureBitset ImpliedFeaturesMOVDIRI = {}; +constexpr FeatureBitset ImpliedFeaturesPCONFIG = {}; +constexpr FeatureBitset ImpliedFeaturesPOPCNT = {}; +constexpr FeatureBitset ImpliedFeaturesPKU = {}; +constexpr FeatureBitset ImpliedFeaturesPREFETCHWT1 = {}; +constexpr FeatureBitset ImpliedFeaturesPRFCHW = {}; +constexpr FeatureBitset ImpliedFeaturesPTWRITE = {}; +constexpr FeatureBitset ImpliedFeaturesRDPID = {}; +constexpr FeatureBitset ImpliedFeaturesRDPRU = {}; +constexpr FeatureBitset ImpliedFeaturesRDRND = {}; +constexpr FeatureBitset ImpliedFeaturesRDSEED = {}; +constexpr FeatureBitset ImpliedFeaturesRTM = {}; +constexpr FeatureBitset ImpliedFeaturesSAHF = {}; +constexpr FeatureBitset ImpliedFeaturesSERIALIZE = {}; +constexpr FeatureBitset ImpliedFeaturesSGX = {}; +constexpr FeatureBitset ImpliedFeaturesSHSTK = {}; +constexpr FeatureBitset ImpliedFeaturesTBM = {}; +constexpr FeatureBitset ImpliedFeaturesTSXLDTRK = {}; +constexpr FeatureBitset ImpliedFeaturesUINTR = {}; +constexpr FeatureBitset ImpliedFeaturesWAITPKG = {}; +constexpr FeatureBitset ImpliedFeaturesWBNOINVD = {}; +constexpr FeatureBitset ImpliedFeaturesVZEROUPPER = {}; +constexpr FeatureBitset ImpliedFeaturesX87 = {}; +constexpr FeatureBitset ImpliedFeaturesXSAVE = {}; + +// Not really CPU features, but need to be in the table because clang uses +// target features to communicate them to the backend. +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_EXTERNAL_THUNK = {}; +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_BRANCHES = {}; +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_CALLS = {}; +constexpr FeatureBitset ImpliedFeaturesLVI_CFI = {}; +constexpr FeatureBitset ImpliedFeaturesLVI_LOAD_HARDENING = {}; + +// XSAVE features are dependent on basic XSAVE. +constexpr FeatureBitset ImpliedFeaturesXSAVEC = FeatureXSAVE; +constexpr FeatureBitset ImpliedFeaturesXSAVEOPT = FeatureXSAVE; +constexpr FeatureBitset ImpliedFeaturesXSAVES = FeatureXSAVE; + +// MMX->3DNOW->3DNOWA chain. +constexpr FeatureBitset ImpliedFeaturesMMX = {}; +constexpr FeatureBitset ImpliedFeatures3DNOW = FeatureMMX; +constexpr FeatureBitset ImpliedFeatures3DNOWA = Feature3DNOW; + +// SSE/AVX/AVX512F chain. +constexpr FeatureBitset ImpliedFeaturesSSE = {}; +constexpr FeatureBitset ImpliedFeaturesSSE2 = FeatureSSE; +constexpr FeatureBitset ImpliedFeaturesSSE3 = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesSSSE3 = FeatureSSE3; +constexpr FeatureBitset ImpliedFeaturesSSE4_1 = FeatureSSSE3; +constexpr FeatureBitset ImpliedFeaturesSSE4_2 = FeatureSSE4_1; +constexpr FeatureBitset ImpliedFeaturesAVX = FeatureSSE4_2; +constexpr FeatureBitset ImpliedFeaturesAVX2 = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesAVX512F = + FeatureAVX2 | FeatureF16C | FeatureFMA; + +// Vector extensions that build on SSE or AVX. +constexpr FeatureBitset ImpliedFeaturesAES = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesF16C = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesFMA = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesGFNI = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesPCLMUL = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesSHA = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesVAES = FeatureAES | FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesVPCLMULQDQ = FeatureAVX | FeaturePCLMUL; + +// AVX512 features. +constexpr FeatureBitset ImpliedFeaturesAVX512CD = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512BW = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512DQ = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512ER = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512PF = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VL = FeatureAVX512F; + +constexpr FeatureBitset ImpliedFeaturesAVX512BF16 = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512BITALG = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512IFMA = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VNNI = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VPOPCNTDQ = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VBMI = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512VBMI2 = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512VP2INTERSECT = FeatureAVX512F; + +// FIXME: These two aren't really implemented and just exist in the feature +// list for __builtin_cpu_supports. So omit their dependencies. +constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {}; +constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {}; + +// SSE4_A->FMA4->XOP chain. +constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSE3; +constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A; +constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4; + +// AMX Features +constexpr FeatureBitset ImpliedFeaturesAMX_TILE = {}; +constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesAMX_FP16 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesHRESET = {}; + +constexpr FeatureBitset ImpliedFeaturesPREFETCHI = {}; +constexpr FeatureBitset ImpliedFeaturesCMPCCXADD = {}; +constexpr FeatureBitset ImpliedFeaturesRAOINT = {}; +constexpr FeatureBitset ImpliedFeaturesAVXVNNIINT8 = FeatureAVX2; +constexpr FeatureBitset ImpliedFeaturesAVXIFMA = FeatureAVX2; +constexpr FeatureBitset ImpliedFeaturesAVXNECONVERT = FeatureAVX2; +constexpr FeatureBitset ImpliedFeaturesAVX512FP16 = + FeatureAVX512BW | FeatureAVX512DQ | FeatureAVX512VL; +// Key Locker Features +constexpr FeatureBitset ImpliedFeaturesKL = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesWIDEKL = FeatureKL; + +// AVXVNNI Features +constexpr FeatureBitset ImpliedFeaturesAVXVNNI = FeatureAVX2; + +constexpr FeatureInfo FeatureInfos[X86::CPU_FEATURE_MAX] = { +#define X86_FEATURE(ENUM, STR) {{STR}, ImpliedFeatures##ENUM}, +#include "llvm/TargetParser/X86TargetParser.def" +}; + +void llvm::X86::getFeaturesForCPU(StringRef CPU, + SmallVectorImpl<StringRef> &EnabledFeatures) { + auto I = llvm::find_if(Processors, + [&](const ProcInfo &P) { return P.Name == CPU; }); + assert(I != std::end(Processors) && "Processor not found!"); + + FeatureBitset Bits = I->Features; + + // Remove the 64-bit feature which we only use to validate if a CPU can + // be used with 64-bit mode. + Bits &= ~Feature64BIT; + + // Add the string version of all set bits. + for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) + if (Bits[i] && !FeatureInfos[i].Name.empty()) + EnabledFeatures.push_back(FeatureInfos[i].Name); +} + +// For each feature that is (transitively) implied by this feature, set it. +static void getImpliedEnabledFeatures(FeatureBitset &Bits, + const FeatureBitset &Implies) { + // Fast path: Implies is often empty. + if (!Implies.any()) + return; + FeatureBitset Prev; + Bits |= Implies; + do { + Prev = Bits; + for (unsigned i = CPU_FEATURE_MAX; i;) + if (Bits[--i]) + Bits |= FeatureInfos[i].ImpliedFeatures; + } while (Prev != Bits); +} + +/// Create bit vector of features that are implied disabled if the feature +/// passed in Value is disabled. +static void getImpliedDisabledFeatures(FeatureBitset &Bits, unsigned Value) { + // Check all features looking for any dependent on this feature. If we find + // one, mark it and recursively find any feature that depend on it. + FeatureBitset Prev; + Bits.set(Value); + do { + Prev = Bits; + for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) + if ((FeatureInfos[i].ImpliedFeatures & Bits).any()) + Bits.set(i); + } while (Prev != Bits); +} + +void llvm::X86::updateImpliedFeatures( + StringRef Feature, bool Enabled, + StringMap<bool> &Features) { + auto I = llvm::find_if( + FeatureInfos, [&](const FeatureInfo &FI) { return FI.Name == Feature; }); + if (I == std::end(FeatureInfos)) { + // FIXME: This shouldn't happen, but may not have all features in the table + // yet. + return; + } + + FeatureBitset ImpliedBits; + if (Enabled) + getImpliedEnabledFeatures(ImpliedBits, I->ImpliedFeatures); + else + getImpliedDisabledFeatures(ImpliedBits, + std::distance(std::begin(FeatureInfos), I)); + + // Update the map entry for all implied features. + for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) + if (ImpliedBits[i] && !FeatureInfos[i].Name.empty()) + Features[FeatureInfos[i].Name] = Enabled; +} + +uint64_t llvm::X86::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { + // Processor features and mapping to processor feature value. + uint64_t FeaturesMask = 0; + for (const StringRef &FeatureStr : FeatureStrs) { + unsigned Feature = StringSwitch<unsigned>(FeatureStr) +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \ + .Case(STR, llvm::X86::FEATURE_##ENUM) +#include "llvm/TargetParser/X86TargetParser.def" + ; + FeaturesMask |= (1ULL << Feature); + } + return FeaturesMask; +} + +unsigned llvm::X86::getFeaturePriority(ProcessorFeatures Feat) { +#ifndef NDEBUG + // Check that priorities are set properly in the .def file. We expect that + // "compat" features are assigned non-duplicate consecutive priorities + // starting from zero (0, 1, ..., num_features - 1). +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) PRIORITY, + unsigned Priorities[] = { +#include "llvm/TargetParser/X86TargetParser.def" + std::numeric_limits<unsigned>::max() // Need to consume last comma. + }; + std::array<unsigned, std::size(Priorities) - 1> HelperList; + std::iota(HelperList.begin(), HelperList.end(), 0); + assert(std::is_permutation(HelperList.begin(), HelperList.end(), + std::begin(Priorities), + std::prev(std::end(Priorities))) && + "Priorities don't form consecutive range!"); +#endif + + switch (Feat) { +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \ + case X86::FEATURE_##ENUM: \ + return PRIORITY; +#include "llvm/TargetParser/X86TargetParser.def" + default: + llvm_unreachable("No Feature Priority for non-CPUSupports Features"); + } +} |
