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.
This commit is contained in:
H.J. Lu 2020-05-18 05:58:41 -07:00
parent eb0ff770e2
commit 1890f2f0e2
5 changed files with 1009 additions and 681 deletions

View File

@ -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;
}

View File

@ -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. */

View File

@ -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);

View File

@ -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

View File

@ -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
<http://www.gnu.org/licenses/>. */
/* Processor Vendor and Models. */
enum processor_vendor
{
VENDOR_INTEL = 1,
VENDOR_AMD,
VENDOR_OTHER,
VENDOR_MAX
};
/* Any new types or subtypes have to be inserted at the end. */
enum processor_types
{
INTEL_BONNELL = 1,
INTEL_CORE2,
INTEL_COREI7,
AMDFAM10H,
AMDFAM15H,
INTEL_SILVERMONT,
INTEL_KNL,
AMD_BTVER1,
AMD_BTVER2,
AMDFAM17H,
INTEL_KNM,
INTEL_GOLDMONT,
INTEL_GOLDMONT_PLUS,
INTEL_TREMONT,
CPU_TYPE_MAX
};
enum processor_subtypes
{
INTEL_COREI7_NEHALEM = 1,
INTEL_COREI7_WESTMERE,
INTEL_COREI7_SANDYBRIDGE,
AMDFAM10H_BARCELONA,
AMDFAM10H_SHANGHAI,
AMDFAM10H_ISTANBUL,
AMDFAM15H_BDVER1,
AMDFAM15H_BDVER2,
AMDFAM15H_BDVER3,
AMDFAM15H_BDVER4,
AMDFAM17H_ZNVER1,
INTEL_COREI7_IVYBRIDGE,
INTEL_COREI7_HASWELL,
INTEL_COREI7_BROADWELL,
INTEL_COREI7_SKYLAKE,
INTEL_COREI7_SKYLAKE_AVX512,
INTEL_COREI7_CANNONLAKE,
INTEL_COREI7_ICELAKE_CLIENT,
INTEL_COREI7_ICELAKE_SERVER,
AMDFAM17H_ZNVER2,
INTEL_COREI7_CASCADELAKE,
INTEL_COREI7_TIGERLAKE,
INTEL_COREI7_COOPERLAKE,
CPU_SUBTYPE_MAX
};
/* ISA Features supported. New features have to be inserted at the end. */
enum processor_features
{
FEATURE_CMOV = 0,
FEATURE_MMX,
FEATURE_POPCNT,
FEATURE_SSE,
FEATURE_SSE2,
FEATURE_SSE3,
FEATURE_SSSE3,
FEATURE_SSE4_1,
FEATURE_SSE4_2,
FEATURE_AVX,
FEATURE_AVX2,
FEATURE_SSE4_A,
FEATURE_FMA4,
FEATURE_XOP,
FEATURE_FMA,
FEATURE_AVX512F,
FEATURE_BMI,
FEATURE_BMI2,
FEATURE_AES,
FEATURE_PCLMUL,
FEATURE_AVX512VL,
FEATURE_AVX512BW,
FEATURE_AVX512DQ,
FEATURE_AVX512CD,
FEATURE_AVX512ER,
FEATURE_AVX512PF,
FEATURE_AVX512VBMI,
FEATURE_AVX512IFMA,
FEATURE_AVX5124VNNIW,
FEATURE_AVX5124FMAPS,
FEATURE_AVX512VPOPCNTDQ,
FEATURE_AVX512VBMI2,
FEATURE_GFNI,
FEATURE_VPCLMULQDQ,
FEATURE_AVX512VNNI,
FEATURE_AVX512BITALG,
FEATURE_AVX512BF16,
FEATURE_AVX512VP2INTERSECT
};
extern struct __processor_model
{
unsigned int __cpu_vendor;
unsigned int __cpu_type;
unsigned int __cpu_subtype;
unsigned int __cpu_features[1];
} __cpu_model;
extern unsigned int __cpu_features2;