[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:
Alina Sbirlea 2016-06-06 18:29:59 +00:00
parent 917a42d8b5
commit 76c4a855bc
1 changed files with 658 additions and 269 deletions

View File

@ -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_IX86) || defined(__x86_64__) || defined(_M_AMD64) || \
defined(_M_X64) 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 /// 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. /// the specified arguments. If we can't run cpuid on the host, return true.
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
@ -199,51 +295,16 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
} }
} }
StringRef sys::getHostCPUName() { static void
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model,
if (getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) unsigned int Brand_id, unsigned int Features,
return "generic"; unsigned *Type, unsigned *Subtype) {
unsigned Family = 0; if (Brand_id != 0)
unsigned Model = 0; return;
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) {
switch (Family) { switch (Family) {
case 3: case 3:
return "i386"; *Type = INTEL_i386;
break;
case 4: case 4:
switch (Model) { switch (Model) {
case 0: // Intel486 DX processors case 0: // Intel486 DX processors
@ -256,7 +317,8 @@ StringRef sys::getHostCPUName() {
case 7: // Write-Back Enhanced IntelDX2 processors case 7: // Write-Back Enhanced IntelDX2 processors
case 8: // IntelDX4 OverDrive processors, IntelDX4 processors case 8: // IntelDX4 OverDrive processors, IntelDX4 processors
default: default:
return "i486"; *Type = INTEL_i486;
break;
} }
case 5: case 5:
switch (Model) { switch (Model) {
@ -267,117 +329,132 @@ StringRef sys::getHostCPUName() {
// 150, 166, 200) // 150, 166, 200)
case 3: // Pentium OverDrive processors for Intel486 processor-based case 3: // Pentium OverDrive processors for Intel486 processor-based
// systems // systems
return "pentium"; *Type = INTEL_PENTIUM;
break;
case 4: // Pentium OverDrive processor with MMX technology for Pentium case 4: // Pentium OverDrive processor with MMX technology for Pentium
// processor (75, 90, 100, 120, 133), Pentium processor with // processor (75, 90, 100, 120, 133), Pentium processor with
// MMX technology (166, 200) // MMX technology (166, 200)
return "pentium-mmx"; *Type = INTEL_PENTIUM;
*Subtype = INTEL_PENTIUM_MMX;
break;
default: default:
return "pentium"; *Type = INTEL_PENTIUM;
break;
} }
case 6: case 6:
switch (Model) { switch (Model) {
case 0x01: // Pentium Pro processor case 0x01: // Pentium Pro processor
return "pentiumpro"; *Type = INTEL_PENTIUM_PRO;
break;
case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor,
// model 03 // model 03
case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor,
// model 05, and Intel Celeron processor, model 05 // model 05, and Intel Celeron processor, model 05
case 0x06: // Celeron processor, model 06 case 0x06: // Celeron processor, model 06
return "pentium2"; *Type = INTEL_PENTIUM_II;
break;
case 0x07: // Pentium III processor, model 07, and Pentium III Xeon case 0x07: // Pentium III processor, model 07, and Pentium III Xeon
// processor, model 07 // processor, model 07
case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor,
// model 08, and Celeron processor, model 08 // model 08, and Celeron processor, model 08
case 0x0a: // Pentium III Xeon processor, model 0Ah case 0x0a: // Pentium III Xeon processor, model 0Ah
case 0x0b: // Pentium III processor, model 0Bh case 0x0b: // Pentium III processor, model 0Bh
return "pentium3"; *Type = INTEL_PENTIUM_III;
break;
case 0x09: // Intel Pentium M processor, Intel Celeron M processor model case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09.
// 09.
case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model
// 0Dh. All processors are manufactured using the 90 nm // 0Dh. All processors are manufactured using the 90 nm process.
// process.
case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579
// Integrated Processor with Intel QuickAssist Technology // 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 case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model
// 0Eh. All processors are manufactured using the 65 nm // 0Eh. All processors are manufactured using the 65 nm process.
// process. *Type = INTEL_CORE_DUO;
return "yonah"; break; // yonah
case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
// processor, Intel Core 2 Quad processor, Intel Core 2 Quad // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
// mobile processor, Intel Core 2 Extreme processor, Intel // mobile processor, Intel Core 2 Extreme processor, Intel
// Pentium Dual-Core processor, Intel Xeon processor, model // Pentium Dual-Core processor, Intel Xeon processor, model
// 0Fh. All processors are manufactured using the 65 nm // 0Fh. All processors are manufactured using the 65 nm process.
// process.
case 0x16: // Intel Celeron processor model 16h. All processors are case 0x16: // Intel Celeron processor model 16h. All processors are
// manufactured using the 65 nm process // 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 case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
// 17h. All processors are manufactured using the 45 nm // 17h. All processors are manufactured using the 45 nm process.
// process.
// //
// 45nm: Penryn , Wolfdale, Yorkfield (XE) // 45nm: Penryn , Wolfdale, Yorkfield (XE)
case 0x1d: // Intel Xeon processor MP. All processors are manufactured case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
// using
// the 45 nm process. // 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 case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
// processors are manufactured using the 45 nm process. // processors are manufactured using the 45 nm process.
case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz.
// As found in a Summer 2010 model iMac. // As found in a Summer 2010 model iMac.
case 0x1f:
case 0x2e: // Nehalem EX case 0x2e: // Nehalem EX
return "nehalem"; *Type = INTEL_COREI7; // "nehalem"
*Subtype = INTEL_COREI7_NEHALEM;
break;
case 0x25: // Intel Core i7, laptop version. case 0x25: // Intel Core i7, laptop version.
case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
// processors are manufactured using the 32 nm process. // processors are manufactured using the 32 nm process.
case 0x2f: // Westmere EX 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 case 0x2a: // Intel Core i7 processor. All processors are manufactured
// using the 32 nm process. // using the 32 nm process.
case 0x2d: case 0x2d:
return "sandybridge"; *Type = INTEL_COREI7; //"sandybridge"
*Subtype = INTEL_COREI7_SANDYBRIDGE;
break;
case 0x3a: case 0x3a:
case 0x3e: // Ivy Bridge EP case 0x3e: // Ivy Bridge EP
return "ivybridge"; *Type = INTEL_COREI7; // "ivybridge"
*Subtype = INTEL_COREI7_IVYBRIDGE;
break;
// Haswell: // Haswell:
case 0x3c: case 0x3c:
case 0x3f: case 0x3f:
case 0x45: case 0x45:
case 0x46: case 0x46:
return "haswell"; *Type = INTEL_COREI7; // "haswell"
*Subtype = INTEL_COREI7_HASWELL;
break;
// Broadwell: // Broadwell:
case 0x3d: case 0x3d:
case 0x47: case 0x47:
case 0x4f: case 0x4f:
case 0x56: case 0x56:
return "broadwell"; *Type = INTEL_COREI7; // "broadwell"
*Subtype = INTEL_COREI7_BROADWELL;
break;
// Skylake: // Skylake:
case 0x4e: case 0x4e:
return "skylake-avx512"; *Type = INTEL_COREI7; // "skylake-avx512"
*Subtype = INTEL_COREI7_SKYLAKE_AVX512;
break;
case 0x5e: case 0x5e:
return "skylake"; *Type = INTEL_COREI7; // "skylake"
*Subtype = INTEL_COREI7_SKYLAKE;
break;
case 0x1c: // Most 45 nm Intel Atom processors case 0x1c: // Most 45 nm Intel Atom processors
case 0x26: // 45 nm Atom Lincroft case 0x26: // 45 nm Atom Lincroft
case 0x27: // 32 nm Atom Medfield case 0x27: // 32 nm Atom Medfield
case 0x35: // 32 nm Atom Midview case 0x35: // 32 nm Atom Midview
case 0x36: // 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. // Atom Silvermont codes from the Intel software optimization guide.
case 0x37: case 0x37:
@ -386,35 +463,79 @@ StringRef sys::getHostCPUName() {
case 0x5a: case 0x5a:
case 0x5d: case 0x5d:
case 0x4c: // really airmont case 0x4c: // really airmont
return "silvermont"; *Type = INTEL_ATOM;
*Subtype = INTEL_ATOM_SILVERMONT;
break; // "silvermont"
case 0x57: case 0x57:
return "knl"; *Type = INTEL_XEONPHI; // knl
*Subtype = INTEL_KNIGHTS_LANDING;
break;
default: // Unknown family 6 CPU, try to guess. default: // Unknown family 6 CPU, try to guess.
if (HasAVX512) if (Features & (1 << FEATURE_AVX512)) {
return "knl"; *Type = INTEL_XEONPHI; // knl
if (HasADX) *Subtype = INTEL_KNIGHTS_LANDING;
return "broadwell"; break;
if (HasAVX2) }
return "haswell"; if (Features & (1 << FEATURE_ADX)) {
if (HasAVX) *Type = INTEL_COREI7;
return "sandybridge"; *Subtype = INTEL_COREI7_BROADWELL;
if (HasSSE42) break;
return HasMOVBE ? "silvermont" : "nehalem"; }
if (HasSSE41) if (Features & (1 << FEATURE_AVX2)) {
return "penryn"; *Type = INTEL_COREI7;
if (HasSSSE3) *Subtype = INTEL_COREI7_HASWELL;
return HasMOVBE ? "bonnell" : "core2"; break;
if (Em64T) }
return "x86-64"; if (Features & (1 << FEATURE_AVX)) {
if (HasSSE2) *Type = INTEL_COREI7;
return "pentium-m"; *Subtype = INTEL_COREI7_SANDYBRIDGE;
if (HasSSE) break;
return "pentium3"; }
if (HasMMX) if (Features & (1 << FEATURE_SSE4_2)) {
return "pentium2"; if (Features & (1 << FEATURE_MOVBE)) {
return "pentiumpro"; *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: { case 15: {
switch (Model) { switch (Model) {
@ -427,7 +548,9 @@ StringRef sys::getHostCPUName() {
// Intel Xeon processor, Intel Xeon processor MP, Intel Celeron // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron
// processor, and Mobile Intel Celeron processor. All processors // processor, and Mobile Intel Celeron processor. All processors
// are model 02h and manufactured using the 0.13 micron process. // 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 case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D
// processor. All processors are model 03h and manufactured using // processor. All processors are model 03h and manufactured using
@ -440,86 +563,352 @@ StringRef sys::getHostCPUName() {
// Extreme Edition, Intel Xeon processor, Intel Xeon processor // Extreme Edition, Intel Xeon processor, Intel Xeon processor
// MP, Intel Celeron D processor. All processors are model 06h // MP, Intel Celeron D processor. All processors are model 06h
// and manufactured using the 65 nm process. // and manufactured using the 65 nm process.
return (Em64T) ? "nocona" : "prescott"; *Type =
((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT);
break;
default: default:
return (Em64T) ? "x86-64" : "pentium4"; *Type =
((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV);
break;
} }
} }
default: 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 // FIXME: this poorly matches the generated SubtargetFeatureKV table. There
// appears to be no way to generate the wide variety of AMD-specific targets // appears to be no way to generate the wide variety of AMD-specific targets
// from the information returned from CPUID. // from the information returned from CPUID.
switch (Family) { switch (Family) {
case 4: case 4:
return "i486"; *Type = AMD_i486;
case 5: case 5:
*Type = AMDPENTIUM;
switch (Model) { switch (Model) {
case 6: case 6:
case 7: case 7:
return "k6"; *Subtype = AMDPENTIUM_K6;
break; // "k6"
case 8: case 8:
return "k6-2"; *Subtype = AMDPENTIUM_K62;
break; // "k6-2"
case 9: case 9:
case 13: case 13:
return "k6-3"; *Subtype = AMDPENTIUM_K63;
break; // "k6-3"
case 10: 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"; return "geode";
default: default:
return "pentium"; return "pentium";
} }
case 6: case AMDATHLON:
switch (Model) { switch (Subtype) {
case 4: case AMDATHLON_TBIRD:
return "athlon-tbird"; return "athlon-tbird";
case 6: case AMDATHLON_MP:
case 7:
case 8:
return "athlon-mp"; return "athlon-mp";
case 10: case AMDATHLON_XP:
return "athlon-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: default:
return "athlon"; return "athlon";
} }
case 15: case AMDFAM10H:
if (HasSSE3) switch (Subtype) {
return "k8-sse3"; case AMDFAM10H_BARCELONA:
switch (Model) { return "amdfam10-barcelona";
case 1: case AMDFAM10H_SHANGHAI:
return "opteron"; return "amdfam10-shanghai";
case 5: case AMDFAM10H_ISTANBUL:
return "athlon-fx"; // also opteron return "amdfam10-istanbul";
default: default:
return "athlon64";
}
case 16:
return "amdfam10"; return "amdfam10";
case 20: }
case AMDFAM14H:
return "btver1"; return "btver1";
case 21: case AMDFAM15H:
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. 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"; return "btver1";
if (Model >= 0x50) default:
return "bdver4"; // 50h-6Fh: Excavator return "amdfam15";
if (Model >= 0x30) }
return "bdver3"; // 30h-3Fh: Steamroller case AMDFAM16H:
if (Model >= 0x10 || HasTBM) switch (Subtype) {
return "bdver2"; // 10h-1Fh: Piledriver case AMD_BTVER1:
return "bdver1"; // 00h-0Fh: Bulldozer
case 22:
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
return "btver1"; return "btver1";
case AMD_BTVER2:
return "btver2"; return "btver2";
default:
return "amdfam16";
}
default: default:
return "generic"; return "generic";
} }
} }
return "generic"; return "generic";
} }
#elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) #elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
StringRef sys::getHostCPUName() { StringRef sys::getHostCPUName() {
host_basic_info_data_t hostInfo; host_basic_info_data_t hostInfo;