forked from OSchip/llvm-project
[cpu-detection] Substantial refactor of Host CPU detection code (x86)
Summary: Following D20970 (committed as r271726). This is a substantial refactoring of the host CPU detection code. There is no functionality change intended, but the changes are extensive. Definitions of architecture types and subtypes are by no means exhaustive or perfectly defined, but a fair starting point. Suggestions for futher improvements are welcome. Reviewers: llvm-commits Differential Revision: http://reviews.llvm.org/D20988 llvm-svn: 271921
This commit is contained in:
parent
917a42d8b5
commit
76c4a855bc
|
@ -73,6 +73,102 @@ static ssize_t LLVM_ATTRIBUTE_UNUSED readCpuInfo(void *Buf, size_t Size) {
|
|||
defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) || \
|
||||
defined(_M_X64)
|
||||
|
||||
enum VendorSignatures {
|
||||
SIG_INTEL = 0x756e6547 /* Genu */,
|
||||
SIG_AMD = 0x68747541 /* Auth */
|
||||
};
|
||||
|
||||
enum ProcessorVendors {
|
||||
VENDOR_INTEL = 1,
|
||||
VENDOR_AMD,
|
||||
VENDOR_OTHER,
|
||||
VENDOR_MAX
|
||||
};
|
||||
|
||||
enum ProcessorTypes {
|
||||
INTEL_ATOM = 1,
|
||||
INTEL_CORE2,
|
||||
INTEL_COREI7,
|
||||
AMDFAM10H,
|
||||
AMDFAM15H,
|
||||
INTEL_i386,
|
||||
INTEL_i486,
|
||||
INTEL_PENTIUM,
|
||||
INTEL_PENTIUM_PRO,
|
||||
INTEL_PENTIUM_II,
|
||||
INTEL_PENTIUM_III,
|
||||
INTEL_PENTIUM_IV,
|
||||
INTEL_PENTIUM_M,
|
||||
INTEL_CORE_DUO,
|
||||
INTEL_XEONPHI,
|
||||
INTEL_X86_64,
|
||||
INTEL_NOCONA,
|
||||
INTEL_PRESCOTT,
|
||||
AMD_i486,
|
||||
AMDPENTIUM,
|
||||
AMDATHLON,
|
||||
AMDFAM14H,
|
||||
AMDFAM16H,
|
||||
CPU_TYPE_MAX
|
||||
};
|
||||
|
||||
enum ProcessorSubtypes {
|
||||
INTEL_COREI7_NEHALEM = 1,
|
||||
INTEL_COREI7_WESTMERE,
|
||||
INTEL_COREI7_SANDYBRIDGE,
|
||||
AMDFAM10H_BARCELONA,
|
||||
AMDFAM10H_SHANGHAI,
|
||||
AMDFAM10H_ISTANBUL,
|
||||
AMDFAM15H_BDVER1,
|
||||
AMDFAM15H_BDVER2,
|
||||
INTEL_PENTIUM_MMX,
|
||||
INTEL_CORE2_65,
|
||||
INTEL_CORE2_45,
|
||||
INTEL_COREI7_IVYBRIDGE,
|
||||
INTEL_COREI7_HASWELL,
|
||||
INTEL_COREI7_BROADWELL,
|
||||
INTEL_COREI7_SKYLAKE,
|
||||
INTEL_COREI7_SKYLAKE_AVX512,
|
||||
INTEL_ATOM_BONNELL,
|
||||
INTEL_ATOM_SILVERMONT,
|
||||
INTEL_KNIGHTS_LANDING,
|
||||
AMDPENTIUM_K6,
|
||||
AMDPENTIUM_K62,
|
||||
AMDPENTIUM_K63,
|
||||
AMDPENTIUM_GEODE,
|
||||
AMDATHLON_TBIRD,
|
||||
AMDATHLON_MP,
|
||||
AMDATHLON_XP,
|
||||
AMDATHLON_K8SSE3,
|
||||
AMDATHLON_OPTERON,
|
||||
AMDATHLON_FX,
|
||||
AMDATHLON_64,
|
||||
AMD_BTVER1,
|
||||
AMD_BTVER2,
|
||||
AMDFAM15H_BDVER3,
|
||||
AMDFAM15H_BDVER4,
|
||||
CPU_SUBTYPE_MAX
|
||||
};
|
||||
|
||||
enum ProcessorFeatures {
|
||||
FEATURE_CMOV = 0,
|
||||
FEATURE_MMX,
|
||||
FEATURE_POPCNT,
|
||||
FEATURE_SSE,
|
||||
FEATURE_SSE2,
|
||||
FEATURE_SSE3,
|
||||
FEATURE_SSSE3,
|
||||
FEATURE_SSE4_1,
|
||||
FEATURE_SSE4_2,
|
||||
FEATURE_AVX,
|
||||
FEATURE_AVX2,
|
||||
FEATURE_AVX512,
|
||||
FEATURE_AVX512SAVE,
|
||||
FEATURE_MOVBE,
|
||||
FEATURE_ADX,
|
||||
FEATURE_EM64T
|
||||
};
|
||||
|
||||
/// 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,
|
||||
|
@ -199,51 +295,16 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
|
|||
}
|
||||
}
|
||||
|
||||
StringRef sys::getHostCPUName() {
|
||||
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
|
||||
if (getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX))
|
||||
return "generic";
|
||||
unsigned Family = 0;
|
||||
unsigned Model = 0;
|
||||
detectX86FamilyModel(EAX, &Family, &Model);
|
||||
|
||||
union {
|
||||
unsigned u[3];
|
||||
char c[12];
|
||||
} text;
|
||||
|
||||
unsigned MaxLeaf;
|
||||
getX86CpuIDAndInfo(0, &MaxLeaf, text.u + 0, text.u + 2, text.u + 1);
|
||||
|
||||
bool HasMMX = (EDX >> 23) & 1;
|
||||
bool HasSSE = (EDX >> 25) & 1;
|
||||
bool HasSSE2 = (EDX >> 26) & 1;
|
||||
bool HasSSE3 = (ECX >> 0) & 1;
|
||||
bool HasSSSE3 = (ECX >> 9) & 1;
|
||||
bool HasSSE41 = (ECX >> 19) & 1;
|
||||
bool HasSSE42 = (ECX >> 20) & 1;
|
||||
bool HasMOVBE = (ECX >> 22) & 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.
|
||||
const unsigned AVXBits = (1 << 27) | (1 << 28);
|
||||
bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&
|
||||
((EAX & 0x6) == 0x6);
|
||||
bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
|
||||
bool HasLeaf7 =
|
||||
MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
|
||||
bool HasADX = HasLeaf7 && ((EBX >> 19) & 1);
|
||||
bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20);
|
||||
bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1);
|
||||
|
||||
getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
|
||||
bool Em64T = (EDX >> 29) & 0x1;
|
||||
bool HasTBM = (ECX >> 21) & 0x1;
|
||||
|
||||
if (memcmp(text.c, "GenuineIntel", 12) == 0) {
|
||||
static void
|
||||
getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model,
|
||||
unsigned int Brand_id, unsigned int Features,
|
||||
unsigned *Type, unsigned *Subtype) {
|
||||
if (Brand_id != 0)
|
||||
return;
|
||||
switch (Family) {
|
||||
case 3:
|
||||
return "i386";
|
||||
*Type = INTEL_i386;
|
||||
break;
|
||||
case 4:
|
||||
switch (Model) {
|
||||
case 0: // Intel486 DX processors
|
||||
|
@ -256,7 +317,8 @@ StringRef sys::getHostCPUName() {
|
|||
case 7: // Write-Back Enhanced IntelDX2 processors
|
||||
case 8: // IntelDX4 OverDrive processors, IntelDX4 processors
|
||||
default:
|
||||
return "i486";
|
||||
*Type = INTEL_i486;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
switch (Model) {
|
||||
|
@ -267,117 +329,132 @@ StringRef sys::getHostCPUName() {
|
|||
// 150, 166, 200)
|
||||
case 3: // Pentium OverDrive processors for Intel486 processor-based
|
||||
// systems
|
||||
return "pentium";
|
||||
|
||||
*Type = INTEL_PENTIUM;
|
||||
break;
|
||||
case 4: // Pentium OverDrive processor with MMX technology for Pentium
|
||||
// processor (75, 90, 100, 120, 133), Pentium processor with
|
||||
// MMX technology (166, 200)
|
||||
return "pentium-mmx";
|
||||
|
||||
*Type = INTEL_PENTIUM;
|
||||
*Subtype = INTEL_PENTIUM_MMX;
|
||||
break;
|
||||
default:
|
||||
return "pentium";
|
||||
*Type = INTEL_PENTIUM;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
switch (Model) {
|
||||
case 0x01: // Pentium Pro processor
|
||||
return "pentiumpro";
|
||||
|
||||
*Type = INTEL_PENTIUM_PRO;
|
||||
break;
|
||||
case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor,
|
||||
// model 03
|
||||
case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor,
|
||||
// model 05, and Intel Celeron processor, model 05
|
||||
case 0x06: // Celeron processor, model 06
|
||||
return "pentium2";
|
||||
|
||||
*Type = INTEL_PENTIUM_II;
|
||||
break;
|
||||
case 0x07: // Pentium III processor, model 07, and Pentium III Xeon
|
||||
// processor, model 07
|
||||
case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor,
|
||||
// model 08, and Celeron processor, model 08
|
||||
case 0x0a: // Pentium III Xeon processor, model 0Ah
|
||||
case 0x0b: // Pentium III processor, model 0Bh
|
||||
return "pentium3";
|
||||
|
||||
case 0x09: // Intel Pentium M processor, Intel Celeron M processor model
|
||||
// 09.
|
||||
*Type = INTEL_PENTIUM_III;
|
||||
break;
|
||||
case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09.
|
||||
case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model
|
||||
// 0Dh. All processors are manufactured using the 90 nm
|
||||
// process.
|
||||
// 0Dh. All processors are manufactured using the 90 nm process.
|
||||
case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579
|
||||
// Integrated Processor with Intel QuickAssist Technology
|
||||
return "pentium-m";
|
||||
|
||||
*Type = INTEL_PENTIUM_M;
|
||||
break;
|
||||
case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model
|
||||
// 0Eh. All processors are manufactured using the 65 nm
|
||||
// process.
|
||||
return "yonah";
|
||||
|
||||
// 0Eh. All processors are manufactured using the 65 nm process.
|
||||
*Type = INTEL_CORE_DUO;
|
||||
break; // yonah
|
||||
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.
|
||||
// 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
|
||||
return "core2";
|
||||
|
||||
*Type = INTEL_CORE2; // "core2"
|
||||
*Subtype = INTEL_CORE2_65;
|
||||
break;
|
||||
case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
|
||||
// 17h. All processors are manufactured using the 45 nm
|
||||
// process.
|
||||
// 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
|
||||
case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
|
||||
// the 45 nm process.
|
||||
return "penryn";
|
||||
|
||||
*Type = INTEL_CORE2; // "penryn"
|
||||
*Subtype = INTEL_CORE2_45;
|
||||
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
|
||||
return "nehalem";
|
||||
*Type = INTEL_COREI7; // "nehalem"
|
||||
*Subtype = 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
|
||||
return "westmere";
|
||||
|
||||
*Type = INTEL_COREI7; // "westmere"
|
||||
*Subtype = INTEL_COREI7_WESTMERE;
|
||||
break;
|
||||
case 0x2a: // Intel Core i7 processor. All processors are manufactured
|
||||
// using the 32 nm process.
|
||||
case 0x2d:
|
||||
return "sandybridge";
|
||||
|
||||
*Type = INTEL_COREI7; //"sandybridge"
|
||||
*Subtype = INTEL_COREI7_SANDYBRIDGE;
|
||||
break;
|
||||
case 0x3a:
|
||||
case 0x3e: // Ivy Bridge EP
|
||||
return "ivybridge";
|
||||
*Type = INTEL_COREI7; // "ivybridge"
|
||||
*Subtype = INTEL_COREI7_IVYBRIDGE;
|
||||
break;
|
||||
|
||||
// Haswell:
|
||||
case 0x3c:
|
||||
case 0x3f:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
return "haswell";
|
||||
*Type = INTEL_COREI7; // "haswell"
|
||||
*Subtype = INTEL_COREI7_HASWELL;
|
||||
break;
|
||||
|
||||
// Broadwell:
|
||||
case 0x3d:
|
||||
case 0x47:
|
||||
case 0x4f:
|
||||
case 0x56:
|
||||
return "broadwell";
|
||||
*Type = INTEL_COREI7; // "broadwell"
|
||||
*Subtype = INTEL_COREI7_BROADWELL;
|
||||
break;
|
||||
|
||||
// Skylake:
|
||||
case 0x4e:
|
||||
return "skylake-avx512";
|
||||
*Type = INTEL_COREI7; // "skylake-avx512"
|
||||
*Subtype = INTEL_COREI7_SKYLAKE_AVX512;
|
||||
break;
|
||||
case 0x5e:
|
||||
return "skylake";
|
||||
*Type = INTEL_COREI7; // "skylake"
|
||||
*Subtype = INTEL_COREI7_SKYLAKE;
|
||||
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
|
||||
return "bonnell";
|
||||
*Type = INTEL_ATOM;
|
||||
*Subtype = INTEL_ATOM_BONNELL;
|
||||
break; // "bonnell"
|
||||
|
||||
// Atom Silvermont codes from the Intel software optimization guide.
|
||||
case 0x37:
|
||||
|
@ -386,35 +463,79 @@ StringRef sys::getHostCPUName() {
|
|||
case 0x5a:
|
||||
case 0x5d:
|
||||
case 0x4c: // really airmont
|
||||
return "silvermont";
|
||||
*Type = INTEL_ATOM;
|
||||
*Subtype = INTEL_ATOM_SILVERMONT;
|
||||
break; // "silvermont"
|
||||
|
||||
case 0x57:
|
||||
return "knl";
|
||||
*Type = INTEL_XEONPHI; // knl
|
||||
*Subtype = INTEL_KNIGHTS_LANDING;
|
||||
break;
|
||||
|
||||
default: // Unknown family 6 CPU, try to guess.
|
||||
if (HasAVX512)
|
||||
return "knl";
|
||||
if (HasADX)
|
||||
return "broadwell";
|
||||
if (HasAVX2)
|
||||
return "haswell";
|
||||
if (HasAVX)
|
||||
return "sandybridge";
|
||||
if (HasSSE42)
|
||||
return HasMOVBE ? "silvermont" : "nehalem";
|
||||
if (HasSSE41)
|
||||
return "penryn";
|
||||
if (HasSSSE3)
|
||||
return HasMOVBE ? "bonnell" : "core2";
|
||||
if (Em64T)
|
||||
return "x86-64";
|
||||
if (HasSSE2)
|
||||
return "pentium-m";
|
||||
if (HasSSE)
|
||||
return "pentium3";
|
||||
if (HasMMX)
|
||||
return "pentium2";
|
||||
return "pentiumpro";
|
||||
if (Features & (1 << FEATURE_AVX512)) {
|
||||
*Type = INTEL_XEONPHI; // knl
|
||||
*Subtype = INTEL_KNIGHTS_LANDING;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_ADX)) {
|
||||
*Type = INTEL_COREI7;
|
||||
*Subtype = INTEL_COREI7_BROADWELL;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_AVX2)) {
|
||||
*Type = INTEL_COREI7;
|
||||
*Subtype = INTEL_COREI7_HASWELL;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_AVX)) {
|
||||
*Type = INTEL_COREI7;
|
||||
*Subtype = INTEL_COREI7_SANDYBRIDGE;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_SSE4_2)) {
|
||||
if (Features & (1 << FEATURE_MOVBE)) {
|
||||
*Type = INTEL_ATOM;
|
||||
*Subtype = INTEL_ATOM_SILVERMONT;
|
||||
} else {
|
||||
*Type = INTEL_COREI7;
|
||||
*Subtype = INTEL_COREI7_NEHALEM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_SSE4_1)) {
|
||||
*Type = INTEL_CORE2; // "penryn"
|
||||
*Subtype = INTEL_CORE2_45;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_SSSE3)) {
|
||||
if (Features & (1 << FEATURE_MOVBE)) {
|
||||
*Type = INTEL_ATOM;
|
||||
*Subtype = INTEL_ATOM_BONNELL; // "bonnell"
|
||||
} else {
|
||||
*Type = INTEL_CORE2; // "core2"
|
||||
*Subtype = INTEL_CORE2_65;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_EM64T)) {
|
||||
*Type = INTEL_X86_64;
|
||||
break; // x86-64
|
||||
}
|
||||
if (Features & (1 << FEATURE_SSE2)) {
|
||||
*Type = INTEL_PENTIUM_M;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_SSE)) {
|
||||
*Type = INTEL_PENTIUM_III;
|
||||
break;
|
||||
}
|
||||
if (Features & (1 << FEATURE_MMX)) {
|
||||
*Type = INTEL_PENTIUM_II;
|
||||
break;
|
||||
}
|
||||
*Type = INTEL_PENTIUM_PRO;
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
switch (Model) {
|
||||
|
@ -427,7 +548,9 @@ StringRef sys::getHostCPUName() {
|
|||
// Intel Xeon processor, Intel Xeon processor MP, Intel Celeron
|
||||
// processor, and Mobile Intel Celeron processor. All processors
|
||||
// are model 02h and manufactured using the 0.13 micron process.
|
||||
return (Em64T) ? "x86-64" : "pentium4";
|
||||
*Type =
|
||||
((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV);
|
||||
break;
|
||||
|
||||
case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D
|
||||
// processor. All processors are model 03h and manufactured using
|
||||
|
@ -440,86 +563,352 @@ StringRef sys::getHostCPUName() {
|
|||
// Extreme Edition, Intel Xeon processor, Intel Xeon processor
|
||||
// MP, Intel Celeron D processor. All processors are model 06h
|
||||
// and manufactured using the 65 nm process.
|
||||
return (Em64T) ? "nocona" : "prescott";
|
||||
*Type =
|
||||
((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (Em64T) ? "x86-64" : "pentium4";
|
||||
*Type =
|
||||
((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return "generic";
|
||||
break; /*"generic"*/
|
||||
}
|
||||
} else if (memcmp(text.c, "AuthenticAMD", 12) == 0) {
|
||||
}
|
||||
|
||||
static void getAMDProcessorTypeAndSubtype(unsigned int Family,
|
||||
unsigned int Model,
|
||||
unsigned int Features,
|
||||
unsigned *Type,
|
||||
unsigned *Subtype) {
|
||||
// FIXME: this poorly matches the generated SubtargetFeatureKV table. There
|
||||
// appears to be no way to generate the wide variety of AMD-specific targets
|
||||
// from the information returned from CPUID.
|
||||
switch (Family) {
|
||||
case 4:
|
||||
return "i486";
|
||||
*Type = AMD_i486;
|
||||
case 5:
|
||||
*Type = AMDPENTIUM;
|
||||
switch (Model) {
|
||||
case 6:
|
||||
case 7:
|
||||
return "k6";
|
||||
*Subtype = AMDPENTIUM_K6;
|
||||
break; // "k6"
|
||||
case 8:
|
||||
return "k6-2";
|
||||
*Subtype = AMDPENTIUM_K62;
|
||||
break; // "k6-2"
|
||||
case 9:
|
||||
case 13:
|
||||
return "k6-3";
|
||||
*Subtype = AMDPENTIUM_K63;
|
||||
break; // "k6-3"
|
||||
case 10:
|
||||
*Subtype = AMDPENTIUM_GEODE;
|
||||
break; // "geode"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
*Type = AMDATHLON;
|
||||
switch (Model) {
|
||||
case 4:
|
||||
*Subtype = AMDATHLON_TBIRD;
|
||||
break; // "athlon-tbird"
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
*Subtype = AMDATHLON_MP;
|
||||
break; // "athlon-mp"
|
||||
case 10:
|
||||
*Subtype = AMDATHLON_XP;
|
||||
break; // "athlon-xp"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
*Type = AMDATHLON;
|
||||
if (Features & (1 << FEATURE_SSE3)) {
|
||||
*Subtype = AMDATHLON_K8SSE3;
|
||||
break; // "k8-sse3"
|
||||
}
|
||||
switch (Model) {
|
||||
case 1:
|
||||
*Subtype = AMDATHLON_OPTERON;
|
||||
break; // "opteron"
|
||||
case 5:
|
||||
*Subtype = AMDATHLON_FX;
|
||||
break; // "athlon-fx"; also opteron
|
||||
default:
|
||||
*Subtype = AMDATHLON_64;
|
||||
break; // "athlon64"
|
||||
}
|
||||
case 16:
|
||||
*Type = AMDFAM10H; // "amdfam10"
|
||||
switch (Model) {
|
||||
case 2:
|
||||
*Subtype = AMDFAM10H_BARCELONA;
|
||||
break;
|
||||
case 4:
|
||||
*Subtype = AMDFAM10H_SHANGHAI;
|
||||
break;
|
||||
case 8:
|
||||
*Subtype = AMDFAM10H_ISTANBUL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case 20:
|
||||
*Type = AMDFAM14H;
|
||||
*Subtype = AMD_BTVER1;
|
||||
break; // "btver1";
|
||||
case 21:
|
||||
*Type = AMDFAM15H;
|
||||
if (!(Features &
|
||||
(1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback.
|
||||
*Subtype = AMD_BTVER1;
|
||||
break; // "btver1"
|
||||
}
|
||||
if (Model >= 0x50 && Model <= 0x6f) {
|
||||
*Subtype = AMDFAM15H_BDVER4;
|
||||
break; // "bdver4"; 50h-6Fh: Excavator
|
||||
}
|
||||
if (Model >= 0x30 && Model <= 0x3f) {
|
||||
*Subtype = AMDFAM15H_BDVER3;
|
||||
break; // "bdver3"; 30h-3Fh: Steamroller
|
||||
}
|
||||
if (Model >= 0x10 && Model <= 0x1f) {
|
||||
*Subtype = AMDFAM15H_BDVER2;
|
||||
break; // "bdver2"; 10h-1Fh: Piledriver
|
||||
}
|
||||
if (Model <= 0x0f) {
|
||||
*Subtype = AMDFAM15H_BDVER1;
|
||||
break; // "bdver1"; 00h-0Fh: Bulldozer
|
||||
}
|
||||
break;
|
||||
case 22:
|
||||
*Type = AMDFAM16H;
|
||||
if (!(Features &
|
||||
(1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback.
|
||||
*Subtype = AMD_BTVER1;
|
||||
break; // "btver1";
|
||||
}
|
||||
*Subtype = AMD_BTVER2;
|
||||
break; // "btver2"
|
||||
default:
|
||||
break; // "generic"
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX,
|
||||
unsigned MaxLeaf) {
|
||||
unsigned Features = 0;
|
||||
unsigned int EAX, EBX;
|
||||
Features |= (((EDX >> 23) & 1) << FEATURE_MMX);
|
||||
Features |= (((EDX >> 25) & 1) << FEATURE_SSE);
|
||||
Features |= (((EDX >> 26) & 1) << FEATURE_SSE2);
|
||||
Features |= (((ECX >> 0) & 1) << FEATURE_SSE3);
|
||||
Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3);
|
||||
Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1);
|
||||
Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2);
|
||||
Features |= (((ECX >> 22) & 1) << 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);
|
||||
bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
|
||||
bool HasLeaf7 =
|
||||
MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
|
||||
bool HasADX = HasLeaf7 && ((EBX >> 19) & 1);
|
||||
bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20);
|
||||
bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1);
|
||||
Features |= (HasAVX << FEATURE_AVX);
|
||||
Features |= (HasAVX2 << FEATURE_AVX2);
|
||||
Features |= (HasAVX512 << FEATURE_AVX512);
|
||||
Features |= (HasAVX512Save << FEATURE_AVX512SAVE);
|
||||
Features |= (HasADX << FEATURE_ADX);
|
||||
|
||||
getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
|
||||
Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T);
|
||||
return Features;
|
||||
}
|
||||
|
||||
StringRef sys::getHostCPUName() {
|
||||
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
|
||||
unsigned MaxLeaf, Vendor;
|
||||
|
||||
if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX))
|
||||
return "generic";
|
||||
if (getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX))
|
||||
return "generic";
|
||||
|
||||
unsigned Brand_id = EBX & 0xff;
|
||||
unsigned Family = 0, Model = 0;
|
||||
unsigned Features = 0;
|
||||
detectX86FamilyModel(EAX, &Family, &Model);
|
||||
Features = getAvailableFeatures(ECX, EDX, MaxLeaf);
|
||||
|
||||
unsigned Type;
|
||||
unsigned Subtype;
|
||||
|
||||
if (Vendor == SIG_INTEL) {
|
||||
getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, &Type,
|
||||
&Subtype);
|
||||
switch (Type) {
|
||||
case INTEL_i386:
|
||||
return "i386";
|
||||
case INTEL_i486:
|
||||
return "i486";
|
||||
case INTEL_PENTIUM:
|
||||
if (Subtype == INTEL_PENTIUM_MMX)
|
||||
return "pentium-mmx";
|
||||
return "pentium";
|
||||
case INTEL_PENTIUM_PRO:
|
||||
return "pentiumpro";
|
||||
case INTEL_PENTIUM_II:
|
||||
return "pentium2";
|
||||
case INTEL_PENTIUM_III:
|
||||
return "pentium3";
|
||||
case INTEL_PENTIUM_IV:
|
||||
return "pentium4";
|
||||
case INTEL_PENTIUM_M:
|
||||
return "pentium-m";
|
||||
case INTEL_CORE_DUO:
|
||||
return "yonah";
|
||||
case INTEL_CORE2:
|
||||
switch (Subtype) {
|
||||
case INTEL_CORE2_65:
|
||||
return "core2";
|
||||
case INTEL_CORE2_45:
|
||||
return "penryn";
|
||||
default:
|
||||
return "core2";
|
||||
}
|
||||
case INTEL_COREI7:
|
||||
switch (Subtype) {
|
||||
case INTEL_COREI7_NEHALEM:
|
||||
return "nehalem";
|
||||
case INTEL_COREI7_WESTMERE:
|
||||
return "westmere";
|
||||
case INTEL_COREI7_SANDYBRIDGE:
|
||||
return "sandybridge";
|
||||
case INTEL_COREI7_IVYBRIDGE:
|
||||
return "ivybridge";
|
||||
case INTEL_COREI7_HASWELL:
|
||||
return "haswell";
|
||||
case INTEL_COREI7_BROADWELL:
|
||||
return "broadwell";
|
||||
case INTEL_COREI7_SKYLAKE:
|
||||
return "skylake";
|
||||
case INTEL_COREI7_SKYLAKE_AVX512:
|
||||
return "skylake-avx512";
|
||||
default:
|
||||
return "corei7";
|
||||
}
|
||||
case INTEL_ATOM:
|
||||
switch (Subtype) {
|
||||
case INTEL_ATOM_BONNELL:
|
||||
return "bonnell";
|
||||
case INTEL_ATOM_SILVERMONT:
|
||||
return "silvermont";
|
||||
default:
|
||||
return "atom";
|
||||
}
|
||||
case INTEL_XEONPHI:
|
||||
return "knl"; /*update for more variants added*/
|
||||
case INTEL_X86_64:
|
||||
return "x86-64";
|
||||
case INTEL_NOCONA:
|
||||
return "nocona";
|
||||
case INTEL_PRESCOTT:
|
||||
return "prescott";
|
||||
default:
|
||||
return "generic";
|
||||
}
|
||||
} else if (Vendor == SIG_AMD) {
|
||||
getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, &Subtype);
|
||||
switch (Type) {
|
||||
case AMD_i486:
|
||||
return "i486";
|
||||
case AMDPENTIUM:
|
||||
switch (Subtype) {
|
||||
case AMDPENTIUM_K6:
|
||||
return "k6";
|
||||
case AMDPENTIUM_K62:
|
||||
return "k6-2";
|
||||
case AMDPENTIUM_K63:
|
||||
return "k6-3";
|
||||
case AMDPENTIUM_GEODE:
|
||||
return "geode";
|
||||
default:
|
||||
return "pentium";
|
||||
}
|
||||
case 6:
|
||||
switch (Model) {
|
||||
case 4:
|
||||
case AMDATHLON:
|
||||
switch (Subtype) {
|
||||
case AMDATHLON_TBIRD:
|
||||
return "athlon-tbird";
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case AMDATHLON_MP:
|
||||
return "athlon-mp";
|
||||
case 10:
|
||||
case AMDATHLON_XP:
|
||||
return "athlon-xp";
|
||||
case AMDATHLON_K8SSE3:
|
||||
return "k8-sse3";
|
||||
case AMDATHLON_OPTERON:
|
||||
return "opteron";
|
||||
case AMDATHLON_FX:
|
||||
return "athlon-fx";
|
||||
case AMDATHLON_64:
|
||||
return "athlon64";
|
||||
default:
|
||||
return "athlon";
|
||||
}
|
||||
case 15:
|
||||
if (HasSSE3)
|
||||
return "k8-sse3";
|
||||
switch (Model) {
|
||||
case 1:
|
||||
return "opteron";
|
||||
case 5:
|
||||
return "athlon-fx"; // also opteron
|
||||
case AMDFAM10H:
|
||||
switch (Subtype) {
|
||||
case AMDFAM10H_BARCELONA:
|
||||
return "amdfam10-barcelona";
|
||||
case AMDFAM10H_SHANGHAI:
|
||||
return "amdfam10-shanghai";
|
||||
case AMDFAM10H_ISTANBUL:
|
||||
return "amdfam10-istanbul";
|
||||
default:
|
||||
return "athlon64";
|
||||
}
|
||||
case 16:
|
||||
return "amdfam10";
|
||||
case 20:
|
||||
}
|
||||
case AMDFAM14H:
|
||||
return "btver1";
|
||||
case 21:
|
||||
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
|
||||
case AMDFAM15H:
|
||||
switch (Subtype) {
|
||||
case AMDFAM15H_BDVER1:
|
||||
return "bdver1";
|
||||
case AMDFAM15H_BDVER2:
|
||||
return "bdver2";
|
||||
case AMDFAM15H_BDVER3:
|
||||
return "bdver3";
|
||||
case AMDFAM15H_BDVER4:
|
||||
return "bdver4";
|
||||
case AMD_BTVER1:
|
||||
return "btver1";
|
||||
if (Model >= 0x50)
|
||||
return "bdver4"; // 50h-6Fh: Excavator
|
||||
if (Model >= 0x30)
|
||||
return "bdver3"; // 30h-3Fh: Steamroller
|
||||
if (Model >= 0x10 || HasTBM)
|
||||
return "bdver2"; // 10h-1Fh: Piledriver
|
||||
return "bdver1"; // 00h-0Fh: Bulldozer
|
||||
case 22:
|
||||
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
|
||||
default:
|
||||
return "amdfam15";
|
||||
}
|
||||
case AMDFAM16H:
|
||||
switch (Subtype) {
|
||||
case AMD_BTVER1:
|
||||
return "btver1";
|
||||
case AMD_BTVER2:
|
||||
return "btver2";
|
||||
default:
|
||||
return "amdfam16";
|
||||
}
|
||||
default:
|
||||
return "generic";
|
||||
}
|
||||
}
|
||||
return "generic";
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
|
||||
StringRef sys::getHostCPUName() {
|
||||
host_basic_info_data_t hostInfo;
|
||||
|
|
Loading…
Reference in New Issue