V7: [PATCH 2/2] x86: Install <sys/platform/x86.h> [BZ #26124]

Message ID 20200630043529.739181-3-hjl.tools@gmail.com
State New
Headers show
Series
  • V7: [PATCH 2/2] x86: Install <sys/platform/x86.h> [BZ #26124]
Related show

Commit Message

H.J. Lu via Libc-alpha June 30, 2020, 4:35 a.m.
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 falses 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.
---
 NEWS                                          |   2 +
 manual/platform.texi                          |  24 +++
 sysdeps/unix/sysv/linux/i386/ld.abilist       |   1 +
 sysdeps/unix/sysv/linux/x86_64/64/ld.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist |   1 +
 sysdeps/x86/Makefile                          |   1 +
 sysdeps/x86/Versions                          |   4 +-
 sysdeps/x86/dl-get-cpu-features.c             |   6 +-
 sysdeps/x86/include/cpu-features.h            | 179 ++++++++++++++++++
 .../{cpu-features.h => sys/platform/x86.h}    | 146 ++------------
 sysdeps/x86/tst-get-cpu-features.c            |   6 +-
 sysdeps/x86_64/fpu/math-tests-arch.h          |   2 +-
 sysdeps/x86_64/multiarch/test-multiarch.c     |   2 +-
 13 files changed, 237 insertions(+), 138 deletions(-)
 create mode 100644 sysdeps/x86/include/cpu-features.h
 rename sysdeps/x86/{cpu-features.h => sys/platform/x86.h} (79%)

-- 
2.26.2

Comments

H.J. Lu via Libc-alpha July 15, 2020, 2:55 p.m. | #1
On Mon, Jun 29, 2020 at 9:35 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> 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 falses 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.


https://sourceware.org/pipermail/libc-alpha/2020-June/115546.html

-- 
H.J.
H.J. Lu via Libc-alpha July 15, 2020, 2:58 p.m. | #2
On Wed, Jul 15, 2020 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Mon, Jun 29, 2020 at 9:35 PM H.J. Lu <hjl.tools@gmail.com> wrote:

> >

> > 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 falses 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.

>

> https://sourceware.org/pipermail/libc-alpha/2020-June/115546.html

>


The first patch has been checked into master branch.   The second patch is at:

https://sourceware.org/pipermail/libc-alpha/2020-June/115547.html

-- 
H.J.
H.J. Lu via Libc-alpha July 16, 2020, 8:15 p.m. | #3
On 6/30/20 12:35 AM, H.J. Lu via Libc-alpha wrote:
> 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 falses 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.


I'm not sure this is ready for 2.32. I think we need to spend more time
writing how a user would use these and including them in the manual (and
contributing that to the linux man pages project which I can help with).

I also want to double check that this mechanism is really backwards and
forwards compatible and probably add some tests. 

This code is going to get used by a lot of developers and x86_64 has
a very large installed user base. I'd like to see a little more review
for this and make sure we get it right. Likewise increase the quality
of the test coverage and use /proc/cpuinfo and __builtin_cpu_supports
to get that coverage.

Are you OK with waiting for when 2.33 opens to commit this? I can set
aside review time in August for this.

> ---

>  NEWS                                          |   2 +

>  manual/platform.texi                          |  24 +++

>  sysdeps/unix/sysv/linux/i386/ld.abilist       |   1 +

>  sysdeps/unix/sysv/linux/x86_64/64/ld.abilist  |   1 +

>  sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist |   1 +

>  sysdeps/x86/Makefile                          |   1 +

>  sysdeps/x86/Versions                          |   4 +-

>  sysdeps/x86/dl-get-cpu-features.c             |   6 +-

>  sysdeps/x86/include/cpu-features.h            | 179 ++++++++++++++++++

>  .../{cpu-features.h => sys/platform/x86.h}    | 146 ++------------

>  sysdeps/x86/tst-get-cpu-features.c            |   6 +-

>  sysdeps/x86_64/fpu/math-tests-arch.h          |   2 +-

>  sysdeps/x86_64/multiarch/test-multiarch.c     |   2 +-

>  13 files changed, 237 insertions(+), 138 deletions(-)

>  create mode 100644 sysdeps/x86/include/cpu-features.h

>  rename sysdeps/x86/{cpu-features.h => sys/platform/x86.h} (79%)

> 

> diff --git a/NEWS b/NEWS

> index a660fc59a8..ae7d1ece35 100644

> --- a/NEWS

> +++ b/NEWS

> @@ -9,6 +9,8 @@ Version 2.32

>  

>  Major new features:

>  

> +* Add <sys/platform/x86.h> to provide query macros for x86 CPU features.

> +

>  * Unicode 12.1.0 Support: Character encoding, character type info, and

>    transliteration tables are all updated to Unicode 12.1.0, using

>    generator scripts contributed by Mike FABIAN (Red Hat).

> diff --git a/manual/platform.texi b/manual/platform.texi

> index 504addc956..97727d656a 100644

> --- a/manual/platform.texi

> +++ b/manual/platform.texi

> @@ -7,6 +7,7 @@

>  @menu

>  * PowerPC::           Facilities Specific to the PowerPC Architecture

>  * RISC-V::            Facilities Specific to the RISC-V Architecture

> +* X86::               Facilities Specific to the X86 Architecture

>  @end menu

>  

>  @node PowerPC

> @@ -134,3 +135,26 @@ all threads in the current process.  Setting the

>  ordering on only the current thread is necessary.  All other flag bits are

>  reserved.

>  @end deftypefun

> +

> +@node X86

> +@appendixsec X86-specific Facilities

> +

> +Facilities specific to X86 that are not specific to a particular

> +operating system are declared in @file{sys/platform/x86.h}.


You need to explain what COMMON_CPUID_INDEX_* values are and how they
relate to the CPUID instruction.

You need to also explain what all the feature values are what they
mean.

> +

> +@deftypefun {const struct cpu_features *} __x86_get_cpu_features (unsigned int @var{max})

> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}

> +Return a pointer to x86 CPU feature structure used by query macros for x86

> +CPU features.  If @var{max} exceeds @code{COMMON_CPUID_INDEX_MAX}, the

> +function returns @code{NULL}.


This needs to explain why this is important.

I'd like to see this manual express the following:

* Raising the max indicates you are requesting an increasing number of
  CPUID categories will be queried and returned.
* If the max you indicate is higher than supported by the runtime then
  you'll get a NULL.

We should have a short example snippet of code.

> +@end deftypefun

> +

> +@deftypefn Macro int HAS_CPU_FEATURE (@var{name})

> +This macro returns a nonzero value (true) if the processor has the feature

> +@var{name}.

> +@end deftypefn

> +

> +@deftypefn Macro int CPU_FEATURE_USABLE (@var{name})

> +This macro returns a nonzero value (true) if the processor has the feature

> +@var{name} and the feature is supported by the operating system.

> +@end deftypefn

> diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist

> index 0478e22071..1226876689 100644

> --- a/sysdeps/unix/sysv/linux/i386/ld.abilist

> +++ b/sysdeps/unix/sysv/linux/i386/ld.abilist

> @@ -3,3 +3,4 @@ GLIBC_2.1 __libc_stack_end D 0x4

>  GLIBC_2.1 _dl_mcount F

>  GLIBC_2.3 ___tls_get_addr F

>  GLIBC_2.3 __tls_get_addr F

> +GLIBC_2.32 __x86_get_cpu_features F

> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist

> index d3cdf7611e..886e57abd5 100644

> --- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist

> +++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist

> @@ -2,3 +2,4 @@ GLIBC_2.2.5 __libc_stack_end D 0x8

>  GLIBC_2.2.5 _dl_mcount F

>  GLIBC_2.2.5 _r_debug D 0x28

>  GLIBC_2.3 __tls_get_addr F

> +GLIBC_2.32 __x86_get_cpu_features F

> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist

> index c70bccf782..0d2f8a2cc5 100644

> --- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist

> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist

> @@ -2,3 +2,4 @@ GLIBC_2.16 __libc_stack_end D 0x4

>  GLIBC_2.16 __tls_get_addr F

>  GLIBC_2.16 _dl_mcount F

>  GLIBC_2.16 _r_debug D 0x14

> +GLIBC_2.32 __x86_get_cpu_features F

> diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile

> index beab426f67..0e4d132803 100644

> --- a/sysdeps/x86/Makefile

> +++ b/sysdeps/x86/Makefile

> @@ -4,6 +4,7 @@ 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-static += tst-get-cpu-features-static

> diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions

> index e02923708e..7e3139dbb1 100644

> --- a/sysdeps/x86/Versions

> +++ b/sysdeps/x86/Versions

> @@ -1,5 +1,5 @@

>  ld {

> -  GLIBC_PRIVATE {

> -    __get_cpu_features;

> +  GLIBC_2.32 {

> +    __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..0f85b5b2dc

> --- /dev/null

> +++ b/sysdeps/x86/include/cpu-features.h

> @@ -0,0 +1,179 @@

> +/* 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, check) \

> +  ptr->features[index_cpu_##name].check.reg_##name |= bit_cpu_##name;

> +# define CPU_FEATURE_UNSET(ptr, name, check) \

> +  ptr->features[index_cpu_##name].check.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_Usable

> +   */

> +  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;

> +};

> +

> +# 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

> similarity index 79%

> rename from sysdeps/x86/cpu-features.h

> rename to sysdeps/x86/sys/platform/x86.h

> index d3e930befc..6a1357b715 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,69 +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_Usable

> -   */

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

>  };

>  

> -/* 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, check) \

> -  ptr->features[index_cpu_##name].check.reg_##name |= bit_cpu_##name;

> -#define CPU_FEATURE_UNSET(ptr, name, check) \

> -  ptr->features[index_cpu_##name].check.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.  */

>  

> @@ -697,71 +652,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-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c

> index 4f0ec8315a..46350a4230 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


We need to improve the quality of this test.

The test should:

* Check if the compiler supports __builtin_cpu_support
* Cross check __builtin_cpu_support values against HAS_CPU_FEATURE
  and CPU_FEATURE_USABLE results.

I would also like to see a Linux-specific variant that uses
/proc/cpuinfo "flags" to cross check all the viable flags against
the __builtin_cpu_support and HAS_CPU_FEATURE/CPU_FEATURE_SUABLE
results.

I want this to be bullet-proof and not something we can change
accidentally without seeing failures.

I understand that we have fallbacks to the non-optimized paths
in the user code, but those fallbacks often have serious negative
performance consequences that can be so slow as to cause serious
application issues.

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

>      {

> diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h

> index 33ea763de2..cc3c2b0c11 100644

> --- a/sysdeps/x86_64/fpu/math-tests-arch.h

> +++ b/sysdeps/x86_64/fpu/math-tests-arch.h

> @@ -16,7 +16,7 @@

>     License along with the GNU C Library; if not, see

>     <https://www.gnu.org/licenses/>.  */

>  

> -#include <cpu-features.h>

> +#include <sys/platform/x86.h>

>  

>  #if defined REQUIRE_AVX

>  

> diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c

> index 7b1fa6811c..9feaf057e5 100644

> --- a/sysdeps/x86_64/multiarch/test-multiarch.c

> +++ b/sysdeps/x86_64/multiarch/test-multiarch.c

> @@ -16,7 +16,7 @@

>     License along with the GNU C Library; if not, see

>     <https://www.gnu.org/licenses/>.  */

>  

> -#include <cpu-features.h>

> +#include <sys/platform/x86.h>

>  #include <stdio.h>

>  #include <stdlib.h>

>  #include <string.h>

> 



-- 
Cheers,
Carlos.

Patch

diff --git a/NEWS b/NEWS
index a660fc59a8..ae7d1ece35 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@  Version 2.32
 
 Major new features:
 
+* Add <sys/platform/x86.h> to provide query macros for x86 CPU features.
+
 * Unicode 12.1.0 Support: Character encoding, character type info, and
   transliteration tables are all updated to Unicode 12.1.0, using
   generator scripts contributed by Mike FABIAN (Red Hat).
diff --git a/manual/platform.texi b/manual/platform.texi
index 504addc956..97727d656a 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -7,6 +7,7 @@ 
 @menu
 * PowerPC::           Facilities Specific to the PowerPC Architecture
 * RISC-V::            Facilities Specific to the RISC-V Architecture
+* X86::               Facilities Specific to the X86 Architecture
 @end menu
 
 @node PowerPC
@@ -134,3 +135,26 @@  all threads in the current process.  Setting the
 ordering on only the current thread is necessary.  All other flag bits are
 reserved.
 @end deftypefun
+
+@node X86
+@appendixsec X86-specific Facilities
+
+Facilities specific to X86 that are not specific to a particular
+operating system are declared in @file{sys/platform/x86.h}.
+
+@deftypefun {const struct cpu_features *} __x86_get_cpu_features (unsigned int @var{max})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Return a pointer to x86 CPU feature structure used by query macros for x86
+CPU features.  If @var{max} exceeds @code{COMMON_CPUID_INDEX_MAX}, the
+function returns @code{NULL}.
+@end deftypefun
+
+@deftypefn Macro int HAS_CPU_FEATURE (@var{name})
+This macro returns a nonzero value (true) if the processor has the feature
+@var{name}.
+@end deftypefn
+
+@deftypefn Macro int CPU_FEATURE_USABLE (@var{name})
+This macro returns a nonzero value (true) if the processor has the feature
+@var{name} and the feature is supported by the operating system.
+@end deftypefn
diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist
index 0478e22071..1226876689 100644
--- a/sysdeps/unix/sysv/linux/i386/ld.abilist
+++ b/sysdeps/unix/sysv/linux/i386/ld.abilist
@@ -3,3 +3,4 @@  GLIBC_2.1 __libc_stack_end D 0x4
 GLIBC_2.1 _dl_mcount F
 GLIBC_2.3 ___tls_get_addr F
 GLIBC_2.3 __tls_get_addr F
+GLIBC_2.32 __x86_get_cpu_features F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist
index d3cdf7611e..886e57abd5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist
@@ -2,3 +2,4 @@  GLIBC_2.2.5 __libc_stack_end D 0x8
 GLIBC_2.2.5 _dl_mcount F
 GLIBC_2.2.5 _r_debug D 0x28
 GLIBC_2.3 __tls_get_addr F
+GLIBC_2.32 __x86_get_cpu_features F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist
index c70bccf782..0d2f8a2cc5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist
@@ -2,3 +2,4 @@  GLIBC_2.16 __libc_stack_end D 0x4
 GLIBC_2.16 __tls_get_addr F
 GLIBC_2.16 _dl_mcount F
 GLIBC_2.16 _r_debug D 0x14
+GLIBC_2.32 __x86_get_cpu_features F
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index beab426f67..0e4d132803 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -4,6 +4,7 @@  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-static += tst-get-cpu-features-static
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
index e02923708e..7e3139dbb1 100644
--- a/sysdeps/x86/Versions
+++ b/sysdeps/x86/Versions
@@ -1,5 +1,5 @@ 
 ld {
-  GLIBC_PRIVATE {
-    __get_cpu_features;
+  GLIBC_2.32 {
+    __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..0f85b5b2dc
--- /dev/null
+++ b/sysdeps/x86/include/cpu-features.h
@@ -0,0 +1,179 @@ 
+/* 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, check) \
+  ptr->features[index_cpu_##name].check.reg_##name |= bit_cpu_##name;
+# define CPU_FEATURE_UNSET(ptr, name, check) \
+  ptr->features[index_cpu_##name].check.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_Usable
+   */
+  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;
+};
+
+# 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
similarity index 79%
rename from sysdeps/x86/cpu-features.h
rename to sysdeps/x86/sys/platform/x86.h
index d3e930befc..6a1357b715 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,69 +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_Usable
-   */
-  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;
 };
 
-/* 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, check) \
-  ptr->features[index_cpu_##name].check.reg_##name |= bit_cpu_##name;
-#define CPU_FEATURE_UNSET(ptr, name, check) \
-  ptr->features[index_cpu_##name].check.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.  */
 
@@ -697,71 +652,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-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index 4f0ec8315a..46350a4230 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)
     {
diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h
index 33ea763de2..cc3c2b0c11 100644
--- a/sysdeps/x86_64/fpu/math-tests-arch.h
+++ b/sysdeps/x86_64/fpu/math-tests-arch.h
@@ -16,7 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <cpu-features.h>
+#include <sys/platform/x86.h>
 
 #if defined REQUIRE_AVX
 
diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c
index 7b1fa6811c..9feaf057e5 100644
--- a/sysdeps/x86_64/multiarch/test-multiarch.c
+++ b/sysdeps/x86_64/multiarch/test-multiarch.c
@@ -16,7 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <cpu-features.h>
+#include <sys/platform/x86.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>