diff mbox series

V7 [PATCH] x86: Move cpuinfo.h from libgcc to common/config/i386

Message ID 20200624122707.GA221500@gmail.com
State New
Headers show
Series V7 [PATCH] x86: Move cpuinfo.h from libgcc to common/config/i386 | expand

Commit Message

H.J. Lu June 24, 2020, 12:27 p.m. UTC
On Mon, Jun 22, 2020 at 04:25:46PM -0700, H.J. Lu wrote:
> On Sun, Jun 21, 2020 at 10:22 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Sun, Jun 21, 2020 at 10:18 AM Uros Bizjak <ubizjak@gmail.com> wrote:
> > >
> > > On Sat, Jun 20, 2020 at 3:40 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > > > > > >> 2) can we automatically deduce option name:
> > > > > > > >>
> > > > > > > >>> +  ISA_NAMES_TABLE_ENTRY("rdpid", FEATURE_RDPID, P_ZERO, "-mrdpid")
> > > > > > > >>> +  ISA_NAMES_TABLE_ENTRY("rdrnd", FEATURE_RDRND, P_ZERO, "-mrdrnd")
> > > > > > > >>
> > > > > > > >> I mean "-m" + "rdrnd" == "-mrdrnd" ?
> > > > > > > >
> > > > > > > > The new option field serves 2 purposes:
> > > > > > > >
> > > > > > > > 1. Not all features have a corresponding command-line option
> > > > > > > >
> > > > > > > > ISA_NAMES_TABLE_ENTRY("cmov", FEATURE_CMOV, P_ZERO, NULL)
> > > > > > > >
> > > > > > > >       for (i = 0; i < ARRAY_SIZE (isa_names_table); i++)
> > > > > > > >          if (isa_names_table[i].option)
> > > > > > > >
> > > > > > > > 2. Some feature has a different name in the command-line option.
> > > > > > > >
> > > > > > > >    ISA_NAMES_TABLE_ENTRY("fxsave", FEATURE_FXSAVE, P_ZERO, "-mfxsr")
> > > > > > >
> > > > > > > I noticed that, one can theoretically use "" for an option that does not
> > > > > > > have a flag. And NULL for these which have option equal to "-m" + name.
> > > > > > > Anyway, that's a nit.
> > > > > > >
> > > > > > > I support the patch!
> > > > > > > Martin
> > > > > > >
> > > > > > > >
> > > > > > > > Here is the updated patch.   OK for master?
> > > > > > > >
> > > > > > > > Thanks.
> > > > > > > >
> > > > > > >
> > > > > >
> > > > > > PING:
> > > > > >
> > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546522.html
> > > > > >
> > > > >
> > > > > PING.
> > > >
> > > > Hi,
> > > >
> > > > We have patches like
> > > >
> > > > https://gcc.gnu.org/pipermail/gcc-bugs/2020-June/705851.html
> > > >
> > > > queued up because of this prerequisite patch.   Are there any objections
> > > > to this patch?
> > >
> > > Yes, there are my objections.
> > >
> > > As explained before, I support unifying libgcc and core gcc handling,
> > > but _NOT_ unifying with driver-i386.c. Unifying libgcc and core gcc
> > > handling would have benefit to avoid desynchronisation between the two
> > > (which happened multiple times in the past, resulting in various API
> > > issues). OTOH, unifying with driver-i386.c would result in quite messy
> > > approach, because driver-i386 handles more targets beside relatively
> > > recent 64bit Intel and AMD targets, not to mention heuristics to
> > > determine the most appropriate target when standard detection fails
> > > (e.g. emulators).
> >
> > Only the duplicated parts of driver-i386.c should be unified.  The only impact
> > should be removing code duplications.  If it isn't the case, it is a bug in my
> > implementation.
> 
> Here is the updated patch to remove FEATURE_OSPKE and use bit_OSPKE
> for FEATURE_PKU.  It uses the same get_amd_cpu and get_intel_cpu in
> libgcc and driver-i386.c:
>    a. Detect the processor name for newer Intel and AMD processors.
>       Since the older processor names are only supported by driver-i386.c,
>       not by libgcc, detection for the older processors remains in
>       driver-i386.c.
>    b. Detect available ISAs for all Intel and AMD processors.
> 

Here is the updated patch for x86 backend and libgcc.  driver-i386.c
is unchanged.

OK for master?

Thannks.

H.J.
---
Both x86 backend and libgcc define enum processor_features.  libgcc sets
enum processor_feature and x86 backend checks enum processor_feature.
They are very easy out of sync and it has happened multiple times in the
past.

1. Move cpuinfo.h from libgcc to common/config/i386 so that we can share
the same enum processor_features in x86 backend and libgcc.
2. Change __cpu_features2 to an array to support more processor features.
3. Add more processor features to enum processor_features.

gcc/

	PR target/95259
	* common/config/i386/cpuinfo.h: New file.
	(__processor_model): Moved from libgcc/config/i386/cpuinfo.h.
	(__processor_model2): New.
	(CHECK___builtin_cpu_is): New.  Defined as empty if not defined.
	(has_cpu_feature): New function.
	(set_cpu_feature): Likewise.
	(get_amd_cpu): Moved from libgcc/config/i386/cpuinfo.c.  Use
	CHECK___builtin_cpu_is.  Return AMD CPU name.
	(get_intel_cpu): Moved from libgcc/config/i386/cpuinfo.c.  Use
	Use CHECK___builtin_cpu_is.  Return Intel CPU name.
	(get_available_features): Moved from libgcc/config/i386/cpuinfo.c.
	Also check FEATURE_3DNOW, FEATURE_3DNOWP, FEATURE_ADX,
	FEATURE_ABM, FEATURE_CLDEMOTE, FEATURE_CLFLUSHOPT, FEATURE_CLWB,
	FEATURE_CLZERO, FEATURE_CMPXCHG16B, FEATURE_CMPXCHG8B,
	FEATURE_ENQCMD, FEATURE_F16C, FEATURE_FSGSBASE, FEATURE_FXSAVE,
	FEATURE_HLE, FEATURE_IBT, FEATURE_LAHF_LM, FEATURE_LM,
	FEATURE_LWP, FEATURE_LZCNT, FEATURE_MOVBE, FEATURE_MOVDIR64B,
	FEATURE_MOVDIRI, FEATURE_MWAITX, FEATURE_OSXSAVE,
	FEATURE_PCONFIG, FEATURE_PKU, FEATURE_PREFETCHWT1, FEATURE_PRFCHW,
	FEATURE_PTWRITE, FEATURE_RDPID, FEATURE_RDRND, FEATURE_RDSEED,
	FEATURE_RTM, FEATURE_SERIALIZE, FEATURE_SGX, FEATURE_SHA,
	FEATURE_SHSTK, FEATURE_TBM, FEATURE_TSXLDTRK, FEATURE_VAES,
	FEATURE_WAITPKG, FEATURE_WBNOINVD, FEATURE_XSAVE, FEATURE_XSAVEC,
	FEATURE_XSAVEOPT and FEATURE_XSAVES
	(cpu_indicator_init): Moved from libgcc/config/i386/cpuinfo.c.
	Also update cpu_model2.
	* common/config/i386/i386-cpuinfo.h (processor_vendor): Add
	Add VENDOR_CENTAUR, VENDOR_CYRIX and VENDOR_NSC.
	(processor_features): Moved from gcc/config/i386/i386-builtins.c.
	Renamed F_XXX to FEATURE_XXX.  Add FEATURE_3DNOW, FEATURE_3DNOWP,
	FEATURE_ADX, FEATURE_ABM, FEATURE_CLDEMOTE, FEATURE_CLFLUSHOPT,
	FEATURE_CLWB, FEATURE_CLZERO, FEATURE_CMPXCHG16B,
	FEATURE_CMPXCHG8B, FEATURE_ENQCMD, FEATURE_F16C,
	FEATURE_FSGSBASE, FEATURE_FXSAVE, FEATURE_HLE, FEATURE_IBT,
	FEATURE_LAHF_LM, FEATURE_LM, FEATURE_LWP, FEATURE_LZCNT,
	FEATURE_MOVBE, FEATURE_MOVDIR64B, FEATURE_MOVDIRI,
	FEATURE_MWAITX, FEATURE_OSXSAVE, FEATURE_PCONFIG,
	FEATURE_PKU, FEATURE_PREFETCHWT1, FEATURE_PRFCHW,
	FEATURE_PTWRITE, FEATURE_RDPID, FEATURE_RDRND, FEATURE_RDSEED,
	FEATURE_RTM, FEATURE_SERIALIZE, FEATURE_SGX, FEATURE_SHA,
	FEATURE_SHSTK, FEATURE_TBM, FEATURE_TSXLDTRK, FEATURE_VAES,
	FEATURE_WAITPKG, FEATURE_WBNOINVD, FEATURE_XSAVE, FEATURE_XSAVEC,
	FEATURE_XSAVEOPT, FEATURE_XSAVES and CPU_FEATURE_MAX.
	(SIZE_OF_CPU_FEATURES): New.
	* config/i386/i386-builtins.c (processor_features): Removed.
	(isa_names_table): Replace F_XXX with FEATURE_XXX.
	(fold_builtin_cpu): Change __cpu_features2 to an array.

libgcc/

	PR target/95259
	* config/i386/cpuinfo.c: Don't include "cpuinfo.h".  Include
	"common/config/i386/i386-cpuinfo.h" and
	"common/config/i386/cpuinfo.h".
	(__cpu_features2): Changed to array.
	(get_amd_cpu): Removed.
	(get_intel_cpu): Likewise.
	(get_available_features): Likewise.
	(__cpu_indicator_init): Call cpu_indicator_init.
	* config/i386/cpuinfo.h: Removed.
---
 gcc/common/config/i386/cpuinfo.h      | 844 ++++++++++++++++++++++++++
 gcc/common/config/i386/i386-cpuinfo.h |  98 +++
 gcc/config/i386/i386-builtins.c       | 147 ++---
 libgcc/config/i386/cpuinfo.c          | 465 +-------------
 libgcc/config/i386/cpuinfo.h          | 136 -----
 5 files changed, 1009 insertions(+), 681 deletions(-)
 create mode 100644 gcc/common/config/i386/cpuinfo.h
 delete mode 100644 libgcc/config/i386/cpuinfo.h

Comments

Uros Bizjak June 24, 2020, 12:43 p.m. UTC | #1
On Wed, Jun 24, 2020 at 2:27 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Jun 22, 2020 at 04:25:46PM -0700, H.J. Lu wrote:
> > On Sun, Jun 21, 2020 at 10:22 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > On Sun, Jun 21, 2020 at 10:18 AM Uros Bizjak <ubizjak@gmail.com> wrote:
> > > >
> > > > On Sat, Jun 20, 2020 at 3:40 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > > > > > > > >> 2) can we automatically deduce option name:
> > > > > > > > >>
> > > > > > > > >>> +  ISA_NAMES_TABLE_ENTRY("rdpid", FEATURE_RDPID, P_ZERO, "-mrdpid")
> > > > > > > > >>> +  ISA_NAMES_TABLE_ENTRY("rdrnd", FEATURE_RDRND, P_ZERO, "-mrdrnd")
> > > > > > > > >>
> > > > > > > > >> I mean "-m" + "rdrnd" == "-mrdrnd" ?
> > > > > > > > >
> > > > > > > > > The new option field serves 2 purposes:
> > > > > > > > >
> > > > > > > > > 1. Not all features have a corresponding command-line option
> > > > > > > > >
> > > > > > > > > ISA_NAMES_TABLE_ENTRY("cmov", FEATURE_CMOV, P_ZERO, NULL)
> > > > > > > > >
> > > > > > > > >       for (i = 0; i < ARRAY_SIZE (isa_names_table); i++)
> > > > > > > > >          if (isa_names_table[i].option)
> > > > > > > > >
> > > > > > > > > 2. Some feature has a different name in the command-line option.
> > > > > > > > >
> > > > > > > > >    ISA_NAMES_TABLE_ENTRY("fxsave", FEATURE_FXSAVE, P_ZERO, "-mfxsr")
> > > > > > > >
> > > > > > > > I noticed that, one can theoretically use "" for an option that does not
> > > > > > > > have a flag. And NULL for these which have option equal to "-m" + name.
> > > > > > > > Anyway, that's a nit.
> > > > > > > >
> > > > > > > > I support the patch!
> > > > > > > > Martin
> > > > > > > >
> > > > > > > > >
> > > > > > > > > Here is the updated patch.   OK for master?
> > > > > > > > >
> > > > > > > > > Thanks.
> > > > > > > > >
> > > > > > > >
> > > > > > >
> > > > > > > PING:
> > > > > > >
> > > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546522.html
> > > > > > >
> > > > > >
> > > > > > PING.
> > > > >
> > > > > Hi,
> > > > >
> > > > > We have patches like
> > > > >
> > > > > https://gcc.gnu.org/pipermail/gcc-bugs/2020-June/705851.html
> > > > >
> > > > > queued up because of this prerequisite patch.   Are there any objections
> > > > > to this patch?
> > > >
> > > > Yes, there are my objections.
> > > >
> > > > As explained before, I support unifying libgcc and core gcc handling,
> > > > but _NOT_ unifying with driver-i386.c. Unifying libgcc and core gcc
> > > > handling would have benefit to avoid desynchronisation between the two
> > > > (which happened multiple times in the past, resulting in various API
> > > > issues). OTOH, unifying with driver-i386.c would result in quite messy
> > > > approach, because driver-i386 handles more targets beside relatively
> > > > recent 64bit Intel and AMD targets, not to mention heuristics to
> > > > determine the most appropriate target when standard detection fails
> > > > (e.g. emulators).
> > >
> > > Only the duplicated parts of driver-i386.c should be unified.  The only impact
> > > should be removing code duplications.  If it isn't the case, it is a bug in my
> > > implementation.
> >
> > Here is the updated patch to remove FEATURE_OSPKE and use bit_OSPKE
> > for FEATURE_PKU.  It uses the same get_amd_cpu and get_intel_cpu in
> > libgcc and driver-i386.c:
> >    a. Detect the processor name for newer Intel and AMD processors.
> >       Since the older processor names are only supported by driver-i386.c,
> >       not by libgcc, detection for the older processors remains in
> >       driver-i386.c.
> >    b. Detect available ISAs for all Intel and AMD processors.
> >
>
> Here is the updated patch for x86 backend and libgcc.  driver-i386.c
> is unchanged.

Thanks. We should change driver-i386.c very carefully and in an
independent way from this patch. It is a complex and interwoven web of
name, model and features check. I propose that we first convert
various has_xxx checks to a new interface, in as trivial way as
possible.

> OK for master?

Yes, this part looks OK to me.

Thanks,
Uros.

