aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/TargetParser
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/TargetParser')
-rw-r--r--llvm/lib/TargetParser/AArch64TargetParser.cpp159
-rw-r--r--llvm/lib/TargetParser/ARMTargetParser.cpp599
-rw-r--r--llvm/lib/TargetParser/ARMTargetParserCommon.cpp181
-rw-r--r--llvm/lib/TargetParser/CSKYTargetParser.cpp181
-rw-r--r--llvm/lib/TargetParser/Host.cpp1869
-rw-r--r--llvm/lib/TargetParser/LoongArchTargetParser.cpp49
-rw-r--r--llvm/lib/TargetParser/RISCVTargetParser.cpp104
-rw-r--r--llvm/lib/TargetParser/TargetParser.cpp253
-rw-r--r--llvm/lib/TargetParser/Triple.cpp1923
-rw-r--r--llvm/lib/TargetParser/Unix/Host.inc87
-rw-r--r--llvm/lib/TargetParser/Windows/Host.inc35
-rw-r--r--llvm/lib/TargetParser/X86TargetParser.cpp744
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");
+ }
+}