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

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