]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/cpu_model.c
Update tcsh to 6.21.00.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / cpu_model.c
1 //===-- cpu_model.c - Support for __cpu_model builtin  ------------*- C -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file is based on LLVM's lib/Support/Host.cpp.
11 //  It implements the operating system Host concept and builtin
12 //  __cpu_model for the compiler_rt library, for x86 only.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #if (defined(__i386__) || defined(_M_IX86) || \
17      defined(__x86_64__) || defined(_M_X64)) && \
18     (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER))
19
20 #include <assert.h>
21
22 #define bool int
23 #define true 1
24 #define false 0
25
26 #ifdef _MSC_VER
27 #include <intrin.h>
28 #endif
29
30 #ifndef __has_attribute
31 #define __has_attribute(attr) 0
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   CPU_TYPE_MAX
62 };
63
64 enum ProcessorSubtypes {
65   INTEL_COREI7_NEHALEM = 1,
66   INTEL_COREI7_WESTMERE,
67   INTEL_COREI7_SANDYBRIDGE,
68   AMDFAM10H_BARCELONA,
69   AMDFAM10H_SHANGHAI,
70   AMDFAM10H_ISTANBUL,
71   AMDFAM15H_BDVER1,
72   AMDFAM15H_BDVER2,
73   AMDFAM15H_BDVER3,
74   AMDFAM15H_BDVER4,
75   AMDFAM17H_ZNVER1,
76   INTEL_COREI7_IVYBRIDGE,
77   INTEL_COREI7_HASWELL,
78   INTEL_COREI7_BROADWELL,
79   INTEL_COREI7_SKYLAKE,
80   INTEL_COREI7_SKYLAKE_AVX512,
81   INTEL_COREI7_CANNONLAKE,
82   INTEL_COREI7_ICELAKE_CLIENT,
83   INTEL_COREI7_ICELAKE_SERVER,
84   CPU_SUBTYPE_MAX
85 };
86
87 enum ProcessorFeatures {
88   FEATURE_CMOV = 0,
89   FEATURE_MMX,
90   FEATURE_POPCNT,
91   FEATURE_SSE,
92   FEATURE_SSE2,
93   FEATURE_SSE3,
94   FEATURE_SSSE3,
95   FEATURE_SSE4_1,
96   FEATURE_SSE4_2,
97   FEATURE_AVX,
98   FEATURE_AVX2,
99   FEATURE_SSE4_A,
100   FEATURE_FMA4,
101   FEATURE_XOP,
102   FEATURE_FMA,
103   FEATURE_AVX512F,
104   FEATURE_BMI,
105   FEATURE_BMI2,
106   FEATURE_AES,
107   FEATURE_PCLMUL,
108   FEATURE_AVX512VL,
109   FEATURE_AVX512BW,
110   FEATURE_AVX512DQ,
111   FEATURE_AVX512CD,
112   FEATURE_AVX512ER,
113   FEATURE_AVX512PF,
114   FEATURE_AVX512VBMI,
115   FEATURE_AVX512IFMA,
116   FEATURE_AVX5124VNNIW,
117   FEATURE_AVX5124FMAPS,
118   FEATURE_AVX512VPOPCNTDQ,
119   FEATURE_AVX512VBMI2,
120   FEATURE_GFNI,
121   FEATURE_VPCLMULQDQ,
122   FEATURE_AVX512VNNI,
123   FEATURE_AVX512BITALG
124 };
125
126 // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
127 // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
128 // support. Consequently, for i386, the presence of CPUID is checked first
129 // via the corresponding eflags bit.
130 static bool isCpuIdSupported() {
131 #if defined(__GNUC__) || defined(__clang__)
132 #if defined(__i386__)
133   int __cpuid_supported;
134   __asm__("  pushfl\n"
135           "  popl   %%eax\n"
136           "  movl   %%eax,%%ecx\n"
137           "  xorl   $0x00200000,%%eax\n"
138           "  pushl  %%eax\n"
139           "  popfl\n"
140           "  pushfl\n"
141           "  popl   %%eax\n"
142           "  movl   $0,%0\n"
143           "  cmpl   %%eax,%%ecx\n"
144           "  je     1f\n"
145           "  movl   $1,%0\n"
146           "1:"
147           : "=r"(__cpuid_supported)
148           :
149           : "eax", "ecx");
150   if (!__cpuid_supported)
151     return false;
152 #endif
153   return true;
154 #endif
155   return true;
156 }
157
158 // This code is copied from lib/Support/Host.cpp.
159 // Changes to either file should be mirrored in the other.
160
161 /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
162 /// the specified arguments.  If we can't run cpuid on the host, return true.
163 static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
164                                unsigned *rECX, unsigned *rEDX) {
165 #if defined(__GNUC__) || defined(__clang__)
166 #if defined(__x86_64__)
167   // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
168   // FIXME: should we save this for Clang?
169   __asm__("movq\t%%rbx, %%rsi\n\t"
170           "cpuid\n\t"
171           "xchgq\t%%rbx, %%rsi\n\t"
172           : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
173           : "a"(value));
174   return false;
175 #elif defined(__i386__)
176   __asm__("movl\t%%ebx, %%esi\n\t"
177           "cpuid\n\t"
178           "xchgl\t%%ebx, %%esi\n\t"
179           : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
180           : "a"(value));
181   return false;
182 #else
183   return true;
184 #endif
185 #elif defined(_MSC_VER)
186   // The MSVC intrinsic is portable across x86 and x64.
187   int registers[4];
188   __cpuid(registers, value);
189   *rEAX = registers[0];
190   *rEBX = registers[1];
191   *rECX = registers[2];
192   *rEDX = registers[3];
193   return false;
194 #else
195   return true;
196 #endif
197 }
198
199 /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return
200 /// the 4 values in the specified arguments.  If we can't run cpuid on the host,
201 /// return true.
202 static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
203                                  unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
204                                  unsigned *rEDX) {
205 #if defined(__GNUC__) || defined(__clang__)
206 #if defined(__x86_64__)
207   // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
208   // FIXME: should we save this for Clang?
209   __asm__("movq\t%%rbx, %%rsi\n\t"
210           "cpuid\n\t"
211           "xchgq\t%%rbx, %%rsi\n\t"
212           : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
213           : "a"(value), "c"(subleaf));
214   return false;
215 #elif defined(__i386__)
216   __asm__("movl\t%%ebx, %%esi\n\t"
217           "cpuid\n\t"
218           "xchgl\t%%ebx, %%esi\n\t"
219           : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
220           : "a"(value), "c"(subleaf));
221   return false;
222 #else
223   return true;
224 #endif
225 #elif defined(_MSC_VER)
226   int registers[4];
227   __cpuidex(registers, value, subleaf);
228   *rEAX = registers[0];
229   *rEBX = registers[1];
230   *rECX = registers[2];
231   *rEDX = registers[3];
232   return false;
233 #else
234   return true;
235 #endif
236 }
237
238 // Read control register 0 (XCR0). Used to detect features such as AVX.
239 static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
240 #if defined(__GNUC__) || defined(__clang__)
241   // Check xgetbv; this uses a .byte sequence instead of the instruction
242   // directly because older assemblers do not include support for xgetbv and
243   // there is no easy way to conditionally compile based on the assembler used.
244   __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0));
245   return false;
246 #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
247   unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
248   *rEAX = Result;
249   *rEDX = Result >> 32;
250   return false;
251 #else
252   return true;
253 #endif
254 }
255
256 static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
257                                  unsigned *Model) {
258   *Family = (EAX >> 8) & 0xf; // Bits 8 - 11
259   *Model = (EAX >> 4) & 0xf;  // Bits 4 - 7
260   if (*Family == 6 || *Family == 0xf) {
261     if (*Family == 0xf)
262       // Examine extended family ID if family ID is F.
263       *Family += (EAX >> 20) & 0xff; // Bits 20 - 27
264     // Examine extended model ID if family ID is 6 or F.
265     *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19
266   }
267 }
268
269 static void
270 getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
271                                 unsigned Brand_id, unsigned Features,
272                                 unsigned *Type, unsigned *Subtype) {
273   if (Brand_id != 0)
274     return;
275   switch (Family) {
276   case 6:
277     switch (Model) {
278     case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
279                // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
280                // mobile processor, Intel Core 2 Extreme processor, Intel
281                // Pentium Dual-Core processor, Intel Xeon processor, model
282                // 0Fh. All processors are manufactured using the 65 nm process.
283     case 0x16: // Intel Celeron processor model 16h. All processors are
284                // manufactured using the 65 nm process
285     case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
286                // 17h. All processors are manufactured using the 45 nm process.
287                //
288                // 45nm: Penryn , Wolfdale, Yorkfield (XE)
289     case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
290                // the 45 nm process.
291       *Type = INTEL_CORE2; // "penryn"
292       break;
293     case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
294                // processors are manufactured using the 45 nm process.
295     case 0x1e: // Intel(R) Core(TM) i7 CPU         870  @ 2.93GHz.
296                // As found in a Summer 2010 model iMac.
297     case 0x1f:
298     case 0x2e:             // Nehalem EX
299       *Type = INTEL_COREI7; // "nehalem"
300       *Subtype = INTEL_COREI7_NEHALEM;
301       break;
302     case 0x25: // Intel Core i7, laptop version.
303     case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
304                // processors are manufactured using the 32 nm process.
305     case 0x2f: // Westmere EX
306       *Type = INTEL_COREI7; // "westmere"
307       *Subtype = INTEL_COREI7_WESTMERE;
308       break;
309     case 0x2a: // Intel Core i7 processor. All processors are manufactured
310                // using the 32 nm process.
311     case 0x2d:
312       *Type = INTEL_COREI7; //"sandybridge"
313       *Subtype = INTEL_COREI7_SANDYBRIDGE;
314       break;
315     case 0x3a:
316     case 0x3e:             // Ivy Bridge EP
317       *Type = INTEL_COREI7; // "ivybridge"
318       *Subtype = INTEL_COREI7_IVYBRIDGE;
319       break;
320
321     // Haswell:
322     case 0x3c:
323     case 0x3f:
324     case 0x45:
325     case 0x46:
326       *Type = INTEL_COREI7; // "haswell"
327       *Subtype = INTEL_COREI7_HASWELL;
328       break;
329
330     // Broadwell:
331     case 0x3d:
332     case 0x47:
333     case 0x4f:
334     case 0x56:
335       *Type = INTEL_COREI7; // "broadwell"
336       *Subtype = INTEL_COREI7_BROADWELL;
337       break;
338
339     // Skylake:
340     case 0x4e: // Skylake mobile
341     case 0x5e: // Skylake desktop
342     case 0x8e: // Kaby Lake mobile
343     case 0x9e: // Kaby Lake desktop
344       *Type = INTEL_COREI7; // "skylake"
345       *Subtype = INTEL_COREI7_SKYLAKE;
346       break;
347
348     // Skylake Xeon:
349     case 0x55:
350       *Type = INTEL_COREI7;
351       *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512"
352       break;
353
354     // Cannonlake:
355     case 0x66:
356       *Type = INTEL_COREI7;
357       *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake"
358       break;
359
360     case 0x1c: // Most 45 nm Intel Atom processors
361     case 0x26: // 45 nm Atom Lincroft
362     case 0x27: // 32 nm Atom Medfield
363     case 0x35: // 32 nm Atom Midview
364     case 0x36: // 32 nm Atom Midview
365       *Type = INTEL_BONNELL;
366       break; // "bonnell"
367
368     // Atom Silvermont codes from the Intel software optimization guide.
369     case 0x37:
370     case 0x4a:
371     case 0x4d:
372     case 0x5a:
373     case 0x5d:
374     case 0x4c: // really airmont
375       *Type = INTEL_SILVERMONT;
376       break; // "silvermont"
377     // Goldmont:
378     case 0x5c: // Apollo Lake
379     case 0x5f: // Denverton
380       *Type = INTEL_GOLDMONT;
381       break; // "goldmont"
382     case 0x7a:
383       *Type = INTEL_GOLDMONT_PLUS;
384       break;
385
386     case 0x57:
387       *Type = INTEL_KNL; // knl
388       break;
389
390     case 0x85:
391       *Type = INTEL_KNM; // knm
392       break;
393
394     default: // Unknown family 6 CPU.
395       break;
396     break;
397     }
398   default:
399     break; // Unknown.
400   }
401 }
402
403 static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
404                                           unsigned Features, unsigned *Type,
405                                           unsigned *Subtype) {
406   // FIXME: this poorly matches the generated SubtargetFeatureKV table.  There
407   // appears to be no way to generate the wide variety of AMD-specific targets
408   // from the information returned from CPUID.
409   switch (Family) {
410   case 16:
411     *Type = AMDFAM10H; // "amdfam10"
412     switch (Model) {
413     case 2:
414       *Subtype = AMDFAM10H_BARCELONA;
415       break;
416     case 4:
417       *Subtype = AMDFAM10H_SHANGHAI;
418       break;
419     case 8:
420       *Subtype = AMDFAM10H_ISTANBUL;
421       break;
422     }
423     break;
424   case 20:
425     *Type = AMD_BTVER1;
426     break; // "btver1";
427   case 21:
428     *Type = AMDFAM15H;
429     if (Model >= 0x60 && Model <= 0x7f) {
430       *Subtype = AMDFAM15H_BDVER4;
431       break; // "bdver4"; 60h-7Fh: Excavator
432     }
433     if (Model >= 0x30 && Model <= 0x3f) {
434       *Subtype = AMDFAM15H_BDVER3;
435       break; // "bdver3"; 30h-3Fh: Steamroller
436     }
437     if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {
438       *Subtype = AMDFAM15H_BDVER2;
439       break; // "bdver2"; 02h, 10h-1Fh: Piledriver
440     }
441     if (Model <= 0x0f) {
442       *Subtype = AMDFAM15H_BDVER1;
443       break; // "bdver1"; 00h-0Fh: Bulldozer
444     }
445     break;
446   case 22:
447     *Type = AMD_BTVER2;
448     break; // "btver2"
449   case 23:
450     *Type = AMDFAM17H;
451     *Subtype = AMDFAM17H_ZNVER1;
452     break;
453   default:
454     break; // "generic"
455   }
456 }
457
458 static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
459                                  unsigned *FeaturesOut,
460                                  unsigned *Features2Out) {
461   unsigned Features = 0;
462   unsigned Features2 = 0;
463   unsigned EAX, EBX;
464
465 #define setFeature(F)                       \
466   do {                                      \
467     if (F < 32)                             \
468       Features |= 1U << (F & 0x1f);         \
469     else if (F < 64)                        \
470       Features2 |= 1U << ((F - 32) & 0x1f); \
471   } while (0)
472
473   if ((EDX >> 15) & 1)
474     setFeature(FEATURE_CMOV);
475   if ((EDX >> 23) & 1)
476     setFeature(FEATURE_MMX);
477   if ((EDX >> 25) & 1)
478     setFeature(FEATURE_SSE);
479   if ((EDX >> 26) & 1)
480     setFeature(FEATURE_SSE2);
481
482   if ((ECX >> 0) & 1)
483     setFeature(FEATURE_SSE3);
484   if ((ECX >> 1) & 1)
485     setFeature(FEATURE_PCLMUL);
486   if ((ECX >> 9) & 1)
487     setFeature(FEATURE_SSSE3);
488   if ((ECX >> 12) & 1)
489     setFeature(FEATURE_FMA);
490   if ((ECX >> 19) & 1)
491     setFeature(FEATURE_SSE4_1);
492   if ((ECX >> 20) & 1)
493     setFeature(FEATURE_SSE4_2);
494   if ((ECX >> 23) & 1)
495     setFeature(FEATURE_POPCNT);
496   if ((ECX >> 25) & 1)
497     setFeature(FEATURE_AES);
498
499   // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
500   // indicates that the AVX registers will be saved and restored on context
501   // switch, then we have full AVX support.
502   const unsigned AVXBits = (1 << 27) | (1 << 28);
503   bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&
504                 ((EAX & 0x6) == 0x6);
505   bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
506
507   if (HasAVX)
508     setFeature(FEATURE_AVX);
509
510   bool HasLeaf7 =
511       MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
512
513   if (HasLeaf7 && ((EBX >> 3) & 1))
514     setFeature(FEATURE_BMI);
515   if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
516     setFeature(FEATURE_AVX2);
517   if (HasLeaf7 && ((EBX >> 9) & 1))
518     setFeature(FEATURE_BMI2);
519   if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
520     setFeature(FEATURE_AVX512F);
521   if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
522     setFeature(FEATURE_AVX512DQ);
523   if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
524     setFeature(FEATURE_AVX512IFMA);
525   if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
526     setFeature(FEATURE_AVX512PF);
527   if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
528     setFeature(FEATURE_AVX512ER);
529   if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
530     setFeature(FEATURE_AVX512CD);
531   if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
532     setFeature(FEATURE_AVX512BW);
533   if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
534     setFeature(FEATURE_AVX512VL);
535
536   if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
537     setFeature(FEATURE_AVX512VBMI);
538   if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)
539     setFeature(FEATURE_AVX512VBMI2);
540   if (HasLeaf7 && ((ECX >> 8) & 1))
541     setFeature(FEATURE_GFNI);
542   if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX)
543     setFeature(FEATURE_VPCLMULQDQ);
544   if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)
545     setFeature(FEATURE_AVX512VNNI);
546   if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)
547     setFeature(FEATURE_AVX512BITALG);
548   if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
549     setFeature(FEATURE_AVX512VPOPCNTDQ);
550
551   if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
552     setFeature(FEATURE_AVX5124VNNIW);
553   if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
554     setFeature(FEATURE_AVX5124FMAPS);
555
556   unsigned MaxExtLevel;
557   getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
558
559   bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
560                      !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
561   if (HasExtLeaf1 && ((ECX >> 6) & 1))
562     setFeature(FEATURE_SSE4_A);
563   if (HasExtLeaf1 && ((ECX >> 11) & 1))
564     setFeature(FEATURE_XOP);
565   if (HasExtLeaf1 && ((ECX >> 16) & 1))
566     setFeature(FEATURE_FMA4);
567
568   *FeaturesOut = Features;
569   *Features2Out = Features2;
570 #undef setFeature
571 }
572
573 #if defined(HAVE_INIT_PRIORITY)
574 #define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))
575 #elif __has_attribute(__constructor__)
576 #define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))
577 #else
578 // FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
579 // this runs during initialization.
580 #define CONSTRUCTOR_ATTRIBUTE
581 #endif
582
583 int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;
584
585 struct __processor_model {
586   unsigned int __cpu_vendor;
587   unsigned int __cpu_type;
588   unsigned int __cpu_subtype;
589   unsigned int __cpu_features[1];
590 } __cpu_model = {0, 0, 0, {0}};
591 unsigned int __cpu_features2;
592
593 /* A constructor function that is sets __cpu_model and __cpu_features2 with
594    the right values.  This needs to run only once.  This constructor is
595    given the highest priority and it should run before constructors without
596    the priority set.  However, it still runs after ifunc initializers and
597    needs to be called explicitly there.  */
598
599 int CONSTRUCTOR_ATTRIBUTE
600 __cpu_indicator_init(void) {
601   unsigned EAX, EBX, ECX, EDX;
602   unsigned MaxLeaf = 5;
603   unsigned Vendor;
604   unsigned Model, Family, Brand_id;
605   unsigned Features = 0;
606   unsigned Features2 = 0;
607
608   /* This function needs to run just once.  */
609   if (__cpu_model.__cpu_vendor)
610     return 0;
611
612   if (!isCpuIdSupported())
613     return -1;
614
615   /* Assume cpuid insn present. Run in level 0 to get vendor id. */
616   if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
617     __cpu_model.__cpu_vendor = VENDOR_OTHER;
618     return -1;
619   }
620   getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
621   detectX86FamilyModel(EAX, &Family, &Model);
622   Brand_id = EBX & 0xff;
623
624   /* Find available features. */
625   getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2);
626   __cpu_model.__cpu_features[0] = Features;
627   __cpu_features2 = Features2;
628
629   if (Vendor == SIG_INTEL) {
630     /* Get CPU type.  */
631     getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features,
632                                     &(__cpu_model.__cpu_type),
633                                     &(__cpu_model.__cpu_subtype));
634     __cpu_model.__cpu_vendor = VENDOR_INTEL;
635   } else if (Vendor == SIG_AMD) {
636     /* Get CPU type.  */
637     getAMDProcessorTypeAndSubtype(Family, Model, Features,
638                                   &(__cpu_model.__cpu_type),
639                                   &(__cpu_model.__cpu_subtype));
640     __cpu_model.__cpu_vendor = VENDOR_AMD;
641   } else
642     __cpu_model.__cpu_vendor = VENDOR_OTHER;
643
644   assert(__cpu_model.__cpu_vendor < VENDOR_MAX);
645   assert(__cpu_model.__cpu_type < CPU_TYPE_MAX);
646   assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
647
648   return 0;
649 }
650
651 #endif