diff mbox series

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

Message ID CAMe9rOoneLTrdKteFsZ_iPJ+JvKMdE72magw5riB-=uHQMGDBg@mail.gmail.com
State New
Headers show
Series V3 [PATCH] x86: Move cpuinfo.h from libgcc to common/config/i386 | expand

Commit Message

H.J. Lu May 22, 2020, 2:51 p.m. UTC
On Thu, May 21, 2020 at 10:37 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Wed, May 20, 2020 at 4:21 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Tue, May 19, 2020 at 11:10 PM Uros Bizjak <ubizjak@gmail.com> wrote:
> > >
> > > On Tue, May 19, 2020 at 11:40 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > > > > > > > > > I will take a look to see if we share the same CPU detection code between
> > > > > > > > > > > libgcc and config/i386/driver-i386.c.
> > > > > > > > > >
> > > > > > > > > > I don't think it will bring any benefit, this is mainly one huge
> > > > > > > > > > switch statement that maps to different stuff in libgcc and
> > > > > > > > > > driver-i386.
> > > > > > > > >
> > > > > > > > > libgcc and config/i386/driver-i386.c differ even before my patch.
> > > > > > > > > I think we can do better.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Move cpuinfo.h from libgcc to common/config/i386 so that get_intel_cpu
> > > > > > > > can be shared by libgcc, GCC driver, gcc.target/i386/builtin_target.c
> > > > > > > > and libgfortran to detect the specific type of Intel CPU.  Update
> > > > > > > > libgfortran to use has_cpu_feature to detect x86 CPU features.
> > > > > > > >
> > > > > > > > Tested on Linux/x86 and Linux/x86-64.  OK for master?
> > > > > > >
> > > > > > > Handling only Intel targets and not others is a sure way for patch to
> > > > > > > be ignored.
> > > > > > >
> > > > > >
> > > > > > Here is the updated patch to cover AMD CPU.  It also fixes:
> > > > > >
> > > > > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95212
> > > > > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95220
> > > > > >
> > > > > > OK for master?
> > > > >
> > > > > Huh... I didn't think the solution will be this messy... I have to
> > > > > rethink the approach a bit.
> > > >
> > > > That is what will happen when we have the same info in more than one place
> > > > There should only one place for CPU info.
> > >
> > > Looking at the patch, it is clear that cpuinfo.c and driver-i386.c
> > > should stay apart. They are two different things, and they are
> > > orthogonal to each other; one can be updated without affecting the
> > > other one. driver-i386.c handles way more targets than cpuinfo.c and
> > > your patch only handles a subset of them. The unification does not
> > > bring any benefit, it even complicates things more.
> >
> > There should one place to check a CPU feature, not 2.  It can
> > be done with a proper cpuinfo.h.
> >
>
> This updated patch does it.   It removes duplicated codes and
> simplifies the implementation.  With this patch, we just to update
> a single place to add the new ISA support.
>

Here is the updated patch to add common/config/i386/cpuinfo-builtins.h.
SIZE_OF_CPU_FEATURES is now defined with CPU_FEATURE_MAX
so that we can simply just add a new feature to enum processor_features
and __cpu_features2 will have the correct size to cover all features.
fold_builtin_cpu is changed to work with any SIZE_OF_CPU_FEATURES
values.

Tested on Linux/x86-64 and Linux/x86.   OK for master?

Thanks.

Comments

Martin Liška May 25, 2020, 9:52 a.m. UTC | #1
Hello.

I really welcome the unification patch and I have some comments (ideas):

1)

> +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)
> +    return cpu_model->__cpu_features[0] & (1U << (f & 31));
> +  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)
> +    {
> +      cpu_model->__cpu_features[0] |= (1U << (f & 31));
> +      return;
> +    }
> +  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 ();
> +}

Can you please add comment about the '32 + 32' and '32 + i * 32', it's unclear from the patch.

2) Can we remove all the:

> +  unsigned int has_lahf_lm, has_sse4a;
> +  unsigned int has_longmode, has_3dnowp, has_3dnow;
> +  unsigned int has_movbe, has_sse4_1, has_sse4_2;
> +  unsigned int has_popcnt, has_aes, has_avx, has_avx2;
> +  unsigned int has_pclmul, has_abm, has_lwp;
> +  unsigned int has_fma, has_fma4, has_xop;
> +  unsigned int has_bmi, has_bmi2, has_tbm, has_lzcnt;

...

> +  has_sse4a = has_feature (FEATURE_SSE4_A);
> +  has_fma4 = has_feature (FEATURE_FMA4);
> +  has_xop = has_feature (FEATURE_XOP);
> +  has_fma = has_feature (FEATURE_FMA);

...

   if (arch)
     {
       const char *mmx = has_mmx ? " -mmmx" : " -mno-mmx";
       const char *mmx3dnow = has_3dnow ? " -m3dnow" : " -mno-3dnow";
       const char *sse = has_sse ? " -msse" : " -mno-sse";
...

       options = concat (options, mmx, mmx3dnow, sse, sse2, sse3, ssse3,
			sse4a, cx16, sahf, movbe, aes, sha, pclmul,
			popcnt, abm, lwp, fma, fma4, xop, bmi, sgx, bmi2,
			pconfig, wbnoinvd,
			tbm, avx, avx2, sse4_2, sse4_1, lzcnt, rtm,
			hle, rdrnd, f16c, fsgsbase, rdseed, prfchw, adx,
			fxsr, xsave, xsaveopt, avx512f, avx512er,
			avx512cd, avx512pf, prefetchwt1, clflushopt,
			xsavec, xsaves, avx512dq, avx512bw, avx512vl,
			avx512ifma, avx512vbmi, avx5124fmaps, avx5124vnniw,
			clwb, mwaitx, clzero, pku, rdpid, gfni, shstk,
			avx512vbmi2, avx512vnni, vaes, vpclmulqdq,
			avx512bitalg, avx512vpopcntdq, movdiri, movdir64b,
			waitpkg, cldemote, ptwrite, avx512bf16, enqcmd,
			avx512vp2intersect, serialize, tsxldtrk, NULL);

and instead mark flags in 'isa_names_table' that should be used for -match=native option emission.
We know names of the flags, their value (has_feature) and so we can generate that automatically?

3) Similarly we can we do automatically all the:

+  if (has_feature (FEATURE_AVX512VBMI2))
+    assert (__builtin_cpu_supports ("avx512vbmi2"));

We should have both information in 'isa_names_table'.

Thanks,
Martin
diff mbox series

Patch

From 74bf612b8f33937cc33dcea46baabf2bf56eb9ee Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 18 May 2020 05:58:41 -0700
Subject: [PATCH] x86: Move cpuinfo.h from libgcc to common/config/i386

Move cpuinfo.h from libgcc to common/config/i386 so that get_intel_cpu
can be shared by libgcc, GCC driver and gcc.target/i386/builtin_target.c
to detect the specific type of Intel and AMD CPUs:

1. Use the same enum processor_features in libgcc and x86 backend.
2. Add more processor features to enum processor_features.
3. Add M_VENDOR, M_CPU_TYPE and M_CPU_SUBTYPE in i386-builtins.c to
avoid duplication in.
4. Use cpu_indicator_init, has_cpu_feature, get_amd_cpu and get_intel_cpu
in driver-i386.c and builtin_target.c.

gcc/

	PR target/95259
	* common/config/i386/cpuinfo-builtins.h: Moved from
	libgcc/config/i386/cpuinfo.h.
	(processor_vendor): Add VENDOR_CENTAUR, VENDOR_CYRIX, VENDOR_NSC
	and BUILTIN_VENDOR_MAX.
	(processor_types): Add BUILTIN_CPU_TYPE_MAX.
	(processor_features): 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_OSPKE, 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.
	(__processor_model): Moved to cpuinfo.h.
	(__cpu_model): Removed.
	(__cpu_features2): Likewise.
	(SIZE_OF_CPU_FEATURES): New.
	* common/config/i386/cpuinfo.h: Moved from
	libgcc/config/i386/cpuinfo.c.
	(__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_OSPKE, 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.
	* config/i386/driver-i386.c: Include
	"common/config/i386/cpuinfo.h".
	(host_detect_local_cpu): Call cpu_indicator_init to get CPU
	features.  Use has_cpu_feature to detect processor features.
	Call get_amd_cpu to get AMD CPU name.  Call get_intel_cpu to
	get Intel CPU name.
	* config/i386/i386-builtins.c: Include
	"common/config/i386/cpuinfo-builtins.h".
	(processor_features): Removed.  Replace F_XXX with FEATURE_XXX.
	(processor_model): Removed.
	(_arch_names_table): Use "const int" on model.
	(M_CPU_TYPE_START): New.
	(M_CPU_SUBTYPE_START): Likewise.
	(M_VENDOR): Likewise.
	(M_CPU_TYPE): Likewise.
	(M_CPU_SUBTYPE): Likewise.
	(arch_names_table): Replace M_XXX with M_VENDOR, M_CPU_TYPE and
	M_CPU_SUBTYPE.
	(isa_names_table): Add more ISAs from enum processor_features.
	(fold_builtin_cpu): Change __cpu_features2 to an array.

gcc/testsuite/

	PR target/95259
	* gcc.target/i386/builtin_target.c: Include <stdlib.h> and
	../../../common/config/i386/cpuinfo.h.
	(check_amd_cpu_model): Removed.
	(check_intel_cpu_model): Likewise,
	(CHECK___builtin_cpu_is): New.
	(gcc_assert): New.  Defined as assert.
	(gcc_unreachable): New.  Defined as abort.
	(inline): New.  Defined as empty.
	(check_features): Use has_cpu_feature to check processor features.
	(check_detailed): Call cpu_indicator_init.  Always call
	check_features.  Call get_amd_cpu instead of check_amd_cpu_model.
	Call get_intel_cpu instead of check_intel_cpu_model.

libgcc/

	PR target/95259
	* config/i386/cpuinfo.c: Include "common/config/i386/cpuinfo.h".
	(__cpu_features2): Changed to array.
	(get_amd_cpu): Moved to ... gcc/common/config/i386/cpuinfo.h.
	(get_intel_cpu): Likewise.
	(get_available_features): Likewise.
	(__cpu_indicator_init): Call cpu_indicator_init.
	* config/i386/cpuinfo.h: Moved to
	gcc/common/config/i386/cpuinfo-builtins.h.
---
 .../common/config/i386/cpuinfo-builtins.h     |  70 +-
 gcc/common/config/i386/cpuinfo.h              | 834 ++++++++++++++++++
 gcc/config/i386/driver-i386.c                 | 598 ++++---------
 gcc/config/i386/i386-builtins.c               | 339 ++++---
 .../gcc.target/i386/builtin_target.c          | 500 ++++-------
 libgcc/config/i386/cpuinfo.c                  | 464 +---------
 6 files changed, 1416 insertions(+), 1389 deletions(-)
 rename libgcc/config/i386/cpuinfo.h => gcc/common/config/i386/cpuinfo-builtins.h (71%)
 create mode 100644 gcc/common/config/i386/cpuinfo.h

diff --git a/libgcc/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo-builtins.h
similarity index 71%
rename from libgcc/config/i386/cpuinfo.h
rename to gcc/common/config/i386/cpuinfo-builtins.h
index 0f97510cde1..7a20dcf9ef8 100644
--- a/libgcc/config/i386/cpuinfo.h
+++ b/gcc/common/config/i386/cpuinfo-builtins.h
@@ -30,6 +30,10 @@  enum processor_vendor
   VENDOR_INTEL = 1,
   VENDOR_AMD,
   VENDOR_OTHER,
+  VENDOR_CENTAUR,
+  VENDOR_CYRIX,
+  VENDOR_NSC,
+  BUILTIN_VENDOR_MAX = VENDOR_OTHER,
   VENDOR_MAX
 };
 
