blob: 2fd39e15a7c52c0a0f2609fcf28a2ef0668db073 [file] [log] [blame]
Alina Sbirlea36f57fb2016-07-14 22:02:35 +00001//===-- 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
Reid Kleckner3ae87c42017-04-07 16:54:32 +000030#ifndef __has_attribute
31#define __has_attribute(attr) 0
32#endif
33
Alina Sbirlea36f57fb2016-07-14 22:02:35 +000034enum 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 {
Craig Toppere6b07072017-07-13 02:56:24 +000047 INTEL_BONNELL = 1,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +000048 INTEL_CORE2,
49 INTEL_COREI7,
50 AMDFAM10H,
51 AMDFAM15H,
Craig Toppere6b07072017-07-13 02:56:24 +000052 INTEL_SILVERMONT,
53 INTEL_KNL,
54 AMD_BTVER1,
55 AMD_BTVER2,
Craig Topper61d84502017-07-10 17:30:20 +000056 AMDFAM17H,
Craig Topper705b9692017-10-11 20:35:43 +000057 INTEL_KNM,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +000058 CPU_TYPE_MAX
59};
60
61enum ProcessorSubtypes {
62 INTEL_COREI7_NEHALEM = 1,
63 INTEL_COREI7_WESTMERE,
64 INTEL_COREI7_SANDYBRIDGE,
65 AMDFAM10H_BARCELONA,
66 AMDFAM10H_SHANGHAI,
67 AMDFAM10H_ISTANBUL,
68 AMDFAM15H_BDVER1,
69 AMDFAM15H_BDVER2,
Craig Toppere6b07072017-07-13 02:56:24 +000070 AMDFAM15H_BDVER3,
71 AMDFAM15H_BDVER4,
72 AMDFAM17H_ZNVER1,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +000073 INTEL_COREI7_IVYBRIDGE,
74 INTEL_COREI7_HASWELL,
75 INTEL_COREI7_BROADWELL,
76 INTEL_COREI7_SKYLAKE,
77 INTEL_COREI7_SKYLAKE_AVX512,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +000078 CPU_SUBTYPE_MAX
79};
80
81enum ProcessorFeatures {
82 FEATURE_CMOV = 0,
83 FEATURE_MMX,
84 FEATURE_POPCNT,
85 FEATURE_SSE,
86 FEATURE_SSE2,
87 FEATURE_SSE3,
88 FEATURE_SSSE3,
89 FEATURE_SSE4_1,
90 FEATURE_SSE4_2,
91 FEATURE_AVX,
92 FEATURE_AVX2,
Craig Toppere6b07072017-07-13 02:56:24 +000093 FEATURE_SSE4_A,
94 FEATURE_FMA4,
95 FEATURE_XOP,
96 FEATURE_FMA,
97 FEATURE_AVX512F,
98 FEATURE_BMI,
99 FEATURE_BMI2,
100 FEATURE_AES,
101 FEATURE_PCLMUL,
102 FEATURE_AVX512VL,
103 FEATURE_AVX512BW,
104 FEATURE_AVX512DQ,
105 FEATURE_AVX512CD,
106 FEATURE_AVX512ER,
107 FEATURE_AVX512PF,
108 FEATURE_AVX512VBMI,
109 FEATURE_AVX512IFMA,
110 FEATURE_AVX5124VNNIW,
111 FEATURE_AVX5124FMAPS,
112 FEATURE_AVX512VPOPCNTDQ
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000113};
114
115// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
116// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
117// support. Consequently, for i386, the presence of CPUID is checked first
118// via the corresponding eflags bit.
119static bool isCpuIdSupported() {
120#if defined(__GNUC__) || defined(__clang__)
121#if defined(__i386__)
122 int __cpuid_supported;
Alina Sbirlea9b476732016-07-17 23:45:55 +0000123 __asm__(" pushfl\n"
124 " popl %%eax\n"
125 " movl %%eax,%%ecx\n"
126 " xorl $0x00200000,%%eax\n"
127 " pushl %%eax\n"
128 " popfl\n"
129 " pushfl\n"
130 " popl %%eax\n"
131 " movl $0,%0\n"
132 " cmpl %%eax,%%ecx\n"
133 " je 1f\n"
134 " movl $1,%0\n"
135 "1:"
136 : "=r"(__cpuid_supported)
137 :
138 : "eax", "ecx");
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000139 if (!__cpuid_supported)
140 return false;
141#endif
142 return true;
143#endif
144 return true;
145}
146
147// This code is copied from lib/Support/Host.cpp.
148// Changes to either file should be mirrored in the other.
149
150/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
151/// the specified arguments. If we can't run cpuid on the host, return true.
Craig Topper61d84502017-07-10 17:30:20 +0000152static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000153 unsigned *rECX, unsigned *rEDX) {
154#if defined(__GNUC__) || defined(__clang__)
155#if defined(__x86_64__)
Craig Topper61d84502017-07-10 17:30:20 +0000156 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
Craig Topper76ac8132017-07-10 17:47:23 +0000157 // FIXME: should we save this for Clang?
Alina Sbirlea9b476732016-07-17 23:45:55 +0000158 __asm__("movq\t%%rbx, %%rsi\n\t"
159 "cpuid\n\t"
160 "xchgq\t%%rbx, %%rsi\n\t"
161 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
162 : "a"(value));
Craig Topper76ac8132017-07-10 17:47:23 +0000163 return false;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000164#elif defined(__i386__)
Alina Sbirlea9b476732016-07-17 23:45:55 +0000165 __asm__("movl\t%%ebx, %%esi\n\t"
166 "cpuid\n\t"
167 "xchgl\t%%ebx, %%esi\n\t"
168 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
169 : "a"(value));
Craig Topper76ac8132017-07-10 17:47:23 +0000170 return false;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000171#else
Craig Topper76ac8132017-07-10 17:47:23 +0000172 return true;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000173#endif
174#elif defined(_MSC_VER)
175 // The MSVC intrinsic is portable across x86 and x64.
176 int registers[4];
177 __cpuid(registers, value);
178 *rEAX = registers[0];
179 *rEBX = registers[1];
180 *rECX = registers[2];
181 *rEDX = registers[3];
Craig Topper61d84502017-07-10 17:30:20 +0000182 return false;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000183#else
Craig Topper61d84502017-07-10 17:30:20 +0000184 return true;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000185#endif
186}
187
188/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return
189/// the 4 values in the specified arguments. If we can't run cpuid on the host,
190/// return true.
Craig Topper61d84502017-07-10 17:30:20 +0000191static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000192 unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
193 unsigned *rEDX) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000194#if defined(__GNUC__) || defined(__clang__)
Craig Topperb7727902017-07-19 05:11:20 +0000195#if defined(__x86_64__)
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000196 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
197 // FIXME: should we save this for Clang?
Alina Sbirlea9b476732016-07-17 23:45:55 +0000198 __asm__("movq\t%%rbx, %%rsi\n\t"
199 "cpuid\n\t"
200 "xchgq\t%%rbx, %%rsi\n\t"
201 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
202 : "a"(value), "c"(subleaf));
Craig Topper76ac8132017-07-10 17:47:23 +0000203 return false;
Craig Topperb7727902017-07-19 05:11:20 +0000204#elif defined(__i386__)
205 __asm__("movl\t%%ebx, %%esi\n\t"
206 "cpuid\n\t"
207 "xchgl\t%%ebx, %%esi\n\t"
208 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
209 : "a"(value), "c"(subleaf));
210 return false;
211#else
212 return true;
213#endif
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000214#elif defined(_MSC_VER)
215 int registers[4];
216 __cpuidex(registers, value, subleaf);
217 *rEAX = registers[0];
218 *rEBX = registers[1];
219 *rECX = registers[2];
220 *rEDX = registers[3];
Craig Topper76ac8132017-07-10 17:47:23 +0000221 return false;
222#else
223 return true;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000224#endif
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000225}
226
227// Read control register 0 (XCR0). Used to detect features such as AVX.
228static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
229#if defined(__GNUC__) || defined(__clang__)
230 // Check xgetbv; this uses a .byte sequence instead of the instruction
231 // directly because older assemblers do not include support for xgetbv and
232 // there is no easy way to conditionally compile based on the assembler used.
233 __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0));
234 return false;
235#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
236 unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
237 *rEAX = Result;
238 *rEDX = Result >> 32;
239 return false;
240#else
241 return true;
242#endif
243}
244
245static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
246 unsigned *Model) {
247 *Family = (EAX >> 8) & 0xf; // Bits 8 - 11
248 *Model = (EAX >> 4) & 0xf; // Bits 4 - 7
249 if (*Family == 6 || *Family == 0xf) {
250 if (*Family == 0xf)
251 // Examine extended family ID if family ID is F.
252 *Family += (EAX >> 20) & 0xff; // Bits 20 - 27
253 // Examine extended model ID if family ID is 6 or F.
254 *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19
255 }
256}
257
Craig Topper76ac8132017-07-10 17:47:23 +0000258static void
259getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
260 unsigned Brand_id, unsigned Features,
261 unsigned *Type, unsigned *Subtype) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000262 if (Brand_id != 0)
263 return;
264 switch (Family) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000265 case 6:
266 switch (Model) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000267 case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
268 // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
269 // mobile processor, Intel Core 2 Extreme processor, Intel
270 // Pentium Dual-Core processor, Intel Xeon processor, model
271 // 0Fh. All processors are manufactured using the 65 nm process.
272 case 0x16: // Intel Celeron processor model 16h. All processors are
273 // manufactured using the 65 nm process
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000274 case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
275 // 17h. All processors are manufactured using the 45 nm process.
276 //
277 // 45nm: Penryn , Wolfdale, Yorkfield (XE)
278 case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
279 // the 45 nm process.
280 *Type = INTEL_CORE2; // "penryn"
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000281 break;
282 case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
283 // processors are manufactured using the 45 nm process.
284 case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz.
285 // As found in a Summer 2010 model iMac.
286 case 0x1f:
Craig Topper76ac8132017-07-10 17:47:23 +0000287 case 0x2e: // Nehalem EX
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000288 *Type = INTEL_COREI7; // "nehalem"
289 *Subtype = INTEL_COREI7_NEHALEM;
290 break;
291 case 0x25: // Intel Core i7, laptop version.
292 case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
293 // processors are manufactured using the 32 nm process.
294 case 0x2f: // Westmere EX
295 *Type = INTEL_COREI7; // "westmere"
296 *Subtype = INTEL_COREI7_WESTMERE;
297 break;
298 case 0x2a: // Intel Core i7 processor. All processors are manufactured
299 // using the 32 nm process.
300 case 0x2d:
301 *Type = INTEL_COREI7; //"sandybridge"
302 *Subtype = INTEL_COREI7_SANDYBRIDGE;
303 break;
304 case 0x3a:
Craig Topper76ac8132017-07-10 17:47:23 +0000305 case 0x3e: // Ivy Bridge EP
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000306 *Type = INTEL_COREI7; // "ivybridge"
307 *Subtype = INTEL_COREI7_IVYBRIDGE;
308 break;
309
310 // Haswell:
311 case 0x3c:
312 case 0x3f:
313 case 0x45:
314 case 0x46:
315 *Type = INTEL_COREI7; // "haswell"
316 *Subtype = INTEL_COREI7_HASWELL;
317 break;
318
319 // Broadwell:
320 case 0x3d:
321 case 0x47:
322 case 0x4f:
323 case 0x56:
324 *Type = INTEL_COREI7; // "broadwell"
325 *Subtype = INTEL_COREI7_BROADWELL;
326 break;
327
328 // Skylake:
Craig Topper61d84502017-07-10 17:30:20 +0000329 case 0x4e: // Skylake mobile
330 case 0x5e: // Skylake desktop
331 case 0x8e: // Kaby Lake mobile
332 case 0x9e: // Kaby Lake desktop
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000333 *Type = INTEL_COREI7; // "skylake"
334 *Subtype = INTEL_COREI7_SKYLAKE;
335 break;
336
Craig Topper61d84502017-07-10 17:30:20 +0000337 // Skylake Xeon:
338 case 0x55:
Craig Topper76ac8132017-07-10 17:47:23 +0000339 *Type = INTEL_COREI7;
Craig Topper61d84502017-07-10 17:30:20 +0000340 *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512"
341 break;
342
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000343 case 0x1c: // Most 45 nm Intel Atom processors
344 case 0x26: // 45 nm Atom Lincroft
345 case 0x27: // 32 nm Atom Medfield
346 case 0x35: // 32 nm Atom Midview
347 case 0x36: // 32 nm Atom Midview
Craig Toppere6b07072017-07-13 02:56:24 +0000348 *Type = INTEL_BONNELL;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000349 break; // "bonnell"
350
351 // Atom Silvermont codes from the Intel software optimization guide.
352 case 0x37:
353 case 0x4a:
354 case 0x4d:
355 case 0x5a:
356 case 0x5d:
357 case 0x4c: // really airmont
Craig Toppere6b07072017-07-13 02:56:24 +0000358 *Type = INTEL_SILVERMONT;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000359 break; // "silvermont"
360
361 case 0x57:
Craig Toppere6b07072017-07-13 02:56:24 +0000362 *Type = INTEL_KNL; // knl
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000363 break;
364
Craig Topper705b9692017-10-11 20:35:43 +0000365 case 0x85:
366 *Type = INTEL_KNM; // knm
367 break;
368
Craig Toppere6b07072017-07-13 02:56:24 +0000369 default: // Unknown family 6 CPU.
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000370 break;
Craig Topper76ac8132017-07-10 17:47:23 +0000371 break;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000372 }
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000373 default:
Craig Toppere6b07072017-07-13 02:56:24 +0000374 break; // Unknown.
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000375 }
376}
377
Craig Topper61d84502017-07-10 17:30:20 +0000378static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
379 unsigned Features, unsigned *Type,
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000380 unsigned *Subtype) {
381 // FIXME: this poorly matches the generated SubtargetFeatureKV table. There
382 // appears to be no way to generate the wide variety of AMD-specific targets
383 // from the information returned from CPUID.
384 switch (Family) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000385 case 16:
386 *Type = AMDFAM10H; // "amdfam10"
387 switch (Model) {
388 case 2:
389 *Subtype = AMDFAM10H_BARCELONA;
390 break;
391 case 4:
392 *Subtype = AMDFAM10H_SHANGHAI;
393 break;
394 case 8:
395 *Subtype = AMDFAM10H_ISTANBUL;
396 break;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000397 }
Craig Topper76ac8132017-07-10 17:47:23 +0000398 break;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000399 case 20:
Craig Toppere6b07072017-07-13 02:56:24 +0000400 *Type = AMD_BTVER1;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000401 break; // "btver1";
402 case 21:
403 *Type = AMDFAM15H;
Craig Topper76ac8132017-07-10 17:47:23 +0000404 if (Model >= 0x60 && Model <= 0x7f) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000405 *Subtype = AMDFAM15H_BDVER4;
Craig Toppere6b07072017-07-13 02:56:24 +0000406 break; // "bdver4"; 60h-7Fh: Excavator
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000407 }
408 if (Model >= 0x30 && Model <= 0x3f) {
409 *Subtype = AMDFAM15H_BDVER3;
410 break; // "bdver3"; 30h-3Fh: Steamroller
411 }
412 if (Model >= 0x10 && Model <= 0x1f) {
413 *Subtype = AMDFAM15H_BDVER2;
414 break; // "bdver2"; 10h-1Fh: Piledriver
415 }
416 if (Model <= 0x0f) {
417 *Subtype = AMDFAM15H_BDVER1;
418 break; // "bdver1"; 00h-0Fh: Bulldozer
419 }
420 break;
421 case 22:
Craig Topper76ac8132017-07-10 17:47:23 +0000422 *Type = AMD_BTVER2;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000423 break; // "btver2"
Craig Topper61d84502017-07-10 17:30:20 +0000424 case 23:
425 *Type = AMDFAM17H;
Craig Topper76ac8132017-07-10 17:47:23 +0000426 *Subtype = AMDFAM17H_ZNVER1;
Craig Topper61d84502017-07-10 17:30:20 +0000427 break;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000428 default:
429 break; // "generic"
430 }
431}
432
Craig Toppere6b07072017-07-13 02:56:24 +0000433static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
434 unsigned *FeaturesOut) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000435 unsigned Features = 0;
Craig Topper61d84502017-07-10 17:30:20 +0000436 unsigned EAX, EBX;
Craig Toppere6b07072017-07-13 02:56:24 +0000437
438 if ((EDX >> 15) & 1)
439 Features |= 1 << FEATURE_CMOV;
440 if ((EDX >> 23) & 1)
441 Features |= 1 << FEATURE_MMX;
442 if ((EDX >> 25) & 1)
443 Features |= 1 << FEATURE_SSE;
444 if ((EDX >> 26) & 1)
445 Features |= 1 << FEATURE_SSE2;
446
447 if ((ECX >> 0) & 1)
448 Features |= 1 << FEATURE_SSE3;
449 if ((ECX >> 1) & 1)
450 Features |= 1 << FEATURE_PCLMUL;
451 if ((ECX >> 9) & 1)
452 Features |= 1 << FEATURE_SSSE3;
453 if ((ECX >> 12) & 1)
454 Features |= 1 << FEATURE_FMA;
455 if ((ECX >> 19) & 1)
456 Features |= 1 << FEATURE_SSE4_1;
457 if ((ECX >> 20) & 1)
458 Features |= 1 << FEATURE_SSE4_2;
459 if ((ECX >> 23) & 1)
460 Features |= 1 << FEATURE_POPCNT;
461 if ((ECX >> 25) & 1)
462 Features |= 1 << FEATURE_AES;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000463
464 // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
465 // indicates that the AVX registers will be saved and restored on context
466 // switch, then we have full AVX support.
467 const unsigned AVXBits = (1 << 27) | (1 << 28);
468 bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&
469 ((EAX & 0x6) == 0x6);
470 bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
Craig Toppere6b07072017-07-13 02:56:24 +0000471
472 if (HasAVX)
473 Features |= 1 << FEATURE_AVX;
474
Craig Topper76ac8132017-07-10 17:47:23 +0000475 bool HasLeaf7 =
476 MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
Craig Toppere6b07072017-07-13 02:56:24 +0000477
478 if (HasLeaf7 && ((EBX >> 3) & 1))
479 Features |= 1 << FEATURE_BMI;
480 if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
481 Features |= 1 << FEATURE_AVX2;
482 if (HasLeaf7 && ((EBX >> 9) & 1))
483 Features |= 1 << FEATURE_BMI2;
484 if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
485 Features |= 1 << FEATURE_AVX512F;
486 if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
487 Features |= 1 << FEATURE_AVX512DQ;
488 if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
489 Features |= 1 << FEATURE_AVX512IFMA;
490 if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
491 Features |= 1 << FEATURE_AVX512PF;
492 if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
493 Features |= 1 << FEATURE_AVX512ER;
494 if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
495 Features |= 1 << FEATURE_AVX512CD;
496 if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
497 Features |= 1 << FEATURE_AVX512BW;
498 if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
499 Features |= 1 << FEATURE_AVX512VL;
500
501 if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
502 Features |= 1 << FEATURE_AVX512VBMI;
503 if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
504 Features |= 1 << FEATURE_AVX512VPOPCNTDQ;
505
506 if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
507 Features |= 1 << FEATURE_AVX5124VNNIW;
508 if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
509 Features |= 1 << FEATURE_AVX5124FMAPS;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000510
Craig Topper61d84502017-07-10 17:30:20 +0000511 unsigned MaxExtLevel;
512 getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
513
514 bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
515 !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
Craig Toppere6b07072017-07-13 02:56:24 +0000516 if (HasExtLeaf1 && ((ECX >> 6) & 1))
517 Features |= 1 << FEATURE_SSE4_A;
518 if (HasExtLeaf1 && ((ECX >> 11) & 1))
519 Features |= 1 << FEATURE_XOP;
520 if (HasExtLeaf1 && ((ECX >> 16) & 1))
521 Features |= 1 << FEATURE_FMA4;
Craig Topper61d84502017-07-10 17:30:20 +0000522
Craig Toppere6b07072017-07-13 02:56:24 +0000523 *FeaturesOut = Features;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000524}
525
Reid Kleckner3ae87c42017-04-07 16:54:32 +0000526#if defined(HAVE_INIT_PRIORITY)
527#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))
528#elif __has_attribute(__constructor__)
529#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000530#else
Reid Kleckner3ae87c42017-04-07 16:54:32 +0000531// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
532// this runs during initialization.
533#define CONSTRUCTOR_ATTRIBUTE
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000534#endif
535
Reid Kleckner3ae87c42017-04-07 16:54:32 +0000536int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000537
538struct __processor_model {
539 unsigned int __cpu_vendor;
540 unsigned int __cpu_type;
541 unsigned int __cpu_subtype;
542 unsigned int __cpu_features[1];
543} __cpu_model = {0, 0, 0, {0}};
544
545/* A constructor function that is sets __cpu_model and __cpu_features with
546 the right values. This needs to run only once. This constructor is
547 given the highest priority and it should run before constructors without
548 the priority set. However, it still runs after ifunc initializers and
549 needs to be called explicitly there. */
550
Reid Kleckner3ae87c42017-04-07 16:54:32 +0000551int CONSTRUCTOR_ATTRIBUTE
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000552__cpu_indicator_init(void) {
Craig Topper61d84502017-07-10 17:30:20 +0000553 unsigned EAX, EBX, ECX, EDX;
554 unsigned MaxLeaf = 5;
555 unsigned Vendor;
556 unsigned Model, Family, Brand_id;
557 unsigned Features = 0;
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000558
559 /* This function needs to run just once. */
560 if (__cpu_model.__cpu_vendor)
561 return 0;
562
563 if (!isCpuIdSupported())
564 return -1;
565
566 /* Assume cpuid insn present. Run in level 0 to get vendor id. */
Craig Topper61d84502017-07-10 17:30:20 +0000567 if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000568 __cpu_model.__cpu_vendor = VENDOR_OTHER;
569 return -1;
570 }
571 getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
572 detectX86FamilyModel(EAX, &Family, &Model);
573 Brand_id = EBX & 0xff;
574
575 /* Find available features. */
Craig Toppere6b07072017-07-13 02:56:24 +0000576 getAvailableFeatures(ECX, EDX, MaxLeaf, &Features);
Alina Sbirlea36f57fb2016-07-14 22:02:35 +0000577 __cpu_model.__cpu_features[0] = Features;
578
579 if (Vendor == SIG_INTEL) {
580 /* Get CPU type. */
581 getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features,
582 &(__cpu_model.__cpu_type),
583 &(__cpu_model.__cpu_subtype));
584 __cpu_model.__cpu_vendor = VENDOR_INTEL;
585 } else if (Vendor == SIG_AMD) {
586 /* Get CPU type. */
587 getAMDProcessorTypeAndSubtype(Family, Model, Features,
588 &(__cpu_model.__cpu_type),
589 &(__cpu_model.__cpu_subtype));
590 __cpu_model.__cpu_vendor = VENDOR_AMD;
591 } else
592 __cpu_model.__cpu_vendor = VENDOR_OTHER;
593
594 assert(__cpu_model.__cpu_vendor < VENDOR_MAX);
595 assert(__cpu_model.__cpu_type < CPU_TYPE_MAX);
596 assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
597
598 return 0;
599}
600
601#endif