xref: /llvm-project/compiler-rt/lib/builtins/cpu_model/x86.c (revision a63931292bad148a3498fdb30bbccb43844aee86)
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 
34 enum VendorSignatures {
35   SIG_INTEL = 0x756e6547, // Genu
36   SIG_AMD = 0x68747541,   // Auth
37 };
38 
39 enum ProcessorVendors {
40   VENDOR_INTEL = 1,
41   VENDOR_AMD,
42   VENDOR_OTHER,
43   VENDOR_MAX
44 };
45 
46 enum 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 
70 enum 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 
110 enum 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.
242 static 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(value, rEAX, rEBX, rECX, 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.
263 static 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(value, subleaf, rEAX, rEBX, rECX, 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.
286 static 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 
306 static 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 
321 static 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 
649 static 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 
823 static 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(&EAX, &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(&EAX, &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(0x7, 0x0, &EAX, &EBX, &ECX, &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(0x7, 0x1, &EAX, &EBX, &ECX, &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(0, &MaxLevel, &EBX, &ECX, &EDX);
1035   bool HasLeafD = MaxLevel >= 0xd &&
1036                   !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &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(0x24, &EAX, &EBX, &ECX, &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(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
1063 
1064   bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
1065                      !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &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(0x80000008, &EAX, &EBX, &ECX, &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(0x14, 0x0, &EAX, &EBX, &ECX, &EDX);
1099   if (HasLeaf14 && ((EBX >> 4) & 1))
1100     setFeature(FEATURE_PTWRITE);
1101 
1102   bool HasLeaf19 =
1103       MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &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
1131 int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;
1132 
1133 #ifndef _WIN32
1134 __attribute__((visibility("hidden")))
1135 #endif
1136 struct __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
1146 unsigned __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 
1154 int 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(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
1168     __cpu_model.__cpu_vendor = VENDOR_OTHER;
1169     return -1;
1170   }
1171 
1172   getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
1173   detectX86FamilyModel(EAX, &Family, &Model);
1174 
1175   // Find available features.
1176   getAvailableFeatures(ECX, EDX, MaxLeaf, &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[0],
1186                                     &(__cpu_model.__cpu_type),
1187                                     &(__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[0],
1192                                   &(__cpu_model.__cpu_type),
1193                                   &(__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