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 |
|
|
enum VendorSignatures { |
31 |
|
|
SIG_INTEL = 0x756e6547 /* Genu */, |
32 |
|
|
SIG_AMD = 0x68747541 /* Auth */ |
33 |
|
|
}; |
34 |
|
|
|
35 |
|
|
enum ProcessorVendors { |
36 |
|
|
VENDOR_INTEL = 1, |
37 |
|
|
VENDOR_AMD, |
38 |
|
|
VENDOR_OTHER, |
39 |
|
|
VENDOR_MAX |
40 |
|
|
}; |
41 |
|
|
|
42 |
|
|
enum ProcessorTypes { |
43 |
|
|
INTEL_ATOM = 1, |
44 |
|
|
INTEL_CORE2, |
45 |
|
|
INTEL_COREI7, |
46 |
|
|
AMDFAM10H, |
47 |
|
|
AMDFAM15H, |
48 |
|
|
INTEL_i386, |
49 |
|
|
INTEL_i486, |
50 |
|
|
INTEL_PENTIUM, |
51 |
|
|
INTEL_PENTIUM_PRO, |
52 |
|
|
INTEL_PENTIUM_II, |
53 |
|
|
INTEL_PENTIUM_III, |
54 |
|
|
INTEL_PENTIUM_IV, |
55 |
|
|
INTEL_PENTIUM_M, |
56 |
|
|
INTEL_CORE_DUO, |
57 |
|
|
INTEL_XEONPHI, |
58 |
|
|
INTEL_X86_64, |
59 |
|
|
INTEL_NOCONA, |
60 |
|
|
INTEL_PRESCOTT, |
61 |
|
|
AMD_i486, |
62 |
|
|
AMDPENTIUM, |
63 |
|
|
AMDATHLON, |
64 |
|
|
AMDFAM14H, |
65 |
|
|
AMDFAM16H, |
66 |
|
|
CPU_TYPE_MAX |
67 |
|
|
}; |
68 |
|
|
|
69 |
|
|
enum ProcessorSubtypes { |
70 |
|
|
INTEL_COREI7_NEHALEM = 1, |
71 |
|
|
INTEL_COREI7_WESTMERE, |
72 |
|
|
INTEL_COREI7_SANDYBRIDGE, |
73 |
|
|
AMDFAM10H_BARCELONA, |
74 |
|
|
AMDFAM10H_SHANGHAI, |
75 |
|
|
AMDFAM10H_ISTANBUL, |
76 |
|
|
AMDFAM15H_BDVER1, |
77 |
|
|
AMDFAM15H_BDVER2, |
78 |
|
|
INTEL_PENTIUM_MMX, |
79 |
|
|
INTEL_CORE2_65, |
80 |
|
|
INTEL_CORE2_45, |
81 |
|
|
INTEL_COREI7_IVYBRIDGE, |
82 |
|
|
INTEL_COREI7_HASWELL, |
83 |
|
|
INTEL_COREI7_BROADWELL, |
84 |
|
|
INTEL_COREI7_SKYLAKE, |
85 |
|
|
INTEL_COREI7_SKYLAKE_AVX512, |
86 |
|
|
INTEL_ATOM_BONNELL, |
87 |
|
|
INTEL_ATOM_SILVERMONT, |
88 |
|
|
INTEL_KNIGHTS_LANDING, |
89 |
|
|
AMDPENTIUM_K6, |
90 |
|
|
AMDPENTIUM_K62, |
91 |
|
|
AMDPENTIUM_K63, |
92 |
|
|
AMDPENTIUM_GEODE, |
93 |
|
|
AMDATHLON_TBIRD, |
94 |
|
|
AMDATHLON_MP, |
95 |
|
|
AMDATHLON_XP, |
96 |
|
|
AMDATHLON_K8SSE3, |
97 |
|
|
AMDATHLON_OPTERON, |
98 |
|
|
AMDATHLON_FX, |
99 |
|
|
AMDATHLON_64, |
100 |
|
|
AMD_BTVER1, |
101 |
|
|
AMD_BTVER2, |
102 |
|
|
AMDFAM15H_BDVER3, |
103 |
|
|
AMDFAM15H_BDVER4, |
104 |
|
|
CPU_SUBTYPE_MAX |
105 |
|
|
}; |
106 |
|
|
|
107 |
|
|
enum ProcessorFeatures { |
108 |
|
|
FEATURE_CMOV = 0, |
109 |
|
|
FEATURE_MMX, |
110 |
|
|
FEATURE_POPCNT, |
111 |
|
|
FEATURE_SSE, |
112 |
|
|
FEATURE_SSE2, |
113 |
|
|
FEATURE_SSE3, |
114 |
|
|
FEATURE_SSSE3, |
115 |
|
|
FEATURE_SSE4_1, |
116 |
|
|
FEATURE_SSE4_2, |
117 |
|
|
FEATURE_AVX, |
118 |
|
|
FEATURE_AVX2, |
119 |
|
|
FEATURE_AVX512, |
120 |
|
|
FEATURE_AVX512SAVE, |
121 |
|
|
FEATURE_MOVBE, |
122 |
|
|
FEATURE_ADX, |
123 |
|
|
FEATURE_EM64T |
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 void 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. Preseve it manually. |
168 |
|
|
__asm__("movq\t%%rbx, %%rsi\n\t" |
169 |
|
|
"cpuid\n\t" |
170 |
|
|
"xchgq\t%%rbx, %%rsi\n\t" |
171 |
|
|
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) |
172 |
|
|
: "a"(value)); |
173 |
|
|
#elif defined(__i386__) |
174 |
|
|
__asm__("movl\t%%ebx, %%esi\n\t" |
175 |
|
|
"cpuid\n\t" |
176 |
|
|
"xchgl\t%%ebx, %%esi\n\t" |
177 |
|
|
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) |
178 |
|
|
: "a"(value)); |
179 |
|
|
// pedantic #else returns to appease -Wunreachable-code (so we don't generate |
180 |
|
|
// postprocessed code that looks like "return true; return false;") |
181 |
|
|
#else |
182 |
|
|
assert(0 && "This method is defined only for x86."); |
183 |
|
|
#endif |
184 |
|
|
#elif defined(_MSC_VER) |
185 |
|
|
// The MSVC intrinsic is portable across x86 and x64. |
186 |
|
|
int registers[4]; |
187 |
|
|
__cpuid(registers, value); |
188 |
|
|
*rEAX = registers[0]; |
189 |
|
|
*rEBX = registers[1]; |
190 |
|
|
*rECX = registers[2]; |
191 |
|
|
*rEDX = registers[3]; |
192 |
|
|
#else |
193 |
|
|
assert(0 && "This method is defined only for GNUC, Clang or MSVC."); |
194 |
|
|
#endif |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return |
198 |
|
|
/// the 4 values in the specified arguments. If we can't run cpuid on the host, |
199 |
|
|
/// return true. |
200 |
|
|
static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, |
201 |
|
|
unsigned *rEAX, unsigned *rEBX, unsigned *rECX, |
202 |
|
|
unsigned *rEDX) { |
203 |
|
|
#if defined(__x86_64__) || defined(_M_X64) |
204 |
|
|
#if defined(__GNUC__) || defined(__clang__) |
205 |
|
|
// gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. |
206 |
|
|
// FIXME: should we save this for Clang? |
207 |
|
|
__asm__("movq\t%%rbx, %%rsi\n\t" |
208 |
|
|
"cpuid\n\t" |
209 |
|
|
"xchgq\t%%rbx, %%rsi\n\t" |
210 |
|
|
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) |
211 |
|
|
: "a"(value), "c"(subleaf)); |
212 |
|
|
#elif defined(_MSC_VER) |
213 |
|
|
int registers[4]; |
214 |
|
|
__cpuidex(registers, value, subleaf); |
215 |
|
|
*rEAX = registers[0]; |
216 |
|
|
*rEBX = registers[1]; |
217 |
|
|
*rECX = registers[2]; |
218 |
|
|
*rEDX = registers[3]; |
219 |
|
|
#else |
220 |
|
|
assert(0 && "This method is defined only for GNUC, Clang or MSVC."); |
221 |
|
|
#endif |
222 |
|
|
#elif defined(__i386__) || defined(_M_IX86) |
223 |
|
|
#if defined(__GNUC__) || defined(__clang__) |
224 |
|
|
__asm__("movl\t%%ebx, %%esi\n\t" |
225 |
|
|
"cpuid\n\t" |
226 |
|
|
"xchgl\t%%ebx, %%esi\n\t" |
227 |
|
|
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) |
228 |
|
|
: "a"(value), "c"(subleaf)); |
229 |
|
|
#elif defined(_MSC_VER) |
230 |
|
|
__asm { |
231 |
|
|
mov eax,value |
232 |
|
|
mov ecx,subleaf |
233 |
|
|
cpuid |
234 |
|
|
mov esi,rEAX |
235 |
|
|
mov dword ptr [esi],eax |
236 |
|
|
mov esi,rEBX |
237 |
|
|
mov dword ptr [esi],ebx |
238 |
|
|
mov esi,rECX |
239 |
|
|
mov dword ptr [esi],ecx |
240 |
|
|
mov esi,rEDX |
241 |
|
|
mov dword ptr [esi],edx |
242 |
|
|
} |
243 |
|
|
#else |
244 |
|
|
assert(0 && "This method is defined only for GNUC, Clang or MSVC."); |
245 |
|
|
#endif |
246 |
|
|
#else |
247 |
|
|
assert(0 && "This method is defined only for x86."); |
248 |
|
|
#endif |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
// Read control register 0 (XCR0). Used to detect features such as AVX. |
252 |
|
|
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { |
253 |
|
|
#if defined(__GNUC__) || defined(__clang__) |
254 |
|
|
// Check xgetbv; this uses a .byte sequence instead of the instruction |
255 |
|
|
// directly because older assemblers do not include support for xgetbv and |
256 |
|
|
// there is no easy way to conditionally compile based on the assembler used. |
257 |
|
|
__asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); |
258 |
|
|
return false; |
259 |
|
|
#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) |
260 |
|
|
unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); |
261 |
|
|
*rEAX = Result; |
262 |
|
|
*rEDX = Result >> 32; |
263 |
|
|
return false; |
264 |
|
|
#else |
265 |
|
|
return true; |
266 |
|
|
#endif |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
static void detectX86FamilyModel(unsigned EAX, unsigned *Family, |
270 |
|
|
unsigned *Model) { |
271 |
|
|
*Family = (EAX >> 8) & 0xf; // Bits 8 - 11 |
272 |
|
|
*Model = (EAX >> 4) & 0xf; // Bits 4 - 7 |
273 |
|
|
if (*Family == 6 || *Family == 0xf) { |
274 |
|
|
if (*Family == 0xf) |
275 |
|
|
// Examine extended family ID if family ID is F. |
276 |
|
|
*Family += (EAX >> 20) & 0xff; // Bits 20 - 27 |
277 |
|
|
// Examine extended model ID if family ID is 6 or F. |
278 |
|
|
*Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 |
279 |
|
|
} |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
static void getIntelProcessorTypeAndSubtype(unsigned int Family, |
283 |
|
|
unsigned int Model, |
284 |
|
|
unsigned int Brand_id, |
285 |
|
|
unsigned int Features, |
286 |
|
|
unsigned *Type, unsigned *Subtype) { |
287 |
|
|
if (Brand_id != 0) |
288 |
|
|
return; |
289 |
|
|
switch (Family) { |
290 |
|
|
case 3: |
291 |
|
|
*Type = INTEL_i386; |
292 |
|
|
break; |
293 |
|
|
case 4: |
294 |
|
|
switch (Model) { |
295 |
|
|
case 0: // Intel486 DX processors |
296 |
|
|
case 1: // Intel486 DX processors |
297 |
|
|
case 2: // Intel486 SX processors |
298 |
|
|
case 3: // Intel487 processors, IntelDX2 OverDrive processors, |
299 |
|
|
// IntelDX2 processors |
300 |
|
|
case 4: // Intel486 SL processor |
301 |
|
|
case 5: // IntelSX2 processors |
302 |
|
|
case 7: // Write-Back Enhanced IntelDX2 processors |
303 |
|
|
case 8: // IntelDX4 OverDrive processors, IntelDX4 processors |
304 |
|
|
default: |
305 |
|
|
*Type = INTEL_i486; |
306 |
|
|
break; |
307 |
|
|
} |
308 |
|
|
case 5: |
309 |
|
|
switch (Model) { |
310 |
|
|
case 1: // Pentium OverDrive processor for Pentium processor (60, 66), |
311 |
|
|
// Pentium processors (60, 66) |
312 |
|
|
case 2: // Pentium OverDrive processor for Pentium processor (75, 90, |
313 |
|
|
// 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, |
314 |
|
|
// 150, 166, 200) |
315 |
|
|
case 3: // Pentium OverDrive processors for Intel486 processor-based |
316 |
|
|
// systems |
317 |
|
|
*Type = INTEL_PENTIUM; |
318 |
|
|
break; |
319 |
|
|
case 4: // Pentium OverDrive processor with MMX technology for Pentium |
320 |
|
|
// processor (75, 90, 100, 120, 133), Pentium processor with |
321 |
|
|
// MMX technology (166, 200) |
322 |
|
|
*Type = INTEL_PENTIUM; |
323 |
|
|
*Subtype = INTEL_PENTIUM_MMX; |
324 |
|
|
break; |
325 |
|
|
default: |
326 |
|
|
*Type = INTEL_PENTIUM; |
327 |
|
|
break; |
328 |
|
|
} |
329 |
|
|
case 6: |
330 |
|
|
switch (Model) { |
331 |
|
|
case 0x01: // Pentium Pro processor |
332 |
|
|
*Type = INTEL_PENTIUM_PRO; |
333 |
|
|
break; |
334 |
|
|
case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, |
335 |
|
|
// model 03 |
336 |
|
|
case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, |
337 |
|
|
// model 05, and Intel Celeron processor, model 05 |
338 |
|
|
case 0x06: // Celeron processor, model 06 |
339 |
|
|
*Type = INTEL_PENTIUM_II; |
340 |
|
|
break; |
341 |
|
|
case 0x07: // Pentium III processor, model 07, and Pentium III Xeon |
342 |
|
|
// processor, model 07 |
343 |
|
|
case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, |
344 |
|
|
// model 08, and Celeron processor, model 08 |
345 |
|
|
case 0x0a: // Pentium III Xeon processor, model 0Ah |
346 |
|
|
case 0x0b: // Pentium III processor, model 0Bh |
347 |
|
|
*Type = INTEL_PENTIUM_III; |
348 |
|
|
break; |
349 |
|
|
case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. |
350 |
|
|
case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model |
351 |
|
|
// 0Dh. All processors are manufactured using the 90 nm process. |
352 |
|
|
case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 |
353 |
|
|
// Integrated Processor with Intel QuickAssist Technology |
354 |
|
|
*Type = INTEL_PENTIUM_M; |
355 |
|
|
break; |
356 |
|
|
case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model |
357 |
|
|
// 0Eh. All processors are manufactured using the 65 nm process. |
358 |
|
|
*Type = INTEL_CORE_DUO; |
359 |
|
|
break; // yonah |
360 |
|
|
case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile |
361 |
|
|
// processor, Intel Core 2 Quad processor, Intel Core 2 Quad |
362 |
|
|
// mobile processor, Intel Core 2 Extreme processor, Intel |
363 |
|
|
// Pentium Dual-Core processor, Intel Xeon processor, model |
364 |
|
|
// 0Fh. All processors are manufactured using the 65 nm process. |
365 |
|
|
case 0x16: // Intel Celeron processor model 16h. All processors are |
366 |
|
|
// manufactured using the 65 nm process |
367 |
|
|
*Type = INTEL_CORE2; // "core2" |
368 |
|
|
*Subtype = INTEL_CORE2_65; |
369 |
|
|
break; |
370 |
|
|
case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model |
371 |
|
|
// 17h. All processors are manufactured using the 45 nm process. |
372 |
|
|
// |
373 |
|
|
// 45nm: Penryn , Wolfdale, Yorkfield (XE) |
374 |
|
|
case 0x1d: // Intel Xeon processor MP. All processors are manufactured using |
375 |
|
|
// the 45 nm process. |
376 |
|
|
*Type = INTEL_CORE2; // "penryn" |
377 |
|
|
*Subtype = INTEL_CORE2_45; |
378 |
|
|
break; |
379 |
|
|
case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All |
380 |
|
|
// processors are manufactured using the 45 nm process. |
381 |
|
|
case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. |
382 |
|
|
// As found in a Summer 2010 model iMac. |
383 |
|
|
case 0x1f: |
384 |
|
|
case 0x2e: // Nehalem EX |
385 |
|
|
*Type = INTEL_COREI7; // "nehalem" |
386 |
|
|
*Subtype = INTEL_COREI7_NEHALEM; |
387 |
|
|
break; |
388 |
|
|
case 0x25: // Intel Core i7, laptop version. |
389 |
|
|
case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All |
390 |
|
|
// processors are manufactured using the 32 nm process. |
391 |
|
|
case 0x2f: // Westmere EX |
392 |
|
|
*Type = INTEL_COREI7; // "westmere" |
393 |
|
|
*Subtype = INTEL_COREI7_WESTMERE; |
394 |
|
|
break; |
395 |
|
|
case 0x2a: // Intel Core i7 processor. All processors are manufactured |
396 |
|
|
// using the 32 nm process. |
397 |
|
|
case 0x2d: |
398 |
|
|
*Type = INTEL_COREI7; //"sandybridge" |
399 |
|
|
*Subtype = INTEL_COREI7_SANDYBRIDGE; |
400 |
|
|
break; |
401 |
|
|
case 0x3a: |
402 |
|
|
case 0x3e: // Ivy Bridge EP |
403 |
|
|
*Type = INTEL_COREI7; // "ivybridge" |
404 |
|
|
*Subtype = INTEL_COREI7_IVYBRIDGE; |
405 |
|
|
break; |
406 |
|
|
|
407 |
|
|
// Haswell: |
408 |
|
|
case 0x3c: |
409 |
|
|
case 0x3f: |
410 |
|
|
case 0x45: |
411 |
|
|
case 0x46: |
412 |
|
|
*Type = INTEL_COREI7; // "haswell" |
413 |
|
|
*Subtype = INTEL_COREI7_HASWELL; |
414 |
|
|
break; |
415 |
|
|
|
416 |
|
|
// Broadwell: |
417 |
|
|
case 0x3d: |
418 |
|
|
case 0x47: |
419 |
|
|
case 0x4f: |
420 |
|
|
case 0x56: |
421 |
|
|
*Type = INTEL_COREI7; // "broadwell" |
422 |
|
|
*Subtype = INTEL_COREI7_BROADWELL; |
423 |
|
|
break; |
424 |
|
|
|
425 |
|
|
// Skylake: |
426 |
|
|
case 0x4e: |
427 |
|
|
*Type = INTEL_COREI7; // "skylake-avx512" |
428 |
|
|
*Subtype = INTEL_COREI7_SKYLAKE_AVX512; |
429 |
|
|
break; |
430 |
|
|
case 0x5e: |
431 |
|
|
*Type = INTEL_COREI7; // "skylake" |
432 |
|
|
*Subtype = INTEL_COREI7_SKYLAKE; |
433 |
|
|
break; |
434 |
|
|
|
435 |
|
|
case 0x1c: // Most 45 nm Intel Atom processors |
436 |
|
|
case 0x26: // 45 nm Atom Lincroft |
437 |
|
|
case 0x27: // 32 nm Atom Medfield |
438 |
|
|
case 0x35: // 32 nm Atom Midview |
439 |
|
|
case 0x36: // 32 nm Atom Midview |
440 |
|
|
*Type = INTEL_ATOM; |
441 |
|
|
*Subtype = INTEL_ATOM_BONNELL; |
442 |
|
|
break; // "bonnell" |
443 |
|
|
|
444 |
|
|
// Atom Silvermont codes from the Intel software optimization guide. |
445 |
|
|
case 0x37: |
446 |
|
|
case 0x4a: |
447 |
|
|
case 0x4d: |
448 |
|
|
case 0x5a: |
449 |
|
|
case 0x5d: |
450 |
|
|
case 0x4c: // really airmont |
451 |
|
|
*Type = INTEL_ATOM; |
452 |
|
|
*Subtype = INTEL_ATOM_SILVERMONT; |
453 |
|
|
break; // "silvermont" |
454 |
|
|
|
455 |
|
|
case 0x57: |
456 |
|
|
*Type = INTEL_XEONPHI; // knl |
457 |
|
|
*Subtype = INTEL_KNIGHTS_LANDING; |
458 |
|
|
break; |
459 |
|
|
|
460 |
|
|
default: // Unknown family 6 CPU, try to guess. |
461 |
|
|
if (Features & (1 << FEATURE_AVX512)) { |
462 |
|
|
*Type = INTEL_XEONPHI; // knl |
463 |
|
|
*Subtype = INTEL_KNIGHTS_LANDING; |
464 |
|
|
break; |
465 |
|
|
} |
466 |
|
|
if (Features & (1 << FEATURE_ADX)) { |
467 |
|
|
*Type = INTEL_COREI7; |
468 |
|
|
*Subtype = INTEL_COREI7_BROADWELL; |
469 |
|
|
break; |
470 |
|
|
} |
471 |
|
|
if (Features & (1 << FEATURE_AVX2)) { |
472 |
|
|
*Type = INTEL_COREI7; |
473 |
|
|
*Subtype = INTEL_COREI7_HASWELL; |
474 |
|
|
break; |
475 |
|
|
} |
476 |
|
|
if (Features & (1 << FEATURE_AVX)) { |
477 |
|
|
*Type = INTEL_COREI7; |
478 |
|
|
*Subtype = INTEL_COREI7_SANDYBRIDGE; |
479 |
|
|
break; |
480 |
|
|
} |
481 |
|
|
if (Features & (1 << FEATURE_SSE4_2)) { |
482 |
|
|
if (Features & (1 << FEATURE_MOVBE)) { |
483 |
|
|
*Type = INTEL_ATOM; |
484 |
|
|
*Subtype = INTEL_ATOM_SILVERMONT; |
485 |
|
|
} else { |
486 |
|
|
*Type = INTEL_COREI7; |
487 |
|
|
*Subtype = INTEL_COREI7_NEHALEM; |
488 |
|
|
} |
489 |
|
|
break; |
490 |
|
|
} |
491 |
|
|
if (Features & (1 << FEATURE_SSE4_1)) { |
492 |
|
|
*Type = INTEL_CORE2; // "penryn" |
493 |
|
|
*Subtype = INTEL_CORE2_45; |
494 |
|
|
break; |
495 |
|
|
} |
496 |
|
|
if (Features & (1 << FEATURE_SSSE3)) { |
497 |
|
|
if (Features & (1 << FEATURE_MOVBE)) { |
498 |
|
|
*Type = INTEL_ATOM; |
499 |
|
|
*Subtype = INTEL_ATOM_BONNELL; // "bonnell" |
500 |
|
|
} else { |
501 |
|
|
*Type = INTEL_CORE2; // "core2" |
502 |
|
|
*Subtype = INTEL_CORE2_65; |
503 |
|
|
} |
504 |
|
|
break; |
505 |
|
|
} |
506 |
|
|
if (Features & (1 << FEATURE_EM64T)) { |
507 |
|
|
*Type = INTEL_X86_64; |
508 |
|
|
break; // x86-64 |
509 |
|
|
} |
510 |
|
|
if (Features & (1 << FEATURE_SSE2)) { |
511 |
|
|
*Type = INTEL_PENTIUM_M; |
512 |
|
|
break; |
513 |
|
|
} |
514 |
|
|
if (Features & (1 << FEATURE_SSE)) { |
515 |
|
|
*Type = INTEL_PENTIUM_III; |
516 |
|
|
break; |
517 |
|
|
} |
518 |
|
|
if (Features & (1 << FEATURE_MMX)) { |
519 |
|
|
*Type = INTEL_PENTIUM_II; |
520 |
|
|
break; |
521 |
|
|
} |
522 |
|
|
*Type = INTEL_PENTIUM_PRO; |
523 |
|
|
break; |
524 |
|
|
} |
525 |
|
|
case 15: { |
526 |
|
|
switch (Model) { |
527 |
|
|
case 0: // Pentium 4 processor, Intel Xeon processor. All processors are |
528 |
|
|
// model 00h and manufactured using the 0.18 micron process. |
529 |
|
|
case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon |
530 |
|
|
// processor MP, and Intel Celeron processor. All processors are |
531 |
|
|
// model 01h and manufactured using the 0.18 micron process. |
532 |
|
|
case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, |
533 |
|
|
// Intel Xeon processor, Intel Xeon processor MP, Intel Celeron |
534 |
|
|
// processor, and Mobile Intel Celeron processor. All processors |
535 |
|
|
// are model 02h and manufactured using the 0.13 micron process. |
536 |
|
|
*Type = |
537 |
|
|
((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); |
538 |
|
|
break; |
539 |
|
|
|
540 |
|
|
case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D |
541 |
|
|
// processor. All processors are model 03h and manufactured using |
542 |
|
|
// the 90 nm process. |
543 |
|
|
case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, |
544 |
|
|
// Pentium D processor, Intel Xeon processor, Intel Xeon |
545 |
|
|
// processor MP, Intel Celeron D processor. All processors are |
546 |
|
|
// model 04h and manufactured using the 90 nm process. |
547 |
|
|
case 6: // Pentium 4 processor, Pentium D processor, Pentium processor |
548 |
|
|
// Extreme Edition, Intel Xeon processor, Intel Xeon processor |
549 |
|
|
// MP, Intel Celeron D processor. All processors are model 06h |
550 |
|
|
// and manufactured using the 65 nm process. |
551 |
|
|
*Type = |
552 |
|
|
((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); |
553 |
|
|
break; |
554 |
|
|
|
555 |
|
|
default: |
556 |
|
|
*Type = |
557 |
|
|
((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); |
558 |
|
|
break; |
559 |
|
|
} |
560 |
|
|
} |
561 |
|
|
default: |
562 |
|
|
break; /*"generic"*/ |
563 |
|
|
} |
564 |
|
|
} |
565 |
|
|
|
566 |
|
|
static void getAMDProcessorTypeAndSubtype(unsigned int Family, |
567 |
|
|
unsigned int Model, |
568 |
|
|
unsigned int Features, unsigned *Type, |
569 |
|
|
unsigned *Subtype) { |
570 |
|
|
// FIXME: this poorly matches the generated SubtargetFeatureKV table. There |
571 |
|
|
// appears to be no way to generate the wide variety of AMD-specific targets |
572 |
|
|
// from the information returned from CPUID. |
573 |
|
|
switch (Family) { |
574 |
|
|
case 4: |
575 |
|
|
*Type = AMD_i486; |
576 |
|
|
case 5: |
577 |
|
|
*Type = AMDPENTIUM; |
578 |
|
|
switch (Model) { |
579 |
|
|
case 6: |
580 |
|
|
case 7: |
581 |
|
|
*Subtype = AMDPENTIUM_K6; |
582 |
|
|
break; // "k6" |
583 |
|
|
case 8: |
584 |
|
|
*Subtype = AMDPENTIUM_K62; |
585 |
|
|
break; // "k6-2" |
586 |
|
|
case 9: |
587 |
|
|
case 13: |
588 |
|
|
*Subtype = AMDPENTIUM_K63; |
589 |
|
|
break; // "k6-3" |
590 |
|
|
case 10: |
591 |
|
|
*Subtype = AMDPENTIUM_GEODE; |
592 |
|
|
break; // "geode" |
593 |
|
|
default: |
594 |
|
|
break; |
595 |
|
|
} |
596 |
|
|
case 6: |
597 |
|
|
*Type = AMDATHLON; |
598 |
|
|
switch (Model) { |
599 |
|
|
case 4: |
600 |
|
|
*Subtype = AMDATHLON_TBIRD; |
601 |
|
|
break; // "athlon-tbird" |
602 |
|
|
case 6: |
603 |
|
|
case 7: |
604 |
|
|
case 8: |
605 |
|
|
*Subtype = AMDATHLON_MP; |
606 |
|
|
break; // "athlon-mp" |
607 |
|
|
case 10: |
608 |
|
|
*Subtype = AMDATHLON_XP; |
609 |
|
|
break; // "athlon-xp" |
610 |
|
|
default: |
611 |
|
|
break; |
612 |
|
|
} |
613 |
|
|
case 15: |
614 |
|
|
*Type = AMDATHLON; |
615 |
|
|
if (Features & (1 << FEATURE_SSE3)) { |
616 |
|
|
*Subtype = AMDATHLON_K8SSE3; |
617 |
|
|
break; // "k8-sse3" |
618 |
|
|
} |
619 |
|
|
switch (Model) { |
620 |
|
|
case 1: |
621 |
|
|
*Subtype = AMDATHLON_OPTERON; |
622 |
|
|
break; // "opteron" |
623 |
|
|
case 5: |
624 |
|
|
*Subtype = AMDATHLON_FX; |
625 |
|
|
break; // "athlon-fx"; also opteron |
626 |
|
|
default: |
627 |
|
|
*Subtype = AMDATHLON_64; |
628 |
|
|
break; // "athlon64" |
629 |
|
|
} |
630 |
|
|
case 16: |
631 |
|
|
*Type = AMDFAM10H; // "amdfam10" |
632 |
|
|
switch (Model) { |
633 |
|
|
case 2: |
634 |
|
|
*Subtype = AMDFAM10H_BARCELONA; |
635 |
|
|
break; |
636 |
|
|
case 4: |
637 |
|
|
*Subtype = AMDFAM10H_SHANGHAI; |
638 |
|
|
break; |
639 |
|
|
case 8: |
640 |
|
|
*Subtype = AMDFAM10H_ISTANBUL; |
641 |
|
|
break; |
642 |
|
|
default: |
643 |
|
|
break; |
644 |
|
|
} |
645 |
|
|
case 20: |
646 |
|
|
*Type = AMDFAM14H; |
647 |
|
|
*Subtype = AMD_BTVER1; |
648 |
|
|
break; // "btver1"; |
649 |
|
|
case 21: |
650 |
|
|
*Type = AMDFAM15H; |
651 |
|
|
if (!(Features & |
652 |
|
|
(1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. |
653 |
|
|
*Subtype = AMD_BTVER1; |
654 |
|
|
break; // "btver1" |
655 |
|
|
} |
656 |
|
|
if (Model >= 0x50 && Model <= 0x6f) { |
657 |
|
|
*Subtype = AMDFAM15H_BDVER4; |
658 |
|
|
break; // "bdver4"; 50h-6Fh: Excavator |
659 |
|
|
} |
660 |
|
|
if (Model >= 0x30 && Model <= 0x3f) { |
661 |
|
|
*Subtype = AMDFAM15H_BDVER3; |
662 |
|
|
break; // "bdver3"; 30h-3Fh: Steamroller |
663 |
|
|
} |
664 |
|
|
if (Model >= 0x10 && Model <= 0x1f) { |
665 |
|
|
*Subtype = AMDFAM15H_BDVER2; |
666 |
|
|
break; // "bdver2"; 10h-1Fh: Piledriver |
667 |
|
|
} |
668 |
|
|
if (Model <= 0x0f) { |
669 |
|
|
*Subtype = AMDFAM15H_BDVER1; |
670 |
|
|
break; // "bdver1"; 00h-0Fh: Bulldozer |
671 |
|
|
} |
672 |
|
|
break; |
673 |
|
|
case 22: |
674 |
|
|
*Type = AMDFAM16H; |
675 |
|
|
if (!(Features & |
676 |
|
|
(1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. |
677 |
|
|
*Subtype = AMD_BTVER1; |
678 |
|
|
break; // "btver1"; |
679 |
|
|
} |
680 |
|
|
*Subtype = AMD_BTVER2; |
681 |
|
|
break; // "btver2" |
682 |
|
|
default: |
683 |
|
|
break; // "generic" |
684 |
|
|
} |
685 |
|
|
} |
686 |
|
|
|
687 |
|
|
static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, |
688 |
|
|
unsigned MaxLeaf) { |
689 |
|
|
unsigned Features = 0; |
690 |
|
|
unsigned int EAX, EBX; |
691 |
|
|
Features |= (((EDX >> 23) & 1) << FEATURE_MMX); |
692 |
|
|
Features |= (((EDX >> 25) & 1) << FEATURE_SSE); |
693 |
|
|
Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); |
694 |
|
|
Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); |
695 |
|
|
Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); |
696 |
|
|
Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); |
697 |
|
|
Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); |
698 |
|
|
Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); |
699 |
|
|
|
700 |
|
|
// If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV |
701 |
|
|
// indicates that the AVX registers will be saved and restored on context |
702 |
|
|
// switch, then we have full AVX support. |
703 |
|
|
const unsigned AVXBits = (1 << 27) | (1 << 28); |
704 |
|
|
bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && |
705 |
|
|
((EAX & 0x6) == 0x6); |
706 |
|
|
bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); |
707 |
|
|
bool HasLeaf7 = MaxLeaf >= 0x7; |
708 |
|
|
getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); |
709 |
|
|
bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); |
710 |
|
|
bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); |
711 |
|
|
bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); |
712 |
|
|
Features |= (HasAVX << FEATURE_AVX); |
713 |
|
|
Features |= (HasAVX2 << FEATURE_AVX2); |
714 |
|
|
Features |= (HasAVX512 << FEATURE_AVX512); |
715 |
|
|
Features |= (HasAVX512Save << FEATURE_AVX512SAVE); |
716 |
|
|
Features |= (HasADX << FEATURE_ADX); |
717 |
|
|
|
718 |
|
|
getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); |
719 |
|
|
Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); |
720 |
|
|
return Features; |
721 |
|
|
} |
722 |
|
|
|
723 |
|
|
#ifdef HAVE_INIT_PRIORITY |
724 |
|
|
#define CONSTRUCTOR_PRIORITY (101) |
725 |
|
|
#else |
726 |
|
|
#define CONSTRUCTOR_PRIORITY |
727 |
|
|
#endif |
728 |
|
|
|
729 |
|
|
int __cpu_indicator_init(void) |
730 |
|
|
__attribute__((constructor CONSTRUCTOR_PRIORITY)); |
731 |
|
|
|
732 |
|
|
struct __processor_model { |
733 |
|
|
unsigned int __cpu_vendor; |
734 |
|
|
unsigned int __cpu_type; |
735 |
|
|
unsigned int __cpu_subtype; |
736 |
|
|
unsigned int __cpu_features[1]; |
737 |
|
|
} __cpu_model = {0, 0, 0, {0}}; |
738 |
|
|
|
739 |
|
|
/* A constructor function that is sets __cpu_model and __cpu_features with |
740 |
|
|
the right values. This needs to run only once. This constructor is |
741 |
|
|
given the highest priority and it should run before constructors without |
742 |
|
|
the priority set. However, it still runs after ifunc initializers and |
743 |
|
|
needs to be called explicitly there. */ |
744 |
|
|
|
745 |
|
|
int __attribute__((constructor CONSTRUCTOR_PRIORITY)) |
746 |
|
|
__cpu_indicator_init(void) { |
747 |
|
|
unsigned int EAX, EBX, ECX, EDX; |
748 |
|
|
unsigned int MaxLeaf = 5; |
749 |
|
|
unsigned int Vendor; |
750 |
|
|
unsigned int Model, Family, Brand_id; |
751 |
|
|
unsigned int Features = 0; |
752 |
|
|
|
753 |
|
|
/* This function needs to run just once. */ |
754 |
|
|
if (__cpu_model.__cpu_vendor) |
755 |
|
|
return 0; |
756 |
|
|
|
757 |
|
|
if (!isCpuIdSupported()) |
758 |
|
|
return -1; |
759 |
|
|
|
760 |
|
|
/* Assume cpuid insn present. Run in level 0 to get vendor id. */ |
761 |
|
|
getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX); |
762 |
|
|
|
763 |
|
|
if (MaxLeaf < 1) { |
764 |
|
|
__cpu_model.__cpu_vendor = VENDOR_OTHER; |
765 |
|
|
return -1; |
766 |
|
|
} |
767 |
|
|
getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); |
768 |
|
|
detectX86FamilyModel(EAX, &Family, &Model); |
769 |
|
|
Brand_id = EBX & 0xff; |
770 |
|
|
|
771 |
|
|
/* Find available features. */ |
772 |
|
|
Features = getAvailableFeatures(ECX, EDX, MaxLeaf); |
773 |
|
|
__cpu_model.__cpu_features[0] = Features; |
774 |
|
|
|
775 |
|
|
if (Vendor == SIG_INTEL) { |
776 |
|
|
/* Get CPU type. */ |
777 |
|
|
getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, |
778 |
|
|
&(__cpu_model.__cpu_type), |
779 |
|
|
&(__cpu_model.__cpu_subtype)); |
780 |
|
|
__cpu_model.__cpu_vendor = VENDOR_INTEL; |
781 |
|
|
} else if (Vendor == SIG_AMD) { |
782 |
|
|
/* Get CPU type. */ |
783 |
|
|
getAMDProcessorTypeAndSubtype(Family, Model, Features, |
784 |
|
|
&(__cpu_model.__cpu_type), |
785 |
|
|
&(__cpu_model.__cpu_subtype)); |
786 |
|
|
__cpu_model.__cpu_vendor = VENDOR_AMD; |
787 |
|
|
} else |
788 |
|
|
__cpu_model.__cpu_vendor = VENDOR_OTHER; |
789 |
|
|
|
790 |
|
|
assert(__cpu_model.__cpu_vendor < VENDOR_MAX); |
791 |
|
|
assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); |
792 |
|
|
assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); |
793 |
|
|
|
794 |
|
|
return 0; |
795 |
|
|
} |
796 |
|
|
|
797 |
|
|
#endif |