>
> Thannks.
>
> H.J.
> ---
> Both x86 backend and libgcc define enum processor_features.  libgcc sets
> enum processor_feature and x86 backend checks enum processor_feature.
> They are very easy out of sync and it has happened multiple times in the
> past.
>
> 1. Move cpuinfo.h from libgcc to common/config/i386 so that we can share
> the same enum processor_features in x86 backend and libgcc.
> 2. Change __cpu_features2 to an array to support more processor features.
> 3. Add more processor features to enum processor_features.
>
> gcc/
>
>         PR target/95259
>         * common/config/i386/cpuinfo.h: New file.
>         (__processor_model): Moved from libgcc/config/i386/cpuinfo.h.
>         (__processor_model2): New.
>         (CHECK___builtin_cpu_is): New.  Defined as empty if not defined.
>         (has_cpu_feature): New function.
>         (set_cpu_feature): Likewise.
>         (get_amd_cpu): Moved from libgcc/config/i386/cpuinfo.c.  Use
>         CHECK___builtin_cpu_is.  Return AMD CPU name.
>         (get_intel_cpu): Moved from libgcc/config/i386/cpuinfo.c.  Use
>         Use CHECK___builtin_cpu_is.  Return Intel CPU name.
>         (get_available_features): Moved from libgcc/config/i386/cpuinfo.c.
>         Also check FEATURE_3DNOW, FEATURE_3DNOWP, FEATURE_ADX,
>         FEATURE_ABM, FEATURE_CLDEMOTE, FEATURE_CLFLUSHOPT, FEATURE_CLWB,
>         FEATURE_CLZERO, FEATURE_CMPXCHG16B, FEATURE_CMPXCHG8B,
>         FEATURE_ENQCMD, FEATURE_F16C, FEATURE_FSGSBASE, FEATURE_FXSAVE,
>         FEATURE_HLE, FEATURE_IBT, FEATURE_LAHF_LM, FEATURE_LM,
>         FEATURE_LWP, FEATURE_LZCNT, FEATURE_MOVBE, FEATURE_MOVDIR64B,
>         FEATURE_MOVDIRI, FEATURE_MWAITX, FEATURE_OSXSAVE,
>         FEATURE_PCONFIG, FEATURE_PKU, FEATURE_PREFETCHWT1, FEATURE_PRFCHW,
>         FEATURE_PTWRITE, FEATURE_RDPID, FEATURE_RDRND, FEATURE_RDSEED,
>         FEATURE_RTM, FEATURE_SERIALIZE, FEATURE_SGX, FEATURE_SHA,
>         FEATURE_SHSTK, FEATURE_TBM, FEATURE_TSXLDTRK, FEATURE_VAES,
>         FEATURE_WAITPKG, FEATURE_WBNOINVD, FEATURE_XSAVE, FEATURE_XSAVEC,
>         FEATURE_XSAVEOPT and FEATURE_XSAVES
>         (cpu_indicator_init): Moved from libgcc/config/i386/cpuinfo.c.
>         Also update cpu_model2.
>         * common/config/i386/i386-cpuinfo.h (processor_vendor): Add
>         Add VENDOR_CENTAUR, VENDOR_CYRIX and VENDOR_NSC.
>         (processor_features): Moved from gcc/config/i386/i386-builtins.c.
>         Renamed F_XXX to FEATURE_XXX.  Add FEATURE_3DNOW, FEATURE_3DNOWP,
>         FEATURE_ADX, FEATURE_ABM, FEATURE_CLDEMOTE, FEATURE_CLFLUSHOPT,
>         FEATURE_CLWB, FEATURE_CLZERO, FEATURE_CMPXCHG16B,
>         FEATURE_CMPXCHG8B, FEATURE_ENQCMD, FEATURE_F16C,
>         FEATURE_FSGSBASE, FEATURE_FXSAVE, FEATURE_HLE, FEATURE_IBT,
>         FEATURE_LAHF_LM, FEATURE_LM, FEATURE_LWP, FEATURE_LZCNT,
>         FEATURE_MOVBE, FEATURE_MOVDIR64B, FEATURE_MOVDIRI,
>         FEATURE_MWAITX, FEATURE_OSXSAVE, FEATURE_PCONFIG,
>         FEATURE_PKU, FEATURE_PREFETCHWT1, FEATURE_PRFCHW,
>         FEATURE_PTWRITE, FEATURE_RDPID, FEATURE_RDRND, FEATURE_RDSEED,
>         FEATURE_RTM, FEATURE_SERIALIZE, FEATURE_SGX, FEATURE_SHA,
>         FEATURE_SHSTK, FEATURE_TBM, FEATURE_TSXLDTRK, FEATURE_VAES,
>         FEATURE_WAITPKG, FEATURE_WBNOINVD, FEATURE_XSAVE, FEATURE_XSAVEC,
>         FEATURE_XSAVEOPT, FEATURE_XSAVES and CPU_FEATURE_MAX.
>         (SIZE_OF_CPU_FEATURES): New.
>         * config/i386/i386-builtins.c (processor_features): Removed.
>         (isa_names_table): Replace F_XXX with FEATURE_XXX.
>         (fold_builtin_cpu): Change __cpu_features2 to an array.
>
> libgcc/
>
>         PR target/95259
>         * config/i386/cpuinfo.c: Don't include "cpuinfo.h".  Include
>         "common/config/i386/i386-cpuinfo.h" and
>         "common/config/i386/cpuinfo.h".
>         (__cpu_features2): Changed to array.
>         (get_amd_cpu): Removed.
>         (get_intel_cpu): Likewise.
>         (get_available_features): Likewise.
>         (__cpu_indicator_init): Call cpu_indicator_init.
>         * config/i386/cpuinfo.h: Removed.
> ---
>  gcc/common/config/i386/cpuinfo.h      | 844 ++++++++++++++++++++++++++
>  gcc/common/config/i386/i386-cpuinfo.h |  98 +++
>  gcc/config/i386/i386-builtins.c       | 147 ++---
>  libgcc/config/i386/cpuinfo.c          | 465 +-------------
>  libgcc/config/i386/cpuinfo.h          | 136 -----
>  5 files changed, 1009 insertions(+), 681 deletions(-)
>  create mode 100644 gcc/common/config/i386/cpuinfo.h
>  delete mode 100644 libgcc/config/i386/cpuinfo.h
>
> diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h
> new file mode 100644
> index 00000000000..2d72b3b60fd
> --- /dev/null
> +++ b/gcc/common/config/i386/cpuinfo.h
> @@ -0,0 +1,844 @@
> +/* Get CPU type and Features for x86 processors.
> +   Copyright (C) 2012-2020 Free Software Foundation, Inc.
> +   Contributed by Sriraman Tallam (tmsriram@google.com)
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +Under Section 7 of GPL version 3, you are granted additional
> +permissions described in the GCC Runtime Library Exception, version
> +3.1, as published by the Free Software Foundation.
> +
> +You should have received a copy of the GNU General Public License and
> +a copy of the GCC Runtime Library Exception along with this program;
> +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +<http://www.gnu.org/licenses/>.  */
> +
> +struct __processor_model
> +{
> +  unsigned int __cpu_vendor;
> +  unsigned int __cpu_type;
> +  unsigned int __cpu_subtype;
> +  /* The first 32 features are stored as bitmasks in __cpu_features.
> +     The rest of features are stored as bitmasks in a separate array
> +     of unsigned int.  */
> +  unsigned int __cpu_features[1];
> +};
> +
> +struct __processor_model2
> +{
> +  unsigned int __cpu_family;
> +  unsigned int __cpu_model;
> +  unsigned int __cpu_max_level;
> +  unsigned int __cpu_ext_level;
> +};
> +
> +#ifndef CHECK___builtin_cpu_is
> +# define CHECK___builtin_cpu_is(cpu)
> +#endif
> +
> +/* Return non-zero if the processor has feature F.  */
> +
> +static inline int
> +has_cpu_feature (struct __processor_model *cpu_model,
> +                unsigned int *cpu_features2,
> +                enum processor_features f)
> +{
> +  unsigned int i;
> +  if (f < 32)
> +    {
> +      /* The first 32 features.  */
> +      return cpu_model->__cpu_features[0] & (1U << (f & 31));
> +    }
> +  /* The rest of features.  cpu_features2[i] contains features from
> +     (32 + i * 32) to (31 + 32 + i * 32), inclusively.  */
> +  for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
> +    if (f < (32 + 32 + i * 32))
> +    return cpu_features2[i] & (1U << ((f - (32 + i * 32)) & 31));
> +  gcc_unreachable ();
> +}
> +
> +static inline void
> +set_cpu_feature (struct __processor_model *cpu_model,
> +                unsigned int *cpu_features2,
> +                enum processor_features f)
> +{
> +  unsigned int i;
> +  if (f < 32)
> +    {
> +      /* The first 32 features.  */
> +      cpu_model->__cpu_features[0] |= (1U << (f & 31));
> +      return;
> +    }
> +  /* The rest of features.  cpu_features2[i] contains features from
> +     (32 + i * 32) to (31 + 32 + i * 32), inclusively.  */
> +  for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
> +    if (f < (32 + 32 + i * 32))
> +      {
> +       cpu_features2[i] |= (1U << ((f - (32 + i * 32)) & 31));
> +       return;
> +      }
> +  gcc_unreachable ();
> +}
> +
> +/* Get the specific type of AMD CPU and return AMD CPU name.  Return
> +   NULL for unknown AMD CPU.  */
> +
> +static inline const char *
> +get_amd_cpu (struct __processor_model *cpu_model,
> +            struct __processor_model2 *cpu_model2,
> +            unsigned int *cpu_features2)
> +{
> +  const char *cpu = NULL;
> +  unsigned int family = cpu_model2->__cpu_family;
> +  unsigned int model = cpu_model2->__cpu_model;
> +
> +  switch (family)
> +    {
> +    case 0x10:
> +      /* AMD Family 10h.  */
> +      cpu = "amdfam10";
> +      cpu_model->__cpu_type = AMDFAM10H;
> +      switch (model)
> +       {
> +       case 0x2:
> +         /* Barcelona.  */
> +         CHECK___builtin_cpu_is ("amdfam10h");
> +         CHECK___builtin_cpu_is ("barcelona");
> +         cpu_model->__cpu_subtype = AMDFAM10H_BARCELONA;
> +         break;
> +       case 0x4:
> +         /* Shanghai.  */
> +         CHECK___builtin_cpu_is ("amdfam10h");
> +         CHECK___builtin_cpu_is ("shanghai");
> +         cpu_model->__cpu_subtype = AMDFAM10H_SHANGHAI;
> +         break;
> +       case 0x8:
> +         /* Istanbul.  */
> +         CHECK___builtin_cpu_is ("amdfam10h");
> +         CHECK___builtin_cpu_is ("istanbul");
> +         cpu_model->__cpu_subtype = AMDFAM10H_ISTANBUL;
> +         break;
> +       default:
> +         break;
> +       }
> +      break;
> +    case 0x14:
> +      /* AMD Family 14h "btver1". */
> +      cpu = "btver1";
> +      CHECK___builtin_cpu_is ("btver1");
> +      cpu_model->__cpu_type = AMD_BTVER1;
> +      break;
> +    case 0x15:
> +      /* AMD Family 15h "Bulldozer".  */
> +      cpu_model->__cpu_type = AMDFAM15H;
> +      if (model == 0x2)
> +       {
> +         /* Bulldozer version 2 "Piledriver" */
> +         cpu = "bdver2";
> +         CHECK___builtin_cpu_is ("bdver2");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
> +       }
> +      else if (model <= 0xf)
> +       {
> +         /* Bulldozer version 1.  */
> +         cpu = "bdver1";
> +         CHECK___builtin_cpu_is ("bdver1");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
> +       }
> +      else if (model <= 0x2f)
> +       {
> +         /* Bulldozer version 2 "Piledriver" */
> +         cpu = "bdver2";
> +         CHECK___builtin_cpu_is ("bdver2");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
> +       }
> +      else if (model <= 0x4f)
> +       {
> +         /* Bulldozer version 3 "Steamroller"  */
> +         cpu = "bdver3";
> +         CHECK___builtin_cpu_is ("bdver3");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
> +       }
> +      else if (model <= 0x7f)
> +       {
> +         /* Bulldozer version 4 "Excavator"   */
> +         cpu = "bdver4";
> +         CHECK___builtin_cpu_is ("bdver4");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_AVX2))
> +       {
> +         cpu = "bdver4";
> +         CHECK___builtin_cpu_is ("bdver4");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_XSAVEOPT))
> +       {
> +         cpu = "bdver3";
> +         CHECK___builtin_cpu_is ("bdver3");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_BMI))
> +       {
> +         cpu = "bdver2";
> +         CHECK___builtin_cpu_is ("bdver2");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_XOP))
> +       {
> +         cpu = "bdver1";
> +         CHECK___builtin_cpu_is ("bdver1");
> +         cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
> +       }
> +      break;
> +    case 0x16:
> +      /* AMD Family 16h "btver2" */
> +      cpu = "btver2";
> +      CHECK___builtin_cpu_is ("btver2");
> +      cpu_model->__cpu_type = AMD_BTVER2;
> +      break;
> +    case 0x17:
> +      cpu_model->__cpu_type = AMDFAM17H;
> +      if (model <= 0x1f)
> +       {
> +         /* AMD family 17h version 1.  */
> +         cpu = "znver1";
> +         CHECK___builtin_cpu_is ("znver1");
> +         cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
> +       }
> +      else if (model >= 0x30)
> +       {
> +         cpu = "znver2";
> +         CHECK___builtin_cpu_is ("znver2");
> +         cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_CLWB))
> +       {
> +         cpu = "znver2";
> +         CHECK___builtin_cpu_is ("znver2");
> +         cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
> +       }
> +      else if (has_cpu_feature (cpu_model, cpu_features2,
> +                               FEATURE_CLZERO))
> +       {
> +         cpu = "znver1";
> +         CHECK___builtin_cpu_is ("znver1");
> +         cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
> +       }
> +      break;
> +    default:
> +      break;
> +    }
> +
> +  return cpu;
> +}
> +
> +/* Get the specific type of Intel CPU and return Intel CPU name.  Return
> +   NULL for unknown Intel CPU.  */
> +
> +static inline const char *
> +get_intel_cpu (struct __processor_model *cpu_model,
> +              struct __processor_model2 *cpu_model2,
> +              unsigned int *cpu_features2,
> +              unsigned int brand_id)
> +{
> +  const char *cpu = NULL;
> +
> +  /* Parse family and model only for brand ID 0 and model 6. */
> +  if (brand_id != 0 || cpu_model2->__cpu_family != 0x6)
> +    return cpu;
> +
> +  switch (cpu_model2->__cpu_model)
> +    {
> +    case 0x1c:
> +    case 0x26:
> +      /* Bonnell.  */
> +      cpu = "bonnell";
> +      CHECK___builtin_cpu_is ("atom");
> +      cpu_model->__cpu_type = INTEL_BONNELL;
> +      break;
> +    case 0x37:
> +    case 0x4a:
> +    case 0x4d:
> +    case 0x5d:
> +      /* Silvermont.  */
> +    case 0x4c:
> +    case 0x5a:
> +    case 0x75:
> +      /* Airmont.  */
> +      cpu = "silvermont";
> +      CHECK___builtin_cpu_is ("silvermont");
> +      cpu_model->__cpu_type = INTEL_SILVERMONT;
> +      break;
> +    case 0x5c:
> +    case 0x5f:
> +      /* Goldmont.  */
> +      cpu = "goldmont";
> +      CHECK___builtin_cpu_is ("goldmont");
> +      cpu_model->__cpu_type = INTEL_GOLDMONT;
> +      break;
> +    case 0x7a:
> +      /* Goldmont Plus.  */
> +      cpu = "goldmont-plus";
> +      CHECK___builtin_cpu_is ("goldmont-plus");
> +      cpu_model->__cpu_type = INTEL_GOLDMONT_PLUS;
> +      break;
> +    case 0x86:
> +    case 0x96:
> +    case 0x9c:
> +      /* Tremont.  */
> +      cpu = "tremont";
> +      CHECK___builtin_cpu_is ("tremont");
> +      cpu_model->__cpu_type = INTEL_TREMONT;
> +      break;
> +    case 0x57:
> +      /* Knights Landing.  */
> +      cpu = "knl";
> +      CHECK___builtin_cpu_is ("knl");
> +      cpu_model->__cpu_type = INTEL_KNL;
> +      break;
> +    case 0x85:
> +      /* Knights Mill. */
> +      cpu = "knm";
> +      CHECK___builtin_cpu_is ("knm");
> +      cpu_model->__cpu_type = INTEL_KNM;
> +      break;
> +    case 0x1a:
> +    case 0x1e:
> +    case 0x1f:
> +    case 0x2e:
> +      /* Nehalem.  */
> +      cpu = "nehalem";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("nehalem");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_NEHALEM;
> +      break;
> +    case 0x25:
> +    case 0x2c:
> +    case 0x2f:
> +      /* Westmere.  */
> +      cpu = "westmere";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("westmere");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_WESTMERE;
> +      break;
> +    case 0x2a:
> +    case 0x2d:
> +      /* Sandy Bridge.  */
> +      cpu = "sandybridge";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("sandybridge");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
> +      break;
> +    case 0x3a:
> +    case 0x3e:
> +      /* Ivy Bridge.  */
> +      cpu = "ivybridge";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("ivybridge");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
> +      break;
> +    case 0x3c:
> +    case 0x3f:
> +    case 0x45:
> +    case 0x46:
> +      /* Haswell.  */
> +      cpu = "haswell";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("haswell");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_HASWELL;
> +      break;
> +    case 0x3d:
> +    case 0x47:
> +    case 0x4f:
> +    case 0x56:
> +      /* Broadwell.  */
> +      cpu = "broadwell";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("broadwell");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_BROADWELL;
> +      break;
> +    case 0x4e:
> +    case 0x5e:
> +      /* Skylake.  */
> +    case 0x8e:
> +    case 0x9e:
> +      /* Kaby Lake.  */
> +    case 0xa5:
> +    case 0xa6:
> +      /* Comet Lake.  */
> +      cpu = "skylake";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("skylake");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE;
> +      break;
> +    case 0x55:
> +      CHECK___builtin_cpu_is ("corei7");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      if (has_cpu_feature (cpu_model, cpu_features2,
> +                          FEATURE_AVX512VNNI))
> +       {
> +         /* Cascade Lake.  */
> +         cpu = "cascadelake";
> +         CHECK___builtin_cpu_is ("cascadelake");
> +         cpu_model->__cpu_subtype = INTEL_COREI7_CASCADELAKE;
> +       }
> +      else
> +       {
> +         /* Skylake with AVX-512 support.  */
> +         cpu = "skylake-avx512";
> +         CHECK___builtin_cpu_is ("skylake-avx512");
> +         cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
> +       }
> +      break;
> +    case 0x66:
> +      /* Cannon Lake.  */
> +      cpu = "cannonlake";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("cannonlake");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_CANNONLAKE;
> +      break;
> +    case 0x6a:
> +    case 0x6c:
> +      /* Ice Lake server.  */
> +      cpu = "icelake-server";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("icelake-server");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_SERVER;
> +      break;
> +    case 0x7e:
> +    case 0x7d:
> +    case 0x9d:
> +       /* Ice Lake client.  */
> +      cpu = "icelake-client";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("icelake-client");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_CLIENT;
> +      break;
> +    case 0x8c:
> +    case 0x8d:
> +      /* Tiger Lake.  */
> +      cpu = "tigerlake";
> +      CHECK___builtin_cpu_is ("corei7");
> +      CHECK___builtin_cpu_is ("tigerlake");
> +      cpu_model->__cpu_type = INTEL_COREI7;
> +      cpu_model->__cpu_subtype = INTEL_COREI7_TIGERLAKE;
> +      break;
> +    case 0x17:
> +    case 0x1d:
> +      /* Penryn.  */
> +    case 0x0f:
> +      /* Merom.  */
> +      cpu = "core2";
> +      CHECK___builtin_cpu_is ("core2");
> +      cpu_model->__cpu_type = INTEL_CORE2;
> +      break;
> +    default:
> +      break;
> +    }
> +
> +  return cpu;
> +}
> +
> +/* ECX and EDX are output of CPUID at level one.  */
> +static inline void
> +get_available_features (struct __processor_model *cpu_model,
> +                       struct __processor_model2 *cpu_model2,
> +                       unsigned int *cpu_features2,
> +                       unsigned int ecx, unsigned int edx)
> +{
> +  unsigned int max_cpuid_level = cpu_model2->__cpu_max_level;
> +  unsigned int eax, ebx;
> +  unsigned int ext_level;
> +
> +  /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv.  */
> +#define XCR_XFEATURE_ENABLED_MASK      0x0
> +#define XSTATE_FP                      0x1
> +#define XSTATE_SSE                     0x2
> +#define XSTATE_YMM                     0x4
> +#define XSTATE_OPMASK                  0x20
> +#define XSTATE_ZMM                     0x40
> +#define XSTATE_HI_ZMM                  0x80
> +
> +#define XCR_AVX_ENABLED_MASK \
> +  (XSTATE_SSE | XSTATE_YMM)
> +#define XCR_AVX512F_ENABLED_MASK \
> +  (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
> +
> +  /* Check if AVX and AVX512 are usable.  */
> +  int avx_usable = 0;
> +  int avx512_usable = 0;
> +  if ((ecx & bit_OSXSAVE))
> +    {
> +      /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
> +        ZMM16-ZMM31 states are supported by OSXSAVE.  */
> +      unsigned int xcrlow;
> +      unsigned int xcrhigh;
> +      __asm__ (".byte 0x0f, 0x01, 0xd0"
> +              : "=a" (xcrlow), "=d" (xcrhigh)
> +              : "c" (XCR_XFEATURE_ENABLED_MASK));
> +      if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
> +       {
> +         avx_usable = 1;
> +         avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
> +                          == XCR_AVX512F_ENABLED_MASK);
> +       }
> +    }
> +
> +#define set_feature(f) \
> +  set_cpu_feature (cpu_model, cpu_features2, f)
> +
> +  if (edx & bit_CMOV)
> +    set_feature (FEATURE_CMOV);
> +  if (edx & bit_MMX)
> +    set_feature (FEATURE_MMX);
> +  if (edx & bit_SSE)
> +    set_feature (FEATURE_SSE);
> +  if (edx & bit_SSE2)
> +    set_feature (FEATURE_SSE2);
> +  if (edx & bit_CMPXCHG8B)
> +    set_feature (FEATURE_CMPXCHG8B);
> +  if (edx & bit_FXSAVE)
> +    set_feature (FEATURE_FXSAVE);
> +
> +  if (ecx & bit_POPCNT)
> +    set_feature (FEATURE_POPCNT);
> +  if (ecx & bit_AES)
> +    set_feature (FEATURE_AES);
> +  if (ecx & bit_PCLMUL)
> +    set_feature (FEATURE_PCLMUL);
> +  if (ecx & bit_SSE3)
> +    set_feature (FEATURE_SSE3);
> +  if (ecx & bit_SSSE3)
> +    set_feature (FEATURE_SSSE3);
> +  if (ecx & bit_SSE4_1)
> +    set_feature (FEATURE_SSE4_1);
> +  if (ecx & bit_SSE4_2)
> +    set_feature (FEATURE_SSE4_2);
> +  if (ecx & bit_OSXSAVE)
> +    set_feature (FEATURE_OSXSAVE);
> +  if (ecx & bit_CMPXCHG16B)
> +    set_feature (FEATURE_CMPXCHG16B);
> +  if (ecx & bit_MOVBE)
> +    set_feature (FEATURE_MOVBE);
> +  if (ecx & bit_AES)
> +    set_feature (FEATURE_AES);
> +  if (ecx & bit_F16C)
> +    set_feature (FEATURE_F16C);
> +  if (ecx & bit_RDRND)
> +    set_feature (FEATURE_RDRND);
> +  if (ecx & bit_XSAVE)
> +    set_feature (FEATURE_XSAVE);
> +  if (avx_usable)
> +    {
> +      if (ecx & bit_AVX)
> +       set_feature (FEATURE_AVX);
> +      if (ecx & bit_FMA)
> +       set_feature (FEATURE_FMA);
> +    }
> +
> +  /* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */
> +  if (max_cpuid_level >= 7)
> +    {
> +      __cpuid_count (7, 0, eax, ebx, ecx, edx);
> +      if (ebx & bit_BMI)
> +       set_feature (FEATURE_BMI);
> +      if (ebx & bit_SGX)
> +       set_feature (FEATURE_SGX);
> +      if (ebx & bit_HLE)
> +       set_feature (FEATURE_HLE);
> +      if (ebx & bit_RTM)
> +       set_feature (FEATURE_RTM);
> +      if (avx_usable)
> +       {
> +         if (ebx & bit_AVX2)
> +           set_feature (FEATURE_AVX2);
> +         if (ecx & bit_VPCLMULQDQ)
> +           set_feature (FEATURE_VPCLMULQDQ);
> +       }
> +      if (ebx & bit_BMI2)
> +       set_feature (FEATURE_BMI2);
> +      if (ebx & bit_FSGSBASE)
> +       set_feature (FEATURE_FSGSBASE);
> +      if (ebx & bit_RDSEED)
> +       set_feature (FEATURE_RDSEED);
> +      if (ebx & bit_ADX)
> +       set_feature (FEATURE_ADX);
> +      if (ebx & bit_SHA)
> +       set_feature (FEATURE_SHA);
> +      if (ebx & bit_CLFLUSHOPT)
> +       set_feature (FEATURE_CLFLUSHOPT);
> +      if (ebx & bit_CLWB)
> +       set_feature (FEATURE_CLWB);
> +      if (ecx & bit_PREFETCHWT1)
> +       set_feature (FEATURE_PREFETCHWT1);
> +      /* NB: bit_OSPKE indicates that OS supports PKU.  */
> +      if (ecx & bit_OSPKE)
> +       set_feature (FEATURE_PKU);
> +      if (ecx & bit_RDPID)
> +       set_feature (FEATURE_RDPID);
> +      if (ecx & bit_VAES)
> +       set_feature (FEATURE_VAES);
> +      if (ecx & bit_GFNI)
> +       set_feature (FEATURE_GFNI);
> +      if (ecx & bit_MOVDIRI)
> +       set_feature (FEATURE_MOVDIRI);
> +      if (ecx & bit_MOVDIR64B)
> +       set_feature (FEATURE_MOVDIR64B);
> +      if (ecx & bit_ENQCMD)
> +       set_feature (FEATURE_ENQCMD);
> +      if (ecx & bit_CLDEMOTE)
> +       set_feature (FEATURE_CLDEMOTE);
> +      if (ecx & bit_WAITPKG)
> +       set_feature (FEATURE_WAITPKG);
> +      if (ecx & bit_SHSTK)
> +       set_feature (FEATURE_SHSTK);
> +      if (edx & bit_SERIALIZE)
> +       set_feature (FEATURE_SERIALIZE);
> +      if (edx & bit_TSXLDTRK)
> +       set_feature (FEATURE_TSXLDTRK);
> +      if (edx & bit_PCONFIG)
> +       set_feature (FEATURE_PCONFIG);
> +      if (edx & bit_IBT)
> +       set_feature (FEATURE_IBT);
> +      if (avx512_usable)
> +       {
> +         if (ebx & bit_AVX512F)
> +           set_feature (FEATURE_AVX512F);
> +         if (ebx & bit_AVX512VL)
> +           set_feature (FEATURE_AVX512VL);
> +         if (ebx & bit_AVX512BW)
> +           set_feature (FEATURE_AVX512BW);
> +         if (ebx & bit_AVX512DQ)
> +           set_feature (FEATURE_AVX512DQ);
> +         if (ebx & bit_AVX512CD)
> +           set_feature (FEATURE_AVX512CD);
> +         if (ebx & bit_AVX512PF)
> +           set_feature (FEATURE_AVX512PF);
> +         if (ebx & bit_AVX512ER)
> +           set_feature (FEATURE_AVX512ER);
> +         if (ebx & bit_AVX512IFMA)
> +           set_feature (FEATURE_AVX512IFMA);
> +         if (ecx & bit_AVX512VBMI)
> +           set_feature (FEATURE_AVX512VBMI);
> +         if (ecx & bit_AVX512VBMI2)
> +           set_feature (FEATURE_AVX512VBMI2);
> +         if (ecx & bit_AVX512VNNI)
> +           set_feature (FEATURE_AVX512VNNI);
> +         if (ecx & bit_AVX512BITALG)
> +           set_feature (FEATURE_AVX512BITALG);
> +         if (ecx & bit_AVX512VPOPCNTDQ)
> +           set_feature (FEATURE_AVX512VPOPCNTDQ);
> +         if (edx & bit_AVX5124VNNIW)
> +           set_feature (FEATURE_AVX5124VNNIW);
> +         if (edx & bit_AVX5124FMAPS)
> +           set_feature (FEATURE_AVX5124FMAPS);
> +         if (edx & bit_AVX512VP2INTERSECT)
> +           set_feature (FEATURE_AVX512VP2INTERSECT);
> +
> +         __cpuid_count (7, 1, eax, ebx, ecx, edx);
> +         if (eax & bit_AVX512BF16)
> +           set_feature (FEATURE_AVX512BF16);
> +       }
> +    }
> +
> +  /* Get Advanced Features at level 0xd (eax = 0xd, ecx = 1). */
> +  if (max_cpuid_level >= 0xd)
> +    {
> +      __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
> +      if (eax & bit_XSAVEOPT)
> +       set_feature (FEATURE_XSAVEOPT);
> +      if (eax & bit_XSAVEC)
> +       set_feature (FEATURE_XSAVEC);
> +      if (eax & bit_XSAVES)
> +       set_feature (FEATURE_XSAVES);
> +    }
> +
> +  /* Get Advanced Features at level 0x14 (eax = 0x14, ecx = 0). */
> +  if (max_cpuid_level >= 0x14)
> +    {
> +      __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
> +      if (ebx & bit_PTWRITE)
> +       set_feature (FEATURE_PTWRITE);
> +    }
> +
> +  /* Check cpuid level of extended features.  */
> +  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
> +
> +  cpu_model2->__cpu_ext_level = ext_level;
> +
> +  if (ext_level >= 0x80000001)
> +    {
> +      __cpuid (0x80000001, eax, ebx, ecx, edx);
> +
> +      if (ecx & bit_SSE4a)
> +       set_feature (FEATURE_SSE4_A);
> +      if (ecx & bit_LAHF_LM)
> +       set_feature (FEATURE_LAHF_LM);
> +      if (ecx & bit_ABM)
> +       set_feature (FEATURE_ABM);
> +      if (ecx & bit_LWP)
> +       set_feature (FEATURE_LWP);
> +      if (ecx & bit_TBM)
> +       set_feature (FEATURE_TBM);
> +      if (ecx & bit_LZCNT)
> +       set_feature (FEATURE_LZCNT);
> +      if (ecx & bit_PRFCHW)
> +       set_feature (FEATURE_PRFCHW);
> +      if (ecx & bit_MWAITX)
> +       set_feature (FEATURE_MWAITX);
> +
> +      if (edx & bit_LM)
> +       set_feature (FEATURE_LM);
> +      if (edx & bit_3DNOWP)
> +       set_feature (FEATURE_3DNOWP);
> +      if (edx & bit_3DNOW)
> +       set_feature (FEATURE_3DNOW);
> +
> +      if (avx_usable)
> +       {
> +         if (ecx & bit_FMA4)
> +           set_feature (FEATURE_FMA4);
> +         if (ecx & bit_XOP)
> +           set_feature (FEATURE_XOP);
> +       }
> +    }
> +
> +  if (ext_level >= 0x80000008)
> +    {
> +      __cpuid (0x80000008, eax, ebx, ecx, edx);
> +      if (ebx & bit_CLZERO)
> +       set_feature (FEATURE_CLZERO);
> +      if (ebx & bit_WBNOINVD)
> +       set_feature (FEATURE_WBNOINVD);
> +    }
> +
> +#undef set_feature
> +}
> +
> +static inline int
> +cpu_indicator_init (struct __processor_model *cpu_model,
> +                   struct __processor_model2 *cpu_model2,
> +                   unsigned int *cpu_features2)
> +{
> +  unsigned int eax, ebx, ecx, edx;
> +
> +  int max_level;
> +  unsigned int vendor;
> +  unsigned int model, family, brand_id;
> +  unsigned int extended_model, extended_family;
> +
> +  /* This function needs to run just once.  */
> +  if (cpu_model->__cpu_vendor)
> +    return 0;
> +
> +  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
> +  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
> +    {
> +      cpu_model->__cpu_vendor = VENDOR_OTHER;
> +      return -1;
> +    }
> +
> +  vendor = ebx;
> +  max_level = eax;
> +
> +  if (max_level < 1)
> +    {
> +      cpu_model->__cpu_vendor = VENDOR_OTHER;
> +      return -1;
> +    }
> +
> +  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
> +    {
> +      cpu_model->__cpu_vendor = VENDOR_OTHER;
> +      return -1;
> +    }
> +
> +  cpu_model2->__cpu_max_level = max_level;
> +
> +  model = (eax >> 4) & 0x0f;
> +  family = (eax >> 8) & 0x0f;
> +  brand_id = ebx & 0xff;
> +  extended_model = (eax >> 12) & 0xf0;
> +  extended_family = (eax >> 20) & 0xff;
> +
> +  if (vendor == signature_INTEL_ebx)
> +    {
> +      /* Adjust model and family for Intel CPUS. */
> +      if (family == 0x0f)
> +       {
> +         family += extended_family;
> +         model += extended_model;
> +       }
> +      else if (family == 0x06)
> +       model += extended_model;
> +
> +      cpu_model2->__cpu_family = family;
> +      cpu_model2->__cpu_model = model;
> +
> +      /* Find available features. */
> +      get_available_features (cpu_model, cpu_model2, cpu_features2,
> +                             ecx, edx);
> +      /* Get CPU type.  */
> +      get_intel_cpu (cpu_model, cpu_model2, cpu_features2, brand_id);
> +      cpu_model->__cpu_vendor = VENDOR_INTEL;
> +    }
> +  else if (vendor == signature_AMD_ebx)
> +    {
> +      /* Adjust model and family for AMD CPUS. */
> +      if (family == 0x0f)
> +       {
> +         family += extended_family;
> +         model += extended_model;
> +       }
> +
> +      cpu_model2->__cpu_family = family;
> +      cpu_model2->__cpu_model = model;
> +
> +      /* Find available features. */
> +      get_available_features (cpu_model, cpu_model2, cpu_features2,
> +                             ecx, edx);
> +      /* Get CPU type.  */
> +      get_amd_cpu (cpu_model, cpu_model2, cpu_features2);
> +      cpu_model->__cpu_vendor = VENDOR_AMD;
> +    }
> +  else if (vendor == signature_CENTAUR_ebx)
> +    cpu_model->__cpu_vendor = VENDOR_CENTAUR;
> +  else if (vendor == signature_CYRIX_ebx)
> +    cpu_model->__cpu_vendor = VENDOR_CYRIX;
> +  else if (vendor == signature_NSC_ebx)
> +    cpu_model->__cpu_vendor = VENDOR_NSC;
> +  else
> +    cpu_model->__cpu_vendor = VENDOR_OTHER;
> +
> +  gcc_assert (cpu_model->__cpu_vendor < VENDOR_MAX);
> +  gcc_assert (cpu_model->__cpu_type < CPU_TYPE_MAX);
> +  gcc_assert (cpu_model->__cpu_subtype < CPU_SUBTYPE_MAX);
> +
> +  return 0;
> +}
> diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h
> index e11c68f46dd..96cf0eaea47 100644
> --- a/gcc/common/config/i386/i386-cpuinfo.h
> +++ b/gcc/common/config/i386/i386-cpuinfo.h
> @@ -30,6 +30,9 @@ enum processor_vendor
>    VENDOR_INTEL = 1,
>    VENDOR_AMD,
>    VENDOR_OTHER,
> +  VENDOR_CENTAUR,
> +  VENDOR_CYRIX,
> +  VENDOR_NSC,
>    BUILTIN_VENDOR_MAX = VENDOR_OTHER,
>    VENDOR_MAX
>  };
> @@ -122,6 +125,101 @@ enum feature_priority
>    P_PROC_DYNAMIC
>  };
>
> +/* ISA Features supported. New features have to be inserted at the end.  */
> +
> +enum processor_features
> +{
> +  FEATURE_CMOV = 0,
> +  FEATURE_MMX,
> +  FEATURE_POPCNT,
> +  FEATURE_SSE,
> +  FEATURE_SSE2,
> +  FEATURE_SSE3,
> +  FEATURE_SSSE3,
> +  FEATURE_SSE4_1,
> +  FEATURE_SSE4_2,
> +  FEATURE_AVX,
> +  FEATURE_AVX2,
> +  FEATURE_SSE4_A,
> +  FEATURE_FMA4,
> +  FEATURE_XOP,
> +  FEATURE_FMA,
> +  FEATURE_AVX512F,
> +  FEATURE_BMI,
> +  FEATURE_BMI2,
> +  FEATURE_AES,
> +  FEATURE_PCLMUL,
> +  FEATURE_AVX512VL,
> +  FEATURE_AVX512BW,
> +  FEATURE_AVX512DQ,
> +  FEATURE_AVX512CD,
> +  FEATURE_AVX512ER,
> +  FEATURE_AVX512PF,
> +  FEATURE_AVX512VBMI,
> +  FEATURE_AVX512IFMA,
> +  FEATURE_AVX5124VNNIW,
> +  FEATURE_AVX5124FMAPS,
> +  FEATURE_AVX512VPOPCNTDQ,
> +  FEATURE_AVX512VBMI2,
> +  FEATURE_GFNI,
> +  FEATURE_VPCLMULQDQ,
> +  FEATURE_AVX512VNNI,
> +  FEATURE_AVX512BITALG,
> +  FEATURE_AVX512BF16,
> +  FEATURE_AVX512VP2INTERSECT,
> +  FEATURE_3DNOW,
> +  FEATURE_3DNOWP,
> +  FEATURE_ADX,
> +  FEATURE_ABM,
> +  FEATURE_CLDEMOTE,
> +  FEATURE_CLFLUSHOPT,
> +  FEATURE_CLWB,
> +  FEATURE_CLZERO,
> +  FEATURE_CMPXCHG16B,
> +  FEATURE_CMPXCHG8B,
> +  FEATURE_ENQCMD,
> +  FEATURE_F16C,
> +  FEATURE_FSGSBASE,
> +  FEATURE_FXSAVE,
> +  FEATURE_HLE,
> +  FEATURE_IBT,
> +  FEATURE_LAHF_LM,
> +  FEATURE_LM,
> +  FEATURE_LWP,
> +  FEATURE_LZCNT,
> +  FEATURE_MOVBE,
> +  FEATURE_MOVDIR64B,
> +  FEATURE_MOVDIRI,
> +  FEATURE_MWAITX,
> +  FEATURE_OSXSAVE,
> +  FEATURE_PCONFIG,
> +  FEATURE_PKU,
> +  FEATURE_PREFETCHWT1,
> +  FEATURE_PRFCHW,
> +  FEATURE_PTWRITE,
> +  FEATURE_RDPID,
> +  FEATURE_RDRND,
> +  FEATURE_RDSEED,
> +  FEATURE_RTM,
> +  FEATURE_SERIALIZE,
> +  FEATURE_SGX,
> +  FEATURE_SHA,
> +  FEATURE_SHSTK,
> +  FEATURE_TBM,
> +  FEATURE_TSXLDTRK,
> +  FEATURE_VAES,
> +  FEATURE_WAITPKG,
> +  FEATURE_WBNOINVD,
> +  FEATURE_XSAVE,
> +  FEATURE_XSAVEC,
> +  FEATURE_XSAVEOPT,
> +  FEATURE_XSAVES,
> +  CPU_FEATURE_MAX
> +};
> +
> +/* Size of __cpu_features2 array in libgcc/config/i386/cpuinfo.c.  */
> +#define SIZE_OF_CPU_FEATURES ((CPU_FEATURE_MAX - 1) / 32)
> +
>  /* These are the values for vendor types, cpu types and subtypes.  Cpu
>     types and subtypes should be subtracted by the corresponding start
>     value.  */
> diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
> index 6f6a8328ef1..57e709d6c43 100644
> --- a/gcc/config/i386/i386-builtins.c
> +++ b/gcc/config/i386/i386-builtins.c
> @@ -1835,50 +1835,6 @@ ix86_builtin_reciprocal (tree fndecl)
>      }
>  }
>
> -/* This is the order of bit-fields in __processor_features in cpuinfo.c */
> -enum processor_features
> -{
> -  F_CMOV = 0,
> -  F_MMX,
> -  F_POPCNT,
> -  F_SSE,
> -  F_SSE2,
> -  F_SSE3,
> -  F_SSSE3,
> -  F_SSE4_1,
> -  F_SSE4_2,
> -  F_AVX,
> -  F_AVX2,
> -  F_SSE4_A,
> -  F_FMA4,
> -  F_XOP,
> -  F_FMA,
> -  F_AVX512F,
> -  F_BMI,
> -  F_BMI2,
> -  F_AES,
> -  F_PCLMUL,
> -  F_AVX512VL,
> -  F_AVX512BW,
> -  F_AVX512DQ,
> -  F_AVX512CD,
> -  F_AVX512ER,
> -  F_AVX512PF,
> -  F_AVX512VBMI,
> -  F_AVX512IFMA,
> -  F_AVX5124VNNIW,
> -  F_AVX5124FMAPS,
> -  F_AVX512VPOPCNTDQ,
> -  F_AVX512VBMI2,
> -  F_GFNI,
> -  F_VPCLMULQDQ,
> -  F_AVX512VNNI,
> -  F_AVX512BITALG,
> -  F_AVX512BF16,
> -  F_AVX512VP2INTERSECT,
> -  F_MAX
> -};
> -
>  /* These are the target attribute strings for which a dispatcher is
>     available, from fold_builtin_cpu.  */
>  struct _isa_names_table
> @@ -1890,44 +1846,44 @@ struct _isa_names_table
>
>  static const _isa_names_table isa_names_table[] =
>  {
> -  {"cmov",    F_CMOV,  P_NONE},
> -  {"mmx",     F_MMX,   P_MMX},
> -  {"popcnt",  F_POPCNT,        P_POPCNT},
> -  {"sse",     F_SSE,   P_SSE},
> -  {"sse2",    F_SSE2,  P_SSE2},
> -  {"sse3",    F_SSE3,  P_SSE3},
> -  {"ssse3",   F_SSSE3, P_SSSE3},
> -  {"sse4a",   F_SSE4_A,        P_SSE4_A},
> -  {"sse4.1",  F_SSE4_1,        P_SSE4_1},
> -  {"sse4.2",  F_SSE4_2,        P_SSE4_2},
> -  {"avx",     F_AVX,   P_AVX},
> -  {"fma4",    F_FMA4,  P_FMA4},
> -  {"xop",     F_XOP,   P_XOP},
> -  {"fma",     F_FMA,   P_FMA},
> -  {"avx2",    F_AVX2,  P_AVX2},
> -  {"avx512f", F_AVX512F, P_AVX512F},
> -  {"bmi",     F_BMI,   P_BMI},
> -  {"bmi2",    F_BMI2,  P_BMI2},
> -  {"aes",     F_AES,   P_AES},
> -  {"pclmul",  F_PCLMUL,        P_PCLMUL},
> -  {"avx512vl",F_AVX512VL, P_NONE},
> -  {"avx512bw",F_AVX512BW, P_NONE},
> -  {"avx512dq",F_AVX512DQ, P_NONE},
> -  {"avx512cd",F_AVX512CD, P_NONE},
> -  {"avx512er",F_AVX512ER, P_NONE},
> -  {"avx512pf",F_AVX512PF, P_NONE},
> -  {"avx512vbmi",F_AVX512VBMI, P_NONE},
> -  {"avx512ifma",F_AVX512IFMA, P_NONE},
> -  {"avx5124vnniw",F_AVX5124VNNIW, P_NONE},
> -  {"avx5124fmaps",F_AVX5124FMAPS, P_NONE},
> -  {"avx512vpopcntdq",F_AVX512VPOPCNTDQ,        P_NONE},
> -  {"avx512vbmi2", F_AVX512VBMI2, P_NONE},
> -  {"gfni",     F_GFNI, P_NONE},
> -  {"vpclmulqdq", F_VPCLMULQDQ, P_NONE},
> -  {"avx512vnni", F_AVX512VNNI, P_NONE},
> -  {"avx512bitalg", F_AVX512BITALG, P_NONE},
> -  {"avx512bf16", F_AVX512BF16, P_NONE},
> -  {"avx512vp2intersect",F_AVX512VP2INTERSECT, P_NONE}
> +  {"cmov",    FEATURE_CMOV,    P_NONE},
> +  {"mmx",     FEATURE_MMX,     P_MMX},
> +  {"popcnt",  FEATURE_POPCNT,  P_POPCNT},
> +  {"sse",     FEATURE_SSE,     P_SSE},
> +  {"sse2",    FEATURE_SSE2,    P_SSE2},
> +  {"sse3",    FEATURE_SSE3,    P_SSE3},
> +  {"ssse3",   FEATURE_SSSE3,   P_SSSE3},
> +  {"sse4a",   FEATURE_SSE4_A,  P_SSE4_A},
> +  {"sse4.1",  FEATURE_SSE4_1,  P_SSE4_1},
> +  {"sse4.2",  FEATURE_SSE4_2,  P_SSE4_2},
> +  {"avx",     FEATURE_AVX,     P_AVX},
> +  {"fma4",    FEATURE_FMA4,    P_FMA4},
> +  {"xop",     FEATURE_XOP,     P_XOP},
> +  {"fma",     FEATURE_FMA,     P_FMA},
> +  {"avx2",    FEATURE_AVX2,    P_AVX2},
> +  {"avx512f", FEATURE_AVX512F, P_AVX512F},
> +  {"bmi",     FEATURE_BMI,     P_BMI},
> +  {"bmi2",    FEATURE_BMI2,    P_BMI2},
> +  {"aes",     FEATURE_AES,     P_AES},
> +  {"pclmul",  FEATURE_PCLMUL,  P_PCLMUL},
> +  {"avx512vl",FEATURE_AVX512VL, P_NONE},
> +  {"avx512bw",FEATURE_AVX512BW, P_NONE},
> +  {"avx512dq",FEATURE_AVX512DQ, P_NONE},
> +  {"avx512cd",FEATURE_AVX512CD, P_NONE},
> +  {"avx512er",FEATURE_AVX512ER, P_NONE},
> +  {"avx512pf",FEATURE_AVX512PF, P_NONE},
> +  {"avx512vbmi",FEATURE_AVX512VBMI, P_NONE},
> +  {"avx512ifma",FEATURE_AVX512IFMA, P_NONE},
> +  {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_NONE},
> +  {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_NONE},
> +  {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ,  P_NONE},
> +  {"avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE},
> +  {"gfni",     FEATURE_GFNI,   P_NONE},
> +  {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE},
> +  {"avx512vnni", FEATURE_AVX512VNNI, P_NONE},
> +  {"avx512bitalg", FEATURE_AVX512BITALG, P_NONE},
> +  {"avx512bf16", FEATURE_AVX512BF16, P_NONE},
> +  {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_NONE}
>  };
>
>  /* This parses the attribute arguments to target in DECL and determines
> @@ -2294,16 +2250,29 @@ fold_builtin_cpu (tree fndecl, tree *args)
>
>        if (isa_names_table[i].feature >= 32)
>         {
> -         tree __cpu_features2_var = make_var_decl (unsigned_type_node,
> +         tree index_type
> +           = build_index_type (size_int (SIZE_OF_CPU_FEATURES));
> +         tree type = build_array_type (unsigned_type_node, index_type);
> +         tree __cpu_features2_var = make_var_decl (type,
>                                                     "__cpu_features2");
>
>           varpool_node::add (__cpu_features2_var);
> -         field_val = (1U << (isa_names_table[i].feature - 32));
> -         /* Return __cpu_features2 & field_val  */
> -         final = build2 (BIT_AND_EXPR, unsigned_type_node,
> -                         __cpu_features2_var,
> -                         build_int_cstu (unsigned_type_node, field_val));
> -         return build1 (CONVERT_EXPR, integer_type_node, final);
> +         for (unsigned int j = 0; j < SIZE_OF_CPU_FEATURES; j++)
> +           if (isa_names_table[i].feature < (32 + 32 + j * 32))
> +             {
> +               field_val = (1U << (isa_names_table[i].feature
> +                                   - (32 + j * 32)));
> +               tree index = size_int (j);
> +               array_elt = build4 (ARRAY_REF, unsigned_type_node,
> +                                   __cpu_features2_var,
> +                                   index, NULL_TREE, NULL_TREE);
> +               /* Return __cpu_features2[index] & field_val  */
> +               final = build2 (BIT_AND_EXPR, unsigned_type_node,
> +                               array_elt,
> +                               build_int_cstu (unsigned_type_node,
> +                                               field_val));
> +               return build1 (CONVERT_EXPR, integer_type_node, final);
> +             }
>         }
>
>        field = TYPE_FIELDS (__processor_model_type);
> diff --git a/libgcc/config/i386/cpuinfo.c b/libgcc/config/i386/cpuinfo.c
> index cf5f0884bb4..7218952f32a 100644
> --- a/libgcc/config/i386/cpuinfo.c
> +++ b/libgcc/config/i386/cpuinfo.c
> @@ -26,7 +26,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #include "cpuid.h"
>  #include "tsystem.h"
>  #include "auto-target.h"
> -#include "cpuinfo.h"
> +#include "common/config/i386/i386-cpuinfo.h"
> +#include "common/config/i386/cpuinfo.h"
>
>  #ifdef HAVE_INIT_PRIORITY
>  #define CONSTRUCTOR_PRIORITY (101)
> @@ -39,386 +40,14 @@ int __cpu_indicator_init (void)
>
>
>  struct __processor_model __cpu_model = { };
> -#ifndef SHARED
>  /* We want to move away from __cpu_model in libgcc_s.so.1 and the
>     size of __cpu_model is part of ABI.  So, new features that don't
>     fit into __cpu_model.__cpu_features[0] go into extra variables
> -   in libgcc.a only, preferrably hidden.  */
> -unsigned int __cpu_features2;
> -#endif
> -
> -
> -/* 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);
> +   in libgcc.a only, preferably hidden.
>
> -         __cpuid_count (7, 1, eax, ebx, ecx, edx);
> -         if (eax & bit_AVX512BF16)
> -           set_feature (FEATURE_AVX512BF16);
> -       }
> -    }
> -
> -  /* Check cpuid level of extended features.  */
> -  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
> -
> -  if (ext_level >= 0x80000001)
> -    {
> -      __cpuid (0x80000001, eax, ebx, ecx, edx);
> -
> -      if (ecx & bit_SSE4a)
> -       set_feature (FEATURE_SSE4_A);
> -      if (avx_usable)
> -       {
> -         if (ecx & bit_FMA4)
> -           set_feature (FEATURE_FMA4);
> -         if (ecx & bit_XOP)
> -           set_feature (FEATURE_XOP);
> -       }
> -    }
> -
> -  __cpu_model.__cpu_features[0] = features;
> -#ifndef SHARED
> -  __cpu_features2 = features2;
> -#else
> -  (void) features2;
> -#endif
> -}
> +   NB: Since older 386-builtins.c accesses __cpu_features2 as scalar or
> +   smaller array, it can only access the first few elements.  */
> +unsigned int __cpu_features2[SIZE_OF_CPU_FEATURES];
>
>  /* A constructor function that is sets __cpu_model and __cpu_features with
>     the right values.  This needs to run only once.  This constructor is
> @@ -429,85 +58,9 @@ get_available_features (unsigned int ecx, unsigned int edx,
>  int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
>  __cpu_indicator_init (void)
>  {
> -  unsigned int eax, ebx, ecx, edx;
> -
> -  int max_level;
> -  unsigned int vendor;
> -  unsigned int model, family, brand_id;
> -  unsigned int extended_model, extended_family;
> -
> -  /* This function needs to run just once.  */
> -  if (__cpu_model.__cpu_vendor)
> -    return 0;
> -
> -  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
> -  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
> -    {
> -      __cpu_model.__cpu_vendor = VENDOR_OTHER;
> -      return -1;
> -    }
> -
> -  vendor = ebx;
> -  max_level = eax;
> -
> -  if (max_level < 1)
> -    {
> -      __cpu_model.__cpu_vendor = VENDOR_OTHER;
> -      return -1;
> -    }
> -
> -  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
> -    {
> -      __cpu_model.__cpu_vendor = VENDOR_OTHER;
> -      return -1;
> -    }
> -
> -  model = (eax >> 4) & 0x0f;
> -  family = (eax >> 8) & 0x0f;
> -  brand_id = ebx & 0xff;
> -  extended_model = (eax >> 12) & 0xf0;
> -  extended_family = (eax >> 20) & 0xff;
> -
> -  if (vendor == signature_INTEL_ebx)
> -    {
> -      /* Adjust model and family for Intel CPUS. */
> -      if (family == 0x0f)
> -       {
> -         family += extended_family;
> -         model += extended_model;
> -       }
> -      else if (family == 0x06)
> -       model += extended_model;
> -
> -      /* Get CPU type.  */
> -      get_intel_cpu (family, model, brand_id);
> -      /* Find available features. */
> -      get_available_features (ecx, edx, max_level);
> -      __cpu_model.__cpu_vendor = VENDOR_INTEL;
> -    }
> -  else if (vendor == signature_AMD_ebx)
> -    {
> -      /* Adjust model and family for AMD CPUS. */
> -      if (family == 0x0f)
> -       {
> -         family += extended_family;
> -         model += extended_model;
> -       }
> -
> -      /* Get CPU type.  */
> -      get_amd_cpu (family, model);
> -      /* Find available features. */
> -      get_available_features (ecx, edx, max_level);
> -      __cpu_model.__cpu_vendor = VENDOR_AMD;
> -    }
> -  else
> -    __cpu_model.__cpu_vendor = VENDOR_OTHER;
> -
> -  gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
> -  gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
> -  gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
> -
> -  return 0;
> +  struct __processor_model2 cpu_model2;
> +  return cpu_indicator_init (&__cpu_model, &cpu_model2,
> +                            __cpu_features2);
>  }
>
>  #if defined SHARED && defined USE_ELF_SYMVER
> diff --git a/libgcc/config/i386/cpuinfo.h b/libgcc/config/i386/cpuinfo.h
> deleted file mode 100644
> index 0f97510cde1..00000000000
> --- a/libgcc/config/i386/cpuinfo.h
> +++ /dev/null
> @@ -1,136 +0,0 @@
> -/* Get CPU type and Features for x86 processors.
> -   Copyright (C) 2012-2020 Free Software Foundation, Inc.
> -   Contributed by Sriraman Tallam (tmsriram@google.com)
> -
> -This file is part of GCC.
> -
> -GCC is free software; you can redistribute it and/or modify it under
> -the terms of the GNU General Public License as published by the Free
> -Software Foundation; either version 3, or (at your option) any later
> -version.
> -
> -GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> -WARRANTY; without even the implied warranty of MERCHANTABILITY or
> -FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> -for more details.
> -
> -Under Section 7 of GPL version 3, you are granted additional
> -permissions described in the GCC Runtime Library Exception, version
> -3.1, as published by the Free Software Foundation.
> -
> -You should have received a copy of the GNU General Public License and
> -a copy of the GCC Runtime Library Exception along with this program;
> -see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> -<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;
> --
> 2.26.2
>
diff mbox series

Patch

diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h
new file mode 100644
index 00000000000..2d72b3b60fd
--- /dev/null
+++ b/gcc/common/config/i386/cpuinfo.h
@@ -0,0 +1,844 @@ 
+/* Get CPU type and Features for x86 processors.
+   Copyright (C) 2012-2020 Free Software Foundation, Inc.
+   Contributed by Sriraman Tallam (tmsriram@google.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+struct __processor_model
+{
+  unsigned int __cpu_vendor;
+  unsigned int __cpu_type;
+  unsigned int __cpu_subtype;
+  /* The first 32 features are stored as bitmasks in __cpu_features.
+     The rest of features are stored as bitmasks in a separate array
+     of unsigned int.  */
+  unsigned int __cpu_features[1];
+};
+
+struct __processor_model2
+{
+  unsigned int __cpu_family;
+  unsigned int __cpu_model;
+  unsigned int __cpu_max_level;
+  unsigned int __cpu_ext_level;
+};
+
+#ifndef CHECK___builtin_cpu_is
+# define CHECK___builtin_cpu_is(cpu)
+#endif
+
+/* Return non-zero if the processor has feature F.  */
+
+static inline int
+has_cpu_feature (struct __processor_model *cpu_model,
+		 unsigned int *cpu_features2,
+		 enum processor_features f)
+{
+  unsigned int i;
+  if (f < 32)
+    {
+      /* The first 32 features.  */
+      return cpu_model->__cpu_features[0] & (1U << (f & 31));
+    }
+  /* The rest of features.  cpu_features2[i] contains features from
+     (32 + i * 32) to (31 + 32 + i * 32), inclusively.  */
+  for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
+    if (f < (32 + 32 + i * 32))
+    return cpu_features2[i] & (1U << ((f - (32 + i * 32)) & 31));
+  gcc_unreachable ();
+}
+
+static inline void
+set_cpu_feature (struct __processor_model *cpu_model,
+		 unsigned int *cpu_features2,
+		 enum processor_features f)
+{
+  unsigned int i;
+  if (f < 32)
+    {
+      /* The first 32 features.  */
+      cpu_model->__cpu_features[0] |= (1U << (f & 31));
+      return;
+    }
+  /* The rest of features.  cpu_features2[i] contains features from
+     (32 + i * 32) to (31 + 32 + i * 32), inclusively.  */
+  for (i = 0; i < SIZE_OF_CPU_FEATURES; i++)
+    if (f < (32 + 32 + i * 32))
+      {
+	cpu_features2[i] |= (1U << ((f - (32 + i * 32)) & 31));
+	return;
+      }
+  gcc_unreachable ();
+}
+
+/* Get the specific type of AMD CPU and return AMD CPU name.  Return
+   NULL for unknown AMD CPU.  */
+
+static inline const char *
+get_amd_cpu (struct __processor_model *cpu_model,
+	     struct __processor_model2 *cpu_model2,
+	     unsigned int *cpu_features2)
+{
+  const char *cpu = NULL;
+  unsigned int family = cpu_model2->__cpu_family;
+  unsigned int model = cpu_model2->__cpu_model;
+
+  switch (family)
+    {
+    case 0x10:
+      /* AMD Family 10h.  */
+      cpu = "amdfam10";
+      cpu_model->__cpu_type = AMDFAM10H;
+      switch (model)
+	{
+	case 0x2:
+	  /* Barcelona.  */
+	  CHECK___builtin_cpu_is ("amdfam10h");
+	  CHECK___builtin_cpu_is ("barcelona");
+	  cpu_model->__cpu_subtype = AMDFAM10H_BARCELONA;
+	  break;
+	case 0x4:
+	  /* Shanghai.  */
+	  CHECK___builtin_cpu_is ("amdfam10h");
+	  CHECK___builtin_cpu_is ("shanghai");
+	  cpu_model->__cpu_subtype = AMDFAM10H_SHANGHAI;
+	  break;
+	case 0x8:
+	  /* Istanbul.  */
+	  CHECK___builtin_cpu_is ("amdfam10h");
+	  CHECK___builtin_cpu_is ("istanbul");
+	  cpu_model->__cpu_subtype = AMDFAM10H_ISTANBUL;
+	  break;
+	default:
+	  break;
+	}
+      break;
+    case 0x14:
+      /* AMD Family 14h "btver1". */
+      cpu = "btver1";
+      CHECK___builtin_cpu_is ("btver1");
+      cpu_model->__cpu_type = AMD_BTVER1;
+      break;
+    case 0x15:
+      /* AMD Family 15h "Bulldozer".  */
+      cpu_model->__cpu_type = AMDFAM15H;
+      if (model == 0x2)
+	{
+	  /* Bulldozer version 2 "Piledriver" */
+	  cpu = "bdver2";
+	  CHECK___builtin_cpu_is ("bdver2");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+	}
+      else if (model <= 0xf)
+	{
+	  /* Bulldozer version 1.  */
+	  cpu = "bdver1";
+	  CHECK___builtin_cpu_is ("bdver1");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
+	}
+      else if (model <= 0x2f)
+	{
+	  /* Bulldozer version 2 "Piledriver" */
+	  cpu = "bdver2";
+	  CHECK___builtin_cpu_is ("bdver2");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+	}
+      else if (model <= 0x4f)
+	{
+	  /* Bulldozer version 3 "Steamroller"  */
+	  cpu = "bdver3";
+	  CHECK___builtin_cpu_is ("bdver3");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
+	}
+      else if (model <= 0x7f)
+	{
+	  /* Bulldozer version 4 "Excavator"   */
+	  cpu = "bdver4";
+	  CHECK___builtin_cpu_is ("bdver4");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_AVX2))
+	{
+	  cpu = "bdver4";
+	  CHECK___builtin_cpu_is ("bdver4");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER4;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_XSAVEOPT))
+	{
+	  cpu = "bdver3";
+	  CHECK___builtin_cpu_is ("bdver3");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER3;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_BMI))
+	{
+	  cpu = "bdver2";
+	  CHECK___builtin_cpu_is ("bdver2");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER2;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_XOP))
+	{
+	  cpu = "bdver1";
+	  CHECK___builtin_cpu_is ("bdver1");
+	  cpu_model->__cpu_subtype = AMDFAM15H_BDVER1;
+	}
+      break;
+    case 0x16:
+      /* AMD Family 16h "btver2" */
+      cpu = "btver2";
+      CHECK___builtin_cpu_is ("btver2");
+      cpu_model->__cpu_type = AMD_BTVER2;
+      break;
+    case 0x17:
+      cpu_model->__cpu_type = AMDFAM17H;
+      if (model <= 0x1f)
+	{
+	  /* AMD family 17h version 1.  */
+	  cpu = "znver1";
+	  CHECK___builtin_cpu_is ("znver1");
+	  cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
+	}
+      else if (model >= 0x30)
+	{
+	  cpu = "znver2";
+	  CHECK___builtin_cpu_is ("znver2");
+	  cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_CLWB))
+	{
+	  cpu = "znver2";
+	  CHECK___builtin_cpu_is ("znver2");
+	  cpu_model->__cpu_subtype = AMDFAM17H_ZNVER2;
+	}
+      else if (has_cpu_feature (cpu_model, cpu_features2,
+				FEATURE_CLZERO))
+	{
+	  cpu = "znver1";
+	  CHECK___builtin_cpu_is ("znver1");
+	  cpu_model->__cpu_subtype = AMDFAM17H_ZNVER1;
+	}
+      break;
+    default:
+      break;
+    }
+
+  return cpu;
+}
+
+/* Get the specific type of Intel CPU and return Intel CPU name.  Return
+   NULL for unknown Intel CPU.  */
+
+static inline const char *
+get_intel_cpu (struct __processor_model *cpu_model,
+	       struct __processor_model2 *cpu_model2,
+	       unsigned int *cpu_features2,
+	       unsigned int brand_id)
+{
+  const char *cpu = NULL;
+
+  /* Parse family and model only for brand ID 0 and model 6. */
+  if (brand_id != 0 || cpu_model2->__cpu_family != 0x6)
+    return cpu;
+
+  switch (cpu_model2->__cpu_model)
+    {
+    case 0x1c:
+    case 0x26:
+      /* Bonnell.  */
+      cpu = "bonnell";
+      CHECK___builtin_cpu_is ("atom");
+      cpu_model->__cpu_type = INTEL_BONNELL;
+      break;
+    case 0x37:
+    case 0x4a:
+    case 0x4d:
+    case 0x5d:
+      /* Silvermont.  */
+    case 0x4c:
+    case 0x5a:
+    case 0x75:
+      /* Airmont.  */
+      cpu = "silvermont";
+      CHECK___builtin_cpu_is ("silvermont");
+      cpu_model->__cpu_type = INTEL_SILVERMONT;
+      break;
+    case 0x5c:
+    case 0x5f:
+      /* Goldmont.  */
+      cpu = "goldmont";
+      CHECK___builtin_cpu_is ("goldmont");
+      cpu_model->__cpu_type = INTEL_GOLDMONT;
+      break;
+    case 0x7a:
+      /* Goldmont Plus.  */
+      cpu = "goldmont-plus";
+      CHECK___builtin_cpu_is ("goldmont-plus");
+      cpu_model->__cpu_type = INTEL_GOLDMONT_PLUS;
+      break;
+    case 0x86:
+    case 0x96:
+    case 0x9c:
+      /* Tremont.  */
+      cpu = "tremont";
+      CHECK___builtin_cpu_is ("tremont");
+      cpu_model->__cpu_type = INTEL_TREMONT;
+      break;
+    case 0x57:
+      /* Knights Landing.  */
+      cpu = "knl";
+      CHECK___builtin_cpu_is ("knl");
+      cpu_model->__cpu_type = INTEL_KNL;
+      break;
+    case 0x85:
+      /* Knights Mill. */
+      cpu = "knm";
+      CHECK___builtin_cpu_is ("knm");
+      cpu_model->__cpu_type = INTEL_KNM;
+      break;
+    case 0x1a:
+    case 0x1e:
+    case 0x1f:
+    case 0x2e:
+      /* Nehalem.  */
+      cpu = "nehalem";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("nehalem");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_NEHALEM;
+      break;
+    case 0x25:
+    case 0x2c:
+    case 0x2f:
+      /* Westmere.  */
+      cpu = "westmere";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("westmere");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_WESTMERE;
+      break;
+    case 0x2a:
+    case 0x2d:
+      /* Sandy Bridge.  */
+      cpu = "sandybridge";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("sandybridge");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
+      break;
+    case 0x3a:
+    case 0x3e:
+      /* Ivy Bridge.  */
+      cpu = "ivybridge";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("ivybridge");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
+      break;
+    case 0x3c:
+    case 0x3f:
+    case 0x45:
+    case 0x46:
+      /* Haswell.  */
+      cpu = "haswell";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("haswell");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_HASWELL;
+      break;
+    case 0x3d:
+    case 0x47:
+    case 0x4f:
+    case 0x56:
+      /* Broadwell.  */
+      cpu = "broadwell";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("broadwell");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_BROADWELL;
+      break;
+    case 0x4e:
+    case 0x5e:
+      /* Skylake.  */
+    case 0x8e:
+    case 0x9e:
+      /* Kaby Lake.  */
+    case 0xa5:
+    case 0xa6:
+      /* Comet Lake.  */
+      cpu = "skylake";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("skylake");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE;
+      break;
+    case 0x55:
+      CHECK___builtin_cpu_is ("corei7");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      if (has_cpu_feature (cpu_model, cpu_features2,
+			   FEATURE_AVX512VNNI))
+	{
+	  /* Cascade Lake.  */
+	  cpu = "cascadelake";
+	  CHECK___builtin_cpu_is ("cascadelake");
+	  cpu_model->__cpu_subtype = INTEL_COREI7_CASCADELAKE;
+	}
+      else
+	{
+	  /* Skylake with AVX-512 support.  */
+	  cpu = "skylake-avx512";
+	  CHECK___builtin_cpu_is ("skylake-avx512");
+	  cpu_model->__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
+	}
+      break;
+    case 0x66:
+      /* Cannon Lake.  */
+      cpu = "cannonlake";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("cannonlake");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_CANNONLAKE;
+      break;
+    case 0x6a:
+    case 0x6c:
+      /* Ice Lake server.  */
+      cpu = "icelake-server";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("icelake-server");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_SERVER;
+      break;
+    case 0x7e:
+    case 0x7d:
+    case 0x9d:
+       /* Ice Lake client.  */
+      cpu = "icelake-client";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("icelake-client");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_ICELAKE_CLIENT;
+      break;
+    case 0x8c:
+    case 0x8d:
+      /* Tiger Lake.  */
+      cpu = "tigerlake";
+      CHECK___builtin_cpu_is ("corei7");
+      CHECK___builtin_cpu_is ("tigerlake");
+      cpu_model->__cpu_type = INTEL_COREI7;
+      cpu_model->__cpu_subtype = INTEL_COREI7_TIGERLAKE;
+      break;
+    case 0x17:
+    case 0x1d:
+      /* Penryn.  */
+    case 0x0f:
+      /* Merom.  */
+      cpu = "core2";
+      CHECK___builtin_cpu_is ("core2");
+      cpu_model->__cpu_type = INTEL_CORE2;
+      break;
+    default:
+      break;
+    }
+
+  return cpu;
+}
+
+/* ECX and EDX are output of CPUID at level one.  */
+static inline void
+get_available_features (struct __processor_model *cpu_model,
+			struct __processor_model2 *cpu_model2,
+			unsigned int *cpu_features2,
+			unsigned int ecx, unsigned int edx)
+{
+  unsigned int max_cpuid_level = cpu_model2->__cpu_max_level;
+  unsigned int eax, ebx;
+  unsigned int ext_level;
+
+  /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv.  */
+#define XCR_XFEATURE_ENABLED_MASK	0x0
+#define XSTATE_FP			0x1
+#define XSTATE_SSE			0x2
+#define XSTATE_YMM			0x4
+#define XSTATE_OPMASK			0x20
+#define XSTATE_ZMM			0x40
+#define XSTATE_HI_ZMM			0x80
+
+#define XCR_AVX_ENABLED_MASK \
+  (XSTATE_SSE | XSTATE_YMM)
+#define XCR_AVX512F_ENABLED_MASK \
+  (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
+
+  /* Check if AVX and AVX512 are usable.  */
+  int avx_usable = 0;
+  int avx512_usable = 0;
+  if ((ecx & bit_OSXSAVE))
+    {
+      /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
+	 ZMM16-ZMM31 states are supported by OSXSAVE.  */
+      unsigned int xcrlow;
+      unsigned int xcrhigh;
+      __asm__ (".byte 0x0f, 0x01, 0xd0"
+	       : "=a" (xcrlow), "=d" (xcrhigh)
+	       : "c" (XCR_XFEATURE_ENABLED_MASK));
+      if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
+	{
+	  avx_usable = 1;
+	  avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
+			   == XCR_AVX512F_ENABLED_MASK);
+	}
+    }
+
+#define set_feature(f) \
+  set_cpu_feature (cpu_model, cpu_features2, f)
+
+  if (edx & bit_CMOV)
+    set_feature (FEATURE_CMOV);
+  if (edx & bit_MMX)
+    set_feature (FEATURE_MMX);
+  if (edx & bit_SSE)
+    set_feature (FEATURE_SSE);
+  if (edx & bit_SSE2)
+    set_feature (FEATURE_SSE2);
+  if (edx & bit_CMPXCHG8B)
+    set_feature (FEATURE_CMPXCHG8B);
+  if (edx & bit_FXSAVE)
+    set_feature (FEATURE_FXSAVE);
+
+  if (ecx & bit_POPCNT)
+    set_feature (FEATURE_POPCNT);
+  if (ecx & bit_AES)
+    set_feature (FEATURE_AES);
+  if (ecx & bit_PCLMUL)
+    set_feature (FEATURE_PCLMUL);
+  if (ecx & bit_SSE3)
+    set_feature (FEATURE_SSE3);
+  if (ecx & bit_SSSE3)
+    set_feature (FEATURE_SSSE3);
+  if (ecx & bit_SSE4_1)
+    set_feature (FEATURE_SSE4_1);
+  if (ecx & bit_SSE4_2)
+    set_feature (FEATURE_SSE4_2);
+  if (ecx & bit_OSXSAVE)
+    set_feature (FEATURE_OSXSAVE);
+  if (ecx & bit_CMPXCHG16B)
+    set_feature (FEATURE_CMPXCHG16B);
+  if (ecx & bit_MOVBE)
+    set_feature (FEATURE_MOVBE);
+  if (ecx & bit_AES)
+    set_feature (FEATURE_AES);
+  if (ecx & bit_F16C)
+    set_feature (FEATURE_F16C);
+  if (ecx & bit_RDRND)
+    set_feature (FEATURE_RDRND);
+  if (ecx & bit_XSAVE)
+    set_feature (FEATURE_XSAVE);
+  if (avx_usable)
+    {
+      if (ecx & bit_AVX)
+	set_feature (FEATURE_AVX);
+      if (ecx & bit_FMA)
+	set_feature (FEATURE_FMA);
+    }
+
+  /* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */
+  if (max_cpuid_level >= 7)
+    {
+      __cpuid_count (7, 0, eax, ebx, ecx, edx);
+      if (ebx & bit_BMI)
+	set_feature (FEATURE_BMI);
+      if (ebx & bit_SGX)
+	set_feature (FEATURE_SGX);
+      if (ebx & bit_HLE)
+	set_feature (FEATURE_HLE);
+      if (ebx & bit_RTM)
+	set_feature (FEATURE_RTM);
+      if (avx_usable)
+	{
+	  if (ebx & bit_AVX2)
+	    set_feature (FEATURE_AVX2);
+	  if (ecx & bit_VPCLMULQDQ)
+	    set_feature (FEATURE_VPCLMULQDQ);
+	}
+      if (ebx & bit_BMI2)
+	set_feature (FEATURE_BMI2);
+      if (ebx & bit_FSGSBASE)
+	set_feature (FEATURE_FSGSBASE);
+      if (ebx & bit_RDSEED)
+	set_feature (FEATURE_RDSEED);
+      if (ebx & bit_ADX)
+	set_feature (FEATURE_ADX);
+      if (ebx & bit_SHA)
+	set_feature (FEATURE_SHA);
+      if (ebx & bit_CLFLUSHOPT)
+	set_feature (FEATURE_CLFLUSHOPT);
+      if (ebx & bit_CLWB)
+	set_feature (FEATURE_CLWB);
+      if (ecx & bit_PREFETCHWT1)
+	set_feature (FEATURE_PREFETCHWT1);
+      /* NB: bit_OSPKE indicates that OS supports PKU.  */
+      if (ecx & bit_OSPKE)
+	set_feature (FEATURE_PKU);
+      if (ecx & bit_RDPID)
+	set_feature (FEATURE_RDPID);
+      if (ecx & bit_VAES)
+	set_feature (FEATURE_VAES);
+      if (ecx & bit_GFNI)
+	set_feature (FEATURE_GFNI);
+      if (ecx & bit_MOVDIRI)
+	set_feature (FEATURE_MOVDIRI);
+      if (ecx & bit_MOVDIR64B)
+	set_feature (FEATURE_MOVDIR64B);
+      if (ecx & bit_ENQCMD)
+	set_feature (FEATURE_ENQCMD);
+      if (ecx & bit_CLDEMOTE)
+	set_feature (FEATURE_CLDEMOTE);
+      if (ecx & bit_WAITPKG)
+	set_feature (FEATURE_WAITPKG);
+      if (ecx & bit_SHSTK)
+	set_feature (FEATURE_SHSTK);
+      if (edx & bit_SERIALIZE)
+	set_feature (FEATURE_SERIALIZE);
+      if (edx & bit_TSXLDTRK)
+	set_feature (FEATURE_TSXLDTRK);
+      if (edx & bit_PCONFIG)
+	set_feature (FEATURE_PCONFIG);
+      if (edx & bit_IBT)
+	set_feature (FEATURE_IBT);
+      if (avx512_usable)
+	{
+	  if (ebx & bit_AVX512F)
+	    set_feature (FEATURE_AVX512F);
+	  if (ebx & bit_AVX512VL)
+	    set_feature (FEATURE_AVX512VL);
+	  if (ebx & bit_AVX512BW)
+	    set_feature (FEATURE_AVX512BW);
+	  if (ebx & bit_AVX512DQ)
+	    set_feature (FEATURE_AVX512DQ);
+	  if (ebx & bit_AVX512CD)
+	    set_feature (FEATURE_AVX512CD);
+	  if (ebx & bit_AVX512PF)
+	    set_feature (FEATURE_AVX512PF);
+	  if (ebx & bit_AVX512ER)
+	    set_feature (FEATURE_AVX512ER);
+	  if (ebx & bit_AVX512IFMA)
+	    set_feature (FEATURE_AVX512IFMA);
+	  if (ecx & bit_AVX512VBMI)
+	    set_feature (FEATURE_AVX512VBMI);
+	  if (ecx & bit_AVX512VBMI2)
+	    set_feature (FEATURE_AVX512VBMI2);
+	  if (ecx & bit_AVX512VNNI)
+	    set_feature (FEATURE_AVX512VNNI);
+	  if (ecx & bit_AVX512BITALG)
+	    set_feature (FEATURE_AVX512BITALG);
+	  if (ecx & bit_AVX512VPOPCNTDQ)
+	    set_feature (FEATURE_AVX512VPOPCNTDQ);
+	  if (edx & bit_AVX5124VNNIW)
+	    set_feature (FEATURE_AVX5124VNNIW);
+	  if (edx & bit_AVX5124FMAPS)
+	    set_feature (FEATURE_AVX5124FMAPS);
+	  if (edx & bit_AVX512VP2INTERSECT)
+	    set_feature (FEATURE_AVX512VP2INTERSECT);
+
+	  __cpuid_count (7, 1, eax, ebx, ecx, edx);
+	  if (eax & bit_AVX512BF16)
+	    set_feature (FEATURE_AVX512BF16);
+	}
+    }
+
+  /* Get Advanced Features at level 0xd (eax = 0xd, ecx = 1). */
+  if (max_cpuid_level >= 0xd)
+    {
+      __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
+      if (eax & bit_XSAVEOPT)
+	set_feature (FEATURE_XSAVEOPT);
+      if (eax & bit_XSAVEC)
+	set_feature (FEATURE_XSAVEC);
+      if (eax & bit_XSAVES)
+	set_feature (FEATURE_XSAVES);
+    }
+
+  /* Get Advanced Features at level 0x14 (eax = 0x14, ecx = 0). */
+  if (max_cpuid_level >= 0x14)
+    {
+      __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
+      if (ebx & bit_PTWRITE)
+	set_feature (FEATURE_PTWRITE);
+    }
+
+  /* Check cpuid level of extended features.  */
+  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
+
+  cpu_model2->__cpu_ext_level = ext_level;
+
+  if (ext_level >= 0x80000001)
+    {
+      __cpuid (0x80000001, eax, ebx, ecx, edx);
+
+      if (ecx & bit_SSE4a)
+	set_feature (FEATURE_SSE4_A);
+      if (ecx & bit_LAHF_LM)
+	set_feature (FEATURE_LAHF_LM);
+      if (ecx & bit_ABM)
+	set_feature (FEATURE_ABM);
+      if (ecx & bit_LWP)
+	set_feature (FEATURE_LWP);
+      if (ecx & bit_TBM)
+	set_feature (FEATURE_TBM);
+      if (ecx & bit_LZCNT)
+	set_feature (FEATURE_LZCNT);
+      if (ecx & bit_PRFCHW)
+	set_feature (FEATURE_PRFCHW);
+      if (ecx & bit_MWAITX)
+	set_feature (FEATURE_MWAITX);
+
+      if (edx & bit_LM)
+	set_feature (FEATURE_LM);
+      if (edx & bit_3DNOWP)
+	set_feature (FEATURE_3DNOWP);
+      if (edx & bit_3DNOW)
+	set_feature (FEATURE_3DNOW);
+
+      if (avx_usable)
+	{
+	  if (ecx & bit_FMA4)
+	    set_feature (FEATURE_FMA4);
+	  if (ecx & bit_XOP)
+	    set_feature (FEATURE_XOP);
+	}
+    }
+
+  if (ext_level >= 0x80000008)
+    {
+      __cpuid (0x80000008, eax, ebx, ecx, edx);
+      if (ebx & bit_CLZERO)
+	set_feature (FEATURE_CLZERO);
+      if (ebx & bit_WBNOINVD)
+	set_feature (FEATURE_WBNOINVD);
+    }
+
+#undef set_feature
+}
+
+static inline int
+cpu_indicator_init (struct __processor_model *cpu_model,
+		    struct __processor_model2 *cpu_model2,
+		    unsigned int *cpu_features2)
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  int max_level;
+  unsigned int vendor;
+  unsigned int model, family, brand_id;
+  unsigned int extended_model, extended_family;
+
+  /* This function needs to run just once.  */
+  if (cpu_model->__cpu_vendor)
+    return 0;
+
+  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
+  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
+    {
+      cpu_model->__cpu_vendor = VENDOR_OTHER;
+      return -1;
+    }
+
+  vendor = ebx;
+  max_level = eax;
+
+  if (max_level < 1)
+    {
+      cpu_model->__cpu_vendor = VENDOR_OTHER;
+      return -1;
+    }
+
+  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+    {
+      cpu_model->__cpu_vendor = VENDOR_OTHER;
+      return -1;
+    }
+
+  cpu_model2->__cpu_max_level = max_level;
+
+  model = (eax >> 4) & 0x0f;
+  family = (eax >> 8) & 0x0f;
+  brand_id = ebx & 0xff;
+  extended_model = (eax >> 12) & 0xf0;
+  extended_family = (eax >> 20) & 0xff;
+
+  if (vendor == signature_INTEL_ebx)
+    {
+      /* Adjust model and family for Intel CPUS. */
+      if (family == 0x0f)
+	{
+	  family += extended_family;
+	  model += extended_model;
+	}
+      else if (family == 0x06)
+	model += extended_model;
+
+      cpu_model2->__cpu_family = family;
+      cpu_model2->__cpu_model = model;
+
+      /* Find available features. */
+      get_available_features (cpu_model, cpu_model2, cpu_features2,
+			      ecx, edx);
+      /* Get CPU type.  */
+      get_intel_cpu (cpu_model, cpu_model2, cpu_features2, brand_id);
+      cpu_model->__cpu_vendor = VENDOR_INTEL;
+    }
+  else if (vendor == signature_AMD_ebx)
+    {
+      /* Adjust model and family for AMD CPUS. */
+      if (family == 0x0f)
+	{
+	  family += extended_family;
+	  model += extended_model;
+	}
+
+      cpu_model2->__cpu_family = family;
+      cpu_model2->__cpu_model = model;
+
+      /* Find available features. */
+      get_available_features (cpu_model, cpu_model2, cpu_features2,
+			      ecx, edx);
+      /* Get CPU type.  */
+      get_amd_cpu (cpu_model, cpu_model2, cpu_features2);
+      cpu_model->__cpu_vendor = VENDOR_AMD;
+    }
+  else if (vendor == signature_CENTAUR_ebx)
+    cpu_model->__cpu_vendor = VENDOR_CENTAUR;
+  else if (vendor == signature_CYRIX_ebx)
+    cpu_model->__cpu_vendor = VENDOR_CYRIX;
+  else if (vendor == signature_NSC_ebx)
+    cpu_model->__cpu_vendor = VENDOR_NSC;
+  else
+    cpu_model->__cpu_vendor = VENDOR_OTHER;
+
+  gcc_assert (cpu_model->__cpu_vendor < VENDOR_MAX);
+  gcc_assert (cpu_model->__cpu_type < CPU_TYPE_MAX);
+  gcc_assert (cpu_model->__cpu_subtype < CPU_SUBTYPE_MAX);
+
+  return 0;
+}
diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h
index e11c68f46dd..96cf0eaea47 100644
--- a/gcc/common/config/i386/i386-cpuinfo.h
+++ b/gcc/common/config/i386/i386-cpuinfo.h
@@ -30,6 +30,9 @@  enum processor_vendor
   VENDOR_INTEL = 1,
   VENDOR_AMD,
   VENDOR_OTHER,
