[X86] Replace PROC macros with an enum and a lookup table of processor information.

This patch removes the PROC macro in favor of CPUKind enum and a
table that contains information about CPUs.

The current information in the table is the CPU name, CPUKind enum
value, key feature for target multiversioning, and Is64Bit capable.
For the strings that are aliases, I've duplicated the information
in the table. This means there are more rows in the table than
CPUKind enums.

This replaces multiple StringSwitch's with loops through the table.
They are linear searches due to the table being more logically
ordered than alphabetical. The StringSwitch's would have also been
linear. I've used StringLiteral on the strings in the table so we
can quickly check the length while searching.

I contemplated having a CPUKind for each string so there was a 1:1
mapping, but didn't want to spread more names to the places that
use the enum.

My ultimate goal here is to store the features for each CPU as a
bitset within the table. Hoping to use constexpr to make this
composable so we can group features and inherit them. After the
table lookup we can turn the bitset into a list of strings for the
frontend. The current switch we have for selecting features for
CPUs has become difficult to maintain while trying to express
inheritance relationships.

Differential Revision: https://reviews.llvm.org/D82414
This commit is contained in:
Craig Topper 2020-06-24 10:36:02 -07:00
parent 98930769dc
commit c00cb13f9c
3 changed files with 209 additions and 276 deletions

View File

