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