/* Get CPU type and Features for x86 processors.
- Copyright (C) 2012-2015 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Contributed by Sriraman Tallam (tmsriram@google.com)
This file is part of GCC.
#include "cpuid.h"
#include "tsystem.h"
#include "auto-target.h"
+#include "cpuinfo.h"
#ifdef HAVE_INIT_PRIORITY
#define CONSTRUCTOR_PRIORITY (101)
int __cpu_indicator_init (void)
__attribute__ ((constructor CONSTRUCTOR_PRIORITY));
-/* Processor Vendor and Models. */
-enum processor_vendor
-{
- VENDOR_INTEL = 1,
- VENDOR_AMD,
- VENDOR_OTHER,
- VENDOR_MAX
-};
-
-/* Any new types or subtypes have to be inserted at the end. */
-
-enum processor_types
-{
- INTEL_BONNELL = 1,
- INTEL_CORE2,
- INTEL_COREI7,
- AMDFAM10H,
- AMDFAM15H,
- INTEL_SILVERMONT,
- INTEL_KNL,
- AMD_BTVER1,
- AMD_BTVER2,
- CPU_TYPE_MAX
-};
-
-enum processor_subtypes
-{
- INTEL_COREI7_NEHALEM = 1,
- INTEL_COREI7_WESTMERE,
- INTEL_COREI7_SANDYBRIDGE,
- AMDFAM10H_BARCELONA,
- AMDFAM10H_SHANGHAI,
- AMDFAM10H_ISTANBUL,
- AMDFAM15H_BDVER1,
- AMDFAM15H_BDVER2,
- AMDFAM15H_BDVER3,
- AMDFAM15H_BDVER4,
- INTEL_COREI7_IVYBRIDGE,
- INTEL_COREI7_HASWELL,
- INTEL_COREI7_BROADWELL,
- INTEL_COREI7_SKYLAKE,
- CPU_SUBTYPE_MAX
-};
-
-/* ISA Features supported. New features have to be inserted at the end. */
-
-enum processor_features
-{
- FEATURE_CMOV = 0,
- FEATURE_MMX,
- FEATURE_POPCNT,
- FEATURE_SSE,
- FEATURE_SSE2,
- FEATURE_SSE3,
- FEATURE_SSSE3,
- FEATURE_SSE4_1,
- FEATURE_SSE4_2,
- FEATURE_AVX,
- FEATURE_AVX2,
- FEATURE_SSE4_A,
- FEATURE_FMA4,
- FEATURE_XOP,
- FEATURE_FMA,
- FEATURE_AVX512F,
- FEATURE_BMI,
- FEATURE_BMI2,
- FEATURE_AES,
- FEATURE_PCLMUL,
- FEATURE_AVX512VL,
- FEATURE_AVX512BW,
- FEATURE_AVX512DQ,
- FEATURE_AVX512CD,
- FEATURE_AVX512ER,
- FEATURE_AVX512PF,
- FEATURE_AVX512VBMI,
- FEATURE_AVX512IFMA
-};
-
-struct __processor_model
-{
- unsigned int __cpu_vendor;
- unsigned int __cpu_type;
- unsigned int __cpu_subtype;
- unsigned int __cpu_features[1];
-} __cpu_model = { };
+struct __processor_model __cpu_model = { };
+#ifndef SHARED
+/* We want to move away from __cpu_model in libgcc_s.so.1 and the
+ size of __cpu_model is part of ABI. So, new features that don't
+ fit into __cpu_model.__cpu_features[0] go into extra variables
+ in libgcc.a only, preferrably hidden. */
+unsigned int __cpu_features2;
+#endif
/* Get the specific type of AMD CPU. */
/* AMD Family 15h "Bulldozer". */
case 0x15:
__cpu_model.__cpu_type = AMDFAM15H;
+
+ if (model == 0x2)
+ __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
/* Bulldozer version 1. */
- if ( model <= 0xf)
+ else if (model <= 0xf)
__cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
/* Bulldozer version 2 "Piledriver" */
- if (model >= 0x10 && model <= 0x2f)
+ else if (model <= 0x2f)
__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
/* Bulldozer version 3 "Steamroller" */
- if (model >= 0x30 && model <= 0x4f)
+ else if (model <= 0x4f)
__cpu_model.__cpu_subtype = AMDFAM15H_BDVER3;
+ /* Bulldozer version 4 "Excavator" */
+ else if (model <= 0x7f)
+ __cpu_model.__cpu_subtype = AMDFAM15H_BDVER4;
break;
/* AMD Family 16h "btver2" */
case 0x16:
__cpu_model.__cpu_type = AMD_BTVER2;
break;
+ case 0x17:
+ __cpu_model.__cpu_type = AMDFAM17H;
+ /* AMD family 17h version 1. */
+ if (model <= 0x1f)
+ __cpu_model.__cpu_subtype = AMDFAM17H_ZNVER1;
+ if (model >= 0x30)
+ __cpu_model.__cpu_subtype = AMDFAM17H_ZNVER2;
+ break;
default:
break;
}
/* Silvermont. */
__cpu_model.__cpu_type = INTEL_SILVERMONT;
break;
+ case 0x5c:
+ case 0x5f:
+ /* Goldmont. */
+ __cpu_model.__cpu_type = INTEL_GOLDMONT;
+ break;
+ case 0x7a:
+ /* Goldmont Plus. */
+ __cpu_model.__cpu_type = INTEL_GOLDMONT_PLUS;
+ break;
case 0x57:
/* Knights Landing. */
__cpu_model.__cpu_type = INTEL_KNL;
break;
+ case 0x85:
+ /* Knights Mill. */
+ __cpu_model.__cpu_type = INTEL_KNM;
+ break;
case 0x1a:
case 0x1e:
case 0x1f:
case 0x4e:
case 0x5e:
/* Skylake. */
+ case 0x8e:
+ case 0x9e:
+ /* Kaby Lake. */
__cpu_model.__cpu_type = INTEL_COREI7;
__cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE;
break;
+ case 0x55:
+ {
+ unsigned int eax, ebx, ecx, edx;
+ __cpu_model.__cpu_type = INTEL_COREI7;
+ __cpuid_count (7, 0, eax, ebx, ecx, edx);
+ if (ecx & bit_AVX512VNNI)
+ /* Cascade Lake. */
+ __cpu_model.__cpu_subtype = INTEL_COREI7_CASCADELAKE;
+ else
+ /* Skylake with AVX-512 support. */
+ __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
+ }
+ break;
+ case 0x66:
+ /* Cannon Lake. */
+ __cpu_model.__cpu_type = INTEL_COREI7;
+ __cpu_model.__cpu_subtype = INTEL_COREI7_CANNONLAKE;
+ break;
case 0x17:
case 0x1d:
/* Penryn. */
get_available_features (unsigned int ecx, unsigned int edx,
int max_cpuid_level)
{
+ unsigned int eax, ebx;
+ unsigned int ext_level;
+
unsigned int features = 0;
+ unsigned int features2 = 0;
+
+ /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv. */
+#define XCR_XFEATURE_ENABLED_MASK 0x0
+#define XSTATE_FP 0x1
+#define XSTATE_SSE 0x2
+#define XSTATE_YMM 0x4
+#define XSTATE_OPMASK 0x20
+#define XSTATE_ZMM 0x40
+#define XSTATE_HI_ZMM 0x80
+
+#define XCR_AVX_ENABLED_MASK \
+ (XSTATE_SSE | XSTATE_YMM)
+#define XCR_AVX512F_ENABLED_MASK \
+ (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
+
+ /* Check if AVX and AVX512 are usable. */
+ int avx_usable = 0;
+ int avx512_usable = 0;
+ if ((ecx & bit_OSXSAVE))
+ {
+ /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
+ ZMM16-ZMM31 states are supported by OSXSAVE. */
+ unsigned int xcrlow;
+ unsigned int xcrhigh;
+ asm (".byte 0x0f, 0x01, 0xd0"
+ : "=a" (xcrlow), "=d" (xcrhigh)
+ : "c" (XCR_XFEATURE_ENABLED_MASK));
+ if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
+ {
+ avx_usable = 1;
+ avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
+ == XCR_AVX512F_ENABLED_MASK);
+ }
+ }
+
+#define set_feature(f) \
+ do \
+ { \
+ if (f < 32) \
+ features |= (1U << (f & 31)); \
+ else \
+ features2 |= (1U << ((f - 32) & 31)); \
+ } \
+ while (0)
if (edx & bit_CMOV)
- features |= (1 << FEATURE_CMOV);
+ set_feature (FEATURE_CMOV);
if (edx & bit_MMX)
- features |= (1 << FEATURE_MMX);
+ set_feature (FEATURE_MMX);
if (edx & bit_SSE)
- features |= (1 << FEATURE_SSE);
+ set_feature (FEATURE_SSE);
if (edx & bit_SSE2)
- features |= (1 << FEATURE_SSE2);
+ set_feature (FEATURE_SSE2);
if (ecx & bit_POPCNT)
- features |= (1 << FEATURE_POPCNT);
+ set_feature (FEATURE_POPCNT);
if (ecx & bit_AES)
- features |= (1 << FEATURE_AES);
+ set_feature (FEATURE_AES);
if (ecx & bit_PCLMUL)
- features |= (1 << FEATURE_PCLMUL);
+ set_feature (FEATURE_PCLMUL);
if (ecx & bit_SSE3)
- features |= (1 << FEATURE_SSE3);
+ set_feature (FEATURE_SSE3);
if (ecx & bit_SSSE3)
- features |= (1 << FEATURE_SSSE3);
+ set_feature (FEATURE_SSSE3);
if (ecx & bit_SSE4_1)
- features |= (1 << FEATURE_SSE4_1);
+ set_feature (FEATURE_SSE4_1);
if (ecx & bit_SSE4_2)
- features |= (1 << FEATURE_SSE4_2);
- if (ecx & bit_AVX)
- features |= (1 << FEATURE_AVX);
- if (ecx & bit_FMA)
- features |= (1 << FEATURE_FMA);
+ set_feature (FEATURE_SSE4_2);
+ if (avx_usable)
+ {
+ if (ecx & bit_AVX)
+ set_feature (FEATURE_AVX);
+ if (ecx & bit_FMA)
+ set_feature (FEATURE_FMA);
+ }
- /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
+ /* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */
if (max_cpuid_level >= 7)
{
- unsigned int eax, ebx, ecx, edx;
__cpuid_count (7, 0, eax, ebx, ecx, edx);
if (ebx & bit_BMI)
- features |= (1 << FEATURE_BMI);
- if (ebx & bit_AVX2)
- features |= (1 << FEATURE_AVX2);
+ set_feature (FEATURE_BMI);
+ if (avx_usable)
+ {
+ if (ebx & bit_AVX2)
+ set_feature (FEATURE_AVX2);
+ }
if (ebx & bit_BMI2)
- features |= (1 << FEATURE_BMI2);
- if (ebx & bit_AVX512F)
- features |= (1 << FEATURE_AVX512F);
- if (ebx & bit_AVX512VL)
- features |= (1 << FEATURE_AVX512VL);
- if (ebx & bit_AVX512BW)
- features |= (1 << FEATURE_AVX512BW);
- if (ebx & bit_AVX512DQ)
- features |= (1 << FEATURE_AVX512DQ);
- if (ebx & bit_AVX512CD)
- features |= (1 << FEATURE_AVX512CD);
- if (ebx & bit_AVX512PF)
- features |= (1 << FEATURE_AVX512PF);
- if (ebx & bit_AVX512ER)
- features |= (1 << FEATURE_AVX512ER);
- if (ebx & bit_AVX512IFMA)
- features |= (1 << FEATURE_AVX512IFMA);
- if (ecx & bit_AVX512VBMI)
- features |= (1 << FEATURE_AVX512VBMI);
+ set_feature (FEATURE_BMI2);
+ if (avx512_usable)
+ {
+ if (ebx & bit_AVX512F)
+ set_feature (FEATURE_AVX512F);
+ if (ebx & bit_AVX512VL)
+ set_feature (FEATURE_AVX512VL);
+ if (ebx & bit_AVX512BW)
+ set_feature (FEATURE_AVX512BW);
+ if (ebx & bit_AVX512DQ)
+ set_feature (FEATURE_AVX512DQ);
+ if (ebx & bit_AVX512CD)
+ set_feature (FEATURE_AVX512CD);
+ if (ebx & bit_AVX512PF)
+ set_feature (FEATURE_AVX512PF);
+ if (ebx & bit_AVX512ER)
+ set_feature (FEATURE_AVX512ER);
+ if (ebx & bit_AVX512IFMA)
+ set_feature (FEATURE_AVX512IFMA);
+ if (ecx & bit_AVX512VBMI)
+ set_feature (FEATURE_AVX512VBMI);
+ if (ecx & bit_AVX512VBMI2)
+ set_feature (FEATURE_AVX512VBMI2);
+ if (ecx & bit_GFNI)
+ set_feature (FEATURE_GFNI);
+ if (ecx & bit_VPCLMULQDQ)
+ set_feature (FEATURE_VPCLMULQDQ);
+ if (ecx & bit_AVX512VNNI)
+ set_feature (FEATURE_AVX512VNNI);
+ if (ecx & bit_AVX512BITALG)
+ set_feature (FEATURE_AVX512BITALG);
+ if (ecx & bit_AVX512VPOPCNTDQ)
+ set_feature (FEATURE_AVX512VPOPCNTDQ);
+ if (edx & bit_AVX5124VNNIW)
+ set_feature (FEATURE_AVX5124VNNIW);
+ if (edx & bit_AVX5124FMAPS)
+ set_feature (FEATURE_AVX5124FMAPS);
+
+ __cpuid_count (7, 1, eax, ebx, ecx, edx);
+ if (eax & bit_AVX512BF16)
+ set_feature (FEATURE_AVX512BF16);
+ }
}
- unsigned int ext_level;
- unsigned int eax, ebx;
/* Check cpuid level of extended features. */
__cpuid (0x80000000, ext_level, ebx, ecx, edx);
- if (ext_level > 0x80000000)
+ if (ext_level >= 0x80000001)
{
__cpuid (0x80000001, eax, ebx, ecx, edx);
if (ecx & bit_SSE4a)
- features |= (1 << FEATURE_SSE4_A);
- if (ecx & bit_FMA4)
- features |= (1 << FEATURE_FMA4);
- if (ecx & bit_XOP)
- features |= (1 << FEATURE_XOP);
+ set_feature (FEATURE_SSE4_A);
+ if (avx_usable)
+ {
+ if (ecx & bit_FMA4)
+ set_feature (FEATURE_FMA4);
+ if (ecx & bit_XOP)
+ set_feature (FEATURE_XOP);
+ }
}
__cpu_model.__cpu_features[0] = features;
+#ifndef SHARED
+ __cpu_features2 = features2;
+#else
+ (void) features2;
+#endif
}
-/* A noinline function calling __get_cpuid. Having many calls to
- cpuid in one function in 32-bit mode causes GCC to complain:
- "can't find a register in class CLOBBERED_REGS". This is
- related to PR rtl-optimization 44174. */
-
-static int __attribute__ ((noinline))
-__get_cpuid_output (unsigned int __level,
- unsigned int *__eax, unsigned int *__ebx,
- unsigned int *__ecx, unsigned int *__edx)
-{
- return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
-}
-
-
/* A constructor function that is sets __cpu_model and __cpu_features with
the right values. This needs to run only once. This constructor is
given the highest priority and it should run before constructors without
{
unsigned int eax, ebx, ecx, edx;
- int max_level = 5;
+ int max_level;
unsigned int vendor;
unsigned int model, family, brand_id;
unsigned int extended_model, extended_family;
return 0;
/* Assume cpuid insn present. Run in level 0 to get vendor id. */
- if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
+ if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
{
__cpu_model.__cpu_vendor = VENDOR_OTHER;
return -1;
return -1;
}
- if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
{
__cpu_model.__cpu_vendor = VENDOR_OTHER;
return -1;
if (family == 0x0f)
{
family += extended_family;
- model += (extended_model << 4);
+ model += extended_model;
}
/* Get CPU type. */