aboutsummaryrefslogtreecommitdiff
path: root/gcc/common
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2020-05-18 05:58:41 -0700
committerH.J. Lu <hjl.tools@gmail.com>2020-06-24 05:47:34 -0700
commit1890f2f0e210ef515c39728c54151372d36dd187 (patch)
treee01fa626db371d11f70e951ae7154761b8fa2a57 /gcc/common
parenteb0ff770e29715deb8b2e6f5da736e0c1e8f8d07 (diff)
downloadgcc-1890f2f0e210ef515c39728c54151372d36dd187.zip
gcc-1890f2f0e210ef515c39728c54151372d36dd187.tar.gz
gcc-1890f2f0e210ef515c39728c54151372d36dd187.tar.bz2
x86: Move cpuinfo.h from libgcc to common/config/i386
Both x86 backend and libgcc define enum processor_features. libgcc sets enum processor_feature and x86 backend checks enum processor_feature. They are very easy out of sync and it has happened multiple times in the past. 1. Move cpuinfo.h from libgcc to common/config/i386 so that we can share the same enum processor_features in x86 backend and libgcc. 2. Change __cpu_features2 to an array to support more processor features. 3. Add more processor features to enum processor_features. gcc/ PR target/95259 * common/config/i386/cpuinfo.h: New file. (__processor_model): Moved from libgcc/config/i386/cpuinfo.h. (__processor_model2): New. (CHECK___builtin_cpu_is): New. Defined as empty if not defined. (has_cpu_feature): New function. (set_cpu_feature): Likewise. (get_amd_cpu): Moved from libgcc/config/i386/cpuinfo.c. Use CHECK___builtin_cpu_is. Return AMD CPU name. (get_intel_cpu): Moved from libgcc/config/i386/cpuinfo.c. Use Use CHECK___builtin_cpu_is. Return Intel CPU name. (get_available_features): Moved from libgcc/config/i386/cpuinfo.c. Also check 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 and FEATURE_XSAVES (cpu_indicator_init): Moved from libgcc/config/i386/cpuinfo.c. Also update cpu_model2. * common/config/i386/i386-cpuinfo.h (processor_vendor): Add Add VENDOR_CENTAUR, VENDOR_CYRIX and VENDOR_NSC. (processor_features): Moved from gcc/config/i386/i386-builtins.c. Renamed F_XXX to FEATURE_XXX. Add 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 and CPU_FEATURE_MAX. (SIZE_OF_CPU_FEATURES): New. * config/i386/i386-builtins.c (processor_features): Removed. (isa_names_table): Replace F_XXX with FEATURE_XXX. (fold_builtin_cpu): Change __cpu_features2 to an array. libgcc/ PR target/95259 * config/i386/cpuinfo.c: Don't include "cpuinfo.h". Include "common/config/i386/i386-cpuinfo.h" and "common/config/i386/cpuinfo.h". (__cpu_features2): Changed to array. (get_amd_cpu): Removed. (get_intel_cpu): Likewise. (get_available_features): Likewise. (__cpu_indicator_init): Call cpu_indicator_init. * config/i386/cpuinfo.h: Removed.
Diffstat (limited to 'gcc/common')
-rw-r--r--gcc/common/config/i386/cpuinfo.h844
-rw-r--r--gcc/common/config/i386/i386-cpuinfo.h98
2 files changed, 942 insertions, 0 deletions
diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h
new file mode 100644
index 0000000..2d72b3b
--- /dev/null
+++ b/gcc/common/config/i386/cpuinfo.h
@@ -0,0 +1,844 @@
+/* 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;
+}
diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h
index e11c68f..96cf0ea 100644
--- a/gcc/common/config/i386/i386-cpuinfo.h
+++ b/gcc/common/config/i386/i386-cpuinfo.h
@@ -30,6 +30,9 @@ enum processor_vendor
VENDOR_INTEL = 1,
VENDOR_AMD,
VENDOR_OTHER,
+ VENDOR_CENTAUR,
+ VENDOR_CYRIX,
+ VENDOR_NSC,
BUILTIN_VENDOR_MAX = VENDOR_OTHER,
VENDOR_MAX
};
@@ -122,6 +125,101 @@ enum feature_priority
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. */