@ -178,245 +178,3 @@ X86_FEATURE (FEATURE_CLFLUSHOPT)
X86_FEATURE (FEATURE_SHA)
#undef X86_FEATURE_COMPAT
#undef X86_FEATURE
#ifndef PROC_WITH_FEAT
#define PROC_WITH_FEAT(ENUM, STRING, IS64BIT, KEYFEATURE) \
PROC(ENUM, STRING, IS64BIT)
#endif
#ifndef PROC
#define PROC(ENUM, STRING, IS64BIT)
#endif
#ifndef PROC_ALIAS
#define PROC_ALIAS(ENUM, ALIAS)
#endif
#define PROC_64_BIT true
#define PROC_32_BIT false
/// \name i386
/// i386-generation processors.
//@{
PROC(i386, "i386", PROC_32_BIT)
//@}
/// \name i486
/// i486-generation processors.
//@{
PROC(i486, "i486", PROC_32_BIT)
PROC(WinChipC6, "winchip-c6", PROC_32_BIT)
PROC(WinChip2, "winchip2", PROC_32_BIT)
PROC(C3, "c3", PROC_32_BIT)
//@}
/// \name i586
/// i586-generation processors, P5 microarchitecture based.
//@{
PROC(i586, "i586", PROC_32_BIT)
PROC(Pentium, "pentium", PROC_32_BIT)
PROC(PentiumMMX, "pentium-mmx", PROC_32_BIT)
//@}
/// \name i686
/// i686-generation processors, P6 / Pentium M microarchitecture based.
//@{
PROC(PentiumPro, "pentiumpro", PROC_32_BIT)
PROC(i686, "i686", PROC_32_BIT)
PROC(Pentium2, "pentium2", PROC_32_BIT)
PROC(Pentium3, "pentium3", PROC_32_BIT)
PROC_ALIAS(Pentium3, "pentium3m")
PROC(PentiumM, "pentium-m", PROC_32_BIT)
PROC(C3_2, "c3-2", PROC_32_BIT)
/// This enumerator is a bit odd, as GCC no longer accepts -march=yonah.
/// Clang however has some logic to support this.
// FIXME: Warn, deprecate, and potentially remove this.
PROC(Yonah, "yonah", PROC_32_BIT)
//@}
/// \name Netburst
/// Netburst microarchitecture based processors.
//@{
PROC(Pentium4, "pentium4", PROC_32_BIT)
PROC_ALIAS(Pentium4, "pentium4m")
PROC(Prescott, "prescott", PROC_32_BIT)
PROC(Nocona, "nocona", PROC_64_BIT)
//@}
/// \name Core
/// Core microarchitecture based processors.
//@{
PROC_WITH_FEAT(Core2, "core2", PROC_64_BIT, FEATURE_SSSE3)
/// This enumerator, like Yonah, is a bit odd. It is another
/// codename which GCC no longer accepts as an option to -march, but Clang
/// has some logic for recognizing it.
// FIXME: Warn, deprecate, and potentially remove this.
PROC(Penryn, "penryn", PROC_64_BIT)
//@}
/// \name Atom
/// Atom processors
//@{
PROC_WITH_FEAT(Bonnell, "bonnell", PROC_64_BIT, FEATURE_SSSE3)
PROC_ALIAS(Bonnell, "atom")
PROC_WITH_FEAT(Silvermont, "silvermont", PROC_64_BIT, FEATURE_SSE4_2)
PROC_ALIAS(Silvermont, "slm")
PROC_WITH_FEAT(Goldmont, "goldmont", PROC_64_BIT, FEATURE_SSE4_2)
PROC_WITH_FEAT(GoldmontPlus, "goldmont-plus", PROC_64_BIT, FEATURE_SSE4_2)
PROC_WITH_FEAT(Tremont, "tremont", PROC_64_BIT, FEATURE_SSE4_2)
//@}
/// \name Nehalem
/// Nehalem microarchitecture based processors.
PROC_WITH_FEAT(Nehalem, "nehalem", PROC_64_BIT, FEATURE_SSE4_2)
PROC_ALIAS(Nehalem, "corei7")
/// \name Westmere
/// Westmere microarchitecture based processors.
PROC_WITH_FEAT(Westmere, "westmere", PROC_64_BIT, FEATURE_PCLMUL)
/// \name Sandy Bridge
/// Sandy Bridge microarchitecture based processors.
PROC_WITH_FEAT(SandyBridge, "sandybridge", PROC_64_BIT, FEATURE_AVX)
PROC_ALIAS(SandyBridge, "corei7-avx")
/// \name Ivy Bridge
/// Ivy Bridge microarchitecture based processors.
PROC_WITH_FEAT(IvyBridge, "ivybridge", PROC_64_BIT, FEATURE_AVX)
PROC_ALIAS(IvyBridge, "core-avx-i")
/// \name Haswell
/// Haswell microarchitecture based processors.
PROC_WITH_FEAT(Haswell, "haswell", PROC_64_BIT, FEATURE_AVX2)
PROC_ALIAS(Haswell, "core-avx2")
/// \name Broadwell
/// Broadwell microarchitecture based processors.
PROC_WITH_FEAT(Broadwell, "broadwell", PROC_64_BIT, FEATURE_AVX2)
/// \name Skylake Client
/// Skylake client microarchitecture based processors.
PROC_WITH_FEAT(SkylakeClient, "skylake", PROC_64_BIT, FEATURE_AVX2)
/// \name Skylake Server
/// Skylake server microarchitecture based processors.
PROC_WITH_FEAT(SkylakeServer, "skylake-avx512", PROC_64_BIT, FEATURE_AVX512F)
PROC_ALIAS(SkylakeServer, "skx")
/// \name Cascadelake Server
/// Cascadelake Server microarchitecture based processors.
PROC_WITH_FEAT(Cascadelake, "cascadelake", PROC_64_BIT, FEATURE_AVX512VNNI)
/// \name Cooperlake Server
/// Cooperlake Server microarchitecture based processors.
PROC_WITH_FEAT(Cooperlake, "cooperlake", PROC_64_BIT, FEATURE_AVX512BF16)
/// \name Cannonlake Client
/// Cannonlake client microarchitecture based processors.
PROC_WITH_FEAT(Cannonlake, "cannonlake", PROC_64_BIT, FEATURE_AVX512VBMI)
/// \name Icelake Client
/// Icelake client microarchitecture based processors.
PROC_WITH_FEAT(IcelakeClient, "icelake-client", PROC_64_BIT, FEATURE_AVX512VBMI2)
/// \name Icelake Server
/// Icelake server microarchitecture based processors.
PROC_WITH_FEAT(IcelakeServer, "icelake-server", PROC_64_BIT, FEATURE_AVX512VBMI2)
/// \name Tigerlake
/// Tigerlake microarchitecture based processors.
PROC_WITH_FEAT(Tigerlake, "tigerlake", PROC_64_BIT, FEATURE_AVX512VP2INTERSECT)
/// \name Knights Landing
/// Knights Landing processor.
PROC_WITH_FEAT(KNL, "knl", PROC_64_BIT, FEATURE_AVX512F)
/// \name Knights Mill
/// Knights Mill processor.
PROC_WITH_FEAT(KNM, "knm", PROC_64_BIT, FEATURE_AVX5124FMAPS)
/// \name Lakemont
/// Lakemont microarchitecture based processors.
PROC(Lakemont, "lakemont", PROC_32_BIT)
/// \name K6
/// K6 architecture processors.
//@{
PROC(K6, "k6", PROC_32_BIT)
PROC(K6_2, "k6-2", PROC_32_BIT)
PROC(K6_3, "k6-3", PROC_32_BIT)
//@}
/// \name K7
/// K7 architecture processors.
//@{
PROC(Athlon, "athlon", PROC_32_BIT)
PROC_ALIAS(Athlon, "athlon-tbird")
PROC(AthlonXP, "athlon-xp", PROC_32_BIT)
PROC_ALIAS(AthlonXP, "athlon-mp")
PROC_ALIAS(AthlonXP, "athlon-4")
//@}
/// \name K8
/// K8 architecture processors.
//@{
PROC(K8, "k8", PROC_64_BIT)
PROC_ALIAS(K8, "athlon64")
PROC_ALIAS(K8, "athlon-fx")
PROC_ALIAS(K8, "opteron")
PROC(K8SSE3, "k8-sse3", PROC_64_BIT)
PROC_ALIAS(K8SSE3, "athlon64-sse3")
PROC_ALIAS(K8SSE3, "opteron-sse3")
PROC_WITH_FEAT(AMDFAM10, "amdfam10", PROC_64_BIT, FEATURE_SSE4_A)
PROC_ALIAS(AMDFAM10, "barcelona")
//@}
/// \name Bobcat
/// Bobcat architecture processors.
//@{
PROC_WITH_FEAT(BTVER1, "btver1", PROC_64_BIT, FEATURE_SSE4_A)
PROC_WITH_FEAT(BTVER2, "btver2", PROC_64_BIT, FEATURE_BMI)
//@}
/// \name Bulldozer
/// Bulldozer architecture processors.
//@{
PROC_WITH_FEAT(BDVER1, "bdver1", PROC_64_BIT, FEATURE_XOP)
PROC_WITH_FEAT(BDVER2, "bdver2", PROC_64_BIT, FEATURE_FMA)
PROC_WITH_FEAT(BDVER3, "bdver3", PROC_64_BIT, FEATURE_FMA)
PROC_WITH_FEAT(BDVER4, "bdver4", PROC_64_BIT, FEATURE_AVX2)
//@}
/// \name zen
/// Zen architecture processors.
//@{
PROC_WITH_FEAT(ZNVER1, "znver1", PROC_64_BIT, FEATURE_AVX2)
PROC_WITH_FEAT(ZNVER2, "znver2", PROC_64_BIT, FEATURE_AVX2)
//@}
/// This specification is deprecated and will be removed in the future.
/// Users should prefer K8.
// FIXME: Warn on this when the CPU is set to it.
//@{
PROC(x86_64, "x86-64", PROC_64_BIT)
//@}
/// \name Geode
/// Geode processors.
//@{
PROC(Geode, "geode", PROC_32_BIT)
//@}
#undef PROC
#undef PROC_ALIAS
#undef PROC_WITH_FEAT

