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

source code of compiler-rt/lib/builtins/cpu_model/x86.c