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