View File

@ -61,8 +61,66 @@ enum ProcessorFeatures {
enum CPUKind {
CK_None,
#define PROC(ENUM, STRING, IS64BIT) CK_##ENUM,
#include "llvm/Support/X86TargetParser.def"
CK_i386,
CK_i486,
CK_WinChipC6,
CK_WinChip2,
CK_C3,
CK_i586,
CK_Pentium,
CK_PentiumMMX,
CK_PentiumPro,
CK_i686,
CK_Pentium2,
CK_Pentium3,
CK_PentiumM,
CK_C3_2,
CK_Yonah,
CK_Pentium4,
CK_Prescott,
CK_Nocona,
CK_Core2,
CK_Penryn,
CK_Bonnell,
CK_Silvermont,
CK_Goldmont,
CK_GoldmontPlus,
CK_Tremont,
CK_Nehalem,
CK_Westmere,
CK_SandyBridge,
CK_IvyBridge,
CK_Haswell,
CK_Broadwell,
CK_SkylakeClient,
CK_SkylakeServer,
CK_Cascadelake,
CK_Cooperlake,
CK_Cannonlake,
CK_IcelakeClient,
CK_IcelakeServer,
CK_Tigerlake,
CK_KNL,
CK_KNM,
CK_Lakemont,
CK_K6,
CK_K6_2,
CK_K6_3,
CK_Athlon,
CK_AthlonXP,
CK_K8,
CK_K8SSE3,
CK_AMDFAM10,
CK_BTVER1,
CK_BTVER2,
CK_BDVER1,
CK_BDVER2,
CK_BDVER3,
CK_BDVER4,
CK_ZNVER1,
CK_ZNVER2,
CK_x86_64,
CK_Geode,
};
/// Parse \p CPU string into a CPUKind. Will only accept 64-bit capable CPUs if
@ -74,6 +132,8 @@ CPUKind parseArchX86(StringRef CPU, bool Only64Bit = false);
void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values,
bool ArchIs32Bit);
ProcessorFeatures getKeyFeature(CPUKind Kind);
} // namespace X86
} // namespace llvm

