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.
isCpuIdSupported()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.
getX86CpuIDAndInfo(unsigned value,unsigned * rEAX,unsigned * rEBX,unsigned * rECX,unsigned * rEDX)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.
getX86CpuIDAndInfoEx(unsigned value,unsigned subleaf,unsigned * rEAX,unsigned * rEBX,unsigned * rECX,unsigned * rEDX)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.
getX86XCR0(unsigned * rEAX,unsigned * rEDX)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
detectX86FamilyModel(unsigned EAX,unsigned * Family,unsigned * Model)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
getIntelProcessorTypeAndSubtype(unsigned Family,unsigned Model,unsigned Brand_id,unsigned Features,unsigned * Type,unsigned * Subtype)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
getAMDProcessorTypeAndSubtype(unsigned Family,unsigned Model,unsigned Features,unsigned * Type,unsigned * Subtype)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
getAvailableFeatures(unsigned ECX,unsigned EDX,unsigned MaxLeaf,unsigned * FeaturesOut,unsigned * Features2Out)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
__cpu_indicator_init(void)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
652