diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-05-18 05:58:41 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-06-24 05:47:34 -0700 |
commit | 1890f2f0e210ef515c39728c54151372d36dd187 (patch) | |
tree | e01fa626db371d11f70e951ae7154761b8fa2a57 /gcc/common | |
parent | eb0ff770e29715deb8b2e6f5da736e0c1e8f8d07 (diff) | |
download | gcc-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.h | 844 | ||||
-rw-r--r-- | gcc/common/config/i386/i386-cpuinfo.h | 98 |
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. */ |