1 /* Get CPU type and Features for x86 processors.
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 Contributed by Sriraman Tallam (tmsriram@google.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
28 #include "auto-target.h"
31 #ifdef HAVE_INIT_PRIORITY
32 #define CONSTRUCTOR_PRIORITY (101)
34 #define CONSTRUCTOR_PRIORITY
37 int __cpu_indicator_init (void)
38 __attribute__ ((constructor CONSTRUCTOR_PRIORITY
));
41 struct __processor_model __cpu_model
= { };
43 /* We want to move away from __cpu_model in libgcc_s.so.1 and the
44 size of __cpu_model is part of ABI. So, new features that don't
45 fit into __cpu_model.__cpu_features[0] go into extra variables
46 in libgcc.a only, preferrably hidden. */
47 unsigned int __cpu_features2
;
51 /* Get the specific type of AMD CPU. */
54 get_amd_cpu (unsigned int family
, unsigned int model
)
60 __cpu_model
.__cpu_type
= AMDFAM10H
;
65 __cpu_model
.__cpu_subtype
= AMDFAM10H_BARCELONA
;
69 __cpu_model
.__cpu_subtype
= AMDFAM10H_SHANGHAI
;
73 __cpu_model
.__cpu_subtype
= AMDFAM10H_ISTANBUL
;
79 /* AMD Family 14h "btver1". */
81 __cpu_model
.__cpu_type
= AMD_BTVER1
;
83 /* AMD Family 15h "Bulldozer". */
85 __cpu_model
.__cpu_type
= AMDFAM15H
;
88 __cpu_model
.__cpu_subtype
= AMDFAM15H_BDVER2
;
89 /* Bulldozer version 1. */
90 else if (model
<= 0xf)
91 __cpu_model
.__cpu_subtype
= AMDFAM15H_BDVER1
;
92 /* Bulldozer version 2 "Piledriver" */
93 else if (model
<= 0x2f)
94 __cpu_model
.__cpu_subtype
= AMDFAM15H_BDVER2
;
95 /* Bulldozer version 3 "Steamroller" */
96 else if (model
<= 0x4f)
97 __cpu_model
.__cpu_subtype
= AMDFAM15H_BDVER3
;
98 /* Bulldozer version 4 "Excavator" */
99 else if (model
<= 0x7f)
100 __cpu_model
.__cpu_subtype
= AMDFAM15H_BDVER4
;
102 /* AMD Family 16h "btver2" */
104 __cpu_model
.__cpu_type
= AMD_BTVER2
;
107 __cpu_model
.__cpu_type
= AMDFAM17H
;
108 /* AMD family 17h version 1. */
110 __cpu_model
.__cpu_subtype
= AMDFAM17H_ZNVER1
;
117 /* Get the specific type of Intel CPU. */
120 get_intel_cpu (unsigned int family
, unsigned int model
, unsigned int brand_id
)
122 /* Parse family and model only if brand ID is 0. */
136 __cpu_model
.__cpu_type
= INTEL_BONNELL
;
144 __cpu_model
.__cpu_type
= INTEL_SILVERMONT
;
149 __cpu_model
.__cpu_type
= INTEL_GOLDMONT
;
153 __cpu_model
.__cpu_type
= INTEL_GOLDMONT_PLUS
;
156 /* Knights Landing. */
157 __cpu_model
.__cpu_type
= INTEL_KNL
;
161 __cpu_model
.__cpu_type
= INTEL_KNM
;
168 __cpu_model
.__cpu_type
= INTEL_COREI7
;
169 __cpu_model
.__cpu_subtype
= INTEL_COREI7_NEHALEM
;
175 __cpu_model
.__cpu_type
= INTEL_COREI7
;
176 __cpu_model
.__cpu_subtype
= INTEL_COREI7_WESTMERE
;
181 __cpu_model
.__cpu_type
= INTEL_COREI7
;
182 __cpu_model
.__cpu_subtype
= INTEL_COREI7_SANDYBRIDGE
;
187 __cpu_model
.__cpu_type
= INTEL_COREI7
;
188 __cpu_model
.__cpu_subtype
= INTEL_COREI7_IVYBRIDGE
;
195 __cpu_model
.__cpu_type
= INTEL_COREI7
;
196 __cpu_model
.__cpu_subtype
= INTEL_COREI7_HASWELL
;
203 __cpu_model
.__cpu_type
= INTEL_COREI7
;
204 __cpu_model
.__cpu_subtype
= INTEL_COREI7_BROADWELL
;
212 __cpu_model
.__cpu_type
= INTEL_COREI7
;
213 __cpu_model
.__cpu_subtype
= INTEL_COREI7_SKYLAKE
;
216 /* Skylake with AVX-512 support. */
217 __cpu_model
.__cpu_type
= INTEL_COREI7
;
218 __cpu_model
.__cpu_subtype
= INTEL_COREI7_SKYLAKE_AVX512
;
222 __cpu_model
.__cpu_type
= INTEL_COREI7
;
223 __cpu_model
.__cpu_subtype
= INTEL_COREI7_CANNONLAKE
;
230 __cpu_model
.__cpu_type
= INTEL_CORE2
;
237 /* We have no idea. */
243 /* ECX and EDX are output of CPUID at level one. MAX_CPUID_LEVEL is
244 the max possible level of CPUID insn. */
246 get_available_features (unsigned int ecx
, unsigned int edx
,
249 unsigned int eax
, ebx
;
250 unsigned int ext_level
;
252 unsigned int features
= 0;
253 unsigned int features2
= 0;
255 /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv. */
256 #define XCR_XFEATURE_ENABLED_MASK 0x0
257 #define XSTATE_FP 0x1
258 #define XSTATE_SSE 0x2
259 #define XSTATE_YMM 0x4
260 #define XSTATE_OPMASK 0x20
261 #define XSTATE_ZMM 0x40
262 #define XSTATE_HI_ZMM 0x80
264 #define XCR_AVX_ENABLED_MASK \
265 (XSTATE_SSE | XSTATE_YMM)
266 #define XCR_AVX512F_ENABLED_MASK \
267 (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
269 /* Check if AVX and AVX512 are usable. */
271 int avx512_usable
= 0;
272 if ((ecx
& bit_OSXSAVE
))
274 /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
275 ZMM16-ZMM31 states are supported by OSXSAVE. */
277 unsigned int xcrhigh
;
278 asm (".byte 0x0f, 0x01, 0xd0"
279 : "=a" (xcrlow
), "=d" (xcrhigh
)
280 : "c" (XCR_XFEATURE_ENABLED_MASK
));
281 if ((xcrlow
& XCR_AVX_ENABLED_MASK
) == XCR_AVX_ENABLED_MASK
)
284 avx512_usable
= ((xcrlow
& XCR_AVX512F_ENABLED_MASK
)
285 == XCR_AVX512F_ENABLED_MASK
);
289 #define set_feature(f) \
293 features |= (1U << (f & 31)); \
295 features2 |= (1U << ((f - 32) & 31)); \
300 set_feature (FEATURE_CMOV
);
302 set_feature (FEATURE_MMX
);
304 set_feature (FEATURE_SSE
);
306 set_feature (FEATURE_SSE2
);
307 if (ecx
& bit_POPCNT
)
308 set_feature (FEATURE_POPCNT
);
310 set_feature (FEATURE_AES
);
311 if (ecx
& bit_PCLMUL
)
312 set_feature (FEATURE_PCLMUL
);
314 set_feature (FEATURE_SSE3
);
316 set_feature (FEATURE_SSSE3
);
317 if (ecx
& bit_SSE4_1
)
318 set_feature (FEATURE_SSE4_1
);
319 if (ecx
& bit_SSE4_2
)
320 set_feature (FEATURE_SSE4_2
);
324 set_feature (FEATURE_AVX
);
326 set_feature (FEATURE_FMA
);
329 /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
330 if (max_cpuid_level
>= 7)
332 __cpuid_count (7, 0, eax
, ebx
, ecx
, edx
);
334 set_feature (FEATURE_BMI
);
338 set_feature (FEATURE_AVX2
);
341 set_feature (FEATURE_BMI2
);
344 if (ebx
& bit_AVX512F
)
345 set_feature (FEATURE_AVX512F
);
346 if (ebx
& bit_AVX512VL
)
347 set_feature (FEATURE_AVX512VL
);
348 if (ebx
& bit_AVX512BW
)
349 set_feature (FEATURE_AVX512BW
);
350 if (ebx
& bit_AVX512DQ
)
351 set_feature (FEATURE_AVX512DQ
);
352 if (ebx
& bit_AVX512CD
)
353 set_feature (FEATURE_AVX512CD
);
354 if (ebx
& bit_AVX512PF
)
355 set_feature (FEATURE_AVX512PF
);
356 if (ebx
& bit_AVX512ER
)
357 set_feature (FEATURE_AVX512ER
);
358 if (ebx
& bit_AVX512IFMA
)
359 set_feature (FEATURE_AVX512IFMA
);
360 if (ecx
& bit_AVX512VBMI
)
361 set_feature (FEATURE_AVX512VBMI
);
362 if (ecx
& bit_AVX512VBMI2
)
363 set_feature (FEATURE_AVX512VBMI2
);
365 set_feature (FEATURE_GFNI
);
366 if (ecx
& bit_VPCLMULQDQ
)
367 set_feature (FEATURE_VPCLMULQDQ
);
368 if (ecx
& bit_AVX512VNNI
)
369 set_feature (FEATURE_AVX512VNNI
);
370 if (ecx
& bit_AVX512BITALG
)
371 set_feature (FEATURE_AVX512BITALG
);
372 if (ecx
& bit_AVX512VPOPCNTDQ
)
373 set_feature (FEATURE_AVX512VPOPCNTDQ
);
374 if (edx
& bit_AVX5124VNNIW
)
375 set_feature (FEATURE_AVX5124VNNIW
);
376 if (edx
& bit_AVX5124FMAPS
)
377 set_feature (FEATURE_AVX5124FMAPS
);
381 /* Check cpuid level of extended features. */
382 __cpuid (0x80000000, ext_level
, ebx
, ecx
, edx
);
384 if (ext_level
>= 0x80000001)
386 __cpuid (0x80000001, eax
, ebx
, ecx
, edx
);
389 set_feature (FEATURE_SSE4_A
);
393 set_feature (FEATURE_FMA4
);
395 set_feature (FEATURE_XOP
);
399 __cpu_model
.__cpu_features
[0] = features
;
401 __cpu_features2
= features2
;
407 /* A constructor function that is sets __cpu_model and __cpu_features with
408 the right values. This needs to run only once. This constructor is
409 given the highest priority and it should run before constructors without
410 the priority set. However, it still runs after ifunc initializers and
411 needs to be called explicitly there. */
413 int __attribute__ ((constructor CONSTRUCTOR_PRIORITY
))
414 __cpu_indicator_init (void)
416 unsigned int eax
, ebx
, ecx
, edx
;
420 unsigned int model
, family
, brand_id
;
421 unsigned int extended_model
, extended_family
;
423 /* This function needs to run just once. */
424 if (__cpu_model
.__cpu_vendor
)
427 /* Assume cpuid insn present. Run in level 0 to get vendor id. */
428 if (!__get_cpuid (0, &eax
, &ebx
, &ecx
, &edx
))
430 __cpu_model
.__cpu_vendor
= VENDOR_OTHER
;
439 __cpu_model
.__cpu_vendor
= VENDOR_OTHER
;
443 if (!__get_cpuid (1, &eax
, &ebx
, &ecx
, &edx
))
445 __cpu_model
.__cpu_vendor
= VENDOR_OTHER
;
449 model
= (eax
>> 4) & 0x0f;
450 family
= (eax
>> 8) & 0x0f;
451 brand_id
= ebx
& 0xff;
452 extended_model
= (eax
>> 12) & 0xf0;
453 extended_family
= (eax
>> 20) & 0xff;
455 if (vendor
== signature_INTEL_ebx
)
457 /* Adjust model and family for Intel CPUS. */
460 family
+= extended_family
;
461 model
+= extended_model
;
463 else if (family
== 0x06)
464 model
+= extended_model
;
467 get_intel_cpu (family
, model
, brand_id
);
468 /* Find available features. */
469 get_available_features (ecx
, edx
, max_level
);
470 __cpu_model
.__cpu_vendor
= VENDOR_INTEL
;
472 else if (vendor
== signature_AMD_ebx
)
474 /* Adjust model and family for AMD CPUS. */
477 family
+= extended_family
;
478 model
+= extended_model
;
482 get_amd_cpu (family
, model
);
483 /* Find available features. */
484 get_available_features (ecx
, edx
, max_level
);
485 __cpu_model
.__cpu_vendor
= VENDOR_AMD
;
488 __cpu_model
.__cpu_vendor
= VENDOR_OTHER
;
490 gcc_assert (__cpu_model
.__cpu_vendor
< VENDOR_MAX
);
491 gcc_assert (__cpu_model
.__cpu_type
< CPU_TYPE_MAX
);
492 gcc_assert (__cpu_model
.__cpu_subtype
< CPU_SUBTYPE_MAX
);
497 #if defined SHARED && defined USE_ELF_SYMVER
498 __asm__ (".symver __cpu_indicator_init, __cpu_indicator_init@GCC_4.8.0");
499 __asm__ (".symver __cpu_model, __cpu_model@GCC_4.8.0");