@@ -45,13 +49,14 @@  enum processor_types
   INTEL_SILVERMONT,
   INTEL_KNL,
   AMD_BTVER1,
-  AMD_BTVER2,  
+  AMD_BTVER2,
   AMDFAM17H,
   INTEL_KNM,
   INTEL_GOLDMONT,
   INTEL_GOLDMONT_PLUS,
   INTEL_TREMONT,
-  CPU_TYPE_MAX
+  CPU_TYPE_MAX,
+  BUILTIN_CPU_TYPE_MAX = CPU_TYPE_MAX
 };
 
 enum processor_subtypes
@@ -123,14 +128,57 @@  enum processor_features
   FEATURE_AVX512VNNI,
   FEATURE_AVX512BITALG,
   FEATURE_AVX512BF16,
-  FEATURE_AVX512VP2INTERSECT
+  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_OSPKE,
+  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
 };
 
-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;
+/* Size of __cpu_features2 array in libgcc/config/i386/cpuinfo.c.  */
+#define SIZE_OF_CPU_FEATURES ((CPU_FEATURE_MAX - 1) / 32)
diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h
new file mode 100644
index 00000000000..9f75bb0c0f0
--- /dev/null
+++ b/gcc/common/config/i386/cpuinfo.h
@@ -0,0 +1,834 @@ 
+/* 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/>.  */
+
+#include "cpuinfo-builtins.h"
+
+struct __processor_model
+{
+  unsigned int __cpu_vendor;
+  unsigned int __cpu_type;
+  unsigned int __cpu_subtype;
+  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)
+    return cpu_model->__cpu_features[0] & (1U << (f & 31));
+  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)
+    {
+      cpu_model->__cpu_features[0] |= (1U << (f & 31));
+      return;
+    }
+  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);
+      if (ecx & bit_OSPKE)
+	set_feature (FEATURE_OSPKE);
+      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/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index 3a816400729..a686e3bb712 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -28,6 +28,7 @@  const char *host_detect_local_cpu (int argc, const char **argv);
 
 #if defined(__GNUC__) && (__GNUC__ >= 5 || !defined(__PIC__))
 #include "cpuid.h"
