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.
isCpuIdSupported(void)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.
getX86CpuIDAndInfo(unsigned value,unsigned * rEAX,unsigned * rEBX,unsigned * rECX,unsigned * rEDX)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.
getX86CpuIDAndInfoEx(unsigned value,unsigned subleaf,unsigned * rEAX,unsigned * rEBX,unsigned * rECX,unsigned * rEDX)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.
getX86XCR0(unsigned * rEAX,unsigned * rEDX)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
detectX86FamilyModel(unsigned EAX,unsigned * Family,unsigned * Model)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
getIntelProcessorTypeAndSubtype(unsigned Family,unsigned Model,const unsigned * Features,unsigned * Type,unsigned * Subtype)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
getAMDProcessorTypeAndSubtype(unsigned Family,unsigned Model,const unsigned * Features,unsigned * Type,unsigned * Subtype)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
getAvailableFeatures(unsigned ECX,unsigned EDX,unsigned MaxLeaf,unsigned * Features)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
__cpu_indicator_init(void)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