1*cb14a3feSDimitry Andric //===-- cpu_model/x86.c - Support for __cpu_model builtin --------*- C -*-===// 2*cb14a3feSDimitry Andric // 3*cb14a3feSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*cb14a3feSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*cb14a3feSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*cb14a3feSDimitry Andric // 7*cb14a3feSDimitry Andric //===----------------------------------------------------------------------===// 8*cb14a3feSDimitry Andric // 9*cb14a3feSDimitry Andric // This file is based on LLVM's lib/Support/Host.cpp. 10*cb14a3feSDimitry Andric // It implements the operating system Host concept and builtin 11*cb14a3feSDimitry Andric // __cpu_model for the compiler_rt library for x86. 12*cb14a3feSDimitry Andric // 13*cb14a3feSDimitry Andric //===----------------------------------------------------------------------===// 14*cb14a3feSDimitry Andric 15*cb14a3feSDimitry Andric #include "cpu_model.h" 16*cb14a3feSDimitry Andric 17*cb14a3feSDimitry Andric #if !(defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \ 18*cb14a3feSDimitry Andric defined(_M_X64)) 19*cb14a3feSDimitry Andric #error This file is intended only for x86-based targets 20*cb14a3feSDimitry Andric #endif 21*cb14a3feSDimitry Andric 22*cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) 23*cb14a3feSDimitry Andric 24*cb14a3feSDimitry Andric #include <assert.h> 25*cb14a3feSDimitry Andric 26*cb14a3feSDimitry Andric #ifdef _MSC_VER 27*cb14a3feSDimitry Andric #include <intrin.h> 28*cb14a3feSDimitry Andric #endif 29*cb14a3feSDimitry Andric 30*cb14a3feSDimitry Andric enum VendorSignatures { 31*cb14a3feSDimitry Andric SIG_INTEL = 0x756e6547, // Genu 32*cb14a3feSDimitry Andric SIG_AMD = 0x68747541, // Auth 33*cb14a3feSDimitry Andric }; 34*cb14a3feSDimitry Andric 35*cb14a3feSDimitry Andric enum ProcessorVendors { 36*cb14a3feSDimitry Andric VENDOR_INTEL = 1, 37*cb14a3feSDimitry Andric VENDOR_AMD, 38*cb14a3feSDimitry Andric VENDOR_OTHER, 39*cb14a3feSDimitry Andric VENDOR_MAX 40*cb14a3feSDimitry Andric }; 41*cb14a3feSDimitry Andric 42*cb14a3feSDimitry Andric enum ProcessorTypes { 43*cb14a3feSDimitry Andric INTEL_BONNELL = 1, 44*cb14a3feSDimitry Andric INTEL_CORE2, 45*cb14a3feSDimitry Andric INTEL_COREI7, 46*cb14a3feSDimitry Andric AMDFAM10H, 47*cb14a3feSDimitry Andric AMDFAM15H, 48*cb14a3feSDimitry Andric INTEL_SILVERMONT, 49*cb14a3feSDimitry Andric INTEL_KNL, 50*cb14a3feSDimitry Andric AMD_BTVER1, 51*cb14a3feSDimitry Andric AMD_BTVER2, 52*cb14a3feSDimitry Andric AMDFAM17H, 53*cb14a3feSDimitry Andric INTEL_KNM, 54*cb14a3feSDimitry Andric INTEL_GOLDMONT, 55*cb14a3feSDimitry Andric INTEL_GOLDMONT_PLUS, 56*cb14a3feSDimitry Andric INTEL_TREMONT, 57*cb14a3feSDimitry Andric AMDFAM19H, 58*cb14a3feSDimitry Andric ZHAOXIN_FAM7H, 59*cb14a3feSDimitry Andric INTEL_SIERRAFOREST, 60*cb14a3feSDimitry Andric INTEL_GRANDRIDGE, 61*cb14a3feSDimitry Andric INTEL_CLEARWATERFOREST, 62*cb14a3feSDimitry Andric CPU_TYPE_MAX 63*cb14a3feSDimitry Andric }; 64*cb14a3feSDimitry Andric 65*cb14a3feSDimitry Andric enum ProcessorSubtypes { 66*cb14a3feSDimitry Andric INTEL_COREI7_NEHALEM = 1, 67*cb14a3feSDimitry Andric INTEL_COREI7_WESTMERE, 68*cb14a3feSDimitry Andric INTEL_COREI7_SANDYBRIDGE, 69*cb14a3feSDimitry Andric AMDFAM10H_BARCELONA, 70*cb14a3feSDimitry Andric AMDFAM10H_SHANGHAI, 71*cb14a3feSDimitry Andric AMDFAM10H_ISTANBUL, 72*cb14a3feSDimitry Andric AMDFAM15H_BDVER1, 73*cb14a3feSDimitry Andric AMDFAM15H_BDVER2, 74*cb14a3feSDimitry Andric AMDFAM15H_BDVER3, 75*cb14a3feSDimitry Andric AMDFAM15H_BDVER4, 76*cb14a3feSDimitry Andric AMDFAM17H_ZNVER1, 77*cb14a3feSDimitry Andric INTEL_COREI7_IVYBRIDGE, 78*cb14a3feSDimitry Andric INTEL_COREI7_HASWELL, 79*cb14a3feSDimitry Andric INTEL_COREI7_BROADWELL, 80*cb14a3feSDimitry Andric INTEL_COREI7_SKYLAKE, 81*cb14a3feSDimitry Andric INTEL_COREI7_SKYLAKE_AVX512, 82*cb14a3feSDimitry Andric INTEL_COREI7_CANNONLAKE, 83*cb14a3feSDimitry Andric INTEL_COREI7_ICELAKE_CLIENT, 84*cb14a3feSDimitry Andric INTEL_COREI7_ICELAKE_SERVER, 85*cb14a3feSDimitry Andric AMDFAM17H_ZNVER2, 86*cb14a3feSDimitry Andric INTEL_COREI7_CASCADELAKE, 87*cb14a3feSDimitry Andric INTEL_COREI7_TIGERLAKE, 88*cb14a3feSDimitry Andric INTEL_COREI7_COOPERLAKE, 89*cb14a3feSDimitry Andric INTEL_COREI7_SAPPHIRERAPIDS, 90*cb14a3feSDimitry Andric INTEL_COREI7_ALDERLAKE, 91*cb14a3feSDimitry Andric AMDFAM19H_ZNVER3, 92*cb14a3feSDimitry Andric INTEL_COREI7_ROCKETLAKE, 93*cb14a3feSDimitry Andric ZHAOXIN_FAM7H_LUJIAZUI, 94*cb14a3feSDimitry Andric AMDFAM19H_ZNVER4, 95*cb14a3feSDimitry Andric INTEL_COREI7_GRANITERAPIDS, 96*cb14a3feSDimitry Andric INTEL_COREI7_GRANITERAPIDS_D, 97*cb14a3feSDimitry Andric INTEL_COREI7_ARROWLAKE, 98*cb14a3feSDimitry Andric INTEL_COREI7_ARROWLAKE_S, 99*cb14a3feSDimitry Andric INTEL_COREI7_PANTHERLAKE, 100*cb14a3feSDimitry Andric CPU_SUBTYPE_MAX 101*cb14a3feSDimitry Andric }; 102*cb14a3feSDimitry Andric 103*cb14a3feSDimitry Andric enum ProcessorFeatures { 104*cb14a3feSDimitry Andric FEATURE_CMOV = 0, 105*cb14a3feSDimitry Andric FEATURE_MMX, 106*cb14a3feSDimitry Andric FEATURE_POPCNT, 107*cb14a3feSDimitry Andric FEATURE_SSE, 108*cb14a3feSDimitry Andric FEATURE_SSE2, 109*cb14a3feSDimitry Andric FEATURE_SSE3, 110*cb14a3feSDimitry Andric FEATURE_SSSE3, 111*cb14a3feSDimitry Andric FEATURE_SSE4_1, 112*cb14a3feSDimitry Andric FEATURE_SSE4_2, 113*cb14a3feSDimitry Andric FEATURE_AVX, 114*cb14a3feSDimitry Andric FEATURE_AVX2, 115*cb14a3feSDimitry Andric FEATURE_SSE4_A, 116*cb14a3feSDimitry Andric FEATURE_FMA4, 117*cb14a3feSDimitry Andric FEATURE_XOP, 118*cb14a3feSDimitry Andric FEATURE_FMA, 119*cb14a3feSDimitry Andric FEATURE_AVX512F, 120*cb14a3feSDimitry Andric FEATURE_BMI, 121*cb14a3feSDimitry Andric FEATURE_BMI2, 122*cb14a3feSDimitry Andric FEATURE_AES, 123*cb14a3feSDimitry Andric FEATURE_PCLMUL, 124*cb14a3feSDimitry Andric FEATURE_AVX512VL, 125*cb14a3feSDimitry Andric FEATURE_AVX512BW, 126*cb14a3feSDimitry Andric FEATURE_AVX512DQ, 127*cb14a3feSDimitry Andric FEATURE_AVX512CD, 128*cb14a3feSDimitry Andric FEATURE_AVX512ER, 129*cb14a3feSDimitry Andric FEATURE_AVX512PF, 130*cb14a3feSDimitry Andric FEATURE_AVX512VBMI, 131*cb14a3feSDimitry Andric FEATURE_AVX512IFMA, 132*cb14a3feSDimitry Andric FEATURE_AVX5124VNNIW, 133*cb14a3feSDimitry Andric FEATURE_AVX5124FMAPS, 134*cb14a3feSDimitry Andric FEATURE_AVX512VPOPCNTDQ, 135*cb14a3feSDimitry Andric FEATURE_AVX512VBMI2, 136*cb14a3feSDimitry Andric FEATURE_GFNI, 137*cb14a3feSDimitry Andric FEATURE_VPCLMULQDQ, 138*cb14a3feSDimitry Andric FEATURE_AVX512VNNI, 139*cb14a3feSDimitry Andric FEATURE_AVX512BITALG, 140*cb14a3feSDimitry Andric FEATURE_AVX512BF16, 141*cb14a3feSDimitry Andric FEATURE_AVX512VP2INTERSECT, 142*cb14a3feSDimitry Andric 143*cb14a3feSDimitry Andric FEATURE_CMPXCHG16B = 46, 144*cb14a3feSDimitry Andric FEATURE_F16C = 49, 145*cb14a3feSDimitry Andric FEATURE_LAHF_LM = 54, 146*cb14a3feSDimitry Andric FEATURE_LM, 147*cb14a3feSDimitry Andric FEATURE_WP, 148*cb14a3feSDimitry Andric FEATURE_LZCNT, 149*cb14a3feSDimitry Andric FEATURE_MOVBE, 150*cb14a3feSDimitry Andric 151*cb14a3feSDimitry Andric FEATURE_X86_64_BASELINE = 95, 152*cb14a3feSDimitry Andric FEATURE_X86_64_V2, 153*cb14a3feSDimitry Andric FEATURE_X86_64_V3, 154*cb14a3feSDimitry Andric FEATURE_X86_64_V4, 155*cb14a3feSDimitry Andric CPU_FEATURE_MAX 156*cb14a3feSDimitry Andric }; 157*cb14a3feSDimitry Andric 158*cb14a3feSDimitry Andric // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). 159*cb14a3feSDimitry Andric // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID 160*cb14a3feSDimitry Andric // support. Consequently, for i386, the presence of CPUID is checked first 161*cb14a3feSDimitry Andric // via the corresponding eflags bit. 162*cb14a3feSDimitry Andric static bool isCpuIdSupported(void) { 163*cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 164*cb14a3feSDimitry Andric #if defined(__i386__) 165*cb14a3feSDimitry Andric int __cpuid_supported; 166*cb14a3feSDimitry Andric __asm__(" pushfl\n" 167*cb14a3feSDimitry Andric " popl %%eax\n" 168*cb14a3feSDimitry Andric " movl %%eax,%%ecx\n" 169*cb14a3feSDimitry Andric " xorl $0x00200000,%%eax\n" 170*cb14a3feSDimitry Andric " pushl %%eax\n" 171*cb14a3feSDimitry Andric " popfl\n" 172*cb14a3feSDimitry Andric " pushfl\n" 173*cb14a3feSDimitry Andric " popl %%eax\n" 174*cb14a3feSDimitry Andric " movl $0,%0\n" 175*cb14a3feSDimitry Andric " cmpl %%eax,%%ecx\n" 176*cb14a3feSDimitry Andric " je 1f\n" 177*cb14a3feSDimitry Andric " movl $1,%0\n" 178*cb14a3feSDimitry Andric "1:" 179*cb14a3feSDimitry Andric : "=r"(__cpuid_supported) 180*cb14a3feSDimitry Andric : 181*cb14a3feSDimitry Andric : "eax", "ecx"); 182*cb14a3feSDimitry Andric if (!__cpuid_supported) 183*cb14a3feSDimitry Andric return false; 184*cb14a3feSDimitry Andric #endif 185*cb14a3feSDimitry Andric return true; 186*cb14a3feSDimitry Andric #endif 187*cb14a3feSDimitry Andric return true; 188*cb14a3feSDimitry Andric } 189*cb14a3feSDimitry Andric 190*cb14a3feSDimitry Andric // This code is copied from lib/Support/Host.cpp. 191*cb14a3feSDimitry Andric // Changes to either file should be mirrored in the other. 192*cb14a3feSDimitry Andric 193*cb14a3feSDimitry Andric /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in 194*cb14a3feSDimitry Andric /// the specified arguments. If we can't run cpuid on the host, return true. 195*cb14a3feSDimitry Andric static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, 196*cb14a3feSDimitry Andric unsigned *rECX, unsigned *rEDX) { 197*cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 198*cb14a3feSDimitry Andric #if defined(__x86_64__) 199*cb14a3feSDimitry Andric // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 200*cb14a3feSDimitry Andric // FIXME: should we save this for Clang? 201*cb14a3feSDimitry Andric __asm__("movq\t%%rbx, %%rsi\n\t" 202*cb14a3feSDimitry Andric "cpuid\n\t" 203*cb14a3feSDimitry Andric "xchgq\t%%rbx, %%rsi\n\t" 204*cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 205*cb14a3feSDimitry Andric : "a"(value)); 206*cb14a3feSDimitry Andric return false; 207*cb14a3feSDimitry Andric #elif defined(__i386__) 208*cb14a3feSDimitry Andric __asm__("movl\t%%ebx, %%esi\n\t" 209*cb14a3feSDimitry Andric "cpuid\n\t" 210*cb14a3feSDimitry Andric "xchgl\t%%ebx, %%esi\n\t" 211*cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 212*cb14a3feSDimitry Andric : "a"(value)); 213*cb14a3feSDimitry Andric return false; 214*cb14a3feSDimitry Andric #else 215*cb14a3feSDimitry Andric return true; 216*cb14a3feSDimitry Andric #endif 217*cb14a3feSDimitry Andric #elif defined(_MSC_VER) 218*cb14a3feSDimitry Andric // The MSVC intrinsic is portable across x86 and x64. 219*cb14a3feSDimitry Andric int registers[4]; 220*cb14a3feSDimitry Andric __cpuid(registers, value); 221*cb14a3feSDimitry Andric *rEAX = registers[0]; 222*cb14a3feSDimitry Andric *rEBX = registers[1]; 223*cb14a3feSDimitry Andric *rECX = registers[2]; 224*cb14a3feSDimitry Andric *rEDX = registers[3]; 225*cb14a3feSDimitry Andric return false; 226*cb14a3feSDimitry Andric #else 227*cb14a3feSDimitry Andric return true; 228*cb14a3feSDimitry Andric #endif 229*cb14a3feSDimitry Andric } 230*cb14a3feSDimitry Andric 231*cb14a3feSDimitry Andric /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return 232*cb14a3feSDimitry Andric /// the 4 values in the specified arguments. If we can't run cpuid on the host, 233*cb14a3feSDimitry Andric /// return true. 234*cb14a3feSDimitry Andric static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, 235*cb14a3feSDimitry Andric unsigned *rEAX, unsigned *rEBX, unsigned *rECX, 236*cb14a3feSDimitry Andric unsigned *rEDX) { 237*cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 238*cb14a3feSDimitry Andric #if defined(__x86_64__) 239*cb14a3feSDimitry Andric // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 240*cb14a3feSDimitry Andric // FIXME: should we save this for Clang? 241*cb14a3feSDimitry Andric __asm__("movq\t%%rbx, %%rsi\n\t" 242*cb14a3feSDimitry Andric "cpuid\n\t" 243*cb14a3feSDimitry Andric "xchgq\t%%rbx, %%rsi\n\t" 244*cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 245*cb14a3feSDimitry Andric : "a"(value), "c"(subleaf)); 246*cb14a3feSDimitry Andric return false; 247*cb14a3feSDimitry Andric #elif defined(__i386__) 248*cb14a3feSDimitry Andric __asm__("movl\t%%ebx, %%esi\n\t" 249*cb14a3feSDimitry Andric "cpuid\n\t" 250*cb14a3feSDimitry Andric "xchgl\t%%ebx, %%esi\n\t" 251*cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 252*cb14a3feSDimitry Andric : "a"(value), "c"(subleaf)); 253*cb14a3feSDimitry Andric return false; 254*cb14a3feSDimitry Andric #else 255*cb14a3feSDimitry Andric return true; 256*cb14a3feSDimitry Andric #endif 257*cb14a3feSDimitry Andric #elif defined(_MSC_VER) 258*cb14a3feSDimitry Andric int registers[4]; 259*cb14a3feSDimitry Andric __cpuidex(registers, value, subleaf); 260*cb14a3feSDimitry Andric *rEAX = registers[0]; 261*cb14a3feSDimitry Andric *rEBX = registers[1]; 262*cb14a3feSDimitry Andric *rECX = registers[2]; 263*cb14a3feSDimitry Andric *rEDX = registers[3]; 264*cb14a3feSDimitry Andric return false; 265*cb14a3feSDimitry Andric #else 266*cb14a3feSDimitry Andric return true; 267*cb14a3feSDimitry Andric #endif 268*cb14a3feSDimitry Andric } 269*cb14a3feSDimitry Andric 270*cb14a3feSDimitry Andric // Read control register 0 (XCR0). Used to detect features such as AVX. 271*cb14a3feSDimitry Andric static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { 272*cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 273*cb14a3feSDimitry Andric // Check xgetbv; this uses a .byte sequence instead of the instruction 274*cb14a3feSDimitry Andric // directly because older assemblers do not include support for xgetbv and 275*cb14a3feSDimitry Andric // there is no easy way to conditionally compile based on the assembler used. 276*cb14a3feSDimitry Andric __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); 277*cb14a3feSDimitry Andric return false; 278*cb14a3feSDimitry Andric #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 279*cb14a3feSDimitry Andric unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 280*cb14a3feSDimitry Andric *rEAX = Result; 281*cb14a3feSDimitry Andric *rEDX = Result >> 32; 282*cb14a3feSDimitry Andric return false; 283*cb14a3feSDimitry Andric #else 284*cb14a3feSDimitry Andric return true; 285*cb14a3feSDimitry Andric #endif 286*cb14a3feSDimitry Andric } 287*cb14a3feSDimitry Andric 288*cb14a3feSDimitry Andric static void detectX86FamilyModel(unsigned EAX, unsigned *Family, 289*cb14a3feSDimitry Andric unsigned *Model) { 290*cb14a3feSDimitry Andric *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 291*cb14a3feSDimitry Andric *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 292*cb14a3feSDimitry Andric if (*Family == 6 || *Family == 0xf) { 293*cb14a3feSDimitry Andric if (*Family == 0xf) 294*cb14a3feSDimitry Andric // Examine extended family ID if family ID is F. 295*cb14a3feSDimitry Andric *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 296*cb14a3feSDimitry Andric // Examine extended model ID if family ID is 6 or F. 297*cb14a3feSDimitry Andric *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 298*cb14a3feSDimitry Andric } 299*cb14a3feSDimitry Andric } 300*cb14a3feSDimitry Andric 301*cb14a3feSDimitry Andric static const char *getIntelProcessorTypeAndSubtype(unsigned Family, 302*cb14a3feSDimitry Andric unsigned Model, 303*cb14a3feSDimitry Andric const unsigned *Features, 304*cb14a3feSDimitry Andric unsigned *Type, 305*cb14a3feSDimitry Andric unsigned *Subtype) { 306*cb14a3feSDimitry Andric #define testFeature(F) (Features[F / 32] & (1 << (F % 32))) != 0 307*cb14a3feSDimitry Andric 308*cb14a3feSDimitry Andric // We select CPU strings to match the code in Host.cpp, but we don't use them 309*cb14a3feSDimitry Andric // in compiler-rt. 310*cb14a3feSDimitry Andric const char *CPU = 0; 311*cb14a3feSDimitry Andric 312*cb14a3feSDimitry Andric switch (Family) { 313*cb14a3feSDimitry Andric case 6: 314*cb14a3feSDimitry Andric switch (Model) { 315*cb14a3feSDimitry Andric case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile 316*cb14a3feSDimitry Andric // processor, Intel Core 2 Quad processor, Intel Core 2 Quad 317*cb14a3feSDimitry Andric // mobile processor, Intel Core 2 Extreme processor, Intel 318*cb14a3feSDimitry Andric // Pentium Dual-Core processor, Intel Xeon processor, model 319*cb14a3feSDimitry Andric // 0Fh. All processors are manufactured using the 65 nm process. 320*cb14a3feSDimitry Andric case 0x16: // Intel Celeron processor model 16h. All processors are 321*cb14a3feSDimitry Andric // manufactured using the 65 nm process 322*cb14a3feSDimitry Andric CPU = "core2"; 323*cb14a3feSDimitry Andric *Type = INTEL_CORE2; 324*cb14a3feSDimitry Andric break; 325*cb14a3feSDimitry Andric case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model 326*cb14a3feSDimitry Andric // 17h. All processors are manufactured using the 45 nm process. 327*cb14a3feSDimitry Andric // 328*cb14a3feSDimitry Andric // 45nm: Penryn , Wolfdale, Yorkfield (XE) 329*cb14a3feSDimitry Andric case 0x1d: // Intel Xeon processor MP. All processors are manufactured using 330*cb14a3feSDimitry Andric // the 45 nm process. 331*cb14a3feSDimitry Andric CPU = "penryn"; 332*cb14a3feSDimitry Andric *Type = INTEL_CORE2; 333*cb14a3feSDimitry Andric break; 334*cb14a3feSDimitry Andric case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All 335*cb14a3feSDimitry Andric // processors are manufactured using the 45 nm process. 336*cb14a3feSDimitry Andric case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. 337*cb14a3feSDimitry Andric // As found in a Summer 2010 model iMac. 338*cb14a3feSDimitry Andric case 0x1f: 339*cb14a3feSDimitry Andric case 0x2e: // Nehalem EX 340*cb14a3feSDimitry Andric CPU = "nehalem"; 341*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 342*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_NEHALEM; 343*cb14a3feSDimitry Andric break; 344*cb14a3feSDimitry Andric case 0x25: // Intel Core i7, laptop version. 345*cb14a3feSDimitry Andric case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All 346*cb14a3feSDimitry Andric // processors are manufactured using the 32 nm process. 347*cb14a3feSDimitry Andric case 0x2f: // Westmere EX 348*cb14a3feSDimitry Andric CPU = "westmere"; 349*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 350*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_WESTMERE; 351*cb14a3feSDimitry Andric break; 352*cb14a3feSDimitry Andric case 0x2a: // Intel Core i7 processor. All processors are manufactured 353*cb14a3feSDimitry Andric // using the 32 nm process. 354*cb14a3feSDimitry Andric case 0x2d: 355*cb14a3feSDimitry Andric CPU = "sandybridge"; 356*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 357*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SANDYBRIDGE; 358*cb14a3feSDimitry Andric break; 359*cb14a3feSDimitry Andric case 0x3a: 360*cb14a3feSDimitry Andric case 0x3e: // Ivy Bridge EP 361*cb14a3feSDimitry Andric CPU = "ivybridge"; 362*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 363*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_IVYBRIDGE; 364*cb14a3feSDimitry Andric break; 365*cb14a3feSDimitry Andric 366*cb14a3feSDimitry Andric // Haswell: 367*cb14a3feSDimitry Andric case 0x3c: 368*cb14a3feSDimitry Andric case 0x3f: 369*cb14a3feSDimitry Andric case 0x45: 370*cb14a3feSDimitry Andric case 0x46: 371*cb14a3feSDimitry Andric CPU = "haswell"; 372*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 373*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_HASWELL; 374*cb14a3feSDimitry Andric break; 375*cb14a3feSDimitry Andric 376*cb14a3feSDimitry Andric // Broadwell: 377*cb14a3feSDimitry Andric case 0x3d: 378*cb14a3feSDimitry Andric case 0x47: 379*cb14a3feSDimitry Andric case 0x4f: 380*cb14a3feSDimitry Andric case 0x56: 381*cb14a3feSDimitry Andric CPU = "broadwell"; 382*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 383*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_BROADWELL; 384*cb14a3feSDimitry Andric break; 385*cb14a3feSDimitry Andric 386*cb14a3feSDimitry Andric // Skylake: 387*cb14a3feSDimitry Andric case 0x4e: // Skylake mobile 388*cb14a3feSDimitry Andric case 0x5e: // Skylake desktop 389*cb14a3feSDimitry Andric case 0x8e: // Kaby Lake mobile 390*cb14a3feSDimitry Andric case 0x9e: // Kaby Lake desktop 391*cb14a3feSDimitry Andric case 0xa5: // Comet Lake-H/S 392*cb14a3feSDimitry Andric case 0xa6: // Comet Lake-U 393*cb14a3feSDimitry Andric CPU = "skylake"; 394*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 395*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SKYLAKE; 396*cb14a3feSDimitry Andric break; 397*cb14a3feSDimitry Andric 398*cb14a3feSDimitry Andric // Rocketlake: 399*cb14a3feSDimitry Andric case 0xa7: 400*cb14a3feSDimitry Andric CPU = "rocketlake"; 401*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 402*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ROCKETLAKE; 403*cb14a3feSDimitry Andric break; 404*cb14a3feSDimitry Andric 405*cb14a3feSDimitry Andric // Skylake Xeon: 406*cb14a3feSDimitry Andric case 0x55: 407*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 408*cb14a3feSDimitry Andric if (testFeature(FEATURE_AVX512BF16)) { 409*cb14a3feSDimitry Andric CPU = "cooperlake"; 410*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_COOPERLAKE; 411*cb14a3feSDimitry Andric } else if (testFeature(FEATURE_AVX512VNNI)) { 412*cb14a3feSDimitry Andric CPU = "cascadelake"; 413*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_CASCADELAKE; 414*cb14a3feSDimitry Andric } else { 415*cb14a3feSDimitry Andric CPU = "skylake-avx512"; 416*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SKYLAKE_AVX512; 417*cb14a3feSDimitry Andric } 418*cb14a3feSDimitry Andric break; 419*cb14a3feSDimitry Andric 420*cb14a3feSDimitry Andric // Cannonlake: 421*cb14a3feSDimitry Andric case 0x66: 422*cb14a3feSDimitry Andric CPU = "cannonlake"; 423*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 424*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_CANNONLAKE; 425*cb14a3feSDimitry Andric break; 426*cb14a3feSDimitry Andric 427*cb14a3feSDimitry Andric // Icelake: 428*cb14a3feSDimitry Andric case 0x7d: 429*cb14a3feSDimitry Andric case 0x7e: 430*cb14a3feSDimitry Andric CPU = "icelake-client"; 431*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 432*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ICELAKE_CLIENT; 433*cb14a3feSDimitry Andric break; 434*cb14a3feSDimitry Andric 435*cb14a3feSDimitry Andric // Tigerlake: 436*cb14a3feSDimitry Andric case 0x8c: 437*cb14a3feSDimitry Andric case 0x8d: 438*cb14a3feSDimitry Andric CPU = "tigerlake"; 439*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 440*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_TIGERLAKE; 441*cb14a3feSDimitry Andric break; 442*cb14a3feSDimitry Andric 443*cb14a3feSDimitry Andric // Alderlake: 444*cb14a3feSDimitry Andric case 0x97: 445*cb14a3feSDimitry Andric case 0x9a: 446*cb14a3feSDimitry Andric // Raptorlake: 447*cb14a3feSDimitry Andric case 0xb7: 448*cb14a3feSDimitry Andric case 0xba: 449*cb14a3feSDimitry Andric case 0xbf: 450*cb14a3feSDimitry Andric // Meteorlake: 451*cb14a3feSDimitry Andric case 0xaa: 452*cb14a3feSDimitry Andric case 0xac: 453*cb14a3feSDimitry Andric // Gracemont: 454*cb14a3feSDimitry Andric case 0xbe: 455*cb14a3feSDimitry Andric CPU = "alderlake"; 456*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 457*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ALDERLAKE; 458*cb14a3feSDimitry Andric break; 459*cb14a3feSDimitry Andric 460*cb14a3feSDimitry Andric // Arrowlake: 461*cb14a3feSDimitry Andric case 0xc5: 462*cb14a3feSDimitry Andric CPU = "arrowlake"; 463*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 464*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ARROWLAKE; 465*cb14a3feSDimitry Andric break; 466*cb14a3feSDimitry Andric 467*cb14a3feSDimitry Andric // Arrowlake S: 468*cb14a3feSDimitry Andric case 0xc6: 469*cb14a3feSDimitry Andric // Lunarlake: 470*cb14a3feSDimitry Andric case 0xbd: 471*cb14a3feSDimitry Andric CPU = "arrowlake-s"; 472*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 473*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ARROWLAKE_S; 474*cb14a3feSDimitry Andric break; 475*cb14a3feSDimitry Andric 476*cb14a3feSDimitry Andric // Pantherlake: 477*cb14a3feSDimitry Andric case 0xcc: 478*cb14a3feSDimitry Andric CPU = "pantherlake"; 479*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 480*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_PANTHERLAKE; 481*cb14a3feSDimitry Andric break; 482*cb14a3feSDimitry Andric 483*cb14a3feSDimitry Andric // Icelake Xeon: 484*cb14a3feSDimitry Andric case 0x6a: 485*cb14a3feSDimitry Andric case 0x6c: 486*cb14a3feSDimitry Andric CPU = "icelake-server"; 487*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 488*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ICELAKE_SERVER; 489*cb14a3feSDimitry Andric break; 490*cb14a3feSDimitry Andric 491*cb14a3feSDimitry Andric // Emerald Rapids: 492*cb14a3feSDimitry Andric case 0xcf: 493*cb14a3feSDimitry Andric // Sapphire Rapids: 494*cb14a3feSDimitry Andric case 0x8f: 495*cb14a3feSDimitry Andric CPU = "sapphirerapids"; 496*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 497*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SAPPHIRERAPIDS; 498*cb14a3feSDimitry Andric break; 499*cb14a3feSDimitry Andric 500*cb14a3feSDimitry Andric // Granite Rapids: 501*cb14a3feSDimitry Andric case 0xad: 502*cb14a3feSDimitry Andric CPU = "graniterapids"; 503*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 504*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_GRANITERAPIDS; 505*cb14a3feSDimitry Andric break; 506*cb14a3feSDimitry Andric 507*cb14a3feSDimitry Andric // Granite Rapids D: 508*cb14a3feSDimitry Andric case 0xae: 509*cb14a3feSDimitry Andric CPU = "graniterapids-d"; 510*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 511*cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_GRANITERAPIDS_D; 512*cb14a3feSDimitry Andric break; 513*cb14a3feSDimitry Andric 514*cb14a3feSDimitry Andric case 0x1c: // Most 45 nm Intel Atom processors 515*cb14a3feSDimitry Andric case 0x26: // 45 nm Atom Lincroft 516*cb14a3feSDimitry Andric case 0x27: // 32 nm Atom Medfield 517*cb14a3feSDimitry Andric case 0x35: // 32 nm Atom Midview 518*cb14a3feSDimitry Andric case 0x36: // 32 nm Atom Midview 519*cb14a3feSDimitry Andric CPU = "bonnell"; 520*cb14a3feSDimitry Andric *Type = INTEL_BONNELL; 521*cb14a3feSDimitry Andric break; 522*cb14a3feSDimitry Andric 523*cb14a3feSDimitry Andric // Atom Silvermont codes from the Intel software optimization guide. 524*cb14a3feSDimitry Andric case 0x37: 525*cb14a3feSDimitry Andric case 0x4a: 526*cb14a3feSDimitry Andric case 0x4d: 527*cb14a3feSDimitry Andric case 0x5a: 528*cb14a3feSDimitry Andric case 0x5d: 529*cb14a3feSDimitry Andric case 0x4c: // really airmont 530*cb14a3feSDimitry Andric CPU = "silvermont"; 531*cb14a3feSDimitry Andric *Type = INTEL_SILVERMONT; 532*cb14a3feSDimitry Andric break; 533*cb14a3feSDimitry Andric // Goldmont: 534*cb14a3feSDimitry Andric case 0x5c: // Apollo Lake 535*cb14a3feSDimitry Andric case 0x5f: // Denverton 536*cb14a3feSDimitry Andric CPU = "goldmont"; 537*cb14a3feSDimitry Andric *Type = INTEL_GOLDMONT; 538*cb14a3feSDimitry Andric break; // "goldmont" 539*cb14a3feSDimitry Andric case 0x7a: 540*cb14a3feSDimitry Andric CPU = "goldmont-plus"; 541*cb14a3feSDimitry Andric *Type = INTEL_GOLDMONT_PLUS; 542*cb14a3feSDimitry Andric break; 543*cb14a3feSDimitry Andric case 0x86: 544*cb14a3feSDimitry Andric case 0x8a: // Lakefield 545*cb14a3feSDimitry Andric case 0x96: // Elkhart Lake 546*cb14a3feSDimitry Andric case 0x9c: // Jasper Lake 547*cb14a3feSDimitry Andric CPU = "tremont"; 548*cb14a3feSDimitry Andric *Type = INTEL_TREMONT; 549*cb14a3feSDimitry Andric break; 550*cb14a3feSDimitry Andric 551*cb14a3feSDimitry Andric // Sierraforest: 552*cb14a3feSDimitry Andric case 0xaf: 553*cb14a3feSDimitry Andric CPU = "sierraforest"; 554*cb14a3feSDimitry Andric *Type = INTEL_SIERRAFOREST; 555*cb14a3feSDimitry Andric break; 556*cb14a3feSDimitry Andric 557*cb14a3feSDimitry Andric // Grandridge: 558*cb14a3feSDimitry Andric case 0xb6: 559*cb14a3feSDimitry Andric CPU = "grandridge"; 560*cb14a3feSDimitry Andric *Type = INTEL_GRANDRIDGE; 561*cb14a3feSDimitry Andric break; 562*cb14a3feSDimitry Andric 563*cb14a3feSDimitry Andric // Clearwaterforest: 564*cb14a3feSDimitry Andric case 0xdd: 565*cb14a3feSDimitry Andric CPU = "clearwaterforest"; 566*cb14a3feSDimitry Andric *Type = INTEL_COREI7; 567*cb14a3feSDimitry Andric *Subtype = INTEL_CLEARWATERFOREST; 568*cb14a3feSDimitry Andric break; 569*cb14a3feSDimitry Andric 570*cb14a3feSDimitry Andric case 0x57: 571*cb14a3feSDimitry Andric CPU = "knl"; 572*cb14a3feSDimitry Andric *Type = INTEL_KNL; 573*cb14a3feSDimitry Andric break; 574*cb14a3feSDimitry Andric 575*cb14a3feSDimitry Andric case 0x85: 576*cb14a3feSDimitry Andric CPU = "knm"; 577*cb14a3feSDimitry Andric *Type = INTEL_KNM; 578*cb14a3feSDimitry Andric break; 579*cb14a3feSDimitry Andric 580*cb14a3feSDimitry Andric default: // Unknown family 6 CPU. 581*cb14a3feSDimitry Andric break; 582*cb14a3feSDimitry Andric } 583*cb14a3feSDimitry Andric break; 584*cb14a3feSDimitry Andric default: 585*cb14a3feSDimitry Andric break; // Unknown. 586*cb14a3feSDimitry Andric } 587*cb14a3feSDimitry Andric 588*cb14a3feSDimitry Andric return CPU; 589*cb14a3feSDimitry Andric } 590*cb14a3feSDimitry Andric 591*cb14a3feSDimitry Andric static const char *getAMDProcessorTypeAndSubtype(unsigned Family, 592*cb14a3feSDimitry Andric unsigned Model, 593*cb14a3feSDimitry Andric const unsigned *Features, 594*cb14a3feSDimitry Andric unsigned *Type, 595*cb14a3feSDimitry Andric unsigned *Subtype) { 596*cb14a3feSDimitry Andric // We select CPU strings to match the code in Host.cpp, but we don't use them 597*cb14a3feSDimitry Andric // in compiler-rt. 598*cb14a3feSDimitry Andric const char *CPU = 0; 599*cb14a3feSDimitry Andric 600*cb14a3feSDimitry Andric switch (Family) { 601*cb14a3feSDimitry Andric case 16: 602*cb14a3feSDimitry Andric CPU = "amdfam10"; 603*cb14a3feSDimitry Andric *Type = AMDFAM10H; 604*cb14a3feSDimitry Andric switch (Model) { 605*cb14a3feSDimitry Andric case 2: 606*cb14a3feSDimitry Andric *Subtype = AMDFAM10H_BARCELONA; 607*cb14a3feSDimitry Andric break; 608*cb14a3feSDimitry Andric case 4: 609*cb14a3feSDimitry Andric *Subtype = AMDFAM10H_SHANGHAI; 610*cb14a3feSDimitry Andric break; 611*cb14a3feSDimitry Andric case 8: 612*cb14a3feSDimitry Andric *Subtype = AMDFAM10H_ISTANBUL; 613*cb14a3feSDimitry Andric break; 614*cb14a3feSDimitry Andric } 615*cb14a3feSDimitry Andric break; 616*cb14a3feSDimitry Andric case 20: 617*cb14a3feSDimitry Andric CPU = "btver1"; 618*cb14a3feSDimitry Andric *Type = AMD_BTVER1; 619*cb14a3feSDimitry Andric break; 620*cb14a3feSDimitry Andric case 21: 621*cb14a3feSDimitry Andric CPU = "bdver1"; 622*cb14a3feSDimitry Andric *Type = AMDFAM15H; 623*cb14a3feSDimitry Andric if (Model >= 0x60 && Model <= 0x7f) { 624*cb14a3feSDimitry Andric CPU = "bdver4"; 625*cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER4; 626*cb14a3feSDimitry Andric break; // 60h-7Fh: Excavator 627*cb14a3feSDimitry Andric } 628*cb14a3feSDimitry Andric if (Model >= 0x30 && Model <= 0x3f) { 629*cb14a3feSDimitry Andric CPU = "bdver3"; 630*cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER3; 631*cb14a3feSDimitry Andric break; // 30h-3Fh: Steamroller 632*cb14a3feSDimitry Andric } 633*cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { 634*cb14a3feSDimitry Andric CPU = "bdver2"; 635*cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER2; 636*cb14a3feSDimitry Andric break; // 02h, 10h-1Fh: Piledriver 637*cb14a3feSDimitry Andric } 638*cb14a3feSDimitry Andric if (Model <= 0x0f) { 639*cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER1; 640*cb14a3feSDimitry Andric break; // 00h-0Fh: Bulldozer 641*cb14a3feSDimitry Andric } 642*cb14a3feSDimitry Andric break; 643*cb14a3feSDimitry Andric case 22: 644*cb14a3feSDimitry Andric CPU = "btver2"; 645*cb14a3feSDimitry Andric *Type = AMD_BTVER2; 646*cb14a3feSDimitry Andric break; 647*cb14a3feSDimitry Andric case 23: 648*cb14a3feSDimitry Andric CPU = "znver1"; 649*cb14a3feSDimitry Andric *Type = AMDFAM17H; 650*cb14a3feSDimitry Andric if ((Model >= 0x30 && Model <= 0x3f) || (Model == 0x47) || 651*cb14a3feSDimitry Andric (Model >= 0x60 && Model <= 0x67) || (Model >= 0x68 && Model <= 0x6f) || 652*cb14a3feSDimitry Andric (Model >= 0x70 && Model <= 0x7f) || (Model >= 0x84 && Model <= 0x87) || 653*cb14a3feSDimitry Andric (Model >= 0x90 && Model <= 0x97) || (Model >= 0x98 && Model <= 0x9f) || 654*cb14a3feSDimitry Andric (Model >= 0xa0 && Model <= 0xaf)) { 655*cb14a3feSDimitry Andric // Family 17h Models 30h-3Fh (Starship) Zen 2 656*cb14a3feSDimitry Andric // Family 17h Models 47h (Cardinal) Zen 2 657*cb14a3feSDimitry Andric // Family 17h Models 60h-67h (Renoir) Zen 2 658*cb14a3feSDimitry Andric // Family 17h Models 68h-6Fh (Lucienne) Zen 2 659*cb14a3feSDimitry Andric // Family 17h Models 70h-7Fh (Matisse) Zen 2 660*cb14a3feSDimitry Andric // Family 17h Models 84h-87h (ProjectX) Zen 2 661*cb14a3feSDimitry Andric // Family 17h Models 90h-97h (VanGogh) Zen 2 662*cb14a3feSDimitry Andric // Family 17h Models 98h-9Fh (Mero) Zen 2 663*cb14a3feSDimitry Andric // Family 17h Models A0h-AFh (Mendocino) Zen 2 664*cb14a3feSDimitry Andric CPU = "znver2"; 665*cb14a3feSDimitry Andric *Subtype = AMDFAM17H_ZNVER2; 666*cb14a3feSDimitry Andric break; 667*cb14a3feSDimitry Andric } 668*cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x20 && Model <= 0x2f)) { 669*cb14a3feSDimitry Andric // Family 17h Models 10h-1Fh (Raven1) Zen 670*cb14a3feSDimitry Andric // Family 17h Models 10h-1Fh (Picasso) Zen+ 671*cb14a3feSDimitry Andric // Family 17h Models 20h-2Fh (Raven2 x86) Zen 672*cb14a3feSDimitry Andric *Subtype = AMDFAM17H_ZNVER1; 673*cb14a3feSDimitry Andric break; 674*cb14a3feSDimitry Andric } 675*cb14a3feSDimitry Andric break; 676*cb14a3feSDimitry Andric case 25: 677*cb14a3feSDimitry Andric CPU = "znver3"; 678*cb14a3feSDimitry Andric *Type = AMDFAM19H; 679*cb14a3feSDimitry Andric if ((Model >= 0x00 && Model <= 0x0f) || (Model >= 0x20 && Model <= 0x2f) || 680*cb14a3feSDimitry Andric (Model >= 0x30 && Model <= 0x3f) || (Model >= 0x40 && Model <= 0x4f) || 681*cb14a3feSDimitry Andric (Model >= 0x50 && Model <= 0x5f)) { 682*cb14a3feSDimitry Andric // Family 19h Models 00h-0Fh (Genesis, Chagall) Zen 3 683*cb14a3feSDimitry Andric // Family 19h Models 20h-2Fh (Vermeer) Zen 3 684*cb14a3feSDimitry Andric // Family 19h Models 30h-3Fh (Badami) Zen 3 685*cb14a3feSDimitry Andric // Family 19h Models 40h-4Fh (Rembrandt) Zen 3+ 686*cb14a3feSDimitry Andric // Family 19h Models 50h-5Fh (Cezanne) Zen 3 687*cb14a3feSDimitry Andric *Subtype = AMDFAM19H_ZNVER3; 688*cb14a3feSDimitry Andric break; 689*cb14a3feSDimitry Andric } 690*cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x60 && Model <= 0x6f) || 691*cb14a3feSDimitry Andric (Model >= 0x70 && Model <= 0x77) || (Model >= 0x78 && Model <= 0x7f) || 692*cb14a3feSDimitry Andric (Model >= 0xa0 && Model <= 0xaf)) { 693*cb14a3feSDimitry Andric // Family 19h Models 10h-1Fh (Stones; Storm Peak) Zen 4 694*cb14a3feSDimitry Andric // Family 19h Models 60h-6Fh (Raphael) Zen 4 695*cb14a3feSDimitry Andric // Family 19h Models 70h-77h (Phoenix, Hawkpoint1) Zen 4 696*cb14a3feSDimitry Andric // Family 19h Models 78h-7Fh (Phoenix 2, Hawkpoint2) Zen 4 697*cb14a3feSDimitry Andric // Family 19h Models A0h-AFh (Stones-Dense) Zen 4 698*cb14a3feSDimitry Andric CPU = "znver4"; 699*cb14a3feSDimitry Andric *Subtype = AMDFAM19H_ZNVER4; 700*cb14a3feSDimitry Andric break; // "znver4" 701*cb14a3feSDimitry Andric } 702*cb14a3feSDimitry Andric break; // family 19h 703*cb14a3feSDimitry Andric default: 704*cb14a3feSDimitry Andric break; // Unknown AMD CPU. 705*cb14a3feSDimitry Andric } 706*cb14a3feSDimitry Andric 707*cb14a3feSDimitry Andric return CPU; 708*cb14a3feSDimitry Andric } 709*cb14a3feSDimitry Andric 710*cb14a3feSDimitry Andric static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, 711*cb14a3feSDimitry Andric unsigned *Features) { 712*cb14a3feSDimitry Andric unsigned EAX = 0, EBX = 0; 713*cb14a3feSDimitry Andric 714*cb14a3feSDimitry Andric #define hasFeature(F) ((Features[F / 32] >> (F % 32)) & 1) 715*cb14a3feSDimitry Andric #define setFeature(F) Features[F / 32] |= 1U << (F % 32) 716*cb14a3feSDimitry Andric 717*cb14a3feSDimitry Andric if ((EDX >> 15) & 1) 718*cb14a3feSDimitry Andric setFeature(FEATURE_CMOV); 719*cb14a3feSDimitry Andric if ((EDX >> 23) & 1) 720*cb14a3feSDimitry Andric setFeature(FEATURE_MMX); 721*cb14a3feSDimitry Andric if ((EDX >> 25) & 1) 722*cb14a3feSDimitry Andric setFeature(FEATURE_SSE); 723*cb14a3feSDimitry Andric if ((EDX >> 26) & 1) 724*cb14a3feSDimitry Andric setFeature(FEATURE_SSE2); 725*cb14a3feSDimitry Andric 726*cb14a3feSDimitry Andric if ((ECX >> 0) & 1) 727*cb14a3feSDimitry Andric setFeature(FEATURE_SSE3); 728*cb14a3feSDimitry Andric if ((ECX >> 1) & 1) 729*cb14a3feSDimitry Andric setFeature(FEATURE_PCLMUL); 730*cb14a3feSDimitry Andric if ((ECX >> 9) & 1) 731*cb14a3feSDimitry Andric setFeature(FEATURE_SSSE3); 732*cb14a3feSDimitry Andric if ((ECX >> 12) & 1) 733*cb14a3feSDimitry Andric setFeature(FEATURE_FMA); 734*cb14a3feSDimitry Andric if ((ECX >> 13) & 1) 735*cb14a3feSDimitry Andric setFeature(FEATURE_CMPXCHG16B); 736*cb14a3feSDimitry Andric if ((ECX >> 19) & 1) 737*cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_1); 738*cb14a3feSDimitry Andric if ((ECX >> 20) & 1) 739*cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_2); 740*cb14a3feSDimitry Andric if ((ECX >> 22) & 1) 741*cb14a3feSDimitry Andric setFeature(FEATURE_MOVBE); 742*cb14a3feSDimitry Andric if ((ECX >> 23) & 1) 743*cb14a3feSDimitry Andric setFeature(FEATURE_POPCNT); 744*cb14a3feSDimitry Andric if ((ECX >> 25) & 1) 745*cb14a3feSDimitry Andric setFeature(FEATURE_AES); 746*cb14a3feSDimitry Andric if ((ECX >> 29) & 1) 747*cb14a3feSDimitry Andric setFeature(FEATURE_F16C); 748*cb14a3feSDimitry Andric 749*cb14a3feSDimitry Andric // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 750*cb14a3feSDimitry Andric // indicates that the AVX registers will be saved and restored on context 751*cb14a3feSDimitry Andric // switch, then we have full AVX support. 752*cb14a3feSDimitry Andric const unsigned AVXBits = (1 << 27) | (1 << 28); 753*cb14a3feSDimitry Andric bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && 754*cb14a3feSDimitry Andric ((EAX & 0x6) == 0x6); 755*cb14a3feSDimitry Andric #if defined(__APPLE__) 756*cb14a3feSDimitry Andric // Darwin lazily saves the AVX512 context on first use: trust that the OS will 757*cb14a3feSDimitry Andric // save the AVX512 context if we use AVX512 instructions, even the bit is not 758*cb14a3feSDimitry Andric // set right now. 759*cb14a3feSDimitry Andric bool HasAVX512Save = true; 760*cb14a3feSDimitry Andric #else 761*cb14a3feSDimitry Andric // AVX512 requires additional context to be saved by the OS. 762*cb14a3feSDimitry Andric bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); 763*cb14a3feSDimitry Andric #endif 764*cb14a3feSDimitry Andric 765*cb14a3feSDimitry Andric if (HasAVX) 766*cb14a3feSDimitry Andric setFeature(FEATURE_AVX); 767*cb14a3feSDimitry Andric 768*cb14a3feSDimitry Andric bool HasLeaf7 = 769*cb14a3feSDimitry Andric MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); 770*cb14a3feSDimitry Andric 771*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 3) & 1)) 772*cb14a3feSDimitry Andric setFeature(FEATURE_BMI); 773*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) 774*cb14a3feSDimitry Andric setFeature(FEATURE_AVX2); 775*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 8) & 1)) 776*cb14a3feSDimitry Andric setFeature(FEATURE_BMI2); 777*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) 778*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512F); 779*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) 780*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512DQ); 781*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) 782*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512IFMA); 783*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) 784*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512PF); 785*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) 786*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512ER); 787*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) 788*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512CD); 789*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) 790*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BW); 791*cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) 792*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VL); 793*cb14a3feSDimitry Andric 794*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) 795*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VBMI); 796*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) 797*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VBMI2); 798*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 8) & 1)) 799*cb14a3feSDimitry Andric setFeature(FEATURE_GFNI); 800*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX) 801*cb14a3feSDimitry Andric setFeature(FEATURE_VPCLMULQDQ); 802*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) 803*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VNNI); 804*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) 805*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BITALG); 806*cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) 807*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VPOPCNTDQ); 808*cb14a3feSDimitry Andric 809*cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) 810*cb14a3feSDimitry Andric setFeature(FEATURE_AVX5124VNNIW); 811*cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) 812*cb14a3feSDimitry Andric setFeature(FEATURE_AVX5124FMAPS); 813*cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) 814*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VP2INTERSECT); 815*cb14a3feSDimitry Andric 816*cb14a3feSDimitry Andric // EAX from subleaf 0 is the maximum subleaf supported. Some CPUs don't 817*cb14a3feSDimitry Andric // return all 0s for invalid subleaves so check the limit. 818*cb14a3feSDimitry Andric bool HasLeaf7Subleaf1 = 819*cb14a3feSDimitry Andric HasLeaf7 && EAX >= 1 && 820*cb14a3feSDimitry Andric !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); 821*cb14a3feSDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save) 822*cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BF16); 823*cb14a3feSDimitry Andric 824*cb14a3feSDimitry Andric unsigned MaxExtLevel; 825*cb14a3feSDimitry Andric getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); 826*cb14a3feSDimitry Andric 827*cb14a3feSDimitry Andric bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && 828*cb14a3feSDimitry Andric !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); 829*cb14a3feSDimitry Andric if (HasExtLeaf1) { 830*cb14a3feSDimitry Andric if (ECX & 1) 831*cb14a3feSDimitry Andric setFeature(FEATURE_LAHF_LM); 832*cb14a3feSDimitry Andric if ((ECX >> 5) & 1) 833*cb14a3feSDimitry Andric setFeature(FEATURE_LZCNT); 834*cb14a3feSDimitry Andric if (((ECX >> 6) & 1)) 835*cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_A); 836*cb14a3feSDimitry Andric if (((ECX >> 11) & 1)) 837*cb14a3feSDimitry Andric setFeature(FEATURE_XOP); 838*cb14a3feSDimitry Andric if (((ECX >> 16) & 1)) 839*cb14a3feSDimitry Andric setFeature(FEATURE_FMA4); 840*cb14a3feSDimitry Andric if (((EDX >> 29) & 1)) 841*cb14a3feSDimitry Andric setFeature(FEATURE_LM); 842*cb14a3feSDimitry Andric } 843*cb14a3feSDimitry Andric 844*cb14a3feSDimitry Andric if (hasFeature(FEATURE_LM) && hasFeature(FEATURE_SSE2)) { 845*cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_BASELINE); 846*cb14a3feSDimitry Andric if (hasFeature(FEATURE_CMPXCHG16B) && hasFeature(FEATURE_POPCNT) && 847*cb14a3feSDimitry Andric hasFeature(FEATURE_LAHF_LM) && hasFeature(FEATURE_SSE4_2)) { 848*cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V2); 849*cb14a3feSDimitry Andric if (hasFeature(FEATURE_AVX2) && hasFeature(FEATURE_BMI) && 850*cb14a3feSDimitry Andric hasFeature(FEATURE_BMI2) && hasFeature(FEATURE_F16C) && 851*cb14a3feSDimitry Andric hasFeature(FEATURE_FMA) && hasFeature(FEATURE_LZCNT) && 852*cb14a3feSDimitry Andric hasFeature(FEATURE_MOVBE)) { 853*cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V3); 854*cb14a3feSDimitry Andric if (hasFeature(FEATURE_AVX512BW) && hasFeature(FEATURE_AVX512CD) && 855*cb14a3feSDimitry Andric hasFeature(FEATURE_AVX512DQ) && hasFeature(FEATURE_AVX512VL)) 856*cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V4); 857*cb14a3feSDimitry Andric } 858*cb14a3feSDimitry Andric } 859*cb14a3feSDimitry Andric } 860*cb14a3feSDimitry Andric 861*cb14a3feSDimitry Andric #undef hasFeature 862*cb14a3feSDimitry Andric #undef setFeature 863*cb14a3feSDimitry Andric } 864*cb14a3feSDimitry Andric 865*cb14a3feSDimitry Andric #ifndef _WIN32 866*cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 867*cb14a3feSDimitry Andric #endif 868*cb14a3feSDimitry Andric int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; 869*cb14a3feSDimitry Andric 870*cb14a3feSDimitry Andric #ifndef _WIN32 871*cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 872*cb14a3feSDimitry Andric #endif 873*cb14a3feSDimitry Andric struct __processor_model { 874*cb14a3feSDimitry Andric unsigned int __cpu_vendor; 875*cb14a3feSDimitry Andric unsigned int __cpu_type; 876*cb14a3feSDimitry Andric unsigned int __cpu_subtype; 877*cb14a3feSDimitry Andric unsigned int __cpu_features[1]; 878*cb14a3feSDimitry Andric } __cpu_model = {0, 0, 0, {0}}; 879*cb14a3feSDimitry Andric 880*cb14a3feSDimitry Andric #ifndef _WIN32 881*cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 882*cb14a3feSDimitry Andric #endif 883*cb14a3feSDimitry Andric unsigned __cpu_features2[(CPU_FEATURE_MAX - 1) / 32]; 884*cb14a3feSDimitry Andric 885*cb14a3feSDimitry Andric // A constructor function that is sets __cpu_model and __cpu_features2 with 886*cb14a3feSDimitry Andric // the right values. This needs to run only once. This constructor is 887*cb14a3feSDimitry Andric // given the highest priority and it should run before constructors without 888*cb14a3feSDimitry Andric // the priority set. However, it still runs after ifunc initializers and 889*cb14a3feSDimitry Andric // needs to be called explicitly there. 890*cb14a3feSDimitry Andric 891*cb14a3feSDimitry Andric int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { 892*cb14a3feSDimitry Andric unsigned EAX, EBX, ECX, EDX; 893*cb14a3feSDimitry Andric unsigned MaxLeaf = 5; 894*cb14a3feSDimitry Andric unsigned Vendor; 895*cb14a3feSDimitry Andric unsigned Model, Family; 896*cb14a3feSDimitry Andric unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0}; 897*cb14a3feSDimitry Andric static_assert(sizeof(Features) / sizeof(Features[0]) == 4, ""); 898*cb14a3feSDimitry Andric static_assert(sizeof(__cpu_features2) / sizeof(__cpu_features2[0]) == 3, ""); 899*cb14a3feSDimitry Andric 900*cb14a3feSDimitry Andric // This function needs to run just once. 901*cb14a3feSDimitry Andric if (__cpu_model.__cpu_vendor) 902*cb14a3feSDimitry Andric return 0; 903*cb14a3feSDimitry Andric 904*cb14a3feSDimitry Andric if (!isCpuIdSupported() || 905*cb14a3feSDimitry Andric getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { 906*cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_OTHER; 907*cb14a3feSDimitry Andric return -1; 908*cb14a3feSDimitry Andric } 909*cb14a3feSDimitry Andric 910*cb14a3feSDimitry Andric getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); 911*cb14a3feSDimitry Andric detectX86FamilyModel(EAX, &Family, &Model); 912*cb14a3feSDimitry Andric 913*cb14a3feSDimitry Andric // Find available features. 914*cb14a3feSDimitry Andric getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]); 915*cb14a3feSDimitry Andric 916*cb14a3feSDimitry Andric __cpu_model.__cpu_features[0] = Features[0]; 917*cb14a3feSDimitry Andric __cpu_features2[0] = Features[1]; 918*cb14a3feSDimitry Andric __cpu_features2[1] = Features[2]; 919*cb14a3feSDimitry Andric __cpu_features2[2] = Features[3]; 920*cb14a3feSDimitry Andric 921*cb14a3feSDimitry Andric if (Vendor == SIG_INTEL) { 922*cb14a3feSDimitry Andric // Get CPU type. 923*cb14a3feSDimitry Andric getIntelProcessorTypeAndSubtype(Family, Model, &Features[0], 924*cb14a3feSDimitry Andric &(__cpu_model.__cpu_type), 925*cb14a3feSDimitry Andric &(__cpu_model.__cpu_subtype)); 926*cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_INTEL; 927*cb14a3feSDimitry Andric } else if (Vendor == SIG_AMD) { 928*cb14a3feSDimitry Andric // Get CPU type. 929*cb14a3feSDimitry Andric getAMDProcessorTypeAndSubtype(Family, Model, &Features[0], 930*cb14a3feSDimitry Andric &(__cpu_model.__cpu_type), 931*cb14a3feSDimitry Andric &(__cpu_model.__cpu_subtype)); 932*cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_AMD; 933*cb14a3feSDimitry Andric } else 934*cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_OTHER; 935*cb14a3feSDimitry Andric 936*cb14a3feSDimitry Andric assert(__cpu_model.__cpu_vendor < VENDOR_MAX); 937*cb14a3feSDimitry Andric assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); 938*cb14a3feSDimitry Andric assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 939*cb14a3feSDimitry Andric 940*cb14a3feSDimitry Andric return 0; 941*cb14a3feSDimitry Andric } 942*cb14a3feSDimitry Andric #endif // defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) 943