+#include "common/config/i386/cpuinfo.h"
 
 struct cache_desc
 {
@@ -388,7 +389,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
   const char *cache = "";
   const char *options = "";
 
-  unsigned int eax, ebx, ecx, edx;
+  unsigned int ebx, ecx, edx;
 
   unsigned int max_level, ext_level;
 
@@ -399,41 +400,40 @@  const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_cmpxchg8b, has_cmov, has_mmx, has_sse, has_sse2;
 
   /* Extended features */
-  unsigned int has_lahf_lm = 0, has_sse4a = 0;
-  unsigned int has_longmode = 0, has_3dnowp = 0, has_3dnow = 0;
-  unsigned int has_movbe = 0, has_sse4_1 = 0, has_sse4_2 = 0;
-  unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0, has_avx2 = 0;
-  unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
-  unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_bmi2 = 0, has_tbm = 0, has_lzcnt = 0;
-  unsigned int has_hle = 0, has_rtm = 0, has_sgx = 0;
-  unsigned int has_pconfig = 0, has_wbnoinvd = 0;
-  unsigned int has_rdrnd = 0, has_f16c = 0, has_fsgsbase = 0;
-  unsigned int has_rdseed = 0, has_prfchw = 0, has_adx = 0;
-  unsigned int has_osxsave = 0, has_fxsr = 0, has_xsave = 0, has_xsaveopt = 0;
-  unsigned int has_avx512er = 0, has_avx512pf = 0, has_avx512cd = 0;
-  unsigned int has_avx512f = 0, has_sha = 0, has_prefetchwt1 = 0;
-  unsigned int has_clflushopt = 0, has_xsavec = 0, has_xsaves = 0;
-  unsigned int has_avx512dq = 0, has_avx512bw = 0, has_avx512vl = 0;
-  unsigned int has_avx512vbmi = 0, has_avx512ifma = 0, has_clwb = 0;
-  unsigned int has_mwaitx = 0, has_clzero = 0, has_pku = 0, has_rdpid = 0;
-  unsigned int has_avx5124fmaps = 0, has_avx5124vnniw = 0;
-  unsigned int has_gfni = 0, has_avx512vbmi2 = 0;
-  unsigned int has_avx512bitalg = 0;
-  unsigned int has_avx512vpopcntdq = 0;
-  unsigned int has_shstk = 0;
-  unsigned int has_avx512vnni = 0, has_vaes = 0;
-  unsigned int has_vpclmulqdq = 0;
-  unsigned int has_avx512vp2intersect = 0;
-  unsigned int has_movdiri = 0, has_movdir64b = 0;
-  unsigned int has_enqcmd = 0;
-  unsigned int has_waitpkg = 0;
-  unsigned int has_cldemote = 0;
-  unsigned int has_avx512bf16 = 0;
-  unsigned int has_serialize = 0;
-  unsigned int has_tsxldtrk = 0;
-
-  unsigned int has_ptwrite = 0;
+  unsigned int has_lahf_lm, has_sse4a;
+  unsigned int has_longmode, has_3dnowp, has_3dnow;
+  unsigned int has_movbe, has_sse4_1, has_sse4_2;
+  unsigned int has_popcnt, has_aes, has_avx, has_avx2;
+  unsigned int has_pclmul, has_abm, has_lwp;
+  unsigned int has_fma, has_fma4, has_xop;
+  unsigned int has_bmi, has_bmi2, has_tbm, has_lzcnt;
+  unsigned int has_hle, has_rtm, has_sgx;
+  unsigned int has_pconfig, has_wbnoinvd;
+  unsigned int has_rdrnd, has_f16c, has_fsgsbase;
+  unsigned int has_rdseed, has_prfchw, has_adx;
+  unsigned int has_fxsr, has_xsave, has_xsaveopt;
+  unsigned int has_avx512er, has_avx512pf, has_avx512cd;
+  unsigned int has_avx512f, has_sha, has_prefetchwt1;
+  unsigned int has_clflushopt, has_xsavec, has_xsaves;
+  unsigned int has_avx512dq, has_avx512bw, has_avx512vl;
+  unsigned int has_avx512vbmi, has_avx512ifma, has_clwb;
+  unsigned int has_mwaitx, has_clzero, has_pku, has_rdpid;
+  unsigned int has_avx5124fmaps, has_avx5124vnniw;
+  unsigned int has_gfni, has_avx512vbmi2;
+  unsigned int has_avx512bitalg;
+  unsigned int has_avx512vpopcntdq;
+  unsigned int has_shstk;
+  unsigned int has_avx512vnni, has_vaes;
+  unsigned int has_vpclmulqdq;
+  unsigned int has_avx512vp2intersect;
+  unsigned int has_movdiri, has_movdir64b;
+  unsigned int has_enqcmd;
+  unsigned int has_waitpkg;
+  unsigned int has_cldemote;
+  unsigned int has_avx512bf16;
+  unsigned int has_serialize;
+  unsigned int has_tsxldtrk;
+  unsigned int has_ptwrite;
 
   bool arch;
 
@@ -447,210 +447,114 @@  const char *host_detect_local_cpu (int argc, const char **argv)
   if (!arch && strcmp (argv[0], "tune"))
     return NULL;
 
-  max_level = __get_cpuid_max (0, &vendor);
-  if (max_level < 1)
-    goto done;
-
-  __cpuid (1, eax, ebx, ecx, edx);
-
-  model = (eax >> 4) & 0x0f;
-  family = (eax >> 8) & 0x0f;
-  if (vendor == signature_INTEL_ebx
-      || vendor == signature_AMD_ebx)
-    {
-      unsigned int extended_model, extended_family;
-
-      extended_model = (eax >> 12) & 0xf0;
-      extended_family = (eax >> 20) & 0xff;
-      if (family == 0x0f)
-	{
-	  family += extended_family;
-	  model += extended_model;
-	}
-      else if (family == 0x06)
-	model += extended_model;
-    }
-
-  has_sse3 = ecx & bit_SSE3;
-  has_ssse3 = ecx & bit_SSSE3;
-  has_sse4_1 = ecx & bit_SSE4_1;
-  has_sse4_2 = ecx & bit_SSE4_2;
-  has_avx = ecx & bit_AVX;
-  has_osxsave = ecx & bit_OSXSAVE;
-  has_cmpxchg16b = ecx & bit_CMPXCHG16B;
-  has_movbe = ecx & bit_MOVBE;
-  has_popcnt = ecx & bit_POPCNT;
-  has_aes = ecx & bit_AES;
-  has_pclmul = ecx & bit_PCLMUL;
-  has_fma = ecx & bit_FMA;
-  has_f16c = ecx & bit_F16C;
-  has_rdrnd = ecx & bit_RDRND;
-  has_xsave = ecx & bit_XSAVE;
-
-  has_cmpxchg8b = edx & bit_CMPXCHG8B;
-  has_cmov = edx & bit_CMOV;
-  has_mmx = edx & bit_MMX;
-  has_fxsr = edx & bit_FXSAVE;
-  has_sse = edx & bit_SSE;
-  has_sse2 = edx & bit_SSE2;
-
-  if (max_level >= 7)
-    {
-      __cpuid_count (7, 0, eax, ebx, ecx, edx);
-
-      has_bmi = ebx & bit_BMI;
-      has_sgx = ebx & bit_SGX;
-      has_hle = ebx & bit_HLE;
-      has_rtm = ebx & bit_RTM;
-      has_avx2 = ebx & bit_AVX2;
-      has_bmi2 = ebx & bit_BMI2;
-      has_fsgsbase = ebx & bit_FSGSBASE;
-      has_rdseed = ebx & bit_RDSEED;
-      has_adx = ebx & bit_ADX;
-      has_avx512f = ebx & bit_AVX512F;
-      has_avx512er = ebx & bit_AVX512ER;
-      has_avx512pf = ebx & bit_AVX512PF;
-      has_avx512cd = ebx & bit_AVX512CD;
-      has_sha = ebx & bit_SHA;
-      has_clflushopt = ebx & bit_CLFLUSHOPT;
-      has_clwb = ebx & bit_CLWB;
-      has_avx512dq = ebx & bit_AVX512DQ;
-      has_avx512bw = ebx & bit_AVX512BW;
-      has_avx512vl = ebx & bit_AVX512VL;
-      has_avx512ifma = ebx & bit_AVX512IFMA;
-
-      has_prefetchwt1 = ecx & bit_PREFETCHWT1;
-      has_avx512vbmi = ecx & bit_AVX512VBMI;
-      has_pku = ecx & bit_OSPKE;
-      has_avx512vbmi2 = ecx & bit_AVX512VBMI2;
-      has_avx512vnni = ecx & bit_AVX512VNNI;
-      has_rdpid = ecx & bit_RDPID;
-      has_gfni = ecx & bit_GFNI;
-      has_vaes = ecx & bit_VAES;
-      has_vpclmulqdq = ecx & bit_VPCLMULQDQ;
-      has_avx512bitalg = ecx & bit_AVX512BITALG;
-      has_avx512vpopcntdq = ecx & bit_AVX512VPOPCNTDQ;
-      has_movdiri = ecx & bit_MOVDIRI;
-      has_movdir64b = ecx & bit_MOVDIR64B;
-      has_enqcmd = ecx & bit_ENQCMD;
-      has_cldemote = ecx & bit_CLDEMOTE;
-
-      has_avx5124vnniw = edx & bit_AVX5124VNNIW;
-      has_avx5124fmaps = edx & bit_AVX5124FMAPS;
-      has_avx512vp2intersect = edx & bit_AVX512VP2INTERSECT;
-      has_serialize = edx & bit_SERIALIZE;
-      has_tsxldtrk = edx & bit_TSXLDTRK;
-
-      has_shstk = ecx & bit_SHSTK;
-      has_pconfig = edx & bit_PCONFIG;
-      has_waitpkg = ecx & bit_WAITPKG;
-
-      __cpuid_count (7, 1, eax, ebx, ecx, edx);
-      has_avx512bf16 = eax & bit_AVX512BF16;
-    }
-
-  if (max_level >= 13)
-    {
-      __cpuid_count (13, 1, eax, ebx, ecx, edx);
-
-      has_xsaveopt = eax & bit_XSAVEOPT;
-      has_xsavec = eax & bit_XSAVEC;
-      has_xsaves = eax & bit_XSAVES;
-    }
-
-  if (max_level >= 0x14)
-    {
-      __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
-
-      has_ptwrite = ebx & bit_PTWRITE;
-    }
+  struct __processor_model cpu_model = { };
+  struct __processor_model2 cpu_model2 = { };
+  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { };
 
-  /* Check cpuid level of extended features.  */
-  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
-
-  if (ext_level >= 0x80000001)
-    {
-      __cpuid (0x80000001, eax, ebx, ecx, edx);
-
-      has_lahf_lm = ecx & bit_LAHF_LM;
-      has_sse4a = ecx & bit_SSE4a;
-      has_abm = ecx & bit_ABM;
-      has_lwp = ecx & bit_LWP;
-      has_fma4 = ecx & bit_FMA4;
-      has_xop = ecx & bit_XOP;
-      has_tbm = ecx & bit_TBM;
-      has_lzcnt = ecx & bit_LZCNT;
-      has_prfchw = ecx & bit_PRFCHW;
-
-      has_longmode = edx & bit_LM;
-      has_3dnowp = edx & bit_3DNOWP;
-      has_3dnow = edx & bit_3DNOW;
-      has_mwaitx = ecx & bit_MWAITX;
-    }
-
-  if (ext_level >= 0x80000008)
-    {
-      __cpuid (0x80000008, eax, ebx, ecx, edx);
-      has_clzero = ebx & bit_CLZERO;
-      has_wbnoinvd = ebx & bit_WBNOINVD;
-    }
-
-  /* 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)
-
-  if (has_osxsave)
-    asm (".byte 0x0f; .byte 0x01; .byte 0xd0"
-	 : "=a" (eax), "=d" (edx)
-	 : "c" (XCR_XFEATURE_ENABLED_MASK));
-  else
-    eax = 0;
+  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
+    goto done;
 
-  /* Check if AVX registers are supported.  */
-  if ((eax & XCR_AVX_ENABLED_MASK) != XCR_AVX_ENABLED_MASK)
-    {
-      has_avx = 0;
-      has_avx2 = 0;
-      has_fma = 0;
-      has_fma4 = 0;
-      has_f16c = 0;
-      has_xop = 0;
-      has_xsave = 0;
-      has_xsaveopt = 0;
-      has_xsaves = 0;
-      has_xsavec = 0;
-    }
+  vendor = cpu_model.__cpu_vendor;
+  family = cpu_model2.__cpu_family;
+  model = cpu_model2.__cpu_model;
+  max_level = cpu_model2.__cpu_max_level;
+  ext_level = cpu_model2.__cpu_ext_level;
 
-  /* Check if AVX512F registers are supported.  */
-  if ((eax & XCR_AVX512F_ENABLED_MASK) != XCR_AVX512F_ENABLED_MASK)
-    {
-      has_avx512f = 0;
-      has_avx512er = 0;
-      has_avx512pf = 0;
-      has_avx512cd = 0;
-      has_avx512dq = 0;
-      has_avx512bw = 0;
-      has_avx512vl = 0;
-    }
+  /* Extended features */
+#define has_feature(f) \
+  has_cpu_feature (&cpu_model, cpu_features2, f)
+  has_cmov = has_feature (FEATURE_CMOV);
+  has_mmx = has_feature (FEATURE_MMX);
+  has_popcnt = has_feature (FEATURE_POPCNT);
+  has_sse = has_feature (FEATURE_SSE);
+  has_sse2 = has_feature (FEATURE_SSE2);
+  has_sse3 = has_feature (FEATURE_SSE3);
+  has_ssse3 = has_feature (FEATURE_SSSE3);
+  has_sse4_1 = has_feature (FEATURE_SSE4_1);
+  has_sse4_2 = has_feature (FEATURE_SSE4_2);
+  has_avx = has_feature (FEATURE_AVX);
+  has_avx2 = has_feature (FEATURE_AVX2);
+  has_sse4a = has_feature (FEATURE_SSE4_A);
+  has_fma4 = has_feature (FEATURE_FMA4);
+  has_xop = has_feature (FEATURE_XOP);
+  has_fma = has_feature (FEATURE_FMA);
+  has_avx512f = has_feature (FEATURE_AVX512F);
+  has_bmi = has_feature (FEATURE_BMI);
+  has_bmi2 = has_feature (FEATURE_BMI2);
+  has_aes = has_feature (FEATURE_AES);
+  has_pclmul = has_feature (FEATURE_PCLMUL);
+  has_avx512vl = has_feature (FEATURE_AVX512VL);
+  has_avx512bw = has_feature (FEATURE_AVX512BW);
+  has_avx512dq = has_feature (FEATURE_AVX512DQ);
+  has_avx512cd = has_feature (FEATURE_AVX512CD);
+  has_avx512er = has_feature (FEATURE_AVX512ER);
+  has_avx512pf = has_feature (FEATURE_AVX512PF);
+  has_avx512vbmi = has_feature (FEATURE_AVX512VBMI);
+  has_avx512ifma = has_feature (FEATURE_AVX512IFMA);
+  has_avx5124vnniw = has_feature (FEATURE_AVX5124VNNIW);
+  has_avx5124fmaps = has_feature (FEATURE_AVX5124FMAPS);
+  has_avx512vpopcntdq = has_feature (FEATURE_AVX512VPOPCNTDQ);
+  has_avx512vbmi2 = has_feature (FEATURE_AVX512VBMI2);
+  has_gfni = has_feature (FEATURE_GFNI);
+  has_vpclmulqdq = has_feature (FEATURE_VPCLMULQDQ);
+  has_avx512vnni = has_feature (FEATURE_AVX512VNNI);
+  has_avx512bitalg = has_feature (FEATURE_AVX512BITALG);
+  has_avx512bf16 = has_feature (FEATURE_AVX512BF16);
+  has_avx512vp2intersect = has_feature (FEATURE_AVX512VP2INTERSECT);
+  has_3dnow = has_feature (FEATURE_3DNOW);
+  has_3dnowp = has_feature (FEATURE_3DNOWP);
+  has_adx = has_feature (FEATURE_ADX);
+  has_abm = has_feature (FEATURE_ABM);
+  has_cldemote = has_feature (FEATURE_CLDEMOTE);
+  has_clflushopt = has_feature (FEATURE_CLFLUSHOPT);
+  has_clwb = has_feature (FEATURE_CLWB);
+  has_clzero = has_feature (FEATURE_CLZERO);
+  has_cmpxchg16b = has_feature (FEATURE_CMPXCHG16B);
+  has_cmpxchg8b = has_feature (FEATURE_CMPXCHG8B);
+  has_enqcmd = has_feature (FEATURE_ENQCMD);
+  has_f16c = has_feature (FEATURE_F16C);
+  has_fsgsbase = has_feature (FEATURE_FSGSBASE);
+  has_fxsr = has_feature (FEATURE_FXSAVE);
+  has_hle = has_feature (FEATURE_HLE);
+  has_lahf_lm = has_feature (FEATURE_LAHF_LM);
+  has_longmode = has_feature (FEATURE_LM);
+  has_lwp = has_feature (FEATURE_LWP);
+  has_lzcnt = has_feature (FEATURE_LZCNT);
+  has_movbe = has_feature (FEATURE_MOVBE);
+  has_movdir64b = has_feature (FEATURE_MOVDIR64B);
+  has_movdiri = has_feature (FEATURE_MOVDIRI);
+  has_mwaitx = has_feature (FEATURE_MWAITX);
+  has_pconfig = has_feature (FEATURE_PCONFIG);
+  has_pku = has_feature (FEATURE_PKU);
+  has_prefetchwt1 = has_feature (FEATURE_PREFETCHWT1);
+  has_prfchw = has_feature (FEATURE_PRFCHW);
+  has_ptwrite = has_feature (FEATURE_PTWRITE);
+  has_rdpid = has_feature (FEATURE_RDPID);
+  has_rdrnd = has_feature (FEATURE_RDRND);
+  has_rdseed = has_feature (FEATURE_RDSEED);
+  has_rtm = has_feature (FEATURE_RTM);
+  has_serialize = has_feature (FEATURE_SERIALIZE);
+  has_sgx = has_feature (FEATURE_SGX);
+  has_sha = has_feature (FEATURE_SHA);
+  has_shstk = has_feature (FEATURE_SHSTK);
+  has_tbm = has_feature (FEATURE_TBM);
+  has_tsxldtrk = has_feature (FEATURE_TSXLDTRK);
+  has_vaes = has_feature (FEATURE_VAES);
+  has_waitpkg = has_feature (FEATURE_WAITPKG);
+  has_wbnoinvd = has_feature (FEATURE_WBNOINVD);
+  has_xsave = has_feature (FEATURE_XSAVE);
+  has_xsavec = has_feature (FEATURE_XSAVEC);
+  has_xsaveopt = has_feature (FEATURE_XSAVEOPT);
+  has_xsaves = has_feature (FEATURE_XSAVES);
 
   if (!arch)
     {
-      if (vendor == signature_AMD_ebx
-	  || vendor == signature_CENTAUR_ebx
-	  || vendor == signature_CYRIX_ebx
-	  || vendor == signature_NSC_ebx)
+      if (vendor == VENDOR_AMD
+	  || vendor == VENDOR_CENTAUR
+	  || vendor == VENDOR_CYRIX
+	  || vendor == VENDOR_NSC)
 	cache = detect_caches_amd (ext_level);
-      else if (vendor == signature_INTEL_ebx)
+      else if (vendor == VENDOR_INTEL)
 	{
 	  bool xeon_mp = (family == 15 && model == 6);
 	  cache = detect_caches_intel (xeon_mp, max_level,
@@ -658,7 +562,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	}
     }
 
-  if (vendor == signature_AMD_ebx)
+  if (vendor == VENDOR_AMD)
     {
       unsigned int name;
 
@@ -668,36 +572,22 @@  const char *host_detect_local_cpu (int argc, const char **argv)
       else
 	name = 0;
 
-      if (name == signature_NSC_ebx)
-	processor = PROCESSOR_GEODE;
-      else if (has_movbe && family == 22)
-	processor = PROCESSOR_BTVER2;
-      else if (has_clwb)
-	processor = PROCESSOR_ZNVER2;
-      else if (has_clzero)
-	processor = PROCESSOR_ZNVER1;
-      else if (has_avx2)
-        processor = PROCESSOR_BDVER4;
-      else if (has_xsaveopt)
-        processor = PROCESSOR_BDVER3;
-      else if (has_bmi)
-        processor = PROCESSOR_BDVER2;
-      else if (has_xop)
-	processor = PROCESSOR_BDVER1;
-      else if (has_sse4a && has_ssse3)
-        processor = PROCESSOR_BTVER1;
-      else if (has_sse4a)
-	processor = PROCESSOR_AMDFAM10;
-      else if (has_sse2 || has_longmode)
-	processor = PROCESSOR_K8;
-      else if (has_3dnowp && family == 6)
-	processor = PROCESSOR_ATHLON;
-      else if (has_mmx)
-	processor = PROCESSOR_K6;
-      else
-	processor = PROCESSOR_PENTIUM;
+      cpu = get_amd_cpu (&cpu_model, &cpu_model2, cpu_features2);
+      if (cpu == NULL)
+	{
+	  if (name == signature_NSC_ebx)
+	    processor = PROCESSOR_GEODE;
+	  else if (has_sse2 || has_longmode)
+	    processor = PROCESSOR_K8;
+	  else if (has_3dnowp && family == 6)
+	    processor = PROCESSOR_ATHLON;
+	  else if (has_mmx)
+	    processor = PROCESSOR_K6;
+	  else
+	    processor = PROCESSOR_PENTIUM;
+	}
     }
-  else if (vendor == signature_CENTAUR_ebx)
+  else if (vendor == VENDOR_CENTAUR)
     {
       processor = PROCESSOR_GENERIC;
 
@@ -749,7 +639,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
       /* Default.  */
       break;
     case PROCESSOR_I486:
-      if (arch && vendor == signature_CENTAUR_ebx)
+      if (arch && vendor == VENDOR_CENTAUR)
 	{
 	  if (model >= 6)
 	    cpu = "c3";
@@ -769,145 +659,23 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	cpu = "pentium";
       break;
     case PROCESSOR_PENTIUMPRO:
-      switch (model)
+      cpu = get_intel_cpu (&cpu_model, &cpu_model2, cpu_features2, 0);
+      if (cpu == NULL)
 	{
-	case 0x1c:
-	case 0x26:
-	  /* Bonnell.  */
-	  cpu = "bonnell";
-	  break;
-	case 0x37:
-	case 0x4a:
-	case 0x4d:
-	case 0x5d:
-	  /* Silvermont.  */
-	case 0x4c:
-	case 0x5a:
-	case 0x75:
-	  /* Airmont.  */
-	  cpu = "silvermont";
-	  break;
-	case 0x5c:
-	case 0x5f:
-	  /* Goldmont.  */
-	  cpu = "goldmont";
-	  break;
-	case 0x7a:
-	  /* Goldmont Plus.  */
-	  cpu = "goldmont-plus";
-	  break;
-	case 0x86:
-	case 0x96:
-	case 0x9c:
-	  /* Tremont.  */
-	  cpu = "tremont";
-	  break;
-	case 0x0f:
-	  /* Merom.  */
-	case 0x17:
-	case 0x1d:
-	  /* Penryn.  */
-	  cpu = "core2";
-	  break;
-	case 0x1a:
-	case 0x1e:
-	case 0x1f:
-	case 0x2e:
-	  /* Nehalem.  */
-	  cpu = "nehalem";
-	  break;
-	case 0x25:
-	case 0x2c:
-	case 0x2f:
-	  /* Westmere.  */
-	  cpu = "westmere";
-	  break;
-	case 0x2a:
-	case 0x2d:
-	  /* Sandy Bridge.  */
-	  cpu = "sandybridge";
-	  break;
-	case 0x3a:
-	case 0x3e:
-	  /* Ivy Bridge.  */
-	  cpu = "ivybridge";
-	  break;
-	case 0x3c:
-	case 0x3f:
-	case 0x45:
-	case 0x46:
-	  /* Haswell.  */
-	  cpu = "haswell";
-	  break;
-	case 0x3d:
-	case 0x47:
-	case 0x4f:
-	case 0x56:
-	  /* Broadwell.  */
-	  cpu = "broadwell";
-	  break;
-	case 0x4e:
-	case 0x5e:
-	  /* Skylake.  */
-	case 0x8e:
-	case 0x9e:
-	  /* Kaby Lake.  */
-	case 0xa5:
-	case 0xa6:
-	  /* Comet Lake.  */
-	  cpu = "skylake";
-	  break;
-	case 0x55:
-	  if (has_avx512vnni)
-	    /* Cascade Lake.  */
-	    cpu = "cascadelake";
-	  else
-	    /* Skylake with AVX-512.  */
-	    cpu = "skylake-avx512";
-	  break;
-	case 0x6a:
-	case 0x6c:
-	  /* Ice Lake server.  */
-	  cpu = "icelake-server";
-	  break;
-	case 0x7e:
-	case 0x7d:
-	case 0x9d:
-	  /* Ice Lake client.  */
-	  cpu = "icelake-client";
-	  break;
-	case 0x8c:
-	case 0x8d:
-	  /* Tiger Lake.  */
-	  cpu = "tigerlake";
-	  break;
-	case 0x57:
-	  /* Knights Landing.  */
-	  cpu = "knl";
-	  break;
-	case 0x66:
-	  /* Cannon Lake.  */
-	  cpu = "cannonlake";
-	  break;
-	case 0x85:
-	  /* Knights Mill.  */
-	  cpu = "knm";
-	  break;
-	default:
 	  if (arch)
 	    {
 	      /* This is unknown family 0x6 CPU.  */
 	      if (has_avx)
-	      {
-		/* Assume Tiger Lake */
-		if (has_avx512vp2intersect)
-		  cpu = "tigerlake";
-		/* Assume Cooper Lake */
-		else if (has_avx512bf16)
-		  cpu = "cooperlake";
-		/* Assume Ice Lake Server.  */
-		else if (has_wbnoinvd)
-		  cpu = "icelake-server";
+		{
+		  /* Assume Tiger Lake */
+		  if (has_avx512vp2intersect)
+		    cpu = "tigerlake";
+		  /* Assume Cooper Lake */
+		  else if (has_avx512bf16)
+		    cpu = "cooperlake";
+		  /* Assume Ice Lake Server.  */
+		  else if (has_wbnoinvd)
+		    cpu = "icelake-server";
 		/* Assume Ice Lake.  */
 		else if (has_avx512bitalg)
 		  cpu = "icelake-client";
@@ -970,7 +738,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 		cpu = "x86-64";
 	      else if (has_sse3)
 		{
-		  if (vendor == signature_CENTAUR_ebx)
+		  if (vendor == VENDOR_CENTAUR)
 		    /* C7 / Eden "Esther" */
 		    cpu = "c7";
 		  else
@@ -982,7 +750,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 		cpu = "pentium-m";
 	      else if (has_sse)
 		{
-		  if (vendor == signature_CENTAUR_ebx)
+		  if (vendor == VENDOR_CENTAUR)
 		    {
 		      if (model >= 9)
 			/* Eden "Nehemiah" */
@@ -1004,7 +772,6 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	  else
 	    /* For -mtune, we default to -mtune=generic.  */
 	    cpu = "generic";
-	  break;
 	}
       break;
     case PROCESSOR_PENTIUM4:
@@ -1036,7 +803,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
     case PROCESSOR_K8:
       if (arch)
 	{
-	  if (vendor == signature_CENTAUR_ebx)
+	  if (vendor == VENDOR_CENTAUR)
 	    {
 	      if (has_sse4_1)
 		/* Nano 3000 | Nano dual / quad core | Eden X4 */
@@ -1060,33 +827,6 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	/* For -mtune, we default to -mtune=k8 */
 	cpu = "k8";
       break;
-    case PROCESSOR_AMDFAM10:
-      cpu = "amdfam10";
-      break;
-    case PROCESSOR_BDVER1:
-      cpu = "bdver1";
-      break;
-    case PROCESSOR_BDVER2:
-      cpu = "bdver2";
-      break;
-    case PROCESSOR_BDVER3:
-      cpu = "bdver3";
-      break;
-    case PROCESSOR_BDVER4:
-      cpu = "bdver4";
-      break;
-    case PROCESSOR_ZNVER1:
-      cpu = "znver1";
-      break;
-    case PROCESSOR_ZNVER2:
-      cpu = "znver2";
-      break;
-    case PROCESSOR_BTVER1:
-      cpu = "btver1";
-      break;
-    case PROCESSOR_BTVER2:
-      cpu = "btver2";
-      break;
 
     default:
       /* Use something reasonable.  */
diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
index be3ed0158f2..41c4a8780e9 100644
--- a/gcc/config/i386/i386-builtins.c
+++ b/gcc/config/i386/i386-builtins.c
@@ -90,6 +90,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "dwarf2out.h"
 #include "i386-builtins.h"
+#include "common/config/i386/cpuinfo-builtins.h"
 
 #undef BDESC
 #undef BDESC_FIRST
@@ -1872,147 +1873,66 @@  enum feature_priority
   P_PROC_AVX512F
 };
 
-/* 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 values for vendor types and cpu types  and subtypes
-   in cpuinfo.c.  Cpu types and subtypes should be subtracted by
-   the corresponding start value.  */
-enum processor_model
-{
-  M_INTEL = 1,
-  M_AMD,
-  M_CPU_TYPE_START,
-  M_INTEL_BONNELL,
-  M_INTEL_CORE2,
-  M_INTEL_COREI7,
-  M_AMDFAM10H,
-  M_AMDFAM15H,
-  M_INTEL_SILVERMONT,
-  M_INTEL_KNL,
-  M_AMD_BTVER1,
-  M_AMD_BTVER2,
-  M_AMDFAM17H,
-  M_INTEL_KNM,
-  M_INTEL_GOLDMONT,
-  M_INTEL_GOLDMONT_PLUS,
-  M_INTEL_TREMONT,
-  M_CPU_SUBTYPE_START,
-  M_INTEL_COREI7_NEHALEM,
-  M_INTEL_COREI7_WESTMERE,
-  M_INTEL_COREI7_SANDYBRIDGE,
-  M_AMDFAM10H_BARCELONA,
-  M_AMDFAM10H_SHANGHAI,
-  M_AMDFAM10H_ISTANBUL,
-  M_AMDFAM15H_BDVER1,
-  M_AMDFAM15H_BDVER2,
-  M_AMDFAM15H_BDVER3,
-  M_AMDFAM15H_BDVER4,
-  M_AMDFAM17H_ZNVER1,
-  M_INTEL_COREI7_IVYBRIDGE,
-  M_INTEL_COREI7_HASWELL,
-  M_INTEL_COREI7_BROADWELL,
-  M_INTEL_COREI7_SKYLAKE,
-  M_INTEL_COREI7_SKYLAKE_AVX512,
-  M_INTEL_COREI7_CANNONLAKE,
-  M_INTEL_COREI7_ICELAKE_CLIENT,
-  M_INTEL_COREI7_ICELAKE_SERVER,
-  M_AMDFAM17H_ZNVER2,
-  M_INTEL_COREI7_CASCADELAKE,
-  M_INTEL_COREI7_TIGERLAKE,
-  M_INTEL_COREI7_COOPERLAKE
-};
-
 struct _arch_names_table
 {
   const char *const name;
-  const enum processor_model model;
+  const int model;
 };
 
+/* These are the values for vendor types, cpu types and subtypes in
+   cpuinfo.h.  Cpu types and subtypes should be subtracted by the
+   corresponding start value.  */
+
+#define M_CPU_TYPE_START (BUILTIN_VENDOR_MAX)
+#define M_CPU_SUBTYPE_START \
+  (M_CPU_TYPE_START + BUILTIN_CPU_TYPE_MAX)
+#define M_VENDOR(a) (a)
+#define M_CPU_TYPE(a) (M_CPU_TYPE_START + a)
+#define M_CPU_SUBTYPE(a) (M_CPU_SUBTYPE_START + a)
+
 static const _arch_names_table arch_names_table[] =
 {
-  {"amd", M_AMD},
-  {"intel", M_INTEL},
-  {"atom", M_INTEL_BONNELL},
-  {"slm", M_INTEL_SILVERMONT},
-  {"core2", M_INTEL_CORE2},
-  {"corei7", M_INTEL_COREI7},
-  {"nehalem", M_INTEL_COREI7_NEHALEM},
-  {"westmere", M_INTEL_COREI7_WESTMERE},
-  {"sandybridge", M_INTEL_COREI7_SANDYBRIDGE},
-  {"ivybridge", M_INTEL_COREI7_IVYBRIDGE},
-  {"haswell", M_INTEL_COREI7_HASWELL},
-  {"broadwell", M_INTEL_COREI7_BROADWELL},
-  {"skylake", M_INTEL_COREI7_SKYLAKE},
-  {"skylake-avx512", M_INTEL_COREI7_SKYLAKE_AVX512},
-  {"cannonlake", M_INTEL_COREI7_CANNONLAKE},
-  {"icelake-client", M_INTEL_COREI7_ICELAKE_CLIENT},
-  {"icelake-server", M_INTEL_COREI7_ICELAKE_SERVER},
-  {"cascadelake", M_INTEL_COREI7_CASCADELAKE},
-  {"tigerlake", M_INTEL_COREI7_TIGERLAKE},
-  {"cooperlake", M_INTEL_COREI7_COOPERLAKE},
-  {"bonnell", M_INTEL_BONNELL},
-  {"silvermont", M_INTEL_SILVERMONT},
-  {"goldmont", M_INTEL_GOLDMONT},
-  {"goldmont-plus", M_INTEL_GOLDMONT_PLUS},
-  {"tremont", M_INTEL_TREMONT},
-  {"knl", M_INTEL_KNL},
-  {"knm", M_INTEL_KNM},
-  {"amdfam10h", M_AMDFAM10H},
-  {"barcelona", M_AMDFAM10H_BARCELONA},
-  {"shanghai", M_AMDFAM10H_SHANGHAI},
-  {"istanbul", M_AMDFAM10H_ISTANBUL},
-  {"btver1", M_AMD_BTVER1},
-  {"amdfam15h", M_AMDFAM15H},
-  {"bdver1", M_AMDFAM15H_BDVER1},
-  {"bdver2", M_AMDFAM15H_BDVER2},
-  {"bdver3", M_AMDFAM15H_BDVER3},
-  {"bdver4", M_AMDFAM15H_BDVER4},
-  {"btver2", M_AMD_BTVER2},
-  {"amdfam17h", M_AMDFAM17H},
-  {"znver1", M_AMDFAM17H_ZNVER1},
-  {"znver2", M_AMDFAM17H_ZNVER2},
+  {"amd", M_VENDOR (VENDOR_AMD)},
+  {"intel", M_VENDOR (VENDOR_INTEL)},
+  {"atom", M_CPU_TYPE (INTEL_BONNELL)},
+  {"slm", M_CPU_TYPE (INTEL_SILVERMONT)},
+  {"core2", M_CPU_TYPE (INTEL_CORE2)},
+  {"corei7", M_CPU_TYPE (INTEL_COREI7)},
+  {"nehalem", M_CPU_SUBTYPE (INTEL_COREI7_NEHALEM)},
+  {"westmere", M_CPU_SUBTYPE (INTEL_COREI7_WESTMERE)},
+  {"sandybridge", M_CPU_SUBTYPE (INTEL_COREI7_SANDYBRIDGE)},
+  {"ivybridge", M_CPU_SUBTYPE (INTEL_COREI7_IVYBRIDGE)},
+  {"haswell", M_CPU_SUBTYPE (INTEL_COREI7_HASWELL)},
+  {"broadwell", M_CPU_SUBTYPE (INTEL_COREI7_BROADWELL)},
+  {"skylake", M_CPU_SUBTYPE (INTEL_COREI7_SKYLAKE)},
+  {"skylake-avx512", M_CPU_SUBTYPE (INTEL_COREI7_SKYLAKE_AVX512)},
+  {"cannonlake", M_CPU_SUBTYPE (INTEL_COREI7_CANNONLAKE)},
+  {"icelake-client", M_CPU_SUBTYPE (INTEL_COREI7_ICELAKE_CLIENT)},
+  {"icelake-server", M_CPU_SUBTYPE (INTEL_COREI7_ICELAKE_SERVER)},
+  {"cascadelake", M_CPU_SUBTYPE (INTEL_COREI7_CASCADELAKE)},
+  {"tigerlake", M_CPU_SUBTYPE (INTEL_COREI7_TIGERLAKE)},
+  {"cooperlake", M_CPU_SUBTYPE (INTEL_COREI7_COOPERLAKE)},
+  {"bonnell", M_CPU_TYPE (INTEL_BONNELL)},
+  {"silvermont", M_CPU_TYPE (INTEL_SILVERMONT)},
+  {"goldmont", M_CPU_TYPE (INTEL_GOLDMONT)},
+  {"goldmont-plus", M_CPU_TYPE (INTEL_GOLDMONT_PLUS)},
+  {"tremont", M_CPU_TYPE (INTEL_TREMONT)},
+  {"knl", M_CPU_TYPE (INTEL_KNL)},
+  {"knm", M_CPU_TYPE (INTEL_KNM)},
+  {"amdfam10h", M_CPU_TYPE (AMDFAM10H)},
+  {"barcelona", M_CPU_SUBTYPE (AMDFAM10H_BARCELONA)},
+  {"shanghai", M_CPU_SUBTYPE (AMDFAM10H_SHANGHAI)},
+  {"istanbul", M_CPU_SUBTYPE (AMDFAM10H_ISTANBUL)},
+  {"btver1", M_CPU_TYPE (AMD_BTVER1)},
+  {"amdfam15h", M_CPU_TYPE (AMDFAM15H)},
+  {"bdver1", M_CPU_SUBTYPE (AMDFAM15H_BDVER1)},
+  {"bdver2", M_CPU_SUBTYPE (AMDFAM15H_BDVER2)},
+  {"bdver3", M_CPU_SUBTYPE (AMDFAM15H_BDVER3)},
+  {"bdver4", M_CPU_SUBTYPE (AMDFAM15H_BDVER4)},
+  {"btver2", M_CPU_TYPE (AMD_BTVER2)},
+  {"amdfam17h", M_CPU_TYPE (AMDFAM17H)},
+  {"znver1", M_CPU_SUBTYPE (AMDFAM17H_ZNVER1)},
+  {"znver2", M_CPU_SUBTYPE (AMDFAM17H_ZNVER2)},
 };
 
 /* These are the target attribute strings for which a dispatcher is
@@ -2026,44 +1946,92 @@  struct _isa_names_table
 
 static const _isa_names_table isa_names_table[] =
 {
-  {"cmov",    F_CMOV,	P_ZERO},
-  {"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_ZERO},
-  {"avx512bw",F_AVX512BW, P_ZERO},
-  {"avx512dq",F_AVX512DQ, P_ZERO},
-  {"avx512cd",F_AVX512CD, P_ZERO},
-  {"avx512er",F_AVX512ER, P_ZERO},
-  {"avx512pf",F_AVX512PF, P_ZERO},
-  {"avx512vbmi",F_AVX512VBMI, P_ZERO},
-  {"avx512ifma",F_AVX512IFMA, P_ZERO},
-  {"avx5124vnniw",F_AVX5124VNNIW, P_ZERO},
-  {"avx5124fmaps",F_AVX5124FMAPS, P_ZERO},
-  {"avx512vpopcntdq",F_AVX512VPOPCNTDQ,	P_ZERO},
-  {"avx512vbmi2", F_AVX512VBMI2, P_ZERO},
-  {"gfni",	F_GFNI,	P_ZERO},
-  {"vpclmulqdq", F_VPCLMULQDQ, P_ZERO},
-  {"avx512vnni", F_AVX512VNNI, P_ZERO},
-  {"avx512bitalg", F_AVX512BITALG, P_ZERO},
-  {"avx512bf16", F_AVX512BF16, P_ZERO},
-  {"avx512vp2intersect",F_AVX512VP2INTERSECT, P_ZERO}
+  {"cmov",    FEATURE_CMOV,	P_ZERO},
+  {"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_ZERO},
+  {"avx512bw",FEATURE_AVX512BW, P_ZERO},
+  {"avx512dq",FEATURE_AVX512DQ, P_ZERO},
+  {"avx512cd",FEATURE_AVX512CD, P_ZERO},
+  {"avx512er",FEATURE_AVX512ER, P_ZERO},
+  {"avx512pf",FEATURE_AVX512PF, P_ZERO},
+  {"avx512vbmi",FEATURE_AVX512VBMI, P_ZERO},
+  {"avx512ifma",FEATURE_AVX512IFMA, P_ZERO},
+  {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_ZERO},
+  {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_ZERO},
+  {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ,	P_ZERO},
+  {"avx512vbmi2", FEATURE_AVX512VBMI2, P_ZERO},
+  {"gfni",	FEATURE_GFNI,	P_ZERO},
+  {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_ZERO},
+  {"avx512vnni", FEATURE_AVX512VNNI, P_ZERO},
+  {"avx512bitalg", FEATURE_AVX512BITALG, P_ZERO},
+  {"avx512bf16", FEATURE_AVX512BF16, P_ZERO},
+  {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_ZERO},
+  {"3dnow", FEATURE_3DNOW, P_ZERO},
+  {"3dnowp", FEATURE_3DNOWP, P_ZERO},
+  {"adx", FEATURE_ADX, P_ZERO},
+  {"abm", FEATURE_ABM, P_ZERO},
+  {"cldemote", FEATURE_CLDEMOTE, P_ZERO},
+  {"clflushopt", FEATURE_CLFLUSHOPT, P_ZERO},
+  {"clwb", FEATURE_CLWB, P_ZERO},
+  {"clzero", FEATURE_CLZERO, P_ZERO},
+  {"cmpxchg16b", FEATURE_CMPXCHG16B, P_ZERO},
+  {"cmpxchg8b", FEATURE_CMPXCHG8B, P_ZERO},
+  {"enqcmd", FEATURE_ENQCMD, P_ZERO},
+  {"f16c", FEATURE_F16C, P_ZERO},
+  {"fsgsbase", FEATURE_FSGSBASE, P_ZERO},
+  {"fxsave", FEATURE_FXSAVE, P_ZERO},
+  {"hle", FEATURE_HLE, P_ZERO},
+  {"ibt", FEATURE_IBT, P_ZERO},
+  {"lahf_lm", FEATURE_LAHF_LM, P_ZERO},
+  {"lm", FEATURE_LM, P_ZERO},
+  {"lwp", FEATURE_LWP, P_ZERO},
+  {"lzcnt", FEATURE_LZCNT, P_ZERO},
+  {"movbe", FEATURE_MOVBE, P_ZERO},
+  {"movdir64b", FEATURE_MOVDIR64B, P_ZERO},
+  {"movdiri", FEATURE_MOVDIRI, P_ZERO},
+  {"mwaitx", FEATURE_MWAITX, P_ZERO},
+  {"ospke", FEATURE_OSPKE, P_ZERO},
+  {"osxsave", FEATURE_OSXSAVE, P_ZERO},
+  {"pconfig", FEATURE_PCONFIG, P_ZERO},
+  {"pku", FEATURE_PKU, P_ZERO},
+  {"prefetchwt1", FEATURE_PREFETCHWT1, P_ZERO},
+  {"prfchw", FEATURE_PRFCHW, P_ZERO},
+  {"ptwrite", FEATURE_PTWRITE, P_ZERO},
+  {"rdpid", FEATURE_RDPID, P_ZERO},
+  {"rdrnd", FEATURE_RDRND, P_ZERO},
+  {"rdseed", FEATURE_RDSEED, P_ZERO},
+  {"rtm", FEATURE_RTM, P_ZERO},
+  {"serialize", FEATURE_SERIALIZE, P_ZERO},
+  {"sgx", FEATURE_SGX, P_ZERO},
+  {"sha", FEATURE_SHA, P_ZERO},
+  {"shstk", FEATURE_SHSTK, P_ZERO},
+  {"tbm", FEATURE_TBM, P_ZERO},
+  {"tsxldtrk", FEATURE_TSXLDTRK, P_ZERO},
+  {"vaes", FEATURE_VAES, P_ZERO},
+  {"waitpkg", FEATURE_WAITPKG, P_ZERO},
+  {"wbnoinvd", FEATURE_WBNOINVD, P_ZERO},
+  {"xsave", FEATURE_XSAVE, P_ZERO},
+  {"xsavec", FEATURE_XSAVEC, P_ZERO},
+  {"xsaveopt", FEATURE_XSAVEOPT, P_ZERO},
+  {"xsaves", FEATURE_XSAVES, P_ZERO}
 };
 
 /* This parses the attribute arguments to target in DECL and determines
@@ -2509,16 +2477,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/gcc/testsuite/gcc.target/i386/builtin_target.c b/gcc/testsuite/gcc.target/i386/builtin_target.c
index 7a8b6e805ed..95e2318fd8b 100644
--- a/gcc/testsuite/gcc.target/i386/builtin_target.c
+++ b/gcc/testsuite/gcc.target/i386/builtin_target.c
@@ -7,348 +7,220 @@ 
 /* { dg-do run } */
 
 #include <assert.h>
+#include <stdlib.h>
 #include "cpuid.h"
-
-/* Check if the Intel CPU model and sub-model are identified.  */
-static void
-check_intel_cpu_model (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:
-	      /* Atom.  */
-	      assert (__builtin_cpu_is ("atom"));
-	      break;
-	    case 0x37:
-	    case 0x4a:
-	    case 0x4d:
-	    case 0x5a:
-	    case 0x5d:
-	      /* Silvermont.  */
-	      assert (__builtin_cpu_is ("silvermont"));
-	      break;
-	    case 0x5c:
-	    case 0x5f:
-	      /* Goldmont.  */
-	      assert (__builtin_cpu_is ("goldmont"));
-	      break;
-	    case 0x7a:
-	      /* Goldmont Plus.  */
-	      assert (__builtin_cpu_is ("goldmont-plus"));
-	      break;
-	    case 0x57:
-	      /* Knights Landing.  */
-	      assert (__builtin_cpu_is ("knl"));
-	      break;
-	    case 0x85:
-	      /* Knights Mill */
-	      assert (__builtin_cpu_is ("knm"));
-	      break;
-	    case 0x1a:
-	    case 0x1e:
-	    case 0x1f:
-	    case 0x2e:
-	      /* Nehalem.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("nehalem"));
-	      break;
-	    case 0x25:
-	    case 0x2c:
-	    case 0x2f:
-	      /* Westmere.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("westmere"));
-	      break;
-	    case 0x2a:
-	    case 0x2d:
-	      /* Sandy Bridge.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("sandybridge"));
-	      break;
-	    case 0x3a:
-	    case 0x3e:
-	      /* Ivy Bridge.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("ivybridge"));
-	      break;
-	    case 0x3c:
-	    case 0x3f:
-	    case 0x45:
-	    case 0x46:
-	      /* Haswell.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("haswell"));
-	      break;
-	    case 0x3d:
-	    case 0x47:
-	    case 0x4f:
-	    case 0x56:
-	      /* Broadwell.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("broadwell"));
-	      break;
-	    case 0x4e:
-	    case 0x5e:
-	      /* Skylake.  */
-	    case 0x8e:
-	    case 0x9e:
-	      /* Kaby Lake.  */
-	      assert (__builtin_cpu_is ("corei7"));
-	      assert (__builtin_cpu_is ("skylake"));
-	      break;
-	    case 0x55:
-	      {
-	        unsigned int eax, ebx, ecx, edx;
-	        __cpuid_count (7, 0, eax, ebx, ecx, edx);
-	        assert (__builtin_cpu_is ("corei7"));
-	        if (ecx & bit_AVX512VNNI)
-	          /* Cascade Lake.  */
-	          assert (__builtin_cpu_is ("cascadelake"));
-	        else
-	          /* Skylake with AVX-512 support.  */
-	          assert (__builtin_cpu_is ("skylake-avx512"));
-	        break;
-	      }
-	    case 0x66:
-	      /* Cannon Lake.  */
-	      assert (__builtin_cpu_is ("cannonlake"));
-	      break;
-	    case 0x17:
-	    case 0x1d:
-	      /* Penryn.  */
-	    case 0x0f:
-	      /* Merom.  */
-	      assert (__builtin_cpu_is ("core2"));
-	      break;
-	    default:
-	      break;
-	    }
-	  break;
-	default:
-	  /* We have no idea.  */
-	  break;
-	}
-    }
-}
-
-/* Check if the AMD CPU model and sub-model are identified.  */
-static void
-check_amd_cpu_model (unsigned int family, unsigned int model)
-{
-  switch (family)
-    {
-    /* AMD Family 10h.  */
-    case 0x10:
-      switch (model)
-	{
-	case 0x2:
-	  /* Barcelona.  */
-	  assert (__builtin_cpu_is ("amdfam10h"));
-	  assert (__builtin_cpu_is ("barcelona"));
-	  break;
-	case 0x4:
-	  /* Shanghai.  */
-	  assert (__builtin_cpu_is ("amdfam10h"));
-	  assert (__builtin_cpu_is ("shanghai"));
-	  break;
-	case 0x8:
-	  /* Istanbul.  */
-	  assert (__builtin_cpu_is ("amdfam10h"));
-	  assert (__builtin_cpu_is ("istanbul"));
-	  break;
-	default:
-	  break;
-	}
-      break;
-    /* AMD Family 15h.  */
-    case 0x15:
-      assert (__builtin_cpu_is ("amdfam15h"));
-      /* Bulldozer version 1.  */
-      if ( model <= 0xf)
-	assert (__builtin_cpu_is ("bdver1"));
-      /* Bulldozer version 2.  */
-      if (model >= 0x10 && model <= 0x1f)
-	assert (__builtin_cpu_is ("bdver2"));
-      break;
-    default:
-      break;
-    }
-}
+#define CHECK___builtin_cpu_is(cpu) assert (__builtin_cpu_is (cpu))
+#define gcc_assert(a) assert (a)
+#define gcc_unreachable() abort ()
+#define inline
+#include "../../../common/config/i386/cpuinfo.h"
 
 /* Check if the ISA features are identified.  */
 static void
-check_features (unsigned int ecx, unsigned int edx,
-		int max_cpuid_level)
+check_features (struct __processor_model *cpu_model,
+		unsigned int *cpu_features2)
 {
-  unsigned int eax, ebx;
-  unsigned int ext_level;
+#define has_feature(f) \
+  has_cpu_feature (cpu_model, cpu_features2, f)
 
-  if (edx & bit_CMOV)
+  if (has_feature (FEATURE_CMOV))
     assert (__builtin_cpu_supports ("cmov"));
-  if (edx & bit_MMX)
+  if (has_feature (FEATURE_MMX))
     assert (__builtin_cpu_supports ("mmx"));
-  if (edx & bit_SSE)
+  if (has_feature (FEATURE_POPCNT))
+    assert (__builtin_cpu_supports ("popcnt"));
+  if (has_feature (FEATURE_SSE))
     assert (__builtin_cpu_supports ("sse"));
-  if (edx & bit_SSE2)
+  if (has_feature (FEATURE_SSE2))
     assert (__builtin_cpu_supports ("sse2"));
-  if (ecx & bit_POPCNT)
-    assert (__builtin_cpu_supports ("popcnt"));
-  if (ecx & bit_AES)
-    assert (__builtin_cpu_supports ("aes"));
-  if (ecx & bit_PCLMUL)
-    assert (__builtin_cpu_supports ("pclmul"));
-  if (ecx & bit_SSE3)
+  if (has_feature (FEATURE_SSE3))
     assert (__builtin_cpu_supports ("sse3"));
-  if (ecx & bit_SSSE3)
+  if (has_feature (FEATURE_SSSE3))
     assert (__builtin_cpu_supports ("ssse3"));
-  if (ecx & bit_SSE4_1)
+  if (has_feature (FEATURE_SSE4_1))
     assert (__builtin_cpu_supports ("sse4.1"));
-  if (ecx & bit_SSE4_2)
+  if (has_feature (FEATURE_SSE4_2))
     assert (__builtin_cpu_supports ("sse4.2"));
-  if (ecx & bit_AVX)
+  if (has_feature (FEATURE_AVX))
     assert (__builtin_cpu_supports ("avx"));
-  if (ecx & bit_FMA)
+  if (has_feature (FEATURE_AVX2))
+    assert (__builtin_cpu_supports ("avx2"));
+  if (has_feature (FEATURE_SSE4_A))
+    assert (__builtin_cpu_supports ("sse4a"));
+  if (has_feature (FEATURE_FMA4))
+    assert (__builtin_cpu_supports ("fma4"));
+  if (has_feature (FEATURE_XOP))
+    assert (__builtin_cpu_supports ("xop"));
+  if (has_feature (FEATURE_FMA))
     assert (__builtin_cpu_supports ("fma"));
-
-  /* Get advanced features at level 7 (eax = 7, ecx = 0).  */
-  if (max_cpuid_level >= 7)
-    {
-      __cpuid_count (7, 0, eax, ebx, ecx, edx);
-      if (ebx & bit_BMI)
-	assert (__builtin_cpu_supports ("bmi"));
-      if (ebx & bit_AVX2)
-	assert (__builtin_cpu_supports ("avx2"));
-      if (ebx & bit_BMI2)
-	assert (__builtin_cpu_supports ("bmi2"));
-      if (ebx & bit_AVX512F)
-	assert (__builtin_cpu_supports ("avx512f"));
-      if (ebx & bit_AVX512VL)
-	assert (__builtin_cpu_supports ("avx512vl"));
-      if (ebx & bit_AVX512BW)
-	assert (__builtin_cpu_supports ("avx512bw"));
-      if (ebx & bit_AVX512DQ)
-	assert (__builtin_cpu_supports ("avx512dq"));
-      if (ebx & bit_AVX512CD)
-	assert (__builtin_cpu_supports ("avx512cd"));
-      if (ebx & bit_AVX512PF)
-	assert (__builtin_cpu_supports ("avx512pf"));
-      if (ebx & bit_AVX512ER)
-	assert (__builtin_cpu_supports ("avx512er"));
-      if (ebx & bit_AVX512IFMA)
-	assert (__builtin_cpu_supports ("avx512ifma"));
-      if (ecx & bit_AVX512VBMI)
-	assert (__builtin_cpu_supports ("avx512vbmi"));
-      if (ecx & bit_AVX512VBMI2)
-	assert (__builtin_cpu_supports ("avx512vbmi2"));
-      if (ecx & bit_GFNI)
-	assert (__builtin_cpu_supports ("gfni"));
-      if (ecx & bit_VPCLMULQDQ)
-	assert (__builtin_cpu_supports ("vpclmulqdq"));
-      if (ecx & bit_AVX512VNNI)
-	assert (__builtin_cpu_supports ("avx512vnni"));
-      if (ecx & bit_AVX512BITALG)
-	assert (__builtin_cpu_supports ("avx512bitalg"));
-      if (ecx & bit_AVX512VPOPCNTDQ)
-	assert (__builtin_cpu_supports ("avx512vpopcntdq"));
-      if (edx & bit_AVX5124VNNIW)
-	assert (__builtin_cpu_supports ("avx5124vnniw"));
-      if (edx & bit_AVX5124FMAPS)
-	assert (__builtin_cpu_supports ("avx5124fmaps"));
-
-      __cpuid_count (7, 1, eax, ebx, ecx, edx);
-      if (eax & bit_AVX512BF16)
-	assert (__builtin_cpu_supports ("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)
-	assert (__builtin_cpu_supports ("sse4a"));
-      if (ecx & bit_FMA4)
-	assert (__builtin_cpu_supports ("fma4"));
-      if (ecx & bit_XOP)
-	assert (__builtin_cpu_supports ("xop"));
-    }
-}
-
-static int __attribute__ ((noinline))
-__get_cpuid_output (unsigned int __level,
-		    unsigned int *__eax, unsigned int *__ebx,
-		    unsigned int *__ecx, unsigned int *__edx)
-{
-  return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
+  if (has_feature (FEATURE_AVX512F))
+    assert (__builtin_cpu_supports ("avx512f"));
+  if (has_feature (FEATURE_BMI))
+    assert (__builtin_cpu_supports ("bmi"));
+  if (has_feature (FEATURE_BMI2))
+    assert (__builtin_cpu_supports ("bmi2"));
+  if (has_feature (FEATURE_AES))
+    assert (__builtin_cpu_supports ("aes"));
+  if (has_feature (FEATURE_PCLMUL))
+    assert (__builtin_cpu_supports ("pclmul"));
+  if (has_feature (FEATURE_AVX512VL))
+    assert (__builtin_cpu_supports ("avx512vl"));
+  if (has_feature (FEATURE_AVX512BW))
+    assert (__builtin_cpu_supports ("avx512bw"));
+  if (has_feature (FEATURE_AVX512DQ))
+    assert (__builtin_cpu_supports ("avx512dq"));
+  if (has_feature (FEATURE_AVX512CD))
+    assert (__builtin_cpu_supports ("avx512cd"));
+  if (has_feature (FEATURE_AVX512ER))
+    assert (__builtin_cpu_supports ("avx512er"));
+  if (has_feature (FEATURE_AVX512PF))
+    assert (__builtin_cpu_supports ("avx512pf"));
+  if (has_feature (FEATURE_AVX512VBMI))
+    assert (__builtin_cpu_supports ("avx512vbmi"));
+  if (has_feature (FEATURE_AVX512IFMA))
+    assert (__builtin_cpu_supports ("avx512ifma"));
+  if (has_feature (FEATURE_AVX5124VNNIW))
+    assert (__builtin_cpu_supports ("avx5124vnniw"));
+  if (has_feature (FEATURE_AVX5124FMAPS))
+    assert (__builtin_cpu_supports ("avx5124fmaps"));
+  if (has_feature (FEATURE_AVX512VPOPCNTDQ))
+    assert (__builtin_cpu_supports ("avx512vpopcntdq"));
+  if (has_feature (FEATURE_AVX512VBMI2))
+    assert (__builtin_cpu_supports ("avx512vbmi2"));
+  if (has_feature (FEATURE_GFNI))
+    assert (__builtin_cpu_supports ("gfni"));
+  if (has_feature (FEATURE_VPCLMULQDQ))
+    assert (__builtin_cpu_supports ("vpclmulqdq"));
+  if (has_feature (FEATURE_AVX512VNNI))
+    assert (__builtin_cpu_supports ("avx512vnni"));
+  if (has_feature (FEATURE_AVX512BITALG))
+    assert (__builtin_cpu_supports ("avx512bitalg"));
+  if (has_feature (FEATURE_AVX512BF16))
+    assert (__builtin_cpu_supports ("avx512bf16"));
+  if (has_feature (FEATURE_AVX512VP2INTERSECT))
+    assert (__builtin_cpu_supports ("avx512vp2intersect"));
+  if (has_feature (FEATURE_3DNOW))
+    assert (__builtin_cpu_supports ("3dnow"));
+  if (has_feature (FEATURE_3DNOWP))
+    assert (__builtin_cpu_supports ("3dnowp"));
+  if (has_feature (FEATURE_ADX))
+    assert (__builtin_cpu_supports ("adx"));
+  if (has_feature (FEATURE_ABM))
+    assert (__builtin_cpu_supports ("abm"));
+  if (has_feature (FEATURE_CLDEMOTE))
+    assert (__builtin_cpu_supports ("cldemote"));
+  if (has_feature (FEATURE_CLFLUSHOPT))
+    assert (__builtin_cpu_supports ("clflushopt"));
+  if (has_feature (FEATURE_CLWB))
+    assert (__builtin_cpu_supports ("clwb"));
+  if (has_feature (FEATURE_CLZERO))
+    assert (__builtin_cpu_supports ("clzero"));
+  if (has_feature (FEATURE_CMPXCHG16B))
+    assert (__builtin_cpu_supports ("cmpxchg16b"));
+  if (has_feature (FEATURE_CMPXCHG8B))
+    assert (__builtin_cpu_supports ("cmpxchg8b"));
+  if (has_feature (FEATURE_ENQCMD))
+    assert (__builtin_cpu_supports ("enqcmd"));
+  if (has_feature (FEATURE_F16C))
+    assert (__builtin_cpu_supports ("f16c"));
+  if (has_feature (FEATURE_FSGSBASE))
+    assert (__builtin_cpu_supports ("fsgsbase"));
+  if (has_feature (FEATURE_FXSAVE))
+    assert (__builtin_cpu_supports ("fxsave"));
+  if (has_feature (FEATURE_HLE))
+    assert (__builtin_cpu_supports ("hle"));
+  if (has_feature (FEATURE_IBT))
+    assert (__builtin_cpu_supports ("ibt"));
+  if (has_feature (FEATURE_LAHF_LM))
+    assert (__builtin_cpu_supports ("lahf_lm"));
+  if (has_feature (FEATURE_LM))
+    assert (__builtin_cpu_supports ("lm"));
+  if (has_feature (FEATURE_LWP))
+    assert (__builtin_cpu_supports ("lwp"));
+  if (has_feature (FEATURE_LZCNT))
+    assert (__builtin_cpu_supports ("lzcnt"));
+  if (has_feature (FEATURE_MOVBE))
+    assert (__builtin_cpu_supports ("movbe"));
+  if (has_feature (FEATURE_MOVDIR64B))
+    assert (__builtin_cpu_supports ("movdir64b"));
+  if (has_feature (FEATURE_MOVDIRI))
+    assert (__builtin_cpu_supports ("movdiri"));
+  if (has_feature (FEATURE_MWAITX))
+    assert (__builtin_cpu_supports ("mwaitx"));
+  if (has_feature (FEATURE_OSPKE))
+    assert (__builtin_cpu_supports ("ospke"));
+  if (has_feature (FEATURE_OSXSAVE))
+    assert (__builtin_cpu_supports ("osxsave"));
+  if (has_feature (FEATURE_PCONFIG))
+    assert (__builtin_cpu_supports ("pconfig"));
+  if (has_feature (FEATURE_PKU))
+    assert (__builtin_cpu_supports ("pku"));
+  if (has_feature (FEATURE_PREFETCHWT1))
+    assert (__builtin_cpu_supports ("prefetchwt1"));
+  if (has_feature (FEATURE_PRFCHW))
+    assert (__builtin_cpu_supports ("prfchw"));
+  if (has_feature (FEATURE_PTWRITE))
+    assert (__builtin_cpu_supports ("ptwrite"));
+  if (has_feature (FEATURE_RDPID))
+    assert (__builtin_cpu_supports ("rdpid"));
+  if (has_feature (FEATURE_RDRND))
+    assert (__builtin_cpu_supports ("rdrnd"));
+  if (has_feature (FEATURE_RDSEED))
+    assert (__builtin_cpu_supports ("rdseed"));
+  if (has_feature (FEATURE_RTM))
+    assert (__builtin_cpu_supports ("rtm"));
+  if (has_feature (FEATURE_SERIALIZE))
+    assert (__builtin_cpu_supports ("serialize"));
+  if (has_feature (FEATURE_SGX))
+    assert (__builtin_cpu_supports ("sgx"));
+  if (has_feature (FEATURE_SHA))
+    assert (__builtin_cpu_supports ("sha"));
+  if (has_feature (FEATURE_SHSTK))
+    assert (__builtin_cpu_supports ("shstk"));
+  if (has_feature (FEATURE_TBM))
+    assert (__builtin_cpu_supports ("tbm"));
+  if (has_feature (FEATURE_TSXLDTRK))
+    assert (__builtin_cpu_supports ("tsxldtrk"));
+  if (has_feature (FEATURE_VAES))
+    assert (__builtin_cpu_supports ("vaes"));
+  if (has_feature (FEATURE_WAITPKG))
+    assert (__builtin_cpu_supports ("waitpkg"));
+  if (has_feature (FEATURE_WBNOINVD))
+    assert (__builtin_cpu_supports ("wbnoinvd"));
+  if (has_feature (FEATURE_XSAVE))
+    assert (__builtin_cpu_supports ("xsave"));
+  if (has_feature (FEATURE_XSAVEC))
+    assert (__builtin_cpu_supports ("xsavec"));
+  if (has_feature (FEATURE_XSAVEOPT))
+    assert (__builtin_cpu_supports ("xsaveopt"));
+  if (has_feature (FEATURE_XSAVES))
+    assert (__builtin_cpu_supports ("xsaves"));
 }
 
 static int
 check_detailed ()
 {
-  unsigned int eax, ebx, ecx, edx;
-
-  int max_level; 
-  unsigned int vendor;
-  unsigned int model, family, brand_id;
-  unsigned int extended_model, extended_family;
+  struct __processor_model cpu_model = { 0 };
+  struct __processor_model2 cpu_model2 = { 0 };
+  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { 0 };
 
-  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
-  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
+  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
     return 0;
 
-  vendor = ebx;
-  max_level = eax;
+  check_features (&cpu_model, cpu_features2);
 
-  if (max_level < 1)
-    return 0;
-
-  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
-    return 0;
-
-  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)
+  switch (cpu_model.__cpu_vendor)
     {
+    case VENDOR_INTEL:
       assert (__builtin_cpu_is ("intel"));
-      /* Adjust family and model for Intel CPUs.  */
-      if (family == 0x0f)
-	{
-	  family += extended_family;
-	  model += extended_model;
-	}
-      else if (family == 0x06)
-	model += extended_model;
-      check_intel_cpu_model (family, model, brand_id);
-      check_features (ecx, edx, max_level);
-    }
-  else if (vendor == signature_AMD_ebx)
-    {
+      get_intel_cpu (&cpu_model, &cpu_model2, cpu_features2, 0);
+      break;
+    case VENDOR_AMD:
       assert (__builtin_cpu_is ("amd"));
-      /* Adjust model and family for AMD CPUS. */
-      if (family == 0x0f)
-	{
-	  family += extended_family;
-	  model += (extended_model << 4);
-	}
-      check_amd_cpu_model (family, model);
-      check_features (ecx, edx, max_level);
+      get_amd_cpu (&cpu_model, &cpu_model2, cpu_features2);
+      break;
+    default:
+      break;
     }
 
   return 0;
diff --git a/libgcc/config/i386/cpuinfo.c b/libgcc/config/i386/cpuinfo.c
index cf5f0884bb4..49c5107546f 100644
--- a/libgcc/config/i386/cpuinfo.c
+++ b/libgcc/config/i386/cpuinfo.c
@@ -26,7 +26,7 @@  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/cpuinfo.h"
 
 #ifdef HAVE_INIT_PRIORITY
 #define CONSTRUCTOR_PRIORITY (101)
@@ -39,386 +39,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 +57,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
-- 
2.26.2