--- /dev/null
+/* Get CPU type and Features for x86 processors.
+ Copyright (C) 2012-2020 Free Software Foundation, Inc.
+ Contributed by Sriraman Tallam (tmsriram@google.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+struct __processor_model
+{
+ unsigned int __cpu_vendor;
+ unsigned int __cpu_type;
+ unsigned int __cpu_subtype;
+ /* The first 32 features are stored as bitmasks in __cpu_features.
+ The rest of features are stored as bitmasks in a separate array
+ of unsigned int. */
+ unsigned int __cpu_features[1];
+};
+
+struct __processor_model2
+{
+ unsigned int __cpu_family;
+ unsigned int __cpu_model;
+ unsigned int __cpu_max_level;
+ unsigned int __cpu_ext_level;
+};
+
+#ifndef CHECK___builtin_cpu_is
+# define CHECK___builtin_cpu_is(cpu)
+#endif
+
+/* Return non-zero if the processor has feature F. */
+
+static inline int
+has_cpu_feature (struct __processor_model *cpu_model,
+ unsigned int *cpu_features2,
+ enum processor_features f)
+{
+ unsigned int i;
+ if (f < 32)
+ {
+ /* The first 32 features. */
+ return cpu_model->__cpu_features[0] & (1U << (f & 31));
+ }
+ /* The rest of features. cpu_features2[i] contains features from
+ (32 + i * 32) to (31 + 32 + i * 32), inclusively. */
+ for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
+ if (f < (32 + 32 + i * 32))
+ return cpu_features2[i] & (1U << ((f - (32 + i * 32)) & 31));
+ gcc_unreachable ();
+}
+
+static inline void
+set_cpu_feature (struct __processor_model *cpu_model,
+ unsigned int *cpu_features2,
+ enum processor_features f)
+{
+ unsigned int i;
+ if (f < 32)
+ {
+ /* The first 32 features. */
+ cpu_model->__cpu_features[0] |= (1U << (f & 31));
+ return;
+ }
+ /* The rest of features. cpu_features2[i] contains features from
+ (32 + i * 32) to (31 + 32 + i * 32), inclusively. */
+ for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
+ if (f < (32 + 32 + i * 32))
+ {
+ cpu_features2[i] |= (1U << ((f - (32 + i * 32)) & 31));
+ return;
+ }
+ gcc_unreachable ();
+}
+
+/* Get the specific type of AMD CPU and return AMD CPU name. Return
+ NULL for unknown AMD CPU. */
+
+static inline const char *
+get_amd_cpu (struct __processor_model *cpu_model,
+ struct __processor_model2 *cpu_model2,
+ unsigned int *cpu_features2)
+{
+ const char *cpu = NULL;
+ unsigned int family = cpu_model2->__cpu_family;
+ unsigned int model = cpu_model2->__cpu_model;
+
+ switch (family)
+ {
+ case 0x10:
+ /* AMD Family 10h. */
+ cpu = "amdfam10";
+ cpu_model->__cpu_type = AMDFAM10H;
+ switch (model)
+ {
+ case 0x2:
+ /* Barcelona. */
+ CHECK___builtin_cpu_is ("amdfam10h");
+ CHECK___builtin_cpu_is ("barcelona");
+ cpu_model->__cpu_subtype = AMDFAM10H_BARCELONA;
+ break;
+ case 0x4:
+ /* Shanghai. */
+ CHECK___builtin_cpu_is ("amdfam10h");
+ CHECK___builtin_cpu_is ("shanghai");
+ cpu_model->__cpu_subtype = AMDFAM10H_SHANGHAI;
+ break;
+ case 0x8:
+ /* Istanbul. */
+ CHECK___builtin_cpu_is ("amdfam10h");
+ CHECK___builtin_cpu_is ("istanbul");
+ cpu_model->__cpu_subtype = AMDFAM10H_ISTANBUL;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0x14:
+ /* AMD Family 14h "btver1". */
+ cpu = "btver1";
+ CHECK___builtin_cpu_is ("btver1");
+ cpu_model->__cpu_type = AMD_BTVER1;
+ break;
+ case 0x15:
+ /* AMD Family 15h "Bulldozer". */
+ cpu_model->__cpu_type = AMDFAM15H;
+ if (model == 0x2)
+ {
+ /* Bulldozer version 2 "Piledriver" */
+ cpu = "bdver2";
+ CHECK___builtin_cpu_is ("bdver2");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+ }
+ else if (model <= 0xf)
+ {
+ /* Bulldozer version 1. */
+ cpu = "bdver1";
+ CHECK___builtin_cpu_is ("bdver1");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
+ }
+ else if (model <= 0x2f)
+ {
+ /* Bulldozer version 2 "Piledriver" */
+ cpu = "bdver2";
+ CHECK___builtin_cpu_is ("bdver2");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+ }
+ else if (model <= 0x4f)
+ {
+ /* Bulldozer version 3 "Steamroller" */
+ cpu = "bdver3";
+ CHECK___builtin_cpu_is ("bdver3");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
+ }
+ else if (model <= 0x7f)
+ {
+ /* Bulldozer version 4 "Excavator" */
+ cpu = "bdver4";
+ CHECK___builtin_cpu_is ("bdver4");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_AVX2))
+ {
+ cpu = "bdver4";
+ CHECK___builtin_cpu_is ("bdver4");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_XSAVEOPT))
+ {
+ cpu = "bdver3";
+ CHECK___builtin_cpu_is ("bdver3");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_BMI))
+ {
+ cpu = "bdver2";
+ CHECK___builtin_cpu_is ("bdver2");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_XOP))
+ {
+ cpu = "bdver1";
+ CHECK___builtin_cpu_is ("bdver1");
+ cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
+ }
+ break;
+ case 0x16:
+ /* AMD Family 16h "btver2" */
+ cpu = "btver2";
+ CHECK___builtin_cpu_is ("btver2");
+ cpu_model->__cpu_type = AMD_BTVER2;
+ break;
+ case 0x17:
+ cpu_model->__cpu_type = AMDFAM17H;
+ if (model <= 0x1f)
+ {
+ /* AMD family 17h version 1. */
+ cpu = "znver1";
+ CHECK___builtin_cpu_is ("znver1");
+ cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
+ }
+ else if (model >= 0x30)
+ {
+ cpu = "znver2";
+ CHECK___builtin_cpu_is ("znver2");
+ cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_CLWB))
+ {
+ cpu = "znver2";
+ CHECK___builtin_cpu_is ("znver2");
+ cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
+ }
+ else if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_CLZERO))
+ {
+ cpu = "znver1";
+ CHECK___builtin_cpu_is ("znver1");
+ cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return cpu;
+}
+
+/* Get the specific type of Intel CPU and return Intel CPU name. Return
+ NULL for unknown Intel CPU. */
+
+static inline const char *
+get_intel_cpu (struct __processor_model *cpu_model,
+ struct __processor_model2 *cpu_model2,
+ unsigned int *cpu_features2,
+ unsigned int brand_id)
+{
+ const char *cpu = NULL;
+
+ /* Parse family and model only for brand ID 0 and model 6. */
+ if (brand_id != 0 || cpu_model2->__cpu_family != 0x6)
+ return cpu;
+
+ switch (cpu_model2->__cpu_model)
+ {
+ case 0x1c:
+ case 0x26:
+ /* Bonnell. */
+ cpu = "bonnell";
+ CHECK___builtin_cpu_is ("atom");
+ cpu_model->__cpu_type = INTEL_BONNELL;
+ break;
+ case 0x37:
+ case 0x4a:
+ case 0x4d:
+ case 0x5d:
+ /* Silvermont. */
+ case 0x4c:
+ case 0x5a:
+ case 0x75:
+ /* Airmont. */
+ cpu = "silvermont";
+ CHECK___builtin_cpu_is ("silvermont");
+ cpu_model->__cpu_type = INTEL_SILVERMONT;
+ break;
+ case 0x5c:
+ case 0x5f:
+ /* Goldmont. */
+ cpu = "goldmont";
+ CHECK___builtin_cpu_is ("goldmont");
+ cpu_model->__cpu_type = INTEL_GOLDMONT;
+ break;
+ case 0x7a:
+ /* Goldmont Plus. */
+ cpu = "goldmont-plus";
+ CHECK___builtin_cpu_is ("goldmont-plus");
+ cpu_model->__cpu_type = INTEL_GOLDMONT_PLUS;
+ break;
+ case 0x86:
+ case 0x96:
+ case 0x9c:
+ /* Tremont. */
+ cpu = "tremont";
+ CHECK___builtin_cpu_is ("tremont");
+ cpu_model->__cpu_type = INTEL_TREMONT;
+ break;
+ case 0x57:
+ /* Knights Landing. */
+ cpu = "knl";
+ CHECK___builtin_cpu_is ("knl");
+ cpu_model->__cpu_type = INTEL_KNL;
+ break;
+ case 0x85:
+ /* Knights Mill. */
+ cpu = "knm";
+ CHECK___builtin_cpu_is ("knm");
+ cpu_model->__cpu_type = INTEL_KNM;
+ break;
+ case 0x1a:
+ case 0x1e:
+ case 0x1f:
+ case 0x2e:
+ /* Nehalem. */
+ cpu = "nehalem";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("nehalem");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_NEHALEM;
+ break;
+ case 0x25:
+ case 0x2c:
+ case 0x2f:
+ /* Westmere. */
+ cpu = "westmere";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("westmere");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_WESTMERE;
+ break;
+ case 0x2a:
+ case 0x2d:
+ /* Sandy Bridge. */
+ cpu = "sandybridge";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("sandybridge");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
+ break;
+ case 0x3a:
+ case 0x3e:
+ /* Ivy Bridge. */
+ cpu = "ivybridge";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("ivybridge");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
+ break;
+ case 0x3c:
+ case 0x3f:
+ case 0x45:
+ case 0x46:
+ /* Haswell. */
+ cpu = "haswell";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("haswell");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_HASWELL;
+ break;
+ case 0x3d:
+ case 0x47:
+ case 0x4f:
+ case 0x56:
+ /* Broadwell. */
+ cpu = "broadwell";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("broadwell");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_BROADWELL;
+ break;
+ case 0x4e:
+ case 0x5e:
+ /* Skylake. */
+ case 0x8e:
+ case 0x9e:
+ /* Kaby Lake. */
+ case 0xa5:
+ case 0xa6:
+ /* Comet Lake. */
+ cpu = "skylake";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("skylake");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE;
+ break;
+ case 0x55:
+ CHECK___builtin_cpu_is ("corei7");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ if (has_cpu_feature (cpu_model, cpu_features2,
+ FEATURE_AVX512VNNI))
+ {
+ /* Cascade Lake. */
+ cpu = "cascadelake";
+ CHECK___builtin_cpu_is ("cascadelake");
+ cpu_model->__cpu_subtype = INTEL_COREI7_CASCADELAKE;
+ }
+ else
+ {
+ /* Skylake with AVX-512 support. */
+ cpu = "skylake-avx512";
+ CHECK___builtin_cpu_is ("skylake-avx512");
+ cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
+ }
+ break;
+ case 0x66:
+ /* Cannon Lake. */
+ cpu = "cannonlake";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("cannonlake");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_CANNONLAKE;
+ break;
+ case 0x6a:
+ case 0x6c:
+ /* Ice Lake server. */
+ cpu = "icelake-server";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("icelake-server");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_SERVER;
+ break;
+ case 0x7e:
+ case 0x7d:
+ case 0x9d:
+ /* Ice Lake client. */
+ cpu = "icelake-client";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("icelake-client");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_CLIENT;
+ break;
+ case 0x8c:
+ case 0x8d:
+ /* Tiger Lake. */
+ cpu = "tigerlake";
+ CHECK___builtin_cpu_is ("corei7");
+ CHECK___builtin_cpu_is ("tigerlake");
+ cpu_model->__cpu_type = INTEL_COREI7;
+ cpu_model->__cpu_subtype = INTEL_COREI7_TIGERLAKE;
+ break;
+ case 0x17:
+ case 0x1d:
+ /* Penryn. */
+ case 0x0f:
+ /* Merom. */
+ cpu = "core2";
+ CHECK___builtin_cpu_is ("core2");
+ cpu_model->__cpu_type = INTEL_CORE2;
+ break;
+ default:
+ break;
+ }
+
+ return cpu;
+}
+
+/* ECX and EDX are output of CPUID at level one. */
+static inline void
+get_available_features (struct __processor_model *cpu_model,
+ struct __processor_model2 *cpu_model2,
+ unsigned int *cpu_features2,
+ unsigned int ecx, unsigned int edx)
+{
+ unsigned int max_cpuid_level = cpu_model2->__cpu_max_level;
+ unsigned int eax, ebx;
+ unsigned int ext_level;
+
+ /* 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) \
+ set_cpu_feature (cpu_model, cpu_features2, f)
+
+ if (edx & bit_CMOV)
+ set_feature (FEATURE_CMOV);
+ if (edx & bit_MMX)
+ set_feature (FEATURE_MMX);
+ if (edx & bit_SSE)
+ set_feature (FEATURE_SSE);
+ if (edx & bit_SSE2)
+ set_feature (FEATURE_SSE2);
+ if (edx & bit_CMPXCHG8B)
+ set_feature (FEATURE_CMPXCHG8B);
+ if (edx & bit_FXSAVE)
+ set_feature (FEATURE_FXSAVE);
+
+ if (ecx & bit_POPCNT)
+ set_feature (FEATURE_POPCNT);
+ if (ecx & bit_AES)
+ set_feature (FEATURE_AES);
+ if (ecx & bit_PCLMUL)
+ set_feature (FEATURE_PCLMUL);
+ if (ecx & bit_SSE3)
+ set_feature (FEATURE_SSE3);
+ if (ecx & bit_SSSE3)
+ set_feature (FEATURE_SSSE3);
+ if (ecx & bit_SSE4_1)
+ set_feature (FEATURE_SSE4_1);
+ if (ecx & bit_SSE4_2)
+ set_feature (FEATURE_SSE4_2);
+ if (ecx & bit_OSXSAVE)
+ set_feature (FEATURE_OSXSAVE);
+ if (ecx & bit_CMPXCHG16B)
+ set_feature (FEATURE_CMPXCHG16B);
+ if (ecx & bit_MOVBE)
+ set_feature (FEATURE_MOVBE);
+ if (ecx & bit_AES)
+ set_feature (FEATURE_AES);
+ if (ecx & bit_F16C)
+ set_feature (FEATURE_F16C);
+ if (ecx & bit_RDRND)
+ set_feature (FEATURE_RDRND);
+ if (ecx & bit_XSAVE)
+ set_feature (FEATURE_XSAVE);
+ 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/1). */
+ if (max_cpuid_level >= 7)
+ {
+ __cpuid_count (7, 0, eax, ebx, ecx, edx);
+ if (ebx & bit_BMI)
+ set_feature (FEATURE_BMI);
+ if (ebx & bit_SGX)
+ set_feature (FEATURE_SGX);
+ if (ebx & bit_HLE)
+ set_feature (FEATURE_HLE);
+ if (ebx & bit_RTM)
+ set_feature (FEATURE_RTM);
+ if (avx_usable)
+ {
+ if (ebx & bit_AVX2)
+ set_feature (FEATURE_AVX2);
+ if (ecx & bit_VPCLMULQDQ)
+ set_feature (FEATURE_VPCLMULQDQ);
+ }
+ if (ebx & bit_BMI2)
+ set_feature (FEATURE_BMI2);
+ if (ebx & bit_FSGSBASE)
+ set_feature (FEATURE_FSGSBASE);
+ if (ebx & bit_RDSEED)
+ set_feature (FEATURE_RDSEED);
+ if (ebx & bit_ADX)
+ set_feature (FEATURE_ADX);
+ if (ebx & bit_SHA)
+ set_feature (FEATURE_SHA);
+ if (ebx & bit_CLFLUSHOPT)
+ set_feature (FEATURE_CLFLUSHOPT);
+ if (ebx & bit_CLWB)
+ set_feature (FEATURE_CLWB);
+ if (ecx & bit_PREFETCHWT1)
+ set_feature (FEATURE_PREFETCHWT1);
+ /* NB: bit_OSPKE indicates that OS supports PKU. */
+ if (ecx & bit_OSPKE)
+ set_feature (FEATURE_PKU);
+ if (ecx & bit_RDPID)
+ set_feature (FEATURE_RDPID);
+ if (ecx & bit_VAES)
+ set_feature (FEATURE_VAES);
+ if (ecx & bit_GFNI)
+ set_feature (FEATURE_GFNI);
+ if (ecx & bit_MOVDIRI)
+ set_feature (FEATURE_MOVDIRI);
+ if (ecx & bit_MOVDIR64B)
+ set_feature (FEATURE_MOVDIR64B);
+ if (ecx & bit_ENQCMD)
+ set_feature (FEATURE_ENQCMD);
+ if (ecx & bit_CLDEMOTE)
+ set_feature (FEATURE_CLDEMOTE);
+ if (ecx & bit_WAITPKG)
+ set_feature (FEATURE_WAITPKG);
+ if (ecx & bit_SHSTK)
+ set_feature (FEATURE_SHSTK);
+ if (edx & bit_SERIALIZE)
+ set_feature (FEATURE_SERIALIZE);
+ if (edx & bit_TSXLDTRK)
+ set_feature (FEATURE_TSXLDTRK);
+ if (edx & bit_PCONFIG)
+ set_feature (FEATURE_PCONFIG);
+ if (edx & bit_IBT)
+ set_feature (FEATURE_IBT);
+ 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_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);
+ if (edx & bit_AVX512VP2INTERSECT)
+ set_feature (FEATURE_AVX512VP2INTERSECT);
+
+ __cpuid_count (7, 1, eax, ebx, ecx, edx);
+ if (eax & bit_AVX512BF16)
+ set_feature (FEATURE_AVX512BF16);
+ }
+ }
+
+ /* Get Advanced Features at level 0xd (eax = 0xd, ecx = 1). */
+ if (max_cpuid_level >= 0xd)
+ {
+ __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
+ if (eax & bit_XSAVEOPT)
+ set_feature (FEATURE_XSAVEOPT);
+ if (eax & bit_XSAVEC)
+ set_feature (FEATURE_XSAVEC);
+ if (eax & bit_XSAVES)
+ set_feature (FEATURE_XSAVES);
+ }
+
+ /* Get Advanced Features at level 0x14 (eax = 0x14, ecx = 0). */
+ if (max_cpuid_level >= 0x14)
+ {
+ __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
+ if (ebx & bit_PTWRITE)
+ set_feature (FEATURE_PTWRITE);
+ }
+
+ /* Check cpuid level of extended features. */
+ __cpuid (0x80000000, ext_level, ebx, ecx, edx);
+
+ cpu_model2->__cpu_ext_level = ext_level;
+
+ if (ext_level >= 0x80000001)
+ {
+ __cpuid (0x80000001, eax, ebx, ecx, edx);
+
+ if (ecx & bit_SSE4a)
+ set_feature (FEATURE_SSE4_A);
+ if (ecx & bit_LAHF_LM)
+ set_feature (FEATURE_LAHF_LM);
+ if (ecx & bit_ABM)
+ set_feature (FEATURE_ABM);
+ if (ecx & bit_LWP)
+ set_feature (FEATURE_LWP);
+ if (ecx & bit_TBM)
+ set_feature (FEATURE_TBM);
+ if (ecx & bit_LZCNT)
+ set_feature (FEATURE_LZCNT);
+ if (ecx & bit_PRFCHW)
+ set_feature (FEATURE_PRFCHW);
+ if (ecx & bit_MWAITX)
+ set_feature (FEATURE_MWAITX);
+
+ if (edx & bit_LM)
+ set_feature (FEATURE_LM);
+ if (edx & bit_3DNOWP)
+ set_feature (FEATURE_3DNOWP);
+ if (edx & bit_3DNOW)
+ set_feature (FEATURE_3DNOW);
+
+ if (avx_usable)
+ {
+ if (ecx & bit_FMA4)
+ set_feature (FEATURE_FMA4);
+ if (ecx & bit_XOP)
+ set_feature (FEATURE_XOP);
+ }
+ }
+
+ if (ext_level >= 0x80000008)
+ {
+ __cpuid (0x80000008, eax, ebx, ecx, edx);
+ if (ebx & bit_CLZERO)
+ set_feature (FEATURE_CLZERO);
+ if (ebx & bit_WBNOINVD)
+ set_feature (FEATURE_WBNOINVD);
+ }
+
+#undef set_feature
+}
+
+static inline int
+cpu_indicator_init (struct __processor_model *cpu_model,
+ struct __processor_model2 *cpu_model2,
+ unsigned int *cpu_features2)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ int max_level;
+ unsigned int vendor;
+ unsigned int model, family, brand_id;
+ unsigned int extended_model, extended_family;
+
+ /* This function needs to run just once. */
+ if (cpu_model->__cpu_vendor)
+ return 0;
+
+ /* Assume cpuid insn present. Run in level 0 to get vendor id. */
+ if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
+ {
+ cpu_model->__cpu_vendor = VENDOR_OTHER;
+ return -1;
+ }
+
+ vendor = ebx;
+ max_level = eax;
+
+ if (max_level < 1)
+ {
+ cpu_model->__cpu_vendor = VENDOR_OTHER;
+ return -1;
+ }
+
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ {
+ cpu_model->__cpu_vendor = VENDOR_OTHER;
+ return -1;
+ }
+
+ cpu_model2->__cpu_max_level = max_level;
+
+ model = (eax >> 4) & 0x0f;
+ family = (eax >> 8) & 0x0f;
+ brand_id = ebx & 0xff;
+ extended_model = (eax >> 12) & 0xf0;
+ extended_family = (eax >> 20) & 0xff;
+
+ if (vendor == signature_INTEL_ebx)
+ {
+ /* Adjust model and family for Intel CPUS. */
+ if (family == 0x0f)
+ {
+ family += extended_family;
+ model += extended_model;
+ }
+ else if (family == 0x06)
+ model += extended_model;
+
+ cpu_model2->__cpu_family = family;
+ cpu_model2->__cpu_model = model;
+
+ /* Find available features. */
+ get_available_features (cpu_model, cpu_model2, cpu_features2,
+ ecx, edx);
+ /* Get CPU type. */
+ get_intel_cpu (cpu_model, cpu_model2, cpu_features2, brand_id);
+ cpu_model->__cpu_vendor = VENDOR_INTEL;
+ }
+ else if (vendor == signature_AMD_ebx)
+ {
+ /* Adjust model and family for AMD CPUS. */
+ if (family == 0x0f)
+ {
+ family += extended_family;
+ model += extended_model;
+ }
+
+ cpu_model2->__cpu_family = family;
+ cpu_model2->__cpu_model = model;
+
+ /* Find available features. */
+ get_available_features (cpu_model, cpu_model2, cpu_features2,
+ ecx, edx);
+ /* Get CPU type. */
+ get_amd_cpu (cpu_model, cpu_model2, cpu_features2);
+ cpu_model->__cpu_vendor = VENDOR_AMD;
+ }
+ else if (vendor == signature_CENTAUR_ebx)
+ cpu_model->__cpu_vendor = VENDOR_CENTAUR;
+ else if (vendor == signature_CYRIX_ebx)
+ cpu_model->__cpu_vendor = VENDOR_CYRIX;
+ else if (vendor == signature_NSC_ebx)
+ cpu_model->__cpu_vendor = VENDOR_NSC;
+ else
+ cpu_model->__cpu_vendor = VENDOR_OTHER;
+
+ gcc_assert (cpu_model->__cpu_vendor < VENDOR_MAX);
+ gcc_assert (cpu_model->__cpu_type < CPU_TYPE_MAX);
+ gcc_assert (cpu_model->__cpu_subtype < CPU_SUBTYPE_MAX);
+
+ return 0;
+}
VENDOR_INTEL = 1,
VENDOR_AMD,
VENDOR_OTHER,
+ VENDOR_CENTAUR,
+ VENDOR_CYRIX,
+ VENDOR_NSC,
BUILTIN_VENDOR_MAX = VENDOR_OTHER,
VENDOR_MAX
};
P_PROC_DYNAMIC
};
+/* 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,
+ FEATURE_AVX5124VNNIW,
+ FEATURE_AVX5124FMAPS,
+ FEATURE_AVX512VPOPCNTDQ,
+ FEATURE_AVX512VBMI2,
+ FEATURE_GFNI,
+ FEATURE_VPCLMULQDQ,
+ FEATURE_AVX512VNNI,
+ FEATURE_AVX512BITALG,
+ FEATURE_AVX512BF16,
+ FEATURE_AVX512VP2INTERSECT,
+ FEATURE_3DNOW,
+ FEATURE_3DNOWP,
+ FEATURE_ADX,
+ FEATURE_ABM,
+ FEATURE_CLDEMOTE,
+ FEATURE_CLFLUSHOPT,
+ FEATURE_CLWB,
+ FEATURE_CLZERO,
+ FEATURE_CMPXCHG16B,
+ FEATURE_CMPXCHG8B,
+ FEATURE_ENQCMD,
+ FEATURE_F16C,
+ FEATURE_FSGSBASE,
+ FEATURE_FXSAVE,
+ FEATURE_HLE,
+ FEATURE_IBT,
+ FEATURE_LAHF_LM,
+ FEATURE_LM,
+ FEATURE_LWP,
+ FEATURE_LZCNT,
+ FEATURE_MOVBE,
+ FEATURE_MOVDIR64B,
+ FEATURE_MOVDIRI,
+ FEATURE_MWAITX,
+ FEATURE_OSXSAVE,
+ FEATURE_PCONFIG,
+ FEATURE_PKU,
+ FEATURE_PREFETCHWT1,
+ FEATURE_PRFCHW,
+ FEATURE_PTWRITE,
+ FEATURE_RDPID,
+ FEATURE_RDRND,
+ FEATURE_RDSEED,
+ FEATURE_RTM,
+ FEATURE_SERIALIZE,
+ FEATURE_SGX,
+ FEATURE_SHA,
+ FEATURE_SHSTK,
+ FEATURE_TBM,
+ FEATURE_TSXLDTRK,
+ FEATURE_VAES,
+ FEATURE_WAITPKG,
+ FEATURE_WBNOINVD,
+ FEATURE_XSAVE,
+ FEATURE_XSAVEC,
+ FEATURE_XSAVEOPT,
+ FEATURE_XSAVES,
+ CPU_FEATURE_MAX
+};
+
+/* Size of __cpu_features2 array in libgcc/config/i386/cpuinfo.c. */
+#define SIZE_OF_CPU_FEATURES ((CPU_FEATURE_MAX - 1) / 32)
+
/* These are the values for vendor types, cpu types and subtypes. Cpu
types and subtypes should be subtracted by the corresponding start
value. */
}
}
-/* This is the order of bit-fields in __processor_features in cpuinfo.c */
-enum processor_features
-{
- F_CMOV = 0,
- F_MMX,
- F_POPCNT,
- F_SSE,
- F_SSE2,
- F_SSE3,
- F_SSSE3,
- F_SSE4_1,
- F_SSE4_2,
- F_AVX,
- F_AVX2,
- F_SSE4_A,
- F_FMA4,
- F_XOP,
- F_FMA,
- F_AVX512F,
- F_BMI,
- F_BMI2,
- F_AES,
- F_PCLMUL,
- F_AVX512VL,
- F_AVX512BW,
- F_AVX512DQ,
- F_AVX512CD,
- F_AVX512ER,
- F_AVX512PF,
- F_AVX512VBMI,
- F_AVX512IFMA,
- F_AVX5124VNNIW,
- F_AVX5124FMAPS,
- F_AVX512VPOPCNTDQ,
- F_AVX512VBMI2,
- F_GFNI,
- F_VPCLMULQDQ,
- F_AVX512VNNI,
- F_AVX512BITALG,
- F_AVX512BF16,
- F_AVX512VP2INTERSECT,
- F_MAX
-};
-
/* These are the target attribute strings for which a dispatcher is
available, from fold_builtin_cpu. */
struct _isa_names_table
static const _isa_names_table isa_names_table[] =
{
- {"cmov", F_CMOV, P_NONE},
- {"mmx", F_MMX, P_MMX},
- {"popcnt", F_POPCNT, P_POPCNT},
- {"sse", F_SSE, P_SSE},
- {"sse2", F_SSE2, P_SSE2},
- {"sse3", F_SSE3, P_SSE3},
- {"ssse3", F_SSSE3, P_SSSE3},
- {"sse4a", F_SSE4_A, P_SSE4_A},
- {"sse4.1", F_SSE4_1, P_SSE4_1},
- {"sse4.2", F_SSE4_2, P_SSE4_2},
- {"avx", F_AVX, P_AVX},
- {"fma4", F_FMA4, P_FMA4},
- {"xop", F_XOP, P_XOP},
- {"fma", F_FMA, P_FMA},
- {"avx2", F_AVX2, P_AVX2},
- {"avx512f", F_AVX512F, P_AVX512F},
- {"bmi", F_BMI, P_BMI},
- {"bmi2", F_BMI2, P_BMI2},
- {"aes", F_AES, P_AES},
- {"pclmul", F_PCLMUL, P_PCLMUL},
- {"avx512vl",F_AVX512VL, P_NONE},
- {"avx512bw",F_AVX512BW, P_NONE},
- {"avx512dq",F_AVX512DQ, P_NONE},
- {"avx512cd",F_AVX512CD, P_NONE},
- {"avx512er",F_AVX512ER, P_NONE},
- {"avx512pf",F_AVX512PF, P_NONE},
- {"avx512vbmi",F_AVX512VBMI, P_NONE},
- {"avx512ifma",F_AVX512IFMA, P_NONE},
- {"avx5124vnniw",F_AVX5124VNNIW, P_NONE},
- {"avx5124fmaps",F_AVX5124FMAPS, P_NONE},
- {"avx512vpopcntdq",F_AVX512VPOPCNTDQ, P_NONE},
- {"avx512vbmi2", F_AVX512VBMI2, P_NONE},
- {"gfni", F_GFNI, P_NONE},
- {"vpclmulqdq", F_VPCLMULQDQ, P_NONE},
- {"avx512vnni", F_AVX512VNNI, P_NONE},
- {"avx512bitalg", F_AVX512BITALG, P_NONE},
- {"avx512bf16", F_AVX512BF16, P_NONE},
- {"avx512vp2intersect",F_AVX512VP2INTERSECT, P_NONE}
+ {"cmov", FEATURE_CMOV, P_NONE},
+ {"mmx", FEATURE_MMX, P_MMX},
+ {"popcnt", FEATURE_POPCNT, P_POPCNT},
+ {"sse", FEATURE_SSE, P_SSE},
+ {"sse2", FEATURE_SSE2, P_SSE2},
+ {"sse3", FEATURE_SSE3, P_SSE3},
+ {"ssse3", FEATURE_SSSE3, P_SSSE3},
+ {"sse4a", FEATURE_SSE4_A, P_SSE4_A},
+ {"sse4.1", FEATURE_SSE4_1, P_SSE4_1},
+ {"sse4.2", FEATURE_SSE4_2, P_SSE4_2},
+ {"avx", FEATURE_AVX, P_AVX},
+ {"fma4", FEATURE_FMA4, P_FMA4},
+ {"xop", FEATURE_XOP, P_XOP},
+ {"fma", FEATURE_FMA, P_FMA},
+ {"avx2", FEATURE_AVX2, P_AVX2},
+ {"avx512f", FEATURE_AVX512F, P_AVX512F},
+ {"bmi", FEATURE_BMI, P_BMI},
+ {"bmi2", FEATURE_BMI2, P_BMI2},
+ {"aes", FEATURE_AES, P_AES},
+ {"pclmul", FEATURE_PCLMUL, P_PCLMUL},
+ {"avx512vl",FEATURE_AVX512VL, P_NONE},
+ {"avx512bw",FEATURE_AVX512BW, P_NONE},
+ {"avx512dq",FEATURE_AVX512DQ, P_NONE},
+ {"avx512cd",FEATURE_AVX512CD, P_NONE},
+ {"avx512er",FEATURE_AVX512ER, P_NONE},
+ {"avx512pf",FEATURE_AVX512PF, P_NONE},
+ {"avx512vbmi",FEATURE_AVX512VBMI, P_NONE},
+ {"avx512ifma",FEATURE_AVX512IFMA, P_NONE},
+ {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_NONE},
+ {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_NONE},
+ {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ, P_NONE},
+ {"avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE},
+ {"gfni", FEATURE_GFNI, P_NONE},
+ {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE},
+ {"avx512vnni", FEATURE_AVX512VNNI, P_NONE},
+ {"avx512bitalg", FEATURE_AVX512BITALG, P_NONE},
+ {"avx512bf16", FEATURE_AVX512BF16, P_NONE},
+ {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_NONE}
};
/* This parses the attribute arguments to target in DECL and determines
if (isa_names_table[i].feature >= 32)
{
- tree __cpu_features2_var = make_var_decl (unsigned_type_node,
+ tree index_type
+ = build_index_type (size_int (SIZE_OF_CPU_FEATURES));
+ tree type = build_array_type (unsigned_type_node, index_type);
+ tree __cpu_features2_var = make_var_decl (type,
"__cpu_features2");
varpool_node::add (__cpu_features2_var);
- field_val = (1U << (isa_names_table[i].feature - 32));
- /* Return __cpu_features2 & field_val */
- final = build2 (BIT_AND_EXPR, unsigned_type_node,
- __cpu_features2_var,
- build_int_cstu (unsigned_type_node, field_val));
- return build1 (CONVERT_EXPR, integer_type_node, final);
+ for (unsigned int j = 0; j < SIZE_OF_CPU_FEATURES; j++)
+ if (isa_names_table[i].feature < (32 + 32 + j * 32))
+ {
+ field_val = (1U << (isa_names_table[i].feature
+ - (32 + j * 32)));
+ tree index = size_int (j);
+ array_elt = build4 (ARRAY_REF, unsigned_type_node,
+ __cpu_features2_var,
+ index, NULL_TREE, NULL_TREE);
+ /* Return __cpu_features2[index] & field_val */
+ final = build2 (BIT_AND_EXPR, unsigned_type_node,
+ array_elt,
+ build_int_cstu (unsigned_type_node,
+ field_val));
+ return build1 (CONVERT_EXPR, integer_type_node, final);
+ }
}
field = TYPE_FIELDS (__processor_model_type);
#include "cpuid.h"
#include "tsystem.h"
#include "auto-target.h"
-#include "cpuinfo.h"
+#include "common/config/i386/i386-cpuinfo.h"
+#include "common/config/i386/cpuinfo.h"
#ifdef HAVE_INIT_PRIORITY
#define CONSTRUCTOR_PRIORITY (101)
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. */
-
-static void
-get_amd_cpu (unsigned int family, unsigned int model)
-{
- switch (family)
- {
- /* AMD Family 10h. */
- case 0x10:
- __cpu_model.__cpu_type = AMDFAM10H;
- switch (model)
- {
- case 0x2:
- /* Barcelona. */
- __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA;
- break;
- case 0x4:
- /* Shanghai. */
- __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI;
- break;
- case 0x8:
- /* Istanbul. */
- __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL;
- break;
- default:
- break;
- }
- break;
- /* AMD Family 14h "btver1". */
- case 0x14:
- __cpu_model.__cpu_type = AMD_BTVER1;
- break;
- /* AMD Family 15h "Bulldozer". */
- case 0x15:
- __cpu_model.__cpu_type = AMDFAM15H;
-
- if (model == 0x2)
- __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
- /* Bulldozer version 1. */
- else if (model <= 0xf)
- __cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
- /* Bulldozer version 2 "Piledriver" */
- else if (model <= 0x2f)
- __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
- /* Bulldozer version 3 "Steamroller" */
- 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;
- }
-}
-
-/* Get the specific type of Intel CPU. */
-
-static void
-get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
-{
- /* Parse family and model only if brand ID is 0. */
- if (brand_id == 0)
- {
- switch (family)
- {
- case 0x5:
- /* Pentium. */
- break;
- case 0x6:
- switch (model)
- {
- case 0x1c:
- case 0x26:
- /* Bonnell. */
- __cpu_model.__cpu_type = INTEL_BONNELL;
- break;
- case 0x37:
- case 0x4a:
- case 0x4d:
- case 0x5a:
- case 0x5d:
- /* 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 0x2e:
- /* Nehalem. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM;
- break;
- case 0x25:
- case 0x2c:
- case 0x2f:
- /* Westmere. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE;
- break;
- case 0x2a:
- case 0x2d:
- /* Sandy Bridge. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
- break;
- case 0x3a:
- case 0x3e:
- /* Ivy Bridge. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
- break;
- case 0x3c:
- case 0x3f:
- case 0x45:
- case 0x46:
- /* Haswell. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_HASWELL;
- break;
- case 0x3d:
- case 0x47:
- case 0x4f:
- case 0x56:
- /* Broadwell. */
- __cpu_model.__cpu_type = INTEL_COREI7;
- __cpu_model.__cpu_subtype = INTEL_COREI7_BROADWELL;
- break;
- 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. */
- case 0x0f:
- /* Merom. */
- __cpu_model.__cpu_type = INTEL_CORE2;
- break;
- default:
- break;
- }
- break;
- default:
- /* We have no idea. */
- break;
- }
- }
-}
-
-/* ECX and EDX are output of CPUID at level one. MAX_CPUID_LEVEL is
- the max possible level of CPUID insn. */
-static void
-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)
- set_feature (FEATURE_CMOV);
- if (edx & bit_MMX)
- set_feature (FEATURE_MMX);
- if (edx & bit_SSE)
- set_feature (FEATURE_SSE);
- if (edx & bit_SSE2)
- set_feature (FEATURE_SSE2);
- if (ecx & bit_POPCNT)
- set_feature (FEATURE_POPCNT);
- if (ecx & bit_AES)
- set_feature (FEATURE_AES);
- if (ecx & bit_PCLMUL)
- set_feature (FEATURE_PCLMUL);
- if (ecx & bit_SSE3)
- set_feature (FEATURE_SSE3);
- if (ecx & bit_SSSE3)
- set_feature (FEATURE_SSSE3);
- if (ecx & bit_SSE4_1)
- set_feature (FEATURE_SSE4_1);
- if (ecx & bit_SSE4_2)
- 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/1). */
- if (max_cpuid_level >= 7)
- {
- __cpuid_count (7, 0, eax, ebx, ecx, edx);
- if (ebx & bit_BMI)
- set_feature (FEATURE_BMI);
- if (avx_usable)
- {
- if (ebx & bit_AVX2)
- set_feature (FEATURE_AVX2);
- if (ecx & bit_VPCLMULQDQ)
- set_feature (FEATURE_VPCLMULQDQ);
- }
- if (ebx & bit_BMI2)
- set_feature (FEATURE_BMI2);
- if (ecx & bit_GFNI)
- set_feature (FEATURE_GFNI);
- 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_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);
- if (edx & bit_AVX512VP2INTERSECT)
- set_feature (FEATURE_AVX512VP2INTERSECT);
+ in libgcc.a only, preferably hidden.
- __cpuid_count (7, 1, eax, ebx, ecx, edx);
- if (eax & bit_AVX512BF16)
- set_feature (FEATURE_AVX512BF16);
- }
- }
-
- /* Check cpuid level of extended features. */
- __cpuid (0x80000000, ext_level, ebx, ecx, edx);
-
- if (ext_level >= 0x80000001)
- {
- __cpuid (0x80000001, eax, ebx, ecx, edx);
-
- if (ecx & bit_SSE4a)
- 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
-}
+ NB: Since older 386-builtins.c accesses __cpu_features2 as scalar or
+ smaller array, it can only access the first few elements. */
+unsigned int __cpu_features2[SIZE_OF_CPU_FEATURES];
/* A constructor function that is sets __cpu_model and __cpu_features with
the right values. This needs to run only once. This constructor is
int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
__cpu_indicator_init (void)
{
- unsigned int eax, ebx, ecx, edx;
-
- int max_level;
- unsigned int vendor;
- unsigned int model, family, brand_id;
- unsigned int extended_model, extended_family;
-
- /* This function needs to run just once. */
- if (__cpu_model.__cpu_vendor)
- return 0;
-
- /* Assume cpuid insn present. Run in level 0 to get vendor id. */
- if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
- {
- __cpu_model.__cpu_vendor = VENDOR_OTHER;
- return -1;
- }
-
- vendor = ebx;
- max_level = eax;
-
- if (max_level < 1)
- {
- __cpu_model.__cpu_vendor = VENDOR_OTHER;
- return -1;
- }
-
- if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
- {
- __cpu_model.__cpu_vendor = VENDOR_OTHER;
- return -1;
- }
-
- model = (eax >> 4) & 0x0f;
- family = (eax >> 8) & 0x0f;
- brand_id = ebx & 0xff;
- extended_model = (eax >> 12) & 0xf0;
- extended_family = (eax >> 20) & 0xff;
-
- if (vendor == signature_INTEL_ebx)
- {
- /* Adjust model and family for Intel CPUS. */
- if (family == 0x0f)
- {
- family += extended_family;
- model += extended_model;
- }
- else if (family == 0x06)
- model += extended_model;
-
- /* Get CPU type. */
- get_intel_cpu (family, model, brand_id);
- /* Find available features. */
- get_available_features (ecx, edx, max_level);
- __cpu_model.__cpu_vendor = VENDOR_INTEL;
- }
- else if (vendor == signature_AMD_ebx)
- {
- /* Adjust model and family for AMD CPUS. */
- if (family == 0x0f)
- {
- family += extended_family;
- model += extended_model;
- }
-
- /* Get CPU type. */
- get_amd_cpu (family, model);
- /* Find available features. */
- get_available_features (ecx, edx, max_level);
- __cpu_model.__cpu_vendor = VENDOR_AMD;
- }
- else
- __cpu_model.__cpu_vendor = VENDOR_OTHER;
-
- gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
- gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
- gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
-
- return 0;
+ struct __processor_model2 cpu_model2;
+ return cpu_indicator_init (&__cpu_model, &cpu_model2,
+ __cpu_features2);
}
#if defined SHARED && defined USE_ELF_SYMVER
+++ /dev/null
-/* Get CPU type and Features for x86 processors.
- Copyright (C) 2012-2020 Free Software Foundation, Inc.
- Contributed by Sriraman Tallam (tmsriram@google.com)
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-Under Section 7 of GPL version 3, you are granted additional
-permissions described in the GCC Runtime Library Exception, version
-3.1, as published by the Free Software Foundation.
-
-You should have received a copy of the GNU General Public License and
-a copy of the GCC Runtime Library Exception along with this program;
-see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-<http://www.gnu.org/licenses/>. */
-
-/* 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,
- AMDFAM17H,
- INTEL_KNM,
- INTEL_GOLDMONT,
- INTEL_GOLDMONT_PLUS,
- INTEL_TREMONT,
- 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,
- AMDFAM17H_ZNVER1,
- INTEL_COREI7_IVYBRIDGE,
- INTEL_COREI7_HASWELL,
- INTEL_COREI7_BROADWELL,
- INTEL_COREI7_SKYLAKE,
- INTEL_COREI7_SKYLAKE_AVX512,
- INTEL_COREI7_CANNONLAKE,
- INTEL_COREI7_ICELAKE_CLIENT,
- INTEL_COREI7_ICELAKE_SERVER,
- AMDFAM17H_ZNVER2,
- INTEL_COREI7_CASCADELAKE,
- INTEL_COREI7_TIGERLAKE,
- INTEL_COREI7_COOPERLAKE,
- 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,
- FEATURE_AVX5124VNNIW,
- FEATURE_AVX5124FMAPS,
- FEATURE_AVX512VPOPCNTDQ,
- FEATURE_AVX512VBMI2,
- FEATURE_GFNI,
- FEATURE_VPCLMULQDQ,
- FEATURE_AVX512VNNI,
- FEATURE_AVX512BITALG,
- FEATURE_AVX512BF16,
- FEATURE_AVX512VP2INTERSECT
-};
-
-extern struct __processor_model
-{
- unsigned int __cpu_vendor;
- unsigned int __cpu_type;
- unsigned int __cpu_subtype;
- unsigned int __cpu_features[1];
-} __cpu_model;
-extern unsigned int __cpu_features2;