diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-06-29 18:30:54 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-09-11 17:20:52 -0700 |
commit | 9620398097de3981c1adf5233e2b3478d36bc1b3 (patch) | |
tree | 20e492ba12ab22a57ed91df3698fdf57eba54810 /sysdeps/x86 | |
parent | a92f4e6299fe0e3cb6f77e79de00817aece501ce (diff) | |
download | glibc-9620398097de3981c1adf5233e2b3478d36bc1b3.tar.gz glibc-9620398097de3981c1adf5233e2b3478d36bc1b3.tar.xz glibc-9620398097de3981c1adf5233e2b3478d36bc1b3.zip |
x86: Install <sys/platform/x86.h> [BZ #26124]
Install <sys/platform/x86.h> so that programmers can do #if __has_include(<sys/platform/x86.h>) #include <sys/platform/x86.h> #endif ... if (CPU_FEATURE_USABLE (SSE2)) ... if (CPU_FEATURE_USABLE (AVX2)) ... <sys/platform/x86.h> exports only: enum { COMMON_CPUID_INDEX_1 = 0, COMMON_CPUID_INDEX_7, COMMON_CPUID_INDEX_80000001, COMMON_CPUID_INDEX_D_ECX_1, COMMON_CPUID_INDEX_80000007, COMMON_CPUID_INDEX_80000008, COMMON_CPUID_INDEX_7_ECX_1, /* Keep the following line at the end. */ COMMON_CPUID_INDEX_MAX }; struct cpuid_features { struct cpuid_registers cpuid; struct cpuid_registers usable; }; struct cpu_features { struct cpu_features_basic basic; struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; }; /* Get a pointer to the CPU features structure. */ extern const struct cpu_features *__x86_get_cpu_features (unsigned int max) __attribute__ ((const)); Since all feature checks are done through macros, programs compiled with a newer <sys/platform/x86.h> are compatible with the older glibc binaries as long as the layout of struct cpu_features is identical. The features array can be expanded with backward binary compatibility for both .o and .so files. When COMMON_CPUID_INDEX_MAX is increased to support new processor features, __x86_get_cpu_features in the older glibc binaries returns NULL and HAS_CPU_FEATURE/CPU_FEATURE_USABLE return false on the new processor feature. No new symbol version is neeeded. Both CPU_FEATURE_USABLE and HAS_CPU_FEATURE are provided. HAS_CPU_FEATURE can be used to identify processor features. Note: Although GCC has __builtin_cpu_supports, it only supports a subset of <sys/platform/x86.h> and it is equivalent to CPU_FEATURE_USABLE. It doesn't support HAS_CPU_FEATURE.
Diffstat (limited to 'sysdeps/x86')
-rw-r--r-- | sysdeps/x86/Makefile | 4 | ||||
-rw-r--r-- | sysdeps/x86/Versions | 4 | ||||
-rw-r--r-- | sysdeps/x86/dl-get-cpu-features.c | 6 | ||||
-rw-r--r-- | sysdeps/x86/include/cpu-features.h | 183 | ||||
-rw-r--r-- | sysdeps/x86/sys/platform/x86.h (renamed from sysdeps/x86/cpu-features.h) | 150 | ||||
-rw-r--r-- | sysdeps/x86/tst-cpu-features-cpuinfo.c | 250 | ||||
-rw-r--r-- | sysdeps/x86/tst-cpu-features-supports.c | 192 | ||||
-rw-r--r-- | sysdeps/x86/tst-get-cpu-features.c | 6 |
8 files changed, 654 insertions, 141 deletions
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index a6736aef25..c369faf00d 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -4,8 +4,10 @@ endif ifeq ($(subdir),elf) sysdep-dl-routines += dl-get-cpu-features +sysdep_headers += sys/platform/x86.h -tests += tst-get-cpu-features tst-get-cpu-features-static +tests += tst-get-cpu-features tst-get-cpu-features-static \ + tst-cpu-features-cpuinfo tst-cpu-features-supports tests-static += tst-get-cpu-features-static endif diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions index e02923708e..59db578a9d 100644 --- a/sysdeps/x86/Versions +++ b/sysdeps/x86/Versions @@ -1,5 +1,5 @@ ld { - GLIBC_PRIVATE { - __get_cpu_features; + GLIBC_2.33 { + __x86_get_cpu_features; } } diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c index 9d61cd56be..5f9e46b0c6 100644 --- a/sysdeps/x86/dl-get-cpu-features.c +++ b/sysdeps/x86/dl-get-cpu-features.c @@ -18,10 +18,12 @@ #include <ldsodefs.h> -#undef __get_cpu_features +#undef __x86_get_cpu_features const struct cpu_features * -__get_cpu_features (void) +__x86_get_cpu_features (unsigned int max) { + if (max > COMMON_CPUID_INDEX_MAX) + return NULL; return &GLRO(dl_x86_cpu_features); } diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h new file mode 100644 index 0000000000..dcf29b6fe8 --- /dev/null +++ b/sysdeps/x86/include/cpu-features.h @@ -0,0 +1,183 @@ +/* Data structure for x86 CPU features. + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _PRIVATE_CPU_FEATURES_H +#define _PRIVATE_CPU_FEATURES_H 1 + +#ifdef _CPU_FEATURES_H +# error this should be impossible +#endif + +#ifndef _ISOMAC +/* Get most of the contents from the public header, but we define a + different `struct cpu_features' type for private use. */ +# define cpu_features cpu_features_public +# define __x86_get_cpu_features __x86_get_cpu_features_public +#endif + +#include <sysdeps/x86/sys/platform/x86.h> + +#ifndef _ISOMAC + +# undef cpu_features +# undef __x86_get_cpu_features +# define __get_cpu_features() __x86_get_cpu_features (0) + +enum +{ + /* The integer bit array index for the first set of preferred feature + bits. */ + PREFERRED_FEATURE_INDEX_1 = 0, + /* The current maximum size of the feature integer bit array. */ + PREFERRED_FEATURE_INDEX_MAX +}; + +/* Only used directly in cpu-features.c. */ +# define CPU_FEATURE_SET(ptr, name) \ + ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; +# define CPU_FEATURE_UNSET(ptr, name) \ + ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; +# define CPU_FEATURE_SET_USABLE(ptr, name) \ + ptr->features[index_cpu_##name].usable.reg_##name \ + |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; +# define CPU_FEATURE_PREFERRED_P(ptr, name) \ + ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) +# define CPU_FEATURE_CPU_P(ptr, name) \ + CPU_FEATURE_CHECK_P (ptr, name, cpuid) + +/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ +# undef HAS_CPU_FEATURE +# define HAS_CPU_FEATURE(name) \ + CPU_FEATURE_CPU_P (__x86_get_cpu_features (0), name) +/* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ +# undef CPU_FEATURE_USABLE +# define CPU_FEATURE_USABLE(name) \ + CPU_FEATURE_USABLE_P (__x86_get_cpu_features (0), name) +/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at + runtime. */ +# define CPU_FEATURE_PREFERRED(name) \ + CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) + +# define CPU_FEATURES_CPU_P(ptr, name) \ + CPU_FEATURE_CPU_P (ptr, name) +# define CPU_FEATURES_ARCH_P(ptr, name) \ + CPU_FEATURE_PREFERRED_P (ptr, name) +# define HAS_ARCH_FEATURE(name) \ + CPU_FEATURE_PREFERRED (name) + +/* PREFERRED_FEATURE_INDEX_1. */ +# define bit_arch_I586 (1u << 0) +# define bit_arch_I686 (1u << 1) +# define bit_arch_Fast_Rep_String (1u << 2) +# define bit_arch_Fast_Copy_Backward (1u << 3) +# define bit_arch_Fast_Unaligned_Load (1u << 4) +# define bit_arch_Fast_Unaligned_Copy (1u << 5) +# define bit_arch_Slow_BSF (1u << 6) +# define bit_arch_Slow_SSE4_2 (1u << 7) +# define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) +# define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) +# define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) +# define bit_arch_Prefer_No_VZEROUPPER (1u << 11) +# define bit_arch_Prefer_ERMS (1u << 12) +# define bit_arch_Prefer_FSRM (1u << 13) +# define bit_arch_Prefer_No_AVX512 (1u << 14) +# define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) + +# define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 +# define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 +# define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 +# define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 +# define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 +# define index_arch_I586 PREFERRED_FEATURE_INDEX_1 +# define index_arch_I686 PREFERRED_FEATURE_INDEX_1 +# define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 +# define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +# define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +# define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 + +/* XCR0 Feature flags. */ +# define bit_XMM_state (1u << 1) +# define bit_YMM_state (1u << 2) +# define bit_Opmask_state (1u << 5) +# define bit_ZMM0_15_state (1u << 6) +# define bit_ZMM16_31_state (1u << 7) +# define bit_XTILECFG_state (1u << 17) +# define bit_XTILEDATA_state (1u << 18) + +struct cpu_features +{ + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use + + sub xsave_state_size_offset(%rip) %RSP_LP + + in _dl_runtime_resolve. */ + unsigned long int xsave_state_size; + /* The full state size for XSAVE when XSAVEC is disabled by + + GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC + */ + unsigned int xsave_state_full_size; + /* Data cache size for use in memory and string routines, typically + L1 size. */ + unsigned long int data_cache_size; + /* Shared cache size for use in memory and string routines, typically + L2 or L3 size. */ + unsigned long int shared_cache_size; + /* Threshold to use non temporal store. */ + unsigned long int non_temporal_threshold; + /* Threshold to use "rep movsb". */ + unsigned long int rep_movsb_threshold; + /* Threshold to use "rep stosb". */ + unsigned long int rep_stosb_threshold; +}; + +# if defined (_LIBC) && !IS_IN (nonlib) +/* Unused for x86. */ +# define INIT_ARCH() +# define __x86_get_cpu_features(max) (&GLRO(dl_x86_cpu_features)) +# endif + +# ifdef __x86_64__ +# define HAS_CPUID 1 +# elif (defined __i586__ || defined __pentium__ \ + || defined __geode__ || defined __k6__) +# define HAS_CPUID 1 +# define HAS_I586 1 +# define HAS_I686 HAS_ARCH_FEATURE (I686) +# elif defined __i486__ +# define HAS_CPUID 0 +# define HAS_I586 HAS_ARCH_FEATURE (I586) +# define HAS_I686 HAS_ARCH_FEATURE (I686) +# else +# define HAS_CPUID 1 +# define HAS_I586 1 +# define HAS_I686 1 +# endif + +#endif /* !_ISOMAC */ + +#endif /* include/cpu-features.h */ diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/sys/platform/x86.h index 78fcec251e..bf3727ebc0 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/sys/platform/x86.h @@ -1,4 +1,5 @@ -/* This file is part of the GNU C Library. +/* Data structure for x86 CPU features. + This file is part of the GNU C Library. Copyright (C) 2008-2020 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or @@ -15,17 +16,8 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#ifndef cpu_features_h -#define cpu_features_h - -enum -{ - /* The integer bit array index for the first set of preferred feature - bits. */ - PREFERRED_FEATURE_INDEX_1 = 0, - /* The current maximum size of the feature integer bit array. */ - PREFERRED_FEATURE_INDEX_MAX -}; +#ifndef _SYS_PLATFORM_X86_H +#define _SYS_PLATFORM_X86_H enum { @@ -76,73 +68,32 @@ struct cpu_features { struct cpu_features_basic basic; struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; - unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; - /* The state size for XSAVEC or XSAVE. The type must be unsigned long - int so that we use - - sub xsave_state_size_offset(%rip) %RSP_LP - - in _dl_runtime_resolve. */ - unsigned long int xsave_state_size; - /* The full state size for XSAVE when XSAVEC is disabled by - - GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC - */ - unsigned int xsave_state_full_size; - /* Data cache size for use in memory and string routines, typically - L1 size. */ - unsigned long int data_cache_size; - /* Shared cache size for use in memory and string routines, typically - L2 or L3 size. */ - unsigned long int shared_cache_size; - /* Threshold to use non temporal store. */ - unsigned long int non_temporal_threshold; - /* Threshold to use "rep movsb". */ - unsigned long int rep_movsb_threshold; - /* Threshold to use "rep stosb". */ - unsigned long int rep_stosb_threshold; }; -/* Used from outside of glibc to get access to the CPU features - structure. */ -extern const struct cpu_features *__get_cpu_features (void) +/* Get a pointer to the CPU features structure. */ +extern const struct cpu_features *__x86_get_cpu_features (unsigned int) __attribute__ ((const)); -/* Only used directly in cpu-features.c. */ #define CPU_FEATURE_CHECK_P(ptr, name, check) \ ((ptr->features[index_cpu_##name].check.reg_##name \ & bit_cpu_##name) != 0) -#define CPU_FEATURE_SET(ptr, name) \ - ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; -#define CPU_FEATURE_UNSET(ptr, name) \ - ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; -#define CPU_FEATURE_SET_USABLE(ptr, name) \ - ptr->features[index_cpu_##name].usable.reg_##name \ - |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; -#define CPU_FEATURE_PREFERRED_P(ptr, name) \ - ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) #define CPU_FEATURE_CPU_P(ptr, name) \ CPU_FEATURE_CHECK_P (ptr, name, cpuid) #define CPU_FEATURE_USABLE_P(ptr, name) \ CPU_FEATURE_CHECK_P (ptr, name, usable) /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ -#define HAS_CPU_FEATURE(name) \ - CPU_FEATURE_CPU_P (__get_cpu_features (), name) +#define HAS_CPU_FEATURE(name) \ + (__extension__ \ + ({ const struct cpu_features *__ptr = \ + __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ + __ptr && CPU_FEATURE_CPU_P (__ptr, name); })) /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ -#define CPU_FEATURE_USABLE(name) \ - CPU_FEATURE_USABLE_P (__get_cpu_features (), name) -/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at - runtime. */ -#define CPU_FEATURE_PREFERRED(name) \ - CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) - -#define CPU_FEATURES_CPU_P(ptr, name) \ - CPU_FEATURE_CPU_P (ptr, name) -#define CPU_FEATURES_ARCH_P(ptr, name) \ - CPU_FEATURE_PREFERRED_P (ptr, name) -#define HAS_ARCH_FEATURE(name) \ - CPU_FEATURE_PREFERRED (name) +#define CPU_FEATURE_USABLE(name) \ + (__extension__ \ + ({ const struct cpu_features *__ptr = \ + __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ + __ptr && CPU_FEATURE_USABLE_P (__ptr, name); })) /* CPU features. */ @@ -787,71 +738,4 @@ extern const struct cpu_features *__get_cpu_features (void) /* EAX. */ #define reg_AVX512_BF16 eax -/* FEATURE_INDEX_2. */ -#define bit_arch_I586 (1u << 0) -#define bit_arch_I686 (1u << 1) -#define bit_arch_Fast_Rep_String (1u << 2) -#define bit_arch_Fast_Copy_Backward (1u << 3) -#define bit_arch_Fast_Unaligned_Load (1u << 4) -#define bit_arch_Fast_Unaligned_Copy (1u << 5) -#define bit_arch_Slow_BSF (1u << 6) -#define bit_arch_Slow_SSE4_2 (1u << 7) -#define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) -#define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) -#define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) -#define bit_arch_Prefer_No_VZEROUPPER (1u << 11) -#define bit_arch_Prefer_ERMS (1u << 12) -#define bit_arch_Prefer_FSRM (1u << 13) -#define bit_arch_Prefer_No_AVX512 (1u << 14) -#define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) - -#define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 -#define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 -#define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 -#define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 -#define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 -#define index_arch_I586 PREFERRED_FEATURE_INDEX_1 -#define index_arch_I686 PREFERRED_FEATURE_INDEX_1 -#define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 -#define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 -#define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 -#define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 - -/* XCR0 Feature flags. */ -#define bit_XMM_state (1u << 1) -#define bit_YMM_state (1u << 2) -#define bit_Opmask_state (1u << 5) -#define bit_ZMM0_15_state (1u << 6) -#define bit_ZMM16_31_state (1u << 7) -#define bit_XTILECFG_state (1u << 17) -#define bit_XTILEDATA_state (1u << 18) - -# if defined (_LIBC) && !IS_IN (nonlib) -/* Unused for x86. */ -# define INIT_ARCH() -# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) -# endif - -#ifdef __x86_64__ -# define HAS_CPUID 1 -#elif (defined __i586__ || defined __pentium__ \ - || defined __geode__ || defined __k6__) -# define HAS_CPUID 1 -# define HAS_I586 1 -# define HAS_I686 HAS_ARCH_FEATURE (I686) -#elif defined __i486__ -# define HAS_CPUID 0 -# define HAS_I586 HAS_ARCH_FEATURE (I586) -# define HAS_I686 HAS_ARCH_FEATURE (I686) -#else -# define HAS_CPUID 1 -# define HAS_I586 1 -# define HAS_I686 1 -#endif - -#endif /* cpu_features_h */ +#endif /* _SYS_PLATFORM_X86_H */ diff --git a/sysdeps/x86/tst-cpu-features-cpuinfo.c b/sysdeps/x86/tst-cpu-features-cpuinfo.c new file mode 100644 index 0000000000..96277284d1 --- /dev/null +++ b/sysdeps/x86/tst-cpu-features-cpuinfo.c @@ -0,0 +1,250 @@ +/* Test CPU feature data against /proc/cpuinfo. + This file is part of the GNU C Library. + Copyright (C) 2012-2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <sys/platform/x86.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char *cpu_flags; + +/* Search for flags in /proc/cpuinfo and store line + in cpu_flags. */ +void +get_cpuinfo (void) +{ + FILE *f; + char *line = NULL; + size_t len = 0; + ssize_t read; + + f = fopen ("/proc/cpuinfo", "r"); + if (f == NULL) + { + printf ("cannot open /proc/cpuinfo\n"); + exit (1); + } + + while ((read = getline (&line, &len, f)) != -1) + { + if (strncmp (line, "flags", 5) == 0) + { + cpu_flags = strdup (line); + break; + } + } + fclose (f); + free (line); +} + +int +check_proc (const char *proc_name, int flag, int usable, const char *name) +{ + int found = 0; + + printf ("Checking %s:\n", name); + if (!usable) + { + printf (" %s: insufficient usable info, skipped\n", name); + return 0; + } + printf (" %s: %d\n", name, flag); + if (strstr (cpu_flags, proc_name) != NULL) + found = 1; + printf (" cpuinfo (%s): %d\n", proc_name, found); + + if (found != flag) + printf (" *** failure ***\n"); + + return (found != flag); +} + +#define CHECK_PROC(str, name) \ + check_proc (#str, HAS_CPU_FEATURE (name), CPU_FEATURE_USABLE (name), \ + "HAS_CPU_FEATURE (" #name ")"); + +static int +do_test (int argc, char **argv) +{ + int fails = 0; + + get_cpuinfo (); + fails += CHECK_PROC (acpi, ACPI); + fails += CHECK_PROC (adx, ADX); + fails += CHECK_PROC (apic, APIC); + fails += CHECK_PROC (aes, AES); + fails += CHECK_PROC (amx_bf16, AMX_BF16); + fails += CHECK_PROC (amx_int8, AMX_INT8); + fails += CHECK_PROC (amx_tile, AMX_TILE); + fails += CHECK_PROC (arch_capabilities, ARCH_CAPABILITIES); + fails += CHECK_PROC (avx, AVX); + fails += CHECK_PROC (avx2, AVX2); + fails += CHECK_PROC (avx512_4fmaps, AVX512_4FMAPS); + fails += CHECK_PROC (avx512_4vnniw, AVX512_4VNNIW); + fails += CHECK_PROC (avx512_bf16, AVX512_BF16); + fails += CHECK_PROC (avx512_bitalg, AVX512_BITALG); + fails += CHECK_PROC (avx512ifma, AVX512_IFMA); + fails += CHECK_PROC (avx512_vbmi, AVX512_VBMI); + fails += CHECK_PROC (avx512_vbmi2, AVX512_VBMI2); + fails += CHECK_PROC (avx512_vnni, AVX512_VNNI); + fails += CHECK_PROC (avx512_vp2intersect, AVX512_VP2INTERSECT); + fails += CHECK_PROC (avx512_vpopcntdq, AVX512_VPOPCNTDQ); + fails += CHECK_PROC (avx512bw, AVX512BW); + fails += CHECK_PROC (avx512cd, AVX512CD); + fails += CHECK_PROC (avx512er, AVX512ER); + fails += CHECK_PROC (avx512dq, AVX512DQ); + fails += CHECK_PROC (avx512f, AVX512F); + fails += CHECK_PROC (avx512pf, AVX512PF); + fails += CHECK_PROC (avx512vl, AVX512VL); + fails += CHECK_PROC (bmi1, BMI1); + fails += CHECK_PROC (bmi2, BMI2); + fails += CHECK_PROC (cldemote, CLDEMOTE); + fails += CHECK_PROC (clflushopt, CLFLUSHOPT); + fails += CHECK_PROC (clflush, CLFSH); + fails += CHECK_PROC (clwb, CLWB); + fails += CHECK_PROC (cmov, CMOV); + fails += CHECK_PROC (cx16, CMPXCHG16B); + fails += CHECK_PROC (cnxt_id, CNXT_ID); + fails += CHECK_PROC (core_capabilities, CORE_CAPABILITIES); + fails += CHECK_PROC (cx8, CX8); + fails += CHECK_PROC (dca, DCA); + fails += CHECK_PROC (de, DE); + fails += CHECK_PROC (zero_fcs_fds, DEPR_FPU_CS_DS); + fails += CHECK_PROC (ds, DS); + fails += CHECK_PROC (ds_cpl, DS_CPL); + fails += CHECK_PROC (dtes64, DTES64); + fails += CHECK_PROC (est, EIST); + fails += CHECK_PROC (enqcmd, ENQCMD); + fails += CHECK_PROC (erms, ERMS); + fails += CHECK_PROC (f16c, F16C); + fails += CHECK_PROC (fma, FMA); + fails += CHECK_PROC (fma4, FMA4); + fails += CHECK_PROC (fpu, FPU); + fails += CHECK_PROC (fsgsbase, FSGSBASE); + fails += CHECK_PROC (fsrm, FSRM); + fails += CHECK_PROC (fxsr, FXSR); + fails += CHECK_PROC (gfni, GFNI); + fails += CHECK_PROC (hle, HLE); + fails += CHECK_PROC (ht, HTT); + fails += CHECK_PROC (hybrid, HYBRID); + fails += CHECK_PROC (ibrs, IBRS_IBPB); + fails += CHECK_PROC (ibt, IBT); + fails += CHECK_PROC (invariant_tsc, INVARIANT_TSC); + fails += CHECK_PROC (invpcid, INVPCID); + fails += CHECK_PROC (flush_l1d, L1D_FLUSH); + fails += CHECK_PROC (lahf_lm, LAHF64_SAHF64); + fails += CHECK_PROC (lm, LM); + fails += CHECK_PROC (lwp, LWP); + fails += CHECK_PROC (abm, LZCNT); + fails += CHECK_PROC (mca, MCA); + fails += CHECK_PROC (mce, MCE); + fails += CHECK_PROC (md_clear, MD_CLEAR); + fails += CHECK_PROC (mmx, MMX); + fails += CHECK_PROC (monitor, MONITOR); + fails += CHECK_PROC (movbe, MOVBE); + fails += CHECK_PROC (movdiri, MOVDIRI); + fails += CHECK_PROC (movdir64b, MOVDIR64B); + fails += CHECK_PROC (mpx, MPX); + fails += CHECK_PROC (msr, MSR); + fails += CHECK_PROC (mtrr, MTRR); + fails += CHECK_PROC (nx, NX); + fails += CHECK_PROC (ospke, OSPKE); +#if 0 + /* NB: /proc/cpuinfo doesn't report this feature. */ + fails += CHECK_PROC (osxsave, OSXSAVE); +#endif + fails += CHECK_PROC (pae, PAE); + fails += CHECK_PROC (pdpe1gb, PAGE1GB); + fails += CHECK_PROC (pat, PAT); + fails += CHECK_PROC (pbe, PBE); + fails += CHECK_PROC (pcid, PCID); + fails += CHECK_PROC (pclmulqdq, PCLMULQDQ); + fails += CHECK_PROC (pconfig, PCONFIG); + fails += CHECK_PROC (pdcm, PDCM); + fails += CHECK_PROC (pge, PGE); + fails += CHECK_PROC (pks, PKS); + fails += CHECK_PROC (pku, PKU); + fails += CHECK_PROC (popcnt, POPCNT); + fails += CHECK_PROC (3dnowprefetch, PREFETCHW); + fails += CHECK_PROC (prefetchwt1, PREFETCHWT1); + fails += CHECK_PROC (pse, PSE); + fails += CHECK_PROC (pse36, PSE_36); + fails += CHECK_PROC (psn, PSN); + fails += CHECK_PROC (rdpid, RDPID); + fails += CHECK_PROC (rdrand, RDRAND); + fails += CHECK_PROC (rdseed, RDSEED); + fails += CHECK_PROC (rdt_a, RDT_A); + fails += CHECK_PROC (cqm, RDT_M); + fails += CHECK_PROC (rdtscp, RDTSCP); + fails += CHECK_PROC (rtm, RTM); + fails += CHECK_PROC (sdbg, SDBG); + fails += CHECK_PROC (sep, SEP); + fails += CHECK_PROC (serialize, SERIALIZE); + fails += CHECK_PROC (sgx, SGX); + fails += CHECK_PROC (sgx_lc, SGX_LC); + fails += CHECK_PROC (sha_ni, SHA); + fails += CHECK_PROC (shstk, SHSTK); + fails += CHECK_PROC (smap, SMAP); + fails += CHECK_PROC (smep, SMEP); + fails += CHECK_PROC (smx, SMX); + fails += CHECK_PROC (ss, SS); + fails += CHECK_PROC (ssbd, SSBD); + fails += CHECK_PROC (sse, SSE); + fails += CHECK_PROC (sse2, SSE2); + fails += CHECK_PROC (sse3, SSE3); + fails += CHECK_PROC (sse4_1, SSE4_1); + fails += CHECK_PROC (sse4_2, SSE4_2); + fails += CHECK_PROC (sse4a, SSE4A); + fails += CHECK_PROC (ssse3, SSSE3); + fails += CHECK_PROC (stibp, STIBP); + fails += CHECK_PROC (svm, SVM); +#ifdef __x86_64__ + /* NB: SYSCALL_SYSRET is 64-bit only. */ + fails += CHECK_PROC (syscall, SYSCALL_SYSRET); +#endif + fails += CHECK_PROC (tbm, TBM); + fails += CHECK_PROC (tm, TM); + fails += CHECK_PROC (tm2, TM2); + fails += CHECK_PROC (intel_pt, TRACE); + fails += CHECK_PROC (tsc, TSC); + fails += CHECK_PROC (tsc_adjust, TSC_ADJUST); + fails += CHECK_PROC (tsc_deadline, TSC_DEADLINE); + fails += CHECK_PROC (tsxldtrk, TSXLDTRK); + fails += CHECK_PROC (umip, UMIP); + fails += CHECK_PROC (vaes, VAES); + fails += CHECK_PROC (vme, VME); + fails += CHECK_PROC (vmx, VMX); + fails += CHECK_PROC (vpclmulqdq, VPCLMULQDQ); + fails += CHECK_PROC (waitpkg, WAITPKG); + fails += CHECK_PROC (wbnoinvd, WBNOINVD); + fails += CHECK_PROC (x2apic, X2APIC); + fails += CHECK_PROC (xfd, XFD); + fails += CHECK_PROC (xgetbv1, XGETBV_ECX_1); + fails += CHECK_PROC (xop, XOP); + fails += CHECK_PROC (xsave, XSAVE); + fails += CHECK_PROC (xsavec, XSAVEC); + fails += CHECK_PROC (xsaveopt, XSAVEOPT); + fails += CHECK_PROC (xsaves, XSAVES); + fails += CHECK_PROC (xtpr, XTPRUPDCTRL); + + printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); + + return (fails != 0); +} + +#include "../../../test-skeleton.c" diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c new file mode 100644 index 0000000000..bf881b531f --- /dev/null +++ b/sysdeps/x86/tst-cpu-features-supports.c @@ -0,0 +1,192 @@ +/* Test CPU feature data against __builtin_cpu_supports. + This file is part of the GNU C Library. + Copyright (C) 2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <sys/platform/x86.h> +#include <stdio.h> + +int +check_supports (int supports, int usable, const char *supports_name, + const char *name) +{ + printf ("Checking %s:\n", name); + printf (" %s: %d\n", name, usable); + printf (" __builtin_cpu_supports (%s): %d\n", + supports_name, supports); + + if ((supports != 0) != (usable != 0)) + { + printf (" *** failure ***\n"); + return 1; + } + + return 0; +} + +#define CHECK_SUPPORTS(str, name) \ + check_supports (__builtin_cpu_supports (#str), \ + CPU_FEATURE_USABLE (name), \ + #str, "HAS_CPU_FEATURE (" #name ")"); + +static int +do_test (int argc, char **argv) +{ + int fails = 0; + +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (adx, ADX); +#endif +#if __GNUC_PREREQ (6, 0) + fails += CHECK_SUPPORTS (aes, AES); +#endif +#if __GNUC_PREREQ (11, 1) + fails += CHECK_SUPPORTS (amx_bf16, AMX_BF16); + fails += CHECK_SUPPORTS (amx_int8, AMX_INT8); + fails += CHECK_SUPPORTS (amx_tile, AMX_TILE); +#endif + fails += CHECK_SUPPORTS (avx, AVX); + fails += CHECK_SUPPORTS (avx2, AVX2); +#if __GNUC_PREREQ (7, 0) + fails += CHECK_SUPPORTS (avx5124fmaps, AVX512_4FMAPS); + fails += CHECK_SUPPORTS (avx5124vnniw, AVX512_4VNNIW); +#endif +#if __GNUC_PREREQ (10, 0) + fails += CHECK_SUPPORTS (avx512bf16, AVX512_BF16); +#endif +#if __GNUC_PREREQ (8, 0) + fails += CHECK_SUPPORTS (avx512bitalg, AVX512_BITALG); +#endif +#if __GNUC_PREREQ (6, 0) + fails += CHECK_SUPPORTS (avx512ifma, AVX512_IFMA); + fails += CHECK_SUPPORTS (avx512vbmi, AVX512_VBMI); +#endif +#if __GNUC_PREREQ (8, 0) + fails += CHECK_SUPPORTS (avx512vbmi2, AVX512_VBMI2); + fails += CHECK_SUPPORTS (avx512vnni, AVX512_VNNI); +#endif +#if __GNUC_PREREQ (10, 0) + fails += CHECK_SUPPORTS (avx512vp2intersect, AVX512_VP2INTERSECT); +#endif +#if __GNUC_PREREQ (7, 0) + fails += CHECK_SUPPORTS (avx512vpopcntdq, AVX512_VPOPCNTDQ); +#endif +#if __GNUC_PREREQ (6, 0) + fails += CHECK_SUPPORTS (avx512bw, AVX512BW); + fails += CHECK_SUPPORTS (avx512cd, AVX512CD); + fails += CHECK_SUPPORTS (avx512er, AVX512ER); + fails += CHECK_SUPPORTS (avx512dq, AVX512DQ); +#endif +#if __GNUC_PREREQ (5, 0) + fails += CHECK_SUPPORTS (avx512f, AVX512F); +#endif +#if __GNUC_PREREQ (6, 0) + fails += CHECK_SUPPORTS (avx512pf, AVX512PF); + fails += CHECK_SUPPORTS (avx512vl, AVX512VL); +#endif +#if __GNUC_PREREQ (5, 0) + fails += CHECK_SUPPORTS (bmi, BMI1); + fails += CHECK_SUPPORTS (bmi2, BMI2); +#endif +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (cldemote, CLDEMOTE); + fails += CHECK_SUPPORTS (clflushopt, CLFLUSHOPT); + fails += CHECK_SUPPORTS (clwb, CLWB); +#endif + fails += CHECK_SUPPORTS (cmov, CMOV); +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (cmpxchg16b, CMPXCHG16B); + fails += CHECK_SUPPORTS (cmpxchg8b, CX8); + fails += CHECK_SUPPORTS (enqcmd, ENQCMD); + fails += CHECK_SUPPORTS (f16c, F16C); +#endif +#if __GNUC_PREREQ (4, 9) + fails += CHECK_SUPPORTS (fma, FMA); + fails += CHECK_SUPPORTS (fma4, FMA4); +#endif +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE); + fails += CHECK_SUPPORTS (fxsave, FXSR); +#endif +#if __GNUC_PREREQ (8, 0) + fails += CHECK_SUPPORTS (gfni, GFNI); +#endif +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (hle, HLE); + fails += CHECK_SUPPORTS (ibt, IBT); + fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64); + fails += CHECK_SUPPORTS (lm, LM); + fails += CHECK_SUPPORTS (lwp, LWP); + fails += CHECK_SUPPORTS (lzcnt, LZCNT); +#endif + fails += CHECK_SUPPORTS (mmx, MMX); +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (movbe, MOVBE); + fails += CHECK_SUPPORTS (movdiri, MOVDIRI); + fails += CHECK_SUPPORTS (movdir64b, MOVDIR64B); + fails += CHECK_SUPPORTS (osxsave, OSXSAVE); + fails += CHECK_SUPPORTS (pconfig, PCONFIG); + fails += CHECK_SUPPORTS (pku, PKU); +#endif + fails += CHECK_SUPPORTS (popcnt, POPCNT); +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (prefetchwt1, PREFETCHWT1); + fails += CHECK_SUPPORTS (rdpid, RDPID); + fails += CHECK_SUPPORTS (rdrnd, RDRAND); + fails += CHECK_SUPPORTS (rdseed, RDSEED); + fails += CHECK_SUPPORTS (rtm, RTM); + fails += CHECK_SUPPORTS (serialize, SERIALIZE); + fails += CHECK_SUPPORTS (sha, SHA); + fails += CHECK_SUPPORTS (shstk, SHSTK); +#endif + fails += CHECK_SUPPORTS (sse, SSE); + fails += CHECK_SUPPORTS (sse2, SSE2); + fails += CHECK_SUPPORTS (sse3, SSE3); + fails += CHECK_SUPPORTS (sse4.1, SSE4_1); + fails += CHECK_SUPPORTS (sse4.2, SSE4_2); +#if __GNUC_PREREQ (4, 9) + fails += CHECK_SUPPORTS (sse4a, SSE4A); +#endif + fails += CHECK_SUPPORTS (ssse3, SSSE3); +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (tbm, TBM); + fails += CHECK_SUPPORTS (tsxldtrk, TSXLDTRK); + fails += CHECK_SUPPORTS (vaes, VAES); +#endif +#if __GNUC_PREREQ (8, 0) + fails += CHECK_SUPPORTS (vpclmulqdq, VPCLMULQDQ); +#endif +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (waitpkg, WAITPKG); + fails += CHECK_SUPPORTS (wbnoinvd, WBNOINVD); +#endif +#if __GNUC_PREREQ (4, 9) + fails += CHECK_SUPPORTS (xop, XOP); +#endif +#if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (xsave, XSAVE); + fails += CHECK_SUPPORTS (xsavec, XSAVEC); + fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT); + fails += CHECK_SUPPORTS (xsaves, XSAVES); +#endif + + printf ("%d differences between __builtin_cpu_supports and glibc code.\n", + fails); + + return (fails != 0); +} + +#include "../../../test-skeleton.c" diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c index 6bfdef0829..3447d17e23 100644 --- a/sysdeps/x86/tst-get-cpu-features.c +++ b/sysdeps/x86/tst-get-cpu-features.c @@ -1,4 +1,4 @@ -/* Test case for x86 __get_cpu_features interface +/* Test case for __x86_get_cpu_features interface Copyright (C) 2015-2020 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -18,7 +18,7 @@ #include <stdlib.h> #include <stdio.h> -#include <cpu-features.h> +#include <sys/platform/x86.h> #include <support/check.h> #define CHECK_CPU_FEATURE(name) \ @@ -45,7 +45,7 @@ static const char * const cpu_kinds[] = static int do_test (void) { - const struct cpu_features *cpu_features = __get_cpu_features (); + const struct cpu_features *cpu_features = __x86_get_cpu_features (0); switch (cpu_features->basic.kind) { |