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, 62*c80e69b0SDimitry Andric AMDFAM1AH, 63cb14a3feSDimitry Andric CPU_TYPE_MAX 64cb14a3feSDimitry Andric }; 65cb14a3feSDimitry Andric 66cb14a3feSDimitry Andric enum ProcessorSubtypes { 67cb14a3feSDimitry Andric INTEL_COREI7_NEHALEM = 1, 68cb14a3feSDimitry Andric INTEL_COREI7_WESTMERE, 69cb14a3feSDimitry Andric INTEL_COREI7_SANDYBRIDGE, 70cb14a3feSDimitry Andric AMDFAM10H_BARCELONA, 71cb14a3feSDimitry Andric AMDFAM10H_SHANGHAI, 72cb14a3feSDimitry Andric AMDFAM10H_ISTANBUL, 73cb14a3feSDimitry Andric AMDFAM15H_BDVER1, 74cb14a3feSDimitry Andric AMDFAM15H_BDVER2, 75cb14a3feSDimitry Andric AMDFAM15H_BDVER3, 76cb14a3feSDimitry Andric AMDFAM15H_BDVER4, 77cb14a3feSDimitry Andric AMDFAM17H_ZNVER1, 78cb14a3feSDimitry Andric INTEL_COREI7_IVYBRIDGE, 79cb14a3feSDimitry Andric INTEL_COREI7_HASWELL, 80cb14a3feSDimitry Andric INTEL_COREI7_BROADWELL, 81cb14a3feSDimitry Andric INTEL_COREI7_SKYLAKE, 82cb14a3feSDimitry Andric INTEL_COREI7_SKYLAKE_AVX512, 83cb14a3feSDimitry Andric INTEL_COREI7_CANNONLAKE, 84cb14a3feSDimitry Andric INTEL_COREI7_ICELAKE_CLIENT, 85cb14a3feSDimitry Andric INTEL_COREI7_ICELAKE_SERVER, 86cb14a3feSDimitry Andric AMDFAM17H_ZNVER2, 87cb14a3feSDimitry Andric INTEL_COREI7_CASCADELAKE, 88cb14a3feSDimitry Andric INTEL_COREI7_TIGERLAKE, 89cb14a3feSDimitry Andric INTEL_COREI7_COOPERLAKE, 90cb14a3feSDimitry Andric INTEL_COREI7_SAPPHIRERAPIDS, 91cb14a3feSDimitry Andric INTEL_COREI7_ALDERLAKE, 92cb14a3feSDimitry Andric AMDFAM19H_ZNVER3, 93cb14a3feSDimitry Andric INTEL_COREI7_ROCKETLAKE, 94cb14a3feSDimitry Andric ZHAOXIN_FAM7H_LUJIAZUI, 95cb14a3feSDimitry Andric AMDFAM19H_ZNVER4, 96cb14a3feSDimitry Andric INTEL_COREI7_GRANITERAPIDS, 97cb14a3feSDimitry Andric INTEL_COREI7_GRANITERAPIDS_D, 98cb14a3feSDimitry Andric INTEL_COREI7_ARROWLAKE, 99cb14a3feSDimitry Andric INTEL_COREI7_ARROWLAKE_S, 100cb14a3feSDimitry Andric INTEL_COREI7_PANTHERLAKE, 101*c80e69b0SDimitry Andric AMDFAM1AH_ZNVER5, 102cb14a3feSDimitry Andric CPU_SUBTYPE_MAX 103cb14a3feSDimitry Andric }; 104cb14a3feSDimitry Andric 105cb14a3feSDimitry Andric enum ProcessorFeatures { 106cb14a3feSDimitry Andric FEATURE_CMOV = 0, 107cb14a3feSDimitry Andric FEATURE_MMX, 108cb14a3feSDimitry Andric FEATURE_POPCNT, 109cb14a3feSDimitry Andric FEATURE_SSE, 110cb14a3feSDimitry Andric FEATURE_SSE2, 111cb14a3feSDimitry Andric FEATURE_SSE3, 112cb14a3feSDimitry Andric FEATURE_SSSE3, 113cb14a3feSDimitry Andric FEATURE_SSE4_1, 114cb14a3feSDimitry Andric FEATURE_SSE4_2, 115cb14a3feSDimitry Andric FEATURE_AVX, 116cb14a3feSDimitry Andric FEATURE_AVX2, 117cb14a3feSDimitry Andric FEATURE_SSE4_A, 118cb14a3feSDimitry Andric FEATURE_FMA4, 119cb14a3feSDimitry Andric FEATURE_XOP, 120cb14a3feSDimitry Andric FEATURE_FMA, 121cb14a3feSDimitry Andric FEATURE_AVX512F, 122cb14a3feSDimitry Andric FEATURE_BMI, 123cb14a3feSDimitry Andric FEATURE_BMI2, 124cb14a3feSDimitry Andric FEATURE_AES, 125cb14a3feSDimitry Andric FEATURE_PCLMUL, 126cb14a3feSDimitry Andric FEATURE_AVX512VL, 127cb14a3feSDimitry Andric FEATURE_AVX512BW, 128cb14a3feSDimitry Andric FEATURE_AVX512DQ, 129cb14a3feSDimitry Andric FEATURE_AVX512CD, 130cb14a3feSDimitry Andric FEATURE_AVX512ER, 131cb14a3feSDimitry Andric FEATURE_AVX512PF, 132cb14a3feSDimitry Andric FEATURE_AVX512VBMI, 133cb14a3feSDimitry Andric FEATURE_AVX512IFMA, 134cb14a3feSDimitry Andric FEATURE_AVX5124VNNIW, 135cb14a3feSDimitry Andric FEATURE_AVX5124FMAPS, 136cb14a3feSDimitry Andric FEATURE_AVX512VPOPCNTDQ, 137cb14a3feSDimitry Andric FEATURE_AVX512VBMI2, 138cb14a3feSDimitry Andric FEATURE_GFNI, 139cb14a3feSDimitry Andric FEATURE_VPCLMULQDQ, 140cb14a3feSDimitry Andric FEATURE_AVX512VNNI, 141cb14a3feSDimitry Andric FEATURE_AVX512BITALG, 142cb14a3feSDimitry Andric FEATURE_AVX512BF16, 143cb14a3feSDimitry Andric FEATURE_AVX512VP2INTERSECT, 1440fca6ea1SDimitry Andric // FIXME: Below Features has some missings comparing to gcc, it's because gcc 1450fca6ea1SDimitry Andric // has some not one-to-one mapped in llvm. 1460fca6ea1SDimitry Andric // FEATURE_3DNOW, 1470fca6ea1SDimitry Andric // FEATURE_3DNOWP, 1480fca6ea1SDimitry Andric FEATURE_ADX = 40, 1490fca6ea1SDimitry Andric // FEATURE_ABM, 1500fca6ea1SDimitry Andric FEATURE_CLDEMOTE = 42, 1510fca6ea1SDimitry Andric FEATURE_CLFLUSHOPT, 1520fca6ea1SDimitry Andric FEATURE_CLWB, 1530fca6ea1SDimitry Andric FEATURE_CLZERO, 1540fca6ea1SDimitry Andric FEATURE_CMPXCHG16B, 1550fca6ea1SDimitry Andric // FIXME: Not adding FEATURE_CMPXCHG8B is a workaround to make 'generic' as 1560fca6ea1SDimitry Andric // a cpu string with no X86_FEATURE_COMPAT features, which is required in 1570fca6ea1SDimitry Andric // current implementantion of cpu_specific/cpu_dispatch FMV feature. 1580fca6ea1SDimitry Andric // FEATURE_CMPXCHG8B, 1590fca6ea1SDimitry Andric FEATURE_ENQCMD = 48, 1600fca6ea1SDimitry Andric FEATURE_F16C, 1610fca6ea1SDimitry Andric FEATURE_FSGSBASE, 1620fca6ea1SDimitry Andric // FEATURE_FXSAVE, 1630fca6ea1SDimitry Andric // FEATURE_HLE, 1640fca6ea1SDimitry Andric // FEATURE_IBT, 165cb14a3feSDimitry Andric FEATURE_LAHF_LM = 54, 166cb14a3feSDimitry Andric FEATURE_LM, 1670fca6ea1SDimitry Andric FEATURE_LWP, 168cb14a3feSDimitry Andric FEATURE_LZCNT, 169cb14a3feSDimitry Andric FEATURE_MOVBE, 1700fca6ea1SDimitry Andric FEATURE_MOVDIR64B, 1710fca6ea1SDimitry Andric FEATURE_MOVDIRI, 1720fca6ea1SDimitry Andric FEATURE_MWAITX, 1730fca6ea1SDimitry Andric // FEATURE_OSXSAVE, 1740fca6ea1SDimitry Andric FEATURE_PCONFIG = 63, 1750fca6ea1SDimitry Andric FEATURE_PKU, 1760fca6ea1SDimitry Andric FEATURE_PREFETCHWT1, 1770fca6ea1SDimitry Andric FEATURE_PRFCHW, 1780fca6ea1SDimitry Andric FEATURE_PTWRITE, 1790fca6ea1SDimitry Andric FEATURE_RDPID, 1800fca6ea1SDimitry Andric FEATURE_RDRND, 1810fca6ea1SDimitry Andric FEATURE_RDSEED, 1820fca6ea1SDimitry Andric FEATURE_RTM, 1830fca6ea1SDimitry Andric FEATURE_SERIALIZE, 1840fca6ea1SDimitry Andric FEATURE_SGX, 1850fca6ea1SDimitry Andric FEATURE_SHA, 1860fca6ea1SDimitry Andric FEATURE_SHSTK, 1870fca6ea1SDimitry Andric FEATURE_TBM, 1880fca6ea1SDimitry Andric FEATURE_TSXLDTRK, 1890fca6ea1SDimitry Andric FEATURE_VAES, 1900fca6ea1SDimitry Andric FEATURE_WAITPKG, 1910fca6ea1SDimitry Andric FEATURE_WBNOINVD, 1920fca6ea1SDimitry Andric FEATURE_XSAVE, 1930fca6ea1SDimitry Andric FEATURE_XSAVEC, 1940fca6ea1SDimitry Andric FEATURE_XSAVEOPT, 1950fca6ea1SDimitry Andric FEATURE_XSAVES, 1960fca6ea1SDimitry Andric FEATURE_AMX_TILE, 1970fca6ea1SDimitry Andric FEATURE_AMX_INT8, 1980fca6ea1SDimitry Andric FEATURE_AMX_BF16, 1990fca6ea1SDimitry Andric FEATURE_UINTR, 2000fca6ea1SDimitry Andric FEATURE_HRESET, 2010fca6ea1SDimitry Andric FEATURE_KL, 2020fca6ea1SDimitry Andric // FEATURE_AESKLE, 2030fca6ea1SDimitry Andric FEATURE_WIDEKL = 92, 2040fca6ea1SDimitry Andric FEATURE_AVXVNNI, 2050fca6ea1SDimitry Andric FEATURE_AVX512FP16, 2067a6dacacSDimitry Andric FEATURE_X86_64_BASELINE, 207cb14a3feSDimitry Andric FEATURE_X86_64_V2, 208cb14a3feSDimitry Andric FEATURE_X86_64_V3, 209cb14a3feSDimitry Andric FEATURE_X86_64_V4, 2100fca6ea1SDimitry Andric FEATURE_AVXIFMA, 2110fca6ea1SDimitry Andric FEATURE_AVXVNNIINT8, 2120fca6ea1SDimitry Andric FEATURE_AVXNECONVERT, 2130fca6ea1SDimitry Andric FEATURE_CMPCCXADD, 2140fca6ea1SDimitry Andric FEATURE_AMX_FP16, 2150fca6ea1SDimitry Andric FEATURE_PREFETCHI, 2160fca6ea1SDimitry Andric FEATURE_RAOINT, 2170fca6ea1SDimitry Andric FEATURE_AMX_COMPLEX, 2180fca6ea1SDimitry Andric FEATURE_AVXVNNIINT16, 2190fca6ea1SDimitry Andric FEATURE_SM3, 2200fca6ea1SDimitry Andric FEATURE_SHA512, 2210fca6ea1SDimitry Andric FEATURE_SM4, 2220fca6ea1SDimitry Andric FEATURE_APXF, 2230fca6ea1SDimitry Andric FEATURE_USERMSR, 2240fca6ea1SDimitry Andric FEATURE_AVX10_1_256, 2250fca6ea1SDimitry Andric FEATURE_AVX10_1_512, 226cb14a3feSDimitry Andric CPU_FEATURE_MAX 227cb14a3feSDimitry Andric }; 228cb14a3feSDimitry Andric 229cb14a3feSDimitry Andric // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). 230cb14a3feSDimitry Andric // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID 231cb14a3feSDimitry Andric // support. Consequently, for i386, the presence of CPUID is checked first 232cb14a3feSDimitry Andric // via the corresponding eflags bit. 233cb14a3feSDimitry Andric static bool isCpuIdSupported(void) { 234cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 235cb14a3feSDimitry Andric #if defined(__i386__) 236cb14a3feSDimitry Andric int __cpuid_supported; 237cb14a3feSDimitry Andric __asm__(" pushfl\n" 238cb14a3feSDimitry Andric " popl %%eax\n" 239cb14a3feSDimitry Andric " movl %%eax,%%ecx\n" 240cb14a3feSDimitry Andric " xorl $0x00200000,%%eax\n" 241cb14a3feSDimitry Andric " pushl %%eax\n" 242cb14a3feSDimitry Andric " popfl\n" 243cb14a3feSDimitry Andric " pushfl\n" 244cb14a3feSDimitry Andric " popl %%eax\n" 245cb14a3feSDimitry Andric " movl $0,%0\n" 246cb14a3feSDimitry Andric " cmpl %%eax,%%ecx\n" 247cb14a3feSDimitry Andric " je 1f\n" 248cb14a3feSDimitry Andric " movl $1,%0\n" 249cb14a3feSDimitry Andric "1:" 250cb14a3feSDimitry Andric : "=r"(__cpuid_supported) 251cb14a3feSDimitry Andric : 252cb14a3feSDimitry Andric : "eax", "ecx"); 253cb14a3feSDimitry Andric if (!__cpuid_supported) 254cb14a3feSDimitry Andric return false; 255cb14a3feSDimitry Andric #endif 256cb14a3feSDimitry Andric return true; 257cb14a3feSDimitry Andric #endif 258cb14a3feSDimitry Andric return true; 259cb14a3feSDimitry Andric } 260cb14a3feSDimitry Andric 261cb14a3feSDimitry Andric // This code is copied from lib/Support/Host.cpp. 262cb14a3feSDimitry Andric // Changes to either file should be mirrored in the other. 263cb14a3feSDimitry Andric 264cb14a3feSDimitry Andric /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in 265cb14a3feSDimitry Andric /// the specified arguments. If we can't run cpuid on the host, return true. 266cb14a3feSDimitry Andric static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, 267cb14a3feSDimitry Andric unsigned *rECX, unsigned *rEDX) { 268cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 269cb14a3feSDimitry Andric #if defined(__x86_64__) 270cb14a3feSDimitry Andric // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 271cb14a3feSDimitry Andric // FIXME: should we save this for Clang? 272cb14a3feSDimitry Andric __asm__("movq\t%%rbx, %%rsi\n\t" 273cb14a3feSDimitry Andric "cpuid\n\t" 274cb14a3feSDimitry Andric "xchgq\t%%rbx, %%rsi\n\t" 275cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 276cb14a3feSDimitry Andric : "a"(value)); 277cb14a3feSDimitry Andric return false; 278cb14a3feSDimitry Andric #elif defined(__i386__) 279cb14a3feSDimitry Andric __asm__("movl\t%%ebx, %%esi\n\t" 280cb14a3feSDimitry Andric "cpuid\n\t" 281cb14a3feSDimitry Andric "xchgl\t%%ebx, %%esi\n\t" 282cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 283cb14a3feSDimitry Andric : "a"(value)); 284cb14a3feSDimitry Andric return false; 285cb14a3feSDimitry Andric #else 286cb14a3feSDimitry Andric return true; 287cb14a3feSDimitry Andric #endif 288cb14a3feSDimitry Andric #elif defined(_MSC_VER) 289cb14a3feSDimitry Andric // The MSVC intrinsic is portable across x86 and x64. 290cb14a3feSDimitry Andric int registers[4]; 291cb14a3feSDimitry Andric __cpuid(registers, value); 292cb14a3feSDimitry Andric *rEAX = registers[0]; 293cb14a3feSDimitry Andric *rEBX = registers[1]; 294cb14a3feSDimitry Andric *rECX = registers[2]; 295cb14a3feSDimitry Andric *rEDX = registers[3]; 296cb14a3feSDimitry Andric return false; 297cb14a3feSDimitry Andric #else 298cb14a3feSDimitry Andric return true; 299cb14a3feSDimitry Andric #endif 300cb14a3feSDimitry Andric } 301cb14a3feSDimitry Andric 302cb14a3feSDimitry Andric /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return 303cb14a3feSDimitry Andric /// the 4 values in the specified arguments. If we can't run cpuid on the host, 304cb14a3feSDimitry Andric /// return true. 305cb14a3feSDimitry Andric static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, 306cb14a3feSDimitry Andric unsigned *rEAX, unsigned *rEBX, unsigned *rECX, 307cb14a3feSDimitry Andric unsigned *rEDX) { 308cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 309cb14a3feSDimitry Andric #if defined(__x86_64__) 310cb14a3feSDimitry Andric // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 311cb14a3feSDimitry Andric // FIXME: should we save this for Clang? 312cb14a3feSDimitry Andric __asm__("movq\t%%rbx, %%rsi\n\t" 313cb14a3feSDimitry Andric "cpuid\n\t" 314cb14a3feSDimitry Andric "xchgq\t%%rbx, %%rsi\n\t" 315cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 316cb14a3feSDimitry Andric : "a"(value), "c"(subleaf)); 317cb14a3feSDimitry Andric return false; 318cb14a3feSDimitry Andric #elif defined(__i386__) 319cb14a3feSDimitry Andric __asm__("movl\t%%ebx, %%esi\n\t" 320cb14a3feSDimitry Andric "cpuid\n\t" 321cb14a3feSDimitry Andric "xchgl\t%%ebx, %%esi\n\t" 322cb14a3feSDimitry Andric : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 323cb14a3feSDimitry Andric : "a"(value), "c"(subleaf)); 324cb14a3feSDimitry Andric return false; 325cb14a3feSDimitry Andric #else 326cb14a3feSDimitry Andric return true; 327cb14a3feSDimitry Andric #endif 328cb14a3feSDimitry Andric #elif defined(_MSC_VER) 329cb14a3feSDimitry Andric int registers[4]; 330cb14a3feSDimitry Andric __cpuidex(registers, value, subleaf); 331cb14a3feSDimitry Andric *rEAX = registers[0]; 332cb14a3feSDimitry Andric *rEBX = registers[1]; 333cb14a3feSDimitry Andric *rECX = registers[2]; 334cb14a3feSDimitry Andric *rEDX = registers[3]; 335cb14a3feSDimitry Andric return false; 336cb14a3feSDimitry Andric #else 337cb14a3feSDimitry Andric return true; 338cb14a3feSDimitry Andric #endif 339cb14a3feSDimitry Andric } 340cb14a3feSDimitry Andric 341cb14a3feSDimitry Andric // Read control register 0 (XCR0). Used to detect features such as AVX. 342cb14a3feSDimitry Andric static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { 343cb14a3feSDimitry Andric #if defined(__GNUC__) || defined(__clang__) 344cb14a3feSDimitry Andric // Check xgetbv; this uses a .byte sequence instead of the instruction 345cb14a3feSDimitry Andric // directly because older assemblers do not include support for xgetbv and 346cb14a3feSDimitry Andric // there is no easy way to conditionally compile based on the assembler used. 347cb14a3feSDimitry Andric __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); 348cb14a3feSDimitry Andric return false; 349cb14a3feSDimitry Andric #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 350cb14a3feSDimitry Andric unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 351cb14a3feSDimitry Andric *rEAX = Result; 352cb14a3feSDimitry Andric *rEDX = Result >> 32; 353cb14a3feSDimitry Andric return false; 354cb14a3feSDimitry Andric #else 355cb14a3feSDimitry Andric return true; 356cb14a3feSDimitry Andric #endif 357cb14a3feSDimitry Andric } 358cb14a3feSDimitry Andric 359cb14a3feSDimitry Andric static void detectX86FamilyModel(unsigned EAX, unsigned *Family, 360cb14a3feSDimitry Andric unsigned *Model) { 361cb14a3feSDimitry Andric *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 362cb14a3feSDimitry Andric *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 363cb14a3feSDimitry Andric if (*Family == 6 || *Family == 0xf) { 364cb14a3feSDimitry Andric if (*Family == 0xf) 365cb14a3feSDimitry Andric // Examine extended family ID if family ID is F. 366cb14a3feSDimitry Andric *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 367cb14a3feSDimitry Andric // Examine extended model ID if family ID is 6 or F. 368cb14a3feSDimitry Andric *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 369cb14a3feSDimitry Andric } 370cb14a3feSDimitry Andric } 371cb14a3feSDimitry Andric 3720fca6ea1SDimitry Andric #define testFeature(F) (Features[F / 32] & (1 << (F % 32))) != 0 3730fca6ea1SDimitry Andric 374cb14a3feSDimitry Andric static const char *getIntelProcessorTypeAndSubtype(unsigned Family, 375cb14a3feSDimitry Andric unsigned Model, 376cb14a3feSDimitry Andric const unsigned *Features, 377cb14a3feSDimitry Andric unsigned *Type, 378cb14a3feSDimitry Andric unsigned *Subtype) { 379cb14a3feSDimitry Andric // We select CPU strings to match the code in Host.cpp, but we don't use them 380cb14a3feSDimitry Andric // in compiler-rt. 381cb14a3feSDimitry Andric const char *CPU = 0; 382cb14a3feSDimitry Andric 383cb14a3feSDimitry Andric switch (Family) { 384cb14a3feSDimitry Andric case 6: 385cb14a3feSDimitry Andric switch (Model) { 386cb14a3feSDimitry Andric case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile 387cb14a3feSDimitry Andric // processor, Intel Core 2 Quad processor, Intel Core 2 Quad 388cb14a3feSDimitry Andric // mobile processor, Intel Core 2 Extreme processor, Intel 389cb14a3feSDimitry Andric // Pentium Dual-Core processor, Intel Xeon processor, model 390cb14a3feSDimitry Andric // 0Fh. All processors are manufactured using the 65 nm process. 391cb14a3feSDimitry Andric case 0x16: // Intel Celeron processor model 16h. All processors are 392cb14a3feSDimitry Andric // manufactured using the 65 nm process 393cb14a3feSDimitry Andric CPU = "core2"; 394cb14a3feSDimitry Andric *Type = INTEL_CORE2; 395cb14a3feSDimitry Andric break; 396cb14a3feSDimitry Andric case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model 397cb14a3feSDimitry Andric // 17h. All processors are manufactured using the 45 nm process. 398cb14a3feSDimitry Andric // 399cb14a3feSDimitry Andric // 45nm: Penryn , Wolfdale, Yorkfield (XE) 400cb14a3feSDimitry Andric case 0x1d: // Intel Xeon processor MP. All processors are manufactured using 401cb14a3feSDimitry Andric // the 45 nm process. 402cb14a3feSDimitry Andric CPU = "penryn"; 403cb14a3feSDimitry Andric *Type = INTEL_CORE2; 404cb14a3feSDimitry Andric break; 405cb14a3feSDimitry Andric case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All 406cb14a3feSDimitry Andric // processors are manufactured using the 45 nm process. 407cb14a3feSDimitry Andric case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. 408cb14a3feSDimitry Andric // As found in a Summer 2010 model iMac. 409cb14a3feSDimitry Andric case 0x1f: 410cb14a3feSDimitry Andric case 0x2e: // Nehalem EX 411cb14a3feSDimitry Andric CPU = "nehalem"; 412cb14a3feSDimitry Andric *Type = INTEL_COREI7; 413cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_NEHALEM; 414cb14a3feSDimitry Andric break; 415cb14a3feSDimitry Andric case 0x25: // Intel Core i7, laptop version. 416cb14a3feSDimitry Andric case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All 417cb14a3feSDimitry Andric // processors are manufactured using the 32 nm process. 418cb14a3feSDimitry Andric case 0x2f: // Westmere EX 419cb14a3feSDimitry Andric CPU = "westmere"; 420cb14a3feSDimitry Andric *Type = INTEL_COREI7; 421cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_WESTMERE; 422cb14a3feSDimitry Andric break; 423cb14a3feSDimitry Andric case 0x2a: // Intel Core i7 processor. All processors are manufactured 424cb14a3feSDimitry Andric // using the 32 nm process. 425cb14a3feSDimitry Andric case 0x2d: 426cb14a3feSDimitry Andric CPU = "sandybridge"; 427cb14a3feSDimitry Andric *Type = INTEL_COREI7; 428cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SANDYBRIDGE; 429cb14a3feSDimitry Andric break; 430cb14a3feSDimitry Andric case 0x3a: 431cb14a3feSDimitry Andric case 0x3e: // Ivy Bridge EP 432cb14a3feSDimitry Andric CPU = "ivybridge"; 433cb14a3feSDimitry Andric *Type = INTEL_COREI7; 434cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_IVYBRIDGE; 435cb14a3feSDimitry Andric break; 436cb14a3feSDimitry Andric 437cb14a3feSDimitry Andric // Haswell: 438cb14a3feSDimitry Andric case 0x3c: 439cb14a3feSDimitry Andric case 0x3f: 440cb14a3feSDimitry Andric case 0x45: 441cb14a3feSDimitry Andric case 0x46: 442cb14a3feSDimitry Andric CPU = "haswell"; 443cb14a3feSDimitry Andric *Type = INTEL_COREI7; 444cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_HASWELL; 445cb14a3feSDimitry Andric break; 446cb14a3feSDimitry Andric 447cb14a3feSDimitry Andric // Broadwell: 448cb14a3feSDimitry Andric case 0x3d: 449cb14a3feSDimitry Andric case 0x47: 450cb14a3feSDimitry Andric case 0x4f: 451cb14a3feSDimitry Andric case 0x56: 452cb14a3feSDimitry Andric CPU = "broadwell"; 453cb14a3feSDimitry Andric *Type = INTEL_COREI7; 454cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_BROADWELL; 455cb14a3feSDimitry Andric break; 456cb14a3feSDimitry Andric 457cb14a3feSDimitry Andric // Skylake: 458cb14a3feSDimitry Andric case 0x4e: // Skylake mobile 459cb14a3feSDimitry Andric case 0x5e: // Skylake desktop 460cb14a3feSDimitry Andric case 0x8e: // Kaby Lake mobile 461cb14a3feSDimitry Andric case 0x9e: // Kaby Lake desktop 462cb14a3feSDimitry Andric case 0xa5: // Comet Lake-H/S 463cb14a3feSDimitry Andric case 0xa6: // Comet Lake-U 464cb14a3feSDimitry Andric CPU = "skylake"; 465cb14a3feSDimitry Andric *Type = INTEL_COREI7; 466cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SKYLAKE; 467cb14a3feSDimitry Andric break; 468cb14a3feSDimitry Andric 469cb14a3feSDimitry Andric // Rocketlake: 470cb14a3feSDimitry Andric case 0xa7: 471cb14a3feSDimitry Andric CPU = "rocketlake"; 472cb14a3feSDimitry Andric *Type = INTEL_COREI7; 473cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ROCKETLAKE; 474cb14a3feSDimitry Andric break; 475cb14a3feSDimitry Andric 476cb14a3feSDimitry Andric // Skylake Xeon: 477cb14a3feSDimitry Andric case 0x55: 478cb14a3feSDimitry Andric *Type = INTEL_COREI7; 479cb14a3feSDimitry Andric if (testFeature(FEATURE_AVX512BF16)) { 480cb14a3feSDimitry Andric CPU = "cooperlake"; 481cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_COOPERLAKE; 482cb14a3feSDimitry Andric } else if (testFeature(FEATURE_AVX512VNNI)) { 483cb14a3feSDimitry Andric CPU = "cascadelake"; 484cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_CASCADELAKE; 485cb14a3feSDimitry Andric } else { 486cb14a3feSDimitry Andric CPU = "skylake-avx512"; 487cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SKYLAKE_AVX512; 488cb14a3feSDimitry Andric } 489cb14a3feSDimitry Andric break; 490cb14a3feSDimitry Andric 491cb14a3feSDimitry Andric // Cannonlake: 492cb14a3feSDimitry Andric case 0x66: 493cb14a3feSDimitry Andric CPU = "cannonlake"; 494cb14a3feSDimitry Andric *Type = INTEL_COREI7; 495cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_CANNONLAKE; 496cb14a3feSDimitry Andric break; 497cb14a3feSDimitry Andric 498cb14a3feSDimitry Andric // Icelake: 499cb14a3feSDimitry Andric case 0x7d: 500cb14a3feSDimitry Andric case 0x7e: 501cb14a3feSDimitry Andric CPU = "icelake-client"; 502cb14a3feSDimitry Andric *Type = INTEL_COREI7; 503cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ICELAKE_CLIENT; 504cb14a3feSDimitry Andric break; 505cb14a3feSDimitry Andric 506cb14a3feSDimitry Andric // Tigerlake: 507cb14a3feSDimitry Andric case 0x8c: 508cb14a3feSDimitry Andric case 0x8d: 509cb14a3feSDimitry Andric CPU = "tigerlake"; 510cb14a3feSDimitry Andric *Type = INTEL_COREI7; 511cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_TIGERLAKE; 512cb14a3feSDimitry Andric break; 513cb14a3feSDimitry Andric 514cb14a3feSDimitry Andric // Alderlake: 515cb14a3feSDimitry Andric case 0x97: 516cb14a3feSDimitry Andric case 0x9a: 517cb14a3feSDimitry Andric // Raptorlake: 518cb14a3feSDimitry Andric case 0xb7: 519cb14a3feSDimitry Andric case 0xba: 520cb14a3feSDimitry Andric case 0xbf: 521cb14a3feSDimitry Andric // Meteorlake: 522cb14a3feSDimitry Andric case 0xaa: 523cb14a3feSDimitry Andric case 0xac: 524cb14a3feSDimitry Andric // Gracemont: 525cb14a3feSDimitry Andric case 0xbe: 526cb14a3feSDimitry Andric CPU = "alderlake"; 527cb14a3feSDimitry Andric *Type = INTEL_COREI7; 528cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ALDERLAKE; 529cb14a3feSDimitry Andric break; 530cb14a3feSDimitry Andric 531cb14a3feSDimitry Andric // Arrowlake: 532cb14a3feSDimitry Andric case 0xc5: 533cb14a3feSDimitry Andric CPU = "arrowlake"; 534cb14a3feSDimitry Andric *Type = INTEL_COREI7; 535cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ARROWLAKE; 536cb14a3feSDimitry Andric break; 537cb14a3feSDimitry Andric 538cb14a3feSDimitry Andric // Arrowlake S: 539cb14a3feSDimitry Andric case 0xc6: 540cb14a3feSDimitry Andric // Lunarlake: 541cb14a3feSDimitry Andric case 0xbd: 542cb14a3feSDimitry Andric CPU = "arrowlake-s"; 543cb14a3feSDimitry Andric *Type = INTEL_COREI7; 544cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ARROWLAKE_S; 545cb14a3feSDimitry Andric break; 546cb14a3feSDimitry Andric 547cb14a3feSDimitry Andric // Pantherlake: 548cb14a3feSDimitry Andric case 0xcc: 549cb14a3feSDimitry Andric CPU = "pantherlake"; 550cb14a3feSDimitry Andric *Type = INTEL_COREI7; 551cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_PANTHERLAKE; 552cb14a3feSDimitry Andric break; 553cb14a3feSDimitry Andric 554cb14a3feSDimitry Andric // Icelake Xeon: 555cb14a3feSDimitry Andric case 0x6a: 556cb14a3feSDimitry Andric case 0x6c: 557cb14a3feSDimitry Andric CPU = "icelake-server"; 558cb14a3feSDimitry Andric *Type = INTEL_COREI7; 559cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_ICELAKE_SERVER; 560cb14a3feSDimitry Andric break; 561cb14a3feSDimitry Andric 562cb14a3feSDimitry Andric // Emerald Rapids: 563cb14a3feSDimitry Andric case 0xcf: 564cb14a3feSDimitry Andric // Sapphire Rapids: 565cb14a3feSDimitry Andric case 0x8f: 566cb14a3feSDimitry Andric CPU = "sapphirerapids"; 567cb14a3feSDimitry Andric *Type = INTEL_COREI7; 568cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_SAPPHIRERAPIDS; 569cb14a3feSDimitry Andric break; 570cb14a3feSDimitry Andric 571cb14a3feSDimitry Andric // Granite Rapids: 572cb14a3feSDimitry Andric case 0xad: 573cb14a3feSDimitry Andric CPU = "graniterapids"; 574cb14a3feSDimitry Andric *Type = INTEL_COREI7; 575cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_GRANITERAPIDS; 576cb14a3feSDimitry Andric break; 577cb14a3feSDimitry Andric 578cb14a3feSDimitry Andric // Granite Rapids D: 579cb14a3feSDimitry Andric case 0xae: 580cb14a3feSDimitry Andric CPU = "graniterapids-d"; 581cb14a3feSDimitry Andric *Type = INTEL_COREI7; 582cb14a3feSDimitry Andric *Subtype = INTEL_COREI7_GRANITERAPIDS_D; 583cb14a3feSDimitry Andric break; 584cb14a3feSDimitry Andric 585cb14a3feSDimitry Andric case 0x1c: // Most 45 nm Intel Atom processors 586cb14a3feSDimitry Andric case 0x26: // 45 nm Atom Lincroft 587cb14a3feSDimitry Andric case 0x27: // 32 nm Atom Medfield 588cb14a3feSDimitry Andric case 0x35: // 32 nm Atom Midview 589cb14a3feSDimitry Andric case 0x36: // 32 nm Atom Midview 590cb14a3feSDimitry Andric CPU = "bonnell"; 591cb14a3feSDimitry Andric *Type = INTEL_BONNELL; 592cb14a3feSDimitry Andric break; 593cb14a3feSDimitry Andric 594cb14a3feSDimitry Andric // Atom Silvermont codes from the Intel software optimization guide. 595cb14a3feSDimitry Andric case 0x37: 596cb14a3feSDimitry Andric case 0x4a: 597cb14a3feSDimitry Andric case 0x4d: 598cb14a3feSDimitry Andric case 0x5a: 599cb14a3feSDimitry Andric case 0x5d: 600cb14a3feSDimitry Andric case 0x4c: // really airmont 601cb14a3feSDimitry Andric CPU = "silvermont"; 602cb14a3feSDimitry Andric *Type = INTEL_SILVERMONT; 603cb14a3feSDimitry Andric break; 604cb14a3feSDimitry Andric // Goldmont: 605cb14a3feSDimitry Andric case 0x5c: // Apollo Lake 606cb14a3feSDimitry Andric case 0x5f: // Denverton 607cb14a3feSDimitry Andric CPU = "goldmont"; 608cb14a3feSDimitry Andric *Type = INTEL_GOLDMONT; 609cb14a3feSDimitry Andric break; // "goldmont" 610cb14a3feSDimitry Andric case 0x7a: 611cb14a3feSDimitry Andric CPU = "goldmont-plus"; 612cb14a3feSDimitry Andric *Type = INTEL_GOLDMONT_PLUS; 613cb14a3feSDimitry Andric break; 614cb14a3feSDimitry Andric case 0x86: 615cb14a3feSDimitry Andric case 0x8a: // Lakefield 616cb14a3feSDimitry Andric case 0x96: // Elkhart Lake 617cb14a3feSDimitry Andric case 0x9c: // Jasper Lake 618cb14a3feSDimitry Andric CPU = "tremont"; 619cb14a3feSDimitry Andric *Type = INTEL_TREMONT; 620cb14a3feSDimitry Andric break; 621cb14a3feSDimitry Andric 622cb14a3feSDimitry Andric // Sierraforest: 623cb14a3feSDimitry Andric case 0xaf: 624cb14a3feSDimitry Andric CPU = "sierraforest"; 625cb14a3feSDimitry Andric *Type = INTEL_SIERRAFOREST; 626cb14a3feSDimitry Andric break; 627cb14a3feSDimitry Andric 628cb14a3feSDimitry Andric // Grandridge: 629cb14a3feSDimitry Andric case 0xb6: 630cb14a3feSDimitry Andric CPU = "grandridge"; 631cb14a3feSDimitry Andric *Type = INTEL_GRANDRIDGE; 632cb14a3feSDimitry Andric break; 633cb14a3feSDimitry Andric 634cb14a3feSDimitry Andric // Clearwaterforest: 635cb14a3feSDimitry Andric case 0xdd: 636cb14a3feSDimitry Andric CPU = "clearwaterforest"; 637cb14a3feSDimitry Andric *Type = INTEL_COREI7; 638cb14a3feSDimitry Andric *Subtype = INTEL_CLEARWATERFOREST; 639cb14a3feSDimitry Andric break; 640cb14a3feSDimitry Andric 641cb14a3feSDimitry Andric case 0x57: 642cb14a3feSDimitry Andric CPU = "knl"; 643cb14a3feSDimitry Andric *Type = INTEL_KNL; 644cb14a3feSDimitry Andric break; 645cb14a3feSDimitry Andric 646cb14a3feSDimitry Andric case 0x85: 647cb14a3feSDimitry Andric CPU = "knm"; 648cb14a3feSDimitry Andric *Type = INTEL_KNM; 649cb14a3feSDimitry Andric break; 650cb14a3feSDimitry Andric 651cb14a3feSDimitry Andric default: // Unknown family 6 CPU. 652cb14a3feSDimitry Andric break; 653cb14a3feSDimitry Andric } 654cb14a3feSDimitry Andric break; 655cb14a3feSDimitry Andric default: 656cb14a3feSDimitry Andric break; // Unknown. 657cb14a3feSDimitry Andric } 658cb14a3feSDimitry Andric 659cb14a3feSDimitry Andric return CPU; 660cb14a3feSDimitry Andric } 661cb14a3feSDimitry Andric 662cb14a3feSDimitry Andric static const char *getAMDProcessorTypeAndSubtype(unsigned Family, 663cb14a3feSDimitry Andric unsigned Model, 664cb14a3feSDimitry Andric const unsigned *Features, 665cb14a3feSDimitry Andric unsigned *Type, 666cb14a3feSDimitry Andric unsigned *Subtype) { 667cb14a3feSDimitry Andric const char *CPU = 0; 668cb14a3feSDimitry Andric 669cb14a3feSDimitry Andric switch (Family) { 6700fca6ea1SDimitry Andric case 4: 6710fca6ea1SDimitry Andric CPU = "i486"; 6720fca6ea1SDimitry Andric break; 6730fca6ea1SDimitry Andric case 5: 6740fca6ea1SDimitry Andric CPU = "pentium"; 6750fca6ea1SDimitry Andric switch (Model) { 6760fca6ea1SDimitry Andric case 6: 6770fca6ea1SDimitry Andric case 7: 6780fca6ea1SDimitry Andric CPU = "k6"; 6790fca6ea1SDimitry Andric break; 6800fca6ea1SDimitry Andric case 8: 6810fca6ea1SDimitry Andric CPU = "k6-2"; 6820fca6ea1SDimitry Andric break; 6830fca6ea1SDimitry Andric case 9: 6840fca6ea1SDimitry Andric case 13: 6850fca6ea1SDimitry Andric CPU = "k6-3"; 6860fca6ea1SDimitry Andric break; 6870fca6ea1SDimitry Andric case 10: 6880fca6ea1SDimitry Andric CPU = "geode"; 6890fca6ea1SDimitry Andric break; 6900fca6ea1SDimitry Andric } 6910fca6ea1SDimitry Andric break; 6920fca6ea1SDimitry Andric case 6: 6930fca6ea1SDimitry Andric if (testFeature(FEATURE_SSE)) { 6940fca6ea1SDimitry Andric CPU = "athlon-xp"; 6950fca6ea1SDimitry Andric break; 6960fca6ea1SDimitry Andric } 6970fca6ea1SDimitry Andric CPU = "athlon"; 6980fca6ea1SDimitry Andric break; 6990fca6ea1SDimitry Andric case 15: 7000fca6ea1SDimitry Andric if (testFeature(FEATURE_SSE3)) { 7010fca6ea1SDimitry Andric CPU = "k8-sse3"; 7020fca6ea1SDimitry Andric break; 7030fca6ea1SDimitry Andric } 7040fca6ea1SDimitry Andric CPU = "k8"; 7050fca6ea1SDimitry Andric break; 706cb14a3feSDimitry Andric case 16: 707cb14a3feSDimitry Andric CPU = "amdfam10"; 7080fca6ea1SDimitry Andric *Type = AMDFAM10H; // "amdfam10" 709cb14a3feSDimitry Andric switch (Model) { 710cb14a3feSDimitry Andric case 2: 711cb14a3feSDimitry Andric *Subtype = AMDFAM10H_BARCELONA; 712cb14a3feSDimitry Andric break; 713cb14a3feSDimitry Andric case 4: 714cb14a3feSDimitry Andric *Subtype = AMDFAM10H_SHANGHAI; 715cb14a3feSDimitry Andric break; 716cb14a3feSDimitry Andric case 8: 717cb14a3feSDimitry Andric *Subtype = AMDFAM10H_ISTANBUL; 718cb14a3feSDimitry Andric break; 719cb14a3feSDimitry Andric } 720cb14a3feSDimitry Andric break; 721cb14a3feSDimitry Andric case 20: 722cb14a3feSDimitry Andric CPU = "btver1"; 723cb14a3feSDimitry Andric *Type = AMD_BTVER1; 724cb14a3feSDimitry Andric break; 725cb14a3feSDimitry Andric case 21: 726cb14a3feSDimitry Andric CPU = "bdver1"; 727cb14a3feSDimitry Andric *Type = AMDFAM15H; 728cb14a3feSDimitry Andric if (Model >= 0x60 && Model <= 0x7f) { 729cb14a3feSDimitry Andric CPU = "bdver4"; 730cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER4; 731cb14a3feSDimitry Andric break; // 60h-7Fh: Excavator 732cb14a3feSDimitry Andric } 733cb14a3feSDimitry Andric if (Model >= 0x30 && Model <= 0x3f) { 734cb14a3feSDimitry Andric CPU = "bdver3"; 735cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER3; 736cb14a3feSDimitry Andric break; // 30h-3Fh: Steamroller 737cb14a3feSDimitry Andric } 738cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { 739cb14a3feSDimitry Andric CPU = "bdver2"; 740cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER2; 741cb14a3feSDimitry Andric break; // 02h, 10h-1Fh: Piledriver 742cb14a3feSDimitry Andric } 743cb14a3feSDimitry Andric if (Model <= 0x0f) { 744cb14a3feSDimitry Andric *Subtype = AMDFAM15H_BDVER1; 745cb14a3feSDimitry Andric break; // 00h-0Fh: Bulldozer 746cb14a3feSDimitry Andric } 747cb14a3feSDimitry Andric break; 748cb14a3feSDimitry Andric case 22: 749cb14a3feSDimitry Andric CPU = "btver2"; 750cb14a3feSDimitry Andric *Type = AMD_BTVER2; 751cb14a3feSDimitry Andric break; 752cb14a3feSDimitry Andric case 23: 753cb14a3feSDimitry Andric CPU = "znver1"; 754cb14a3feSDimitry Andric *Type = AMDFAM17H; 755cb14a3feSDimitry Andric if ((Model >= 0x30 && Model <= 0x3f) || (Model == 0x47) || 756cb14a3feSDimitry Andric (Model >= 0x60 && Model <= 0x67) || (Model >= 0x68 && Model <= 0x6f) || 757cb14a3feSDimitry Andric (Model >= 0x70 && Model <= 0x7f) || (Model >= 0x84 && Model <= 0x87) || 758cb14a3feSDimitry Andric (Model >= 0x90 && Model <= 0x97) || (Model >= 0x98 && Model <= 0x9f) || 759cb14a3feSDimitry Andric (Model >= 0xa0 && Model <= 0xaf)) { 760cb14a3feSDimitry Andric // Family 17h Models 30h-3Fh (Starship) Zen 2 761cb14a3feSDimitry Andric // Family 17h Models 47h (Cardinal) Zen 2 762cb14a3feSDimitry Andric // Family 17h Models 60h-67h (Renoir) Zen 2 763cb14a3feSDimitry Andric // Family 17h Models 68h-6Fh (Lucienne) Zen 2 764cb14a3feSDimitry Andric // Family 17h Models 70h-7Fh (Matisse) Zen 2 765cb14a3feSDimitry Andric // Family 17h Models 84h-87h (ProjectX) Zen 2 766cb14a3feSDimitry Andric // Family 17h Models 90h-97h (VanGogh) Zen 2 767cb14a3feSDimitry Andric // Family 17h Models 98h-9Fh (Mero) Zen 2 768cb14a3feSDimitry Andric // Family 17h Models A0h-AFh (Mendocino) Zen 2 769cb14a3feSDimitry Andric CPU = "znver2"; 770cb14a3feSDimitry Andric *Subtype = AMDFAM17H_ZNVER2; 771cb14a3feSDimitry Andric break; 772cb14a3feSDimitry Andric } 773cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x20 && Model <= 0x2f)) { 774cb14a3feSDimitry Andric // Family 17h Models 10h-1Fh (Raven1) Zen 775cb14a3feSDimitry Andric // Family 17h Models 10h-1Fh (Picasso) Zen+ 776cb14a3feSDimitry Andric // Family 17h Models 20h-2Fh (Raven2 x86) Zen 777cb14a3feSDimitry Andric *Subtype = AMDFAM17H_ZNVER1; 778cb14a3feSDimitry Andric break; 779cb14a3feSDimitry Andric } 780cb14a3feSDimitry Andric break; 781cb14a3feSDimitry Andric case 25: 782cb14a3feSDimitry Andric CPU = "znver3"; 783cb14a3feSDimitry Andric *Type = AMDFAM19H; 7840fca6ea1SDimitry Andric if (Model <= 0x0f || (Model >= 0x20 && Model <= 0x2f) || 785cb14a3feSDimitry Andric (Model >= 0x30 && Model <= 0x3f) || (Model >= 0x40 && Model <= 0x4f) || 786cb14a3feSDimitry Andric (Model >= 0x50 && Model <= 0x5f)) { 787cb14a3feSDimitry Andric // Family 19h Models 00h-0Fh (Genesis, Chagall) Zen 3 788cb14a3feSDimitry Andric // Family 19h Models 20h-2Fh (Vermeer) Zen 3 789cb14a3feSDimitry Andric // Family 19h Models 30h-3Fh (Badami) Zen 3 790cb14a3feSDimitry Andric // Family 19h Models 40h-4Fh (Rembrandt) Zen 3+ 791cb14a3feSDimitry Andric // Family 19h Models 50h-5Fh (Cezanne) Zen 3 792cb14a3feSDimitry Andric *Subtype = AMDFAM19H_ZNVER3; 793cb14a3feSDimitry Andric break; 794cb14a3feSDimitry Andric } 795cb14a3feSDimitry Andric if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x60 && Model <= 0x6f) || 796cb14a3feSDimitry Andric (Model >= 0x70 && Model <= 0x77) || (Model >= 0x78 && Model <= 0x7f) || 797cb14a3feSDimitry Andric (Model >= 0xa0 && Model <= 0xaf)) { 798cb14a3feSDimitry Andric // Family 19h Models 10h-1Fh (Stones; Storm Peak) Zen 4 799cb14a3feSDimitry Andric // Family 19h Models 60h-6Fh (Raphael) Zen 4 800cb14a3feSDimitry Andric // Family 19h Models 70h-77h (Phoenix, Hawkpoint1) Zen 4 801cb14a3feSDimitry Andric // Family 19h Models 78h-7Fh (Phoenix 2, Hawkpoint2) Zen 4 802cb14a3feSDimitry Andric // Family 19h Models A0h-AFh (Stones-Dense) Zen 4 803cb14a3feSDimitry Andric CPU = "znver4"; 804cb14a3feSDimitry Andric *Subtype = AMDFAM19H_ZNVER4; 805cb14a3feSDimitry Andric break; // "znver4" 806cb14a3feSDimitry Andric } 807cb14a3feSDimitry Andric break; // family 19h 808*c80e69b0SDimitry Andric case 26: 809*c80e69b0SDimitry Andric CPU = "znver5"; 810*c80e69b0SDimitry Andric *Type = AMDFAM1AH; 811*c80e69b0SDimitry Andric if (Model <= 0x77) { 812*c80e69b0SDimitry Andric // Models 00h-0Fh (Breithorn). 813*c80e69b0SDimitry Andric // Models 10h-1Fh (Breithorn-Dense). 814*c80e69b0SDimitry Andric // Models 20h-2Fh (Strix 1). 815*c80e69b0SDimitry Andric // Models 30h-37h (Strix 2). 816*c80e69b0SDimitry Andric // Models 38h-3Fh (Strix 3). 817*c80e69b0SDimitry Andric // Models 40h-4Fh (Granite Ridge). 818*c80e69b0SDimitry Andric // Models 50h-5Fh (Weisshorn). 819*c80e69b0SDimitry Andric // Models 60h-6Fh (Krackan1). 820*c80e69b0SDimitry Andric // Models 70h-77h (Sarlak). 821*c80e69b0SDimitry Andric CPU = "znver5"; 822*c80e69b0SDimitry Andric *Subtype = AMDFAM1AH_ZNVER5; 823*c80e69b0SDimitry Andric break; // "znver5" 824*c80e69b0SDimitry Andric } 825*c80e69b0SDimitry Andric break; 826cb14a3feSDimitry Andric default: 827cb14a3feSDimitry Andric break; // Unknown AMD CPU. 828cb14a3feSDimitry Andric } 829cb14a3feSDimitry Andric 830cb14a3feSDimitry Andric return CPU; 831cb14a3feSDimitry Andric } 832cb14a3feSDimitry Andric 8330fca6ea1SDimitry Andric #undef testFeature 8340fca6ea1SDimitry Andric 835cb14a3feSDimitry Andric static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, 836cb14a3feSDimitry Andric unsigned *Features) { 837cb14a3feSDimitry Andric unsigned EAX = 0, EBX = 0; 838cb14a3feSDimitry Andric 839cb14a3feSDimitry Andric #define hasFeature(F) ((Features[F / 32] >> (F % 32)) & 1) 840cb14a3feSDimitry Andric #define setFeature(F) Features[F / 32] |= 1U << (F % 32) 841cb14a3feSDimitry Andric 842cb14a3feSDimitry Andric if ((EDX >> 15) & 1) 843cb14a3feSDimitry Andric setFeature(FEATURE_CMOV); 844cb14a3feSDimitry Andric if ((EDX >> 23) & 1) 845cb14a3feSDimitry Andric setFeature(FEATURE_MMX); 846cb14a3feSDimitry Andric if ((EDX >> 25) & 1) 847cb14a3feSDimitry Andric setFeature(FEATURE_SSE); 848cb14a3feSDimitry Andric if ((EDX >> 26) & 1) 849cb14a3feSDimitry Andric setFeature(FEATURE_SSE2); 850cb14a3feSDimitry Andric 851cb14a3feSDimitry Andric if ((ECX >> 0) & 1) 852cb14a3feSDimitry Andric setFeature(FEATURE_SSE3); 853cb14a3feSDimitry Andric if ((ECX >> 1) & 1) 854cb14a3feSDimitry Andric setFeature(FEATURE_PCLMUL); 855cb14a3feSDimitry Andric if ((ECX >> 9) & 1) 856cb14a3feSDimitry Andric setFeature(FEATURE_SSSE3); 857cb14a3feSDimitry Andric if ((ECX >> 12) & 1) 858cb14a3feSDimitry Andric setFeature(FEATURE_FMA); 859cb14a3feSDimitry Andric if ((ECX >> 13) & 1) 860cb14a3feSDimitry Andric setFeature(FEATURE_CMPXCHG16B); 861cb14a3feSDimitry Andric if ((ECX >> 19) & 1) 862cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_1); 863cb14a3feSDimitry Andric if ((ECX >> 20) & 1) 864cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_2); 865cb14a3feSDimitry Andric if ((ECX >> 22) & 1) 866cb14a3feSDimitry Andric setFeature(FEATURE_MOVBE); 867cb14a3feSDimitry Andric if ((ECX >> 23) & 1) 868cb14a3feSDimitry Andric setFeature(FEATURE_POPCNT); 869cb14a3feSDimitry Andric if ((ECX >> 25) & 1) 870cb14a3feSDimitry Andric setFeature(FEATURE_AES); 871cb14a3feSDimitry Andric if ((ECX >> 29) & 1) 872cb14a3feSDimitry Andric setFeature(FEATURE_F16C); 8730fca6ea1SDimitry Andric if ((ECX >> 30) & 1) 8740fca6ea1SDimitry Andric setFeature(FEATURE_RDRND); 875cb14a3feSDimitry Andric 876cb14a3feSDimitry Andric // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 877cb14a3feSDimitry Andric // indicates that the AVX registers will be saved and restored on context 878cb14a3feSDimitry Andric // switch, then we have full AVX support. 879cb14a3feSDimitry Andric const unsigned AVXBits = (1 << 27) | (1 << 28); 8800fca6ea1SDimitry Andric bool HasAVXSave = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && 881cb14a3feSDimitry Andric ((EAX & 0x6) == 0x6); 882cb14a3feSDimitry Andric #if defined(__APPLE__) 883cb14a3feSDimitry Andric // Darwin lazily saves the AVX512 context on first use: trust that the OS will 884cb14a3feSDimitry Andric // save the AVX512 context if we use AVX512 instructions, even the bit is not 885cb14a3feSDimitry Andric // set right now. 886cb14a3feSDimitry Andric bool HasAVX512Save = true; 887cb14a3feSDimitry Andric #else 888cb14a3feSDimitry Andric // AVX512 requires additional context to be saved by the OS. 8890fca6ea1SDimitry Andric bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); 890cb14a3feSDimitry Andric #endif 8910fca6ea1SDimitry Andric // AMX requires additional context to be saved by the OS. 8920fca6ea1SDimitry Andric const unsigned AMXBits = (1 << 17) | (1 << 18); 8930fca6ea1SDimitry Andric bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX); 8940fca6ea1SDimitry Andric bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits); 895cb14a3feSDimitry Andric 8960fca6ea1SDimitry Andric if (HasAVXSave) 897cb14a3feSDimitry Andric setFeature(FEATURE_AVX); 898cb14a3feSDimitry Andric 8990fca6ea1SDimitry Andric if (((ECX >> 26) & 1) && HasAVXSave) 9000fca6ea1SDimitry Andric setFeature(FEATURE_XSAVE); 9010fca6ea1SDimitry Andric 902cb14a3feSDimitry Andric bool HasLeaf7 = 903cb14a3feSDimitry Andric MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); 904cb14a3feSDimitry Andric 9050fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 0) & 1)) 9060fca6ea1SDimitry Andric setFeature(FEATURE_FSGSBASE); 9070fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 2) & 1)) 9080fca6ea1SDimitry Andric setFeature(FEATURE_SGX); 909cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 3) & 1)) 910cb14a3feSDimitry Andric setFeature(FEATURE_BMI); 9110fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave) 912cb14a3feSDimitry Andric setFeature(FEATURE_AVX2); 913cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 8) & 1)) 914cb14a3feSDimitry Andric setFeature(FEATURE_BMI2); 9150fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 11) & 1)) 9160fca6ea1SDimitry Andric setFeature(FEATURE_RTM); 917cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) 918cb14a3feSDimitry Andric setFeature(FEATURE_AVX512F); 919cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) 920cb14a3feSDimitry Andric setFeature(FEATURE_AVX512DQ); 9210fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 18) & 1)) 9220fca6ea1SDimitry Andric setFeature(FEATURE_RDSEED); 9230fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 19) & 1)) 9240fca6ea1SDimitry Andric setFeature(FEATURE_ADX); 925cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) 926cb14a3feSDimitry Andric setFeature(FEATURE_AVX512IFMA); 9270fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 24) & 1)) 9280fca6ea1SDimitry Andric setFeature(FEATURE_CLWB); 929cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) 930cb14a3feSDimitry Andric setFeature(FEATURE_AVX512PF); 931cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) 932cb14a3feSDimitry Andric setFeature(FEATURE_AVX512ER); 933cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) 934cb14a3feSDimitry Andric setFeature(FEATURE_AVX512CD); 9350fca6ea1SDimitry Andric if (HasLeaf7 && ((EBX >> 29) & 1)) 9360fca6ea1SDimitry Andric setFeature(FEATURE_SHA); 937cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) 938cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BW); 939cb14a3feSDimitry Andric if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) 940cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VL); 941cb14a3feSDimitry Andric 9420fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 0) & 1)) 9430fca6ea1SDimitry Andric setFeature(FEATURE_PREFETCHWT1); 944cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) 945cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VBMI); 9460fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 4) & 1)) 9470fca6ea1SDimitry Andric setFeature(FEATURE_PKU); 9480fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 5) & 1)) 9490fca6ea1SDimitry Andric setFeature(FEATURE_WAITPKG); 950cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) 951cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VBMI2); 9520fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 7) & 1)) 9530fca6ea1SDimitry Andric setFeature(FEATURE_SHSTK); 954cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 8) & 1)) 955cb14a3feSDimitry Andric setFeature(FEATURE_GFNI); 9560fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave) 9570fca6ea1SDimitry Andric setFeature(FEATURE_VAES); 9580fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave) 959cb14a3feSDimitry Andric setFeature(FEATURE_VPCLMULQDQ); 960cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) 961cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VNNI); 962cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) 963cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BITALG); 964cb14a3feSDimitry Andric if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) 965cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VPOPCNTDQ); 9660fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 22) & 1)) 9670fca6ea1SDimitry Andric setFeature(FEATURE_RDPID); 9680fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 23) & 1)) 9690fca6ea1SDimitry Andric setFeature(FEATURE_KL); 9700fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 25) & 1)) 9710fca6ea1SDimitry Andric setFeature(FEATURE_CLDEMOTE); 9720fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 27) & 1)) 9730fca6ea1SDimitry Andric setFeature(FEATURE_MOVDIRI); 9740fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 28) & 1)) 9750fca6ea1SDimitry Andric setFeature(FEATURE_MOVDIR64B); 9760fca6ea1SDimitry Andric if (HasLeaf7 && ((ECX >> 29) & 1)) 9770fca6ea1SDimitry Andric setFeature(FEATURE_ENQCMD); 978cb14a3feSDimitry Andric 979cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) 980cb14a3feSDimitry Andric setFeature(FEATURE_AVX5124VNNIW); 981cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) 982cb14a3feSDimitry Andric setFeature(FEATURE_AVX5124FMAPS); 9830fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 5) & 1)) 9840fca6ea1SDimitry Andric setFeature(FEATURE_UINTR); 985cb14a3feSDimitry Andric if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) 986cb14a3feSDimitry Andric setFeature(FEATURE_AVX512VP2INTERSECT); 9870fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 14) & 1)) 9880fca6ea1SDimitry Andric setFeature(FEATURE_SERIALIZE); 9890fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 16) & 1)) 9900fca6ea1SDimitry Andric setFeature(FEATURE_TSXLDTRK); 9910fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 18) & 1)) 9920fca6ea1SDimitry Andric setFeature(FEATURE_PCONFIG); 9930fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave) 9940fca6ea1SDimitry Andric setFeature(FEATURE_AMX_BF16); 9957a6dacacSDimitry Andric if (HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save) 9967a6dacacSDimitry Andric setFeature(FEATURE_AVX512FP16); 9970fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave) 9980fca6ea1SDimitry Andric setFeature(FEATURE_AMX_TILE); 9990fca6ea1SDimitry Andric if (HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave) 10000fca6ea1SDimitry Andric setFeature(FEATURE_AMX_INT8); 1001cb14a3feSDimitry Andric 1002cb14a3feSDimitry Andric // EAX from subleaf 0 is the maximum subleaf supported. Some CPUs don't 1003cb14a3feSDimitry Andric // return all 0s for invalid subleaves so check the limit. 1004cb14a3feSDimitry Andric bool HasLeaf7Subleaf1 = 1005cb14a3feSDimitry Andric HasLeaf7 && EAX >= 1 && 1006cb14a3feSDimitry Andric !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); 10070fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 0) & 1)) 10080fca6ea1SDimitry Andric setFeature(FEATURE_SHA512); 10090fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 1) & 1)) 10100fca6ea1SDimitry Andric setFeature(FEATURE_SM3); 10110fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 2) & 1)) 10120fca6ea1SDimitry Andric setFeature(FEATURE_SM4); 10130fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 3) & 1)) 10140fca6ea1SDimitry Andric setFeature(FEATURE_RAOINT); 10150fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave) 10160fca6ea1SDimitry Andric setFeature(FEATURE_AVXVNNI); 1017cb14a3feSDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save) 1018cb14a3feSDimitry Andric setFeature(FEATURE_AVX512BF16); 10190fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 7) & 1)) 10200fca6ea1SDimitry Andric setFeature(FEATURE_CMPCCXADD); 10210fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 21) & 1) && HasAMXSave) 10220fca6ea1SDimitry Andric setFeature(FEATURE_AMX_FP16); 10230fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 22) & 1)) 10240fca6ea1SDimitry Andric setFeature(FEATURE_HRESET); 10250fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave) 10260fca6ea1SDimitry Andric setFeature(FEATURE_AVXIFMA); 10270fca6ea1SDimitry Andric 10280fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave) 10290fca6ea1SDimitry Andric setFeature(FEATURE_AVXVNNIINT8); 10300fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 5) & 1) && HasAVXSave) 10310fca6ea1SDimitry Andric setFeature(FEATURE_AVXNECONVERT); 10320fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 8) & 1) && HasAMXSave) 10330fca6ea1SDimitry Andric setFeature(FEATURE_AMX_COMPLEX); 10340fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 10) & 1) && HasAVXSave) 10350fca6ea1SDimitry Andric setFeature(FEATURE_AVXVNNIINT16); 10360fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 14) & 1)) 10370fca6ea1SDimitry Andric setFeature(FEATURE_PREFETCHI); 10380fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 15) & 1)) 10390fca6ea1SDimitry Andric setFeature(FEATURE_USERMSR); 10400fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1)) 10410fca6ea1SDimitry Andric setFeature(FEATURE_AVX10_1_256); 10420fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 21) & 1)) 10430fca6ea1SDimitry Andric setFeature(FEATURE_APXF); 10440fca6ea1SDimitry Andric 10450fca6ea1SDimitry Andric unsigned MaxLevel; 10460fca6ea1SDimitry Andric getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX); 10470fca6ea1SDimitry Andric bool HasLeafD = MaxLevel >= 0xd && 10480fca6ea1SDimitry Andric !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); 10490fca6ea1SDimitry Andric if (HasLeafD && ((EAX >> 0) & 1) && HasAVXSave) 10500fca6ea1SDimitry Andric setFeature(FEATURE_XSAVEOPT); 10510fca6ea1SDimitry Andric if (HasLeafD && ((EAX >> 1) & 1) && HasAVXSave) 10520fca6ea1SDimitry Andric setFeature(FEATURE_XSAVEC); 10530fca6ea1SDimitry Andric if (HasLeafD && ((EAX >> 3) & 1) && HasAVXSave) 10540fca6ea1SDimitry Andric setFeature(FEATURE_XSAVES); 10550fca6ea1SDimitry Andric 10560fca6ea1SDimitry Andric bool HasLeaf24 = 10570fca6ea1SDimitry Andric MaxLevel >= 0x24 && !getX86CpuIDAndInfo(0x24, &EAX, &EBX, &ECX, &EDX); 10580fca6ea1SDimitry Andric if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1) && HasLeaf24 && ((EBX >> 18) & 1)) 10590fca6ea1SDimitry Andric setFeature(FEATURE_AVX10_1_512); 1060cb14a3feSDimitry Andric 1061cb14a3feSDimitry Andric unsigned MaxExtLevel; 1062cb14a3feSDimitry Andric getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); 1063cb14a3feSDimitry Andric 1064cb14a3feSDimitry Andric bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && 1065cb14a3feSDimitry Andric !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); 1066cb14a3feSDimitry Andric if (HasExtLeaf1) { 1067cb14a3feSDimitry Andric if (ECX & 1) 1068cb14a3feSDimitry Andric setFeature(FEATURE_LAHF_LM); 1069cb14a3feSDimitry Andric if ((ECX >> 5) & 1) 1070cb14a3feSDimitry Andric setFeature(FEATURE_LZCNT); 1071cb14a3feSDimitry Andric if (((ECX >> 6) & 1)) 1072cb14a3feSDimitry Andric setFeature(FEATURE_SSE4_A); 10730fca6ea1SDimitry Andric if (((ECX >> 8) & 1)) 10740fca6ea1SDimitry Andric setFeature(FEATURE_PRFCHW); 1075cb14a3feSDimitry Andric if (((ECX >> 11) & 1)) 1076cb14a3feSDimitry Andric setFeature(FEATURE_XOP); 10770fca6ea1SDimitry Andric if (((ECX >> 15) & 1)) 10780fca6ea1SDimitry Andric setFeature(FEATURE_LWP); 1079cb14a3feSDimitry Andric if (((ECX >> 16) & 1)) 1080cb14a3feSDimitry Andric setFeature(FEATURE_FMA4); 10810fca6ea1SDimitry Andric if (((ECX >> 21) & 1)) 10820fca6ea1SDimitry Andric setFeature(FEATURE_TBM); 10830fca6ea1SDimitry Andric if (((ECX >> 29) & 1)) 10840fca6ea1SDimitry Andric setFeature(FEATURE_MWAITX); 10850fca6ea1SDimitry Andric 1086cb14a3feSDimitry Andric if (((EDX >> 29) & 1)) 1087cb14a3feSDimitry Andric setFeature(FEATURE_LM); 1088cb14a3feSDimitry Andric } 1089cb14a3feSDimitry Andric 10900fca6ea1SDimitry Andric bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && 10910fca6ea1SDimitry Andric !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); 10920fca6ea1SDimitry Andric if (HasExtLeaf8 && ((EBX >> 0) & 1)) 10930fca6ea1SDimitry Andric setFeature(FEATURE_CLZERO); 10940fca6ea1SDimitry Andric if (HasExtLeaf8 && ((EBX >> 9) & 1)) 10950fca6ea1SDimitry Andric setFeature(FEATURE_WBNOINVD); 10960fca6ea1SDimitry Andric 10970fca6ea1SDimitry Andric bool HasLeaf14 = MaxLevel >= 0x14 && 10980fca6ea1SDimitry Andric !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX); 10990fca6ea1SDimitry Andric if (HasLeaf14 && ((EBX >> 4) & 1)) 11000fca6ea1SDimitry Andric setFeature(FEATURE_PTWRITE); 11010fca6ea1SDimitry Andric 11020fca6ea1SDimitry Andric bool HasLeaf19 = 11030fca6ea1SDimitry Andric MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX); 11040fca6ea1SDimitry Andric if (HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1)) 11050fca6ea1SDimitry Andric setFeature(FEATURE_WIDEKL); 11060fca6ea1SDimitry Andric 1107cb14a3feSDimitry Andric if (hasFeature(FEATURE_LM) && hasFeature(FEATURE_SSE2)) { 1108cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_BASELINE); 1109cb14a3feSDimitry Andric if (hasFeature(FEATURE_CMPXCHG16B) && hasFeature(FEATURE_POPCNT) && 1110cb14a3feSDimitry Andric hasFeature(FEATURE_LAHF_LM) && hasFeature(FEATURE_SSE4_2)) { 1111cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V2); 1112cb14a3feSDimitry Andric if (hasFeature(FEATURE_AVX2) && hasFeature(FEATURE_BMI) && 1113cb14a3feSDimitry Andric hasFeature(FEATURE_BMI2) && hasFeature(FEATURE_F16C) && 1114cb14a3feSDimitry Andric hasFeature(FEATURE_FMA) && hasFeature(FEATURE_LZCNT) && 1115cb14a3feSDimitry Andric hasFeature(FEATURE_MOVBE)) { 1116cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V3); 1117cb14a3feSDimitry Andric if (hasFeature(FEATURE_AVX512BW) && hasFeature(FEATURE_AVX512CD) && 1118cb14a3feSDimitry Andric hasFeature(FEATURE_AVX512DQ) && hasFeature(FEATURE_AVX512VL)) 1119cb14a3feSDimitry Andric setFeature(FEATURE_X86_64_V4); 1120cb14a3feSDimitry Andric } 1121cb14a3feSDimitry Andric } 1122cb14a3feSDimitry Andric } 1123cb14a3feSDimitry Andric 1124cb14a3feSDimitry Andric #undef hasFeature 1125cb14a3feSDimitry Andric #undef setFeature 1126cb14a3feSDimitry Andric } 1127cb14a3feSDimitry Andric 1128cb14a3feSDimitry Andric #ifndef _WIN32 1129cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 1130cb14a3feSDimitry Andric #endif 1131cb14a3feSDimitry Andric int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; 1132cb14a3feSDimitry Andric 1133cb14a3feSDimitry Andric #ifndef _WIN32 1134cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 1135cb14a3feSDimitry Andric #endif 1136cb14a3feSDimitry Andric struct __processor_model { 1137cb14a3feSDimitry Andric unsigned int __cpu_vendor; 1138cb14a3feSDimitry Andric unsigned int __cpu_type; 1139cb14a3feSDimitry Andric unsigned int __cpu_subtype; 1140cb14a3feSDimitry Andric unsigned int __cpu_features[1]; 1141cb14a3feSDimitry Andric } __cpu_model = {0, 0, 0, {0}}; 1142cb14a3feSDimitry Andric 1143cb14a3feSDimitry Andric #ifndef _WIN32 1144cb14a3feSDimitry Andric __attribute__((visibility("hidden"))) 1145cb14a3feSDimitry Andric #endif 1146cb14a3feSDimitry Andric unsigned __cpu_features2[(CPU_FEATURE_MAX - 1) / 32]; 1147cb14a3feSDimitry Andric 1148cb14a3feSDimitry Andric // A constructor function that is sets __cpu_model and __cpu_features2 with 1149cb14a3feSDimitry Andric // the right values. This needs to run only once. This constructor is 1150cb14a3feSDimitry Andric // given the highest priority and it should run before constructors without 1151cb14a3feSDimitry Andric // the priority set. However, it still runs after ifunc initializers and 1152cb14a3feSDimitry Andric // needs to be called explicitly there. 1153cb14a3feSDimitry Andric 1154cb14a3feSDimitry Andric int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { 1155cb14a3feSDimitry Andric unsigned EAX, EBX, ECX, EDX; 1156cb14a3feSDimitry Andric unsigned MaxLeaf = 5; 1157cb14a3feSDimitry Andric unsigned Vendor; 1158cb14a3feSDimitry Andric unsigned Model, Family; 1159cb14a3feSDimitry Andric unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0}; 1160cb14a3feSDimitry Andric static_assert(sizeof(Features) / sizeof(Features[0]) == 4, ""); 1161cb14a3feSDimitry Andric static_assert(sizeof(__cpu_features2) / sizeof(__cpu_features2[0]) == 3, ""); 1162cb14a3feSDimitry Andric 1163cb14a3feSDimitry Andric // This function needs to run just once. 1164cb14a3feSDimitry Andric if (__cpu_model.__cpu_vendor) 1165cb14a3feSDimitry Andric return 0; 1166cb14a3feSDimitry Andric 1167cb14a3feSDimitry Andric if (!isCpuIdSupported() || 1168cb14a3feSDimitry Andric getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { 1169cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_OTHER; 1170cb14a3feSDimitry Andric return -1; 1171cb14a3feSDimitry Andric } 1172cb14a3feSDimitry Andric 1173cb14a3feSDimitry Andric getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); 1174cb14a3feSDimitry Andric detectX86FamilyModel(EAX, &Family, &Model); 1175cb14a3feSDimitry Andric 1176cb14a3feSDimitry Andric // Find available features. 1177cb14a3feSDimitry Andric getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]); 1178cb14a3feSDimitry Andric 1179cb14a3feSDimitry Andric __cpu_model.__cpu_features[0] = Features[0]; 1180cb14a3feSDimitry Andric __cpu_features2[0] = Features[1]; 1181cb14a3feSDimitry Andric __cpu_features2[1] = Features[2]; 1182cb14a3feSDimitry Andric __cpu_features2[2] = Features[3]; 1183cb14a3feSDimitry Andric 1184cb14a3feSDimitry Andric if (Vendor == SIG_INTEL) { 1185cb14a3feSDimitry Andric // Get CPU type. 1186cb14a3feSDimitry Andric getIntelProcessorTypeAndSubtype(Family, Model, &Features[0], 1187cb14a3feSDimitry Andric &(__cpu_model.__cpu_type), 1188cb14a3feSDimitry Andric &(__cpu_model.__cpu_subtype)); 1189cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_INTEL; 1190cb14a3feSDimitry Andric } else if (Vendor == SIG_AMD) { 1191cb14a3feSDimitry Andric // Get CPU type. 1192cb14a3feSDimitry Andric getAMDProcessorTypeAndSubtype(Family, Model, &Features[0], 1193cb14a3feSDimitry Andric &(__cpu_model.__cpu_type), 1194cb14a3feSDimitry Andric &(__cpu_model.__cpu_subtype)); 1195cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_AMD; 1196cb14a3feSDimitry Andric } else 1197cb14a3feSDimitry Andric __cpu_model.__cpu_vendor = VENDOR_OTHER; 1198cb14a3feSDimitry Andric 1199cb14a3feSDimitry Andric assert(__cpu_model.__cpu_vendor < VENDOR_MAX); 1200cb14a3feSDimitry Andric assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); 1201cb14a3feSDimitry Andric assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 1202cb14a3feSDimitry Andric 1203cb14a3feSDimitry Andric return 0; 1204cb14a3feSDimitry Andric } 1205cb14a3feSDimitry Andric #endif // defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) 1206