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