+  VENDOR_CENTAUR,
+  VENDOR_CYRIX,
+  VENDOR_NSC,
   BUILTIN_VENDOR_MAX = VENDOR_OTHER,
   VENDOR_MAX
 };
@@ -122,6 +125,101 @@  enum feature_priority
   P_PROC_DYNAMIC
 };
 
+/* ISA Features supported. New features have to be inserted at the end.  */
+
+enum processor_features
+{
+  FEATURE_CMOV = 0,
+  FEATURE_MMX,
+  FEATURE_POPCNT,
+  FEATURE_SSE,
+  FEATURE_SSE2,
+  FEATURE_SSE3,
+  FEATURE_SSSE3,
+  FEATURE_SSE4_1,
+  FEATURE_SSE4_2,
+  FEATURE_AVX,
+  FEATURE_AVX2,
+  FEATURE_SSE4_A,
+  FEATURE_FMA4,
+  FEATURE_XOP,
+  FEATURE_FMA,
+  FEATURE_AVX512F,
+  FEATURE_BMI,
+  FEATURE_BMI2,
+  FEATURE_AES,
+  FEATURE_PCLMUL,
+  FEATURE_AVX512VL,
+  FEATURE_AVX512BW,
+  FEATURE_AVX512DQ,
+  FEATURE_AVX512CD,
+  FEATURE_AVX512ER,
+  FEATURE_AVX512PF,
+  FEATURE_AVX512VBMI,
+  FEATURE_AVX512IFMA,
+  FEATURE_AVX5124VNNIW,
+  FEATURE_AVX5124FMAPS,
+  FEATURE_AVX512VPOPCNTDQ,
+  FEATURE_AVX512VBMI2,
+  FEATURE_GFNI,
+  FEATURE_VPCLMULQDQ,
+  FEATURE_AVX512VNNI,
+  FEATURE_AVX512BITALG,
+  FEATURE_AVX512BF16,
+  FEATURE_AVX512VP2INTERSECT,
+  FEATURE_3DNOW,
+  FEATURE_3DNOWP,
+  FEATURE_ADX,
+  FEATURE_ABM,
+  FEATURE_CLDEMOTE,
+  FEATURE_CLFLUSHOPT,
+  FEATURE_CLWB,
+  FEATURE_CLZERO,
+  FEATURE_CMPXCHG16B,
+  FEATURE_CMPXCHG8B,
+  FEATURE_ENQCMD,
+  FEATURE_F16C,
+  FEATURE_FSGSBASE,
+  FEATURE_FXSAVE,
+  FEATURE_HLE,
+  FEATURE_IBT,
+  FEATURE_LAHF_LM,
+  FEATURE_LM,
+  FEATURE_LWP,
+  FEATURE_LZCNT,
+  FEATURE_MOVBE,
+  FEATURE_MOVDIR64B,
+  FEATURE_MOVDIRI,
+  FEATURE_MWAITX,
+  FEATURE_OSXSAVE,
+  FEATURE_PCONFIG,
+  FEATURE_PKU,
+  FEATURE_PREFETCHWT1,
+  FEATURE_PRFCHW,
+  FEATURE_PTWRITE,
+  FEATURE_RDPID,
+  FEATURE_RDRND,
+  FEATURE_RDSEED,
+  FEATURE_RTM,
+  FEATURE_SERIALIZE,
+  FEATURE_SGX,
+  FEATURE_SHA,
+  FEATURE_SHSTK,
+  FEATURE_TBM,
+  FEATURE_TSXLDTRK,
+  FEATURE_VAES,
+  FEATURE_WAITPKG,
+  FEATURE_WBNOINVD,
+  FEATURE_XSAVE,
+  FEATURE_XSAVEC,
+  FEATURE_XSAVEOPT,
+  FEATURE_XSAVES,
+  CPU_FEATURE_MAX
+};
+
+/* Size of __cpu_features2 array in libgcc/config/i386/cpuinfo.c.  */
+#define SIZE_OF_CPU_FEATURES ((CPU_FEATURE_MAX - 1) / 32)
+
 /* These are the values for vendor types, cpu types and subtypes.  Cpu
    types and subtypes should be subtracted by the corresponding start
    value.  */
diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
index 6f6a8328ef1..57e709d6c43 100644
--- a/gcc/config/i386/i386-builtins.c
+++ b/gcc/config/i386/i386-builtins.c
@@ -1835,50 +1835,6 @@  ix86_builtin_reciprocal (tree fndecl)
     }
 }
 
-/* This is the order of bit-fields in __processor_features in cpuinfo.c */
-enum processor_features
-{
-  F_CMOV = 0,
-  F_MMX,
-  F_POPCNT,
-  F_SSE,
-  F_SSE2,
-  F_SSE3,
-  F_SSSE3,
-  F_SSE4_1,
-  F_SSE4_2,
-  F_AVX,
-  F_AVX2,
-  F_SSE4_A,
-  F_FMA4,
-  F_XOP,
-  F_FMA,
-  F_AVX512F,
-  F_BMI,
-  F_BMI2,
-  F_AES,
-  F_PCLMUL,
-  F_AVX512VL,
-  F_AVX512BW,
-  F_AVX512DQ,
-  F_AVX512CD,
-  F_AVX512ER,
-  F_AVX512PF,
-  F_AVX512VBMI,
-  F_AVX512IFMA,
-  F_AVX5124VNNIW,
-  F_AVX5124FMAPS,
-  F_AVX512VPOPCNTDQ,
-  F_AVX512VBMI2,
-  F_GFNI,
-  F_VPCLMULQDQ,
-  F_AVX512VNNI,
-  F_AVX512BITALG,
-  F_AVX512BF16,
-  F_AVX512VP2INTERSECT,
-  F_MAX
-};
-
 /* These are the target attribute strings for which a dispatcher is
    available, from fold_builtin_cpu.  */
 struct _isa_names_table