View File

@ -15,44 +15,159 @@
#include "llvm/ADT/Triple.h"
using namespace llvm;
using namespace llvm::X86;
bool checkCPUKind(llvm::X86::CPUKind Kind, bool Only64Bit) {
using namespace X86;
// Perform any per-CPU checks necessary to determine if this CPU is
// acceptable.
switch (Kind) {
case CK_None:
// No processor selected!
return false;
#define PROC(ENUM, STRING, IS64BIT) \
case CK_##ENUM: \
return IS64BIT || !Only64Bit;
#include "llvm/Support/X86TargetParser.def"
}
llvm_unreachable("Unhandled CPU kind");
}
namespace {
struct ProcInfo {
StringLiteral Name;
X86::CPUKind Kind;
unsigned KeyFeature;
bool Is64Bit;
};
} // end anonymous namespace
#define PROC_64_BIT true
#define PROC_32_BIT false
static constexpr ProcInfo Processors[] = {
// i386-generation processors.
{ {"i386"}, CK_i386, ~0U, PROC_32_BIT },
// i486-generation processors.
{ {"i486"}, CK_i486, ~0U, PROC_32_BIT },
{ {"winchip-c6"}, CK_WinChipC6, ~0U, PROC_32_BIT },
{ {"winchip2"}, CK_WinChip2, ~0U, PROC_32_BIT },
{ {"c3"}, CK_C3, ~0U, PROC_32_BIT },
// i586-generation processors, P5 microarchitecture based.
{ {"i586"}, CK_i586, ~0U, PROC_32_BIT },
{ {"pentium"}, CK_Pentium, ~0U, PROC_32_BIT },
{ {"pentium-mmx"}, CK_PentiumMMX, ~0U, PROC_32_BIT },
{ {"pentiumpro"}, CK_PentiumPro, ~0U, PROC_32_BIT },
// i686-generation processors, P6 / Pentium M microarchitecture based.
{ {"i686"}, CK_i686, ~0U, PROC_32_BIT },
{ {"pentium2"}, CK_Pentium2, ~0U, PROC_32_BIT },
{ {"pentium3"}, CK_Pentium3, ~0U, PROC_32_BIT },
{ {"pentium3m"}, CK_Pentium3, ~0U, PROC_32_BIT },
{ {"pentium-m"}, CK_PentiumM, ~0U, PROC_32_BIT },
{ {"c3-2"}, CK_C3_2, ~0U, PROC_32_BIT },
{ {"yonah"}, CK_Yonah, ~0U, PROC_32_BIT },
// Netburst microarchitecture based processors.
{ {"pentium4"}, CK_Pentium4, ~0U, PROC_32_BIT },
{ {"pentium4m"}, CK_Pentium4, ~0U, PROC_32_BIT },
{ {"prescott"}, CK_Prescott, ~0U, PROC_32_BIT },
{ {"nocona"}, CK_Nocona, ~0U, PROC_64_BIT },
// Core microarchitecture based processors.
{ {"core2"}, CK_Core2, ~0U, PROC_64_BIT },
{ {"penryn"}, CK_Penryn, ~0U, PROC_64_BIT },
// Atom processors
{ {"bonnell"}, CK_Bonnell, FEATURE_SSSE3, PROC_64_BIT },
{ {"atom"}, CK_Bonnell, FEATURE_SSSE3, PROC_64_BIT },
{ {"silvermont"}, CK_Silvermont, FEATURE_SSE4_2, PROC_64_BIT },
{ {"slm"}, CK_Silvermont, FEATURE_SSE4_2, PROC_64_BIT },
{ {"goldmont"}, CK_Goldmont, FEATURE_SSE4_2, PROC_64_BIT },
{ {"goldmont-plus"}, CK_GoldmontPlus, FEATURE_SSE4_2, PROC_64_BIT },
{ {"tremont"}, CK_Tremont, FEATURE_SSE4_2, PROC_64_BIT },
// Nehalem microarchitecture based processors.
{ {"nehalem"}, CK_Nehalem, FEATURE_SSE4_2, PROC_64_BIT },
{ {"corei7"}, CK_Nehalem, FEATURE_SSE4_2, PROC_64_BIT },
// Westmere microarchitecture based processors.
{ {"westmere"}, CK_Westmere, FEATURE_PCLMUL, PROC_64_BIT },
// Sandy Bridge microarchitecture based processors.
{ {"sandybridge"}, CK_SandyBridge, FEATURE_AVX, PROC_64_BIT },
{ {"corei7-avx"}, CK_SandyBridge, FEATURE_AVX, PROC_64_BIT },
// Ivy Bridge microarchitecture based processors.
{ {"ivybridge"}, CK_IvyBridge, FEATURE_AVX, PROC_64_BIT },
{ {"core-avx-i"}, CK_IvyBridge, FEATURE_AVX, PROC_64_BIT },
// Haswell microarchitecture based processors.
{ {"haswell"}, CK_Haswell, FEATURE_AVX2, PROC_64_BIT },
{ {"core-avx2"}, CK_Haswell, FEATURE_AVX2, PROC_64_BIT },
// Broadwell microarchitecture based processors.
{ {"broadwell"}, CK_Broadwell, FEATURE_AVX2, PROC_64_BIT },
// Skylake client microarchitecture based processors.
{ {"skylake"}, CK_SkylakeClient, FEATURE_AVX2, PROC_64_BIT },
// Skylake server microarchitecture based processors.
{ {"skylake-avx512"}, CK_SkylakeServer, FEATURE_AVX512F, PROC_64_BIT },
{ {"skx"}, CK_SkylakeServer, FEATURE_AVX512F, PROC_64_BIT },
// Cascadelake Server microarchitecture based processors.
{ {"cascadelake"}, CK_Cascadelake, FEATURE_AVX512VNNI, PROC_64_BIT },
// Cooperlake Server microarchitecture based processors.
{ {"cooperlake"}, CK_Cooperlake, FEATURE_AVX512BF16, PROC_64_BIT },
// Cannonlake client microarchitecture based processors.
{ {"cannonlake"}, CK_Cannonlake, FEATURE_AVX512VBMI, PROC_64_BIT },
// Icelake client microarchitecture based processors.
{ {"icelake-client"}, CK_IcelakeClient, FEATURE_AVX512VBMI2, PROC_64_BIT },
// Icelake server microarchitecture based processors.
{ {"icelake-server"}, CK_IcelakeServer, FEATURE_AVX512VBMI2, PROC_64_BIT },
// Tigerlake microarchitecture based processors.
{ {"tigerlake"}, CK_Tigerlake, FEATURE_AVX512VP2INTERSECT, PROC_64_BIT },
// Knights Landing processor.
{ {"knl"}, CK_KNL, FEATURE_AVX512F, PROC_64_BIT },
// Knights Mill processor.
{ {"knm"}, CK_KNM, FEATURE_AVX5124FMAPS, PROC_64_BIT },
// Lakemont microarchitecture based processors.
{ {"lakemont"}, CK_Lakemont, ~0U, PROC_32_BIT },
// K6 architecture processors.
{ {"k6"}, CK_K6, ~0U, PROC_32_BIT },
{ {"k6-2"}, CK_K6_2, ~0U, PROC_32_BIT },
{ {"k6-3"}, CK_K6_3, ~0U, PROC_32_BIT },
// K7 architecture processors.
{ {"athlon"}, CK_Athlon, ~0U, PROC_32_BIT },
{ {"athlon-tbird"}, CK_Athlon, ~0U, PROC_32_BIT },
{ {"athlon-xp"}, CK_AthlonXP, ~0U, PROC_32_BIT },
{ {"athlon-mp"}, CK_AthlonXP, ~0U, PROC_32_BIT },
{ {"athlon-4"}, CK_AthlonXP, ~0U, PROC_32_BIT },
// K8 architecture processors.
{ {"k8"}, CK_K8, ~0U, PROC_64_BIT },
{ {"athlon64"}, CK_K8, ~0U, PROC_64_BIT },
{ {"athlon-fx"}, CK_K8, ~0U, PROC_64_BIT },
{ {"opteron"}, CK_K8, ~0U, PROC_64_BIT },
{ {"k8-sse3"}, CK_K8SSE3, ~0U, PROC_64_BIT },
{ {"athlon64-sse3"}, CK_K8SSE3, ~0U, PROC_64_BIT },
{ {"opteron-sse3"}, CK_K8SSE3, ~0U, PROC_64_BIT },
{ {"amdfam10"}, CK_AMDFAM10, FEATURE_SSE4_A, PROC_64_BIT },
{ {"barcelona"}, CK_AMDFAM10, FEATURE_SSE4_A, PROC_64_BIT },
// Bobcat architecture processors.
{ {"btver1"}, CK_BTVER1, FEATURE_SSE4_A, PROC_64_BIT },
{ {"btver2"}, CK_BTVER2, FEATURE_BMI, PROC_64_BIT },
// Bulldozer architecture processors.
{ {"bdver1"}, CK_BDVER1, FEATURE_XOP, PROC_64_BIT },
{ {"bdver2"}, CK_BDVER2, FEATURE_FMA, PROC_64_BIT },
{ {"bdver3"}, CK_BDVER3, FEATURE_FMA, PROC_64_BIT },
{ {"bdver4"}, CK_BDVER4, FEATURE_AVX2, PROC_64_BIT },
// Zen architecture processors.
{ {"znver1"}, CK_ZNVER1, FEATURE_AVX2, PROC_64_BIT },
{ {"znver2"}, CK_ZNVER2, FEATURE_AVX2, PROC_64_BIT },
// Generic 64-bit processor.
{ {"x86-64"}, CK_x86_64, ~0U, PROC_64_BIT },
// Geode processors.
{ {"geode"}, CK_Geode, ~0U, PROC_32_BIT },
};
X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) {
X86::CPUKind Kind = llvm::StringSwitch<CPUKind>(CPU)
#define PROC(ENUM, STRING, IS64BIT) .Case(STRING, CK_##ENUM)
#define PROC_ALIAS(ENUM, ALIAS) .Case(ALIAS, CK_##ENUM)
#include "llvm/Support/X86TargetParser.def"
.Default(CK_None);
for (const auto &P : Processors)
if (P.Name == CPU && (P.Is64Bit || !Only64Bit))
return P.Kind;
if (!checkCPUKind(Kind, Only64Bit))
Kind = CK_None;
return Kind;
return CK_None;
}
void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values,
bool Only64Bit) {
#define PROC(ENUM, STRING, IS64BIT) \
if (IS64BIT || !Only64Bit) \
Values.emplace_back(STRING);
// For aliases we need to lookup the CPUKind to get the 64-bit ness.
#define PROC_ALIAS(ENUM, ALIAS) \
if (checkCPUKind(CK_##ENUM, Only64Bit)) \
Values.emplace_back(ALIAS);
#include "llvm/Support/X86TargetParser.def"
for (const auto &P : Processors)
if (P.Is64Bit || !Only64Bit)
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!");
}