From 1890f2f0e210ef515c39728c54151372d36dd187 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 18 May 2020 05:58:41 -0700 Subject: [PATCH] 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. --- gcc/common/config/i386/cpuinfo.h | 844 ++++++++++++++++++++++++++ gcc/common/config/i386/i386-cpuinfo.h | 98 +++ gcc/config/i386/i386-builtins.c | 147 ++--- libgcc/config/i386/cpuinfo.c | 465 +------------- libgcc/config/i386/cpuinfo.h | 136 ----- 5 files changed, 1009 insertions(+), 681 deletions(-) create mode 100644 gcc/common/config/i386/cpuinfo.h delete mode 100644 libgcc/config/i386/cpuinfo.h diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h new file mode 100644 index 00000000000..2d72b3b60fd --- /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 +. */ + +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 e11c68f46dd..96cf0eaea47 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. */ diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c index 6f6a8328ef1..57e709d6c43 100644 --- a/gcc/config/i386/i386-builtins.c +++ b/gcc/config/i386/i386-builtins.c @@ -1835,50 +1835,6 @@ ix86_builtin_reciprocal (tree fndecl) } } -/* 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 @@ -1890,44 +1846,44 @@ 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 @@ -2294,16 +2250,29 @@ fold_builtin_cpu (tree fndecl, tree *args) 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); diff --git a/libgcc/config/i386/cpuinfo.c b/libgcc/config/i386/cpuinfo.c index cf5f0884bb4..7218952f32a 100644 --- a/libgcc/config/i386/cpuinfo.c +++ b/libgcc/config/i386/cpuinfo.c @@ -26,7 +26,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #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) @@ -39,386 +40,14 @@ int __cpu_indicator_init (void) 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 + in libgcc.a only, preferably hidden. - -/* 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); - - __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 @@ -429,85 +58,9 @@ get_available_features (unsigned int ecx, unsigned int edx, 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 diff --git a/libgcc/config/i386/cpuinfo.h b/libgcc/config/i386/cpuinfo.h deleted file mode 100644 index 0f97510cde1..00000000000 --- a/libgcc/config/i386/cpuinfo.h +++ /dev/null @@ -1,136 +0,0 @@ -/* 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 -. */ - -/* 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;