@@ -1890,44 +1846,44 @@  struct _isa_names_table
 
 static const _isa_names_table isa_names_table[] =
 {
-  {"cmov",    F_CMOV,	P_NONE},
-  {"mmx",     F_MMX,	P_MMX},
-  {"popcnt",  F_POPCNT,	P_POPCNT},
-  {"sse",     F_SSE,	P_SSE},
-  {"sse2",    F_SSE2,	P_SSE2},
-  {"sse3",    F_SSE3,	P_SSE3},
-  {"ssse3",   F_SSSE3,	P_SSSE3},
-  {"sse4a",   F_SSE4_A,	P_SSE4_A},
-  {"sse4.1",  F_SSE4_1,	P_SSE4_1},
-  {"sse4.2",  F_SSE4_2,	P_SSE4_2},
-  {"avx",     F_AVX,	P_AVX},
-  {"fma4",    F_FMA4,	P_FMA4},
-  {"xop",     F_XOP,	P_XOP},
-  {"fma",     F_FMA,	P_FMA},
-  {"avx2",    F_AVX2,	P_AVX2},
-  {"avx512f", F_AVX512F, P_AVX512F},
-  {"bmi",     F_BMI,	P_BMI},
-  {"bmi2",    F_BMI2,	P_BMI2},
-  {"aes",     F_AES,	P_AES},
-  {"pclmul",  F_PCLMUL,	P_PCLMUL},
-  {"avx512vl",F_AVX512VL, P_NONE},
-  {"avx512bw",F_AVX512BW, P_NONE},
-  {"avx512dq",F_AVX512DQ, P_NONE},
-  {"avx512cd",F_AVX512CD, P_NONE},
-  {"avx512er",F_AVX512ER, P_NONE},
-  {"avx512pf",F_AVX512PF, P_NONE},
-  {"avx512vbmi",F_AVX512VBMI, P_NONE},
-  {"avx512ifma",F_AVX512IFMA, P_NONE},
-  {"avx5124vnniw",F_AVX5124VNNIW, P_NONE},
-  {"avx5124fmaps",F_AVX5124FMAPS, P_NONE},
-  {"avx512vpopcntdq",F_AVX512VPOPCNTDQ,	P_NONE},
-  {"avx512vbmi2", F_AVX512VBMI2, P_NONE},
-  {"gfni",	F_GFNI,	P_NONE},
-  {"vpclmulqdq", F_VPCLMULQDQ, P_NONE},
-  {"avx512vnni", F_AVX512VNNI, P_NONE},
-  {"avx512bitalg", F_AVX512BITALG, P_NONE},
-  {"avx512bf16", F_AVX512BF16, P_NONE},
-  {"avx512vp2intersect",F_AVX512VP2INTERSECT, P_NONE}
+  {"cmov",    FEATURE_CMOV,	P_NONE},
+  {"mmx",     FEATURE_MMX,	P_MMX},
+  {"popcnt",  FEATURE_POPCNT,	P_POPCNT},
+  {"sse",     FEATURE_SSE,	P_SSE},
+  {"sse2",    FEATURE_SSE2,	P_SSE2},
+  {"sse3",    FEATURE_SSE3,	P_SSE3},
+  {"ssse3",   FEATURE_SSSE3,	P_SSSE3},
+  {"sse4a",   FEATURE_SSE4_A,	P_SSE4_A},
+  {"sse4.1",  FEATURE_SSE4_1,	P_SSE4_1},
+  {"sse4.2",  FEATURE_SSE4_2,	P_SSE4_2},
+  {"avx",     FEATURE_AVX,	P_AVX},
+  {"fma4",    FEATURE_FMA4,	P_FMA4},
+  {"xop",     FEATURE_XOP,	P_XOP},
+  {"fma",     FEATURE_FMA,	P_FMA},
+  {"avx2",    FEATURE_AVX2,	P_AVX2},
+  {"avx512f", FEATURE_AVX512F, P_AVX512F},
+  {"bmi",     FEATURE_BMI,	P_BMI},
+  {"bmi2",    FEATURE_BMI2,	P_BMI2},
+  {"aes",     FEATURE_AES,	P_AES},
+  {"pclmul",  FEATURE_PCLMUL,	P_PCLMUL},
+  {"avx512vl",FEATURE_AVX512VL, P_NONE},
+  {"avx512bw",FEATURE_AVX512BW, P_NONE},
+  {"avx512dq",FEATURE_AVX512DQ, P_NONE},
+  {"avx512cd",FEATURE_AVX512CD, P_NONE},
+  {"avx512er",FEATURE_AVX512ER, P_NONE},
+  {"avx512pf",FEATURE_AVX512PF, P_NONE},
+  {"avx512vbmi",FEATURE_AVX512VBMI, P_NONE},
+  {"avx512ifma",FEATURE_AVX512IFMA, P_NONE},
+  {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_NONE},
+  {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_NONE},
+  {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ,	P_NONE},
+  {"avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE},
+  {"gfni",	FEATURE_GFNI,	P_NONE},
+  {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE},
+  {"avx512vnni", FEATURE_AVX512VNNI, P_NONE},
+  {"avx512bitalg", FEATURE_AVX512BITALG, P_NONE},
+  {"avx512bf16", FEATURE_AVX512BF16, P_NONE},
+  {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_NONE}
 };
 
 /* This parses the attribute arguments to target in DECL and determines
@@ -2294,16 +2250,29 @@  fold_builtin_cpu (tree fndecl, tree *args)
 
       if (isa_names_table[i].feature >= 32)
 	{
-	  tree __cpu_features2_var = make_var_decl (unsigned_type_node,
+	  tree index_type
+	    = build_index_type (size_int (SIZE_OF_CPU_FEATURES));
+	  tree type = build_array_type (unsigned_type_node, index_type);
+	  tree __cpu_features2_var = make_var_decl (type,
 						    "__cpu_features2");
 
 	  varpool_node::add (__cpu_features2_var);
-	  field_val = (1U << (isa_names_table[i].feature - 32));
-	  /* Return __cpu_features2 & field_val  */
-	  final = build2 (BIT_AND_EXPR, unsigned_type_node,
-			  __cpu_features2_var,
-			  build_int_cstu (unsigned_type_node, field_val));
-	  return build1 (CONVERT_EXPR, integer_type_node, final);
+	  for (unsigned int j = 0; j < SIZE_OF_CPU_FEATURES; j++)
+	    if (isa_names_table[i].feature < (32 + 32 + j * 32))
+	      {
+		field_val = (1U << (isa_names_table[i].feature
+				    - (32 + j * 32)));
+		tree index = size_int (j);
+		array_elt = build4 (ARRAY_REF, unsigned_type_node,
+				    __cpu_features2_var,
+				    index, NULL_TREE, NULL_TREE);
+		/* Return __cpu_features2[index] & field_val  */
+		final = build2 (BIT_AND_EXPR, unsigned_type_node,
+				array_elt,
+				build_int_cstu (unsigned_type_node,
+						field_val));
+		return build1 (CONVERT_EXPR, integer_type_node, final);
+	      }
 	}
 
       field = TYPE_FIELDS (__processor_model_type);
