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