diff --git a/libgcc/config/i386/cpuinfo.c b/libgcc/config/i386/cpuinfo.c
index cf5f0884bb4..7218952f32a 100644
--- a/libgcc/config/i386/cpuinfo.c
+++ b/libgcc/config/i386/cpuinfo.c
@@ -26,7 +26,8 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "cpuid.h"
 #include "tsystem.h"
 #include "auto-target.h"
-#include "cpuinfo.h"
+#include "common/config/i386/i386-cpuinfo.h"
+#include "common/config/i386/cpuinfo.h"
 
 #ifdef HAVE_INIT_PRIORITY
 #define CONSTRUCTOR_PRIORITY (101)
@@ -39,386 +40,14 @@  int __cpu_indicator_init (void)
 
 
 struct __processor_model __cpu_model = { };
-#ifndef SHARED
 /* We want to move away from __cpu_model in libgcc_s.so.1 and the
    size of __cpu_model is part of ABI.  So, new features that don't
    fit into __cpu_model.__cpu_features[0] go into extra variables
-   in libgcc.a only, preferrably hidden.  */
-unsigned int __cpu_features2;
-#endif
-
-
-/* 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);
+   in libgcc.a only, preferably hidden.
 
-	  __cpuid_count (7, 1, eax, ebx, ecx, edx);
-	  if (eax & bit_AVX512BF16)
-	    set_feature (FEATURE_AVX512BF16);
-	}
-    }
-
-  /* Check cpuid level of extended features.  */
-  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
-
-  if (ext_level >= 0x80000001)
-    {
-      __cpuid (0x80000001, eax, ebx, ecx, edx);
-
-      if (ecx & bit_SSE4a)
-	set_feature (FEATURE_SSE4_A);
-      if (avx_usable)
-	{
-	  if (ecx & bit_FMA4)
-	    set_feature (FEATURE_FMA4);
-	  if (ecx & bit_XOP)
-	    set_feature (FEATURE_XOP);
-	}
-    }
-    
-  __cpu_model.__cpu_features[0] = features;
-#ifndef SHARED
-  __cpu_features2 = features2;
-#else
-  (void) features2;
-#endif
-}
+   NB: Since older 386-builtins.c accesses __cpu_features2 as scalar or
+   smaller array, it can only access the first few elements.  */
+unsigned int __cpu_features2[SIZE_OF_CPU_FEATURES];
 
 /* A constructor function that is sets __cpu_model and __cpu_features with
    the right values.  This needs to run only once.  This constructor is
@@ -429,85 +58,9 @@  get_available_features (unsigned int ecx, unsigned int edx,
 int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
 __cpu_indicator_init (void)
 {
-  unsigned int eax, ebx, ecx, edx;
-
-  int max_level;
-  unsigned int vendor;
-  unsigned int model, family, brand_id;
-  unsigned int extended_model, extended_family;
-
-  /* This function needs to run just once.  */
-  if (__cpu_model.__cpu_vendor)
-    return 0;
-
-  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
-  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
-    {
-      __cpu_model.__cpu_vendor = VENDOR_OTHER;
-      return -1;
-    }
-
-  vendor = ebx;
-  max_level = eax;
-
-  if (max_level < 1)
-    {
-      __cpu_model.__cpu_vendor = VENDOR_OTHER;
-      return -1;
-    }
-
-  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
-    {
-      __cpu_model.__cpu_vendor = VENDOR_OTHER;
-      return -1;
-    }
-
-  model = (eax >> 4) & 0x0f;
-  family = (eax >> 8) & 0x0f;
-  brand_id = ebx & 0xff;
-  extended_model = (eax >> 12) & 0xf0;
-  extended_family = (eax >> 20) & 0xff;
-
-  if (vendor == signature_INTEL_ebx)
-    {
-      /* Adjust model and family for Intel CPUS. */
-      if (family == 0x0f)
-	{
-	  family += extended_family;
-	  model += extended_model;
-	}
-      else if (family == 0x06)
-	model += extended_model;
-
-      /* Get CPU type.  */
-      get_intel_cpu (family, model, brand_id);
-      /* Find available features. */
-      get_available_features (ecx, edx, max_level);
-      __cpu_model.__cpu_vendor = VENDOR_INTEL;
-    }
-  else if (vendor == signature_AMD_ebx)
-    {
-      /* Adjust model and family for AMD CPUS. */
-      if (family == 0x0f)
-	{
-	  family += extended_family;
-	  model += extended_model;
-	}
-
-      /* Get CPU type.  */
-      get_amd_cpu (family, model);
-      /* Find available features. */
-      get_available_features (ecx, edx, max_level);
-      __cpu_model.__cpu_vendor = VENDOR_AMD;
-    }
-  else
-    __cpu_model.__cpu_vendor = VENDOR_OTHER;
-
-  gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
-  gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
-  gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
-
-  return 0;
+  struct __processor_model2 cpu_model2;
+  return cpu_indicator_init (&__cpu_model, &cpu_model2,
+			     __cpu_features2);
 }
 
 #if defined SHARED && defined USE_ELF_SYMVER
diff --git a/libgcc/config/i386/cpuinfo.h b/libgcc/config/i386/cpuinfo.h
deleted file mode 100644
index 0f97510cde1..00000000000
--- a/libgcc/config/i386/cpuinfo.h
+++ /dev/null
@@ -1,136 +0,0 @@ 
-/* Get CPU type and Features for x86 processors.
-   Copyright (C) 2012-2020 Free Software Foundation, Inc.
-   Contributed by Sriraman Tallam (tmsriram@google.com)
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-Under Section 7 of GPL version 3, you are granted additional
-permissions described in the GCC Runtime Library Exception, version
-3.1, as published by the Free Software Foundation.
-
-You should have received a copy of the GNU General Public License and
-a copy of the GCC Runtime Library Exception along with this program;
-see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-<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;