diff mbox series

V2 [PATCH] x86: Share _isa_names_table and use cpuinfo.h

Message ID 20200624143809.GA343785@gmail.com
State New
Headers show
Series V2 [PATCH] x86: Share _isa_names_table and use cpuinfo.h | expand

Commit Message

H.J. Lu June 24, 2020, 2:38 p.m. UTC
On Wed, Jun 24, 2020 at 03:46:25PM +0200, Uros Bizjak wrote:
> On Wed, Jun 24, 2020 at 3:37 PM Uros Bizjak <ubizjak@gmail.com> wrote:
> >
> > On Wed, Jun 24, 2020 at 3:06 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > On Wed, Jun 24, 2020 at 02:43:43PM +0200, Uros Bizjak wrote:
> > > > >
> > > > > Here is the updated patch for x86 backend and libgcc.  driver-i386.c
> > > > > is unchanged.
> > > >
> > > > Thanks. We should change driver-i386.c very carefully and in an
> > > > independent way from this patch. It is a complex and interwoven web of
> > > > name, model and features check. I propose that we first convert
> > > > various has_xxx checks to a new interface, in as trivial way as
> > > > possible.
> > > >
> > >
> > > Here is the patch to share isa_names_table and use cpuinfo.h to check
> > > ISAs as well as detect newer Intel/AMD processors.
> > >
> > > OK for master?
> >
> > No. Don't use get_intel_cpu and get_amd_cpu in driver-i386.c.
> 
> +      cpu = get_amd_cpu (&cpu_model, &cpu_model2, cpu_features2);
> +      if (cpu == NULL)
> +       {
> +         if (name == signature_NSC_ebx)
> +           processor = PROCESSOR_GEODE;
> +         else if (has_feature (FEATURE_SSE2)
> 
> Here is where your patch fails. AMD part has early bypass for
> signature_NSC_ebx, so it is detected as NSC processor regardless of
> what is detected by generic code.
> 
> Uros.

Here is the updated patch not to use get_amd_cpu in driver-i386.c.
I believe the usage of get_intel_cpu in driver-i386.c is correct.

OK for master?

Thanks.

H.J.
---
Both driver-i386.c and libgcc use CPUID to detect the processor name
as well as available ISAs.  To detect the same processor or ISAs, the
same detection logic is duplicated in 2 places.  Sometimes only one place
was up to date or got it right.  Sometimes both places got it wrong.

1. Add common/config/i386/i386-isas.h to define _isa_names_table.
2. Use isa_names_table to auto-generate ISA command-line options.
3. Use isa_names_table to auto-generate __builtin_cpu_supports tests.
4. Use common/config/i386/cpuinfo.h to check available ISAs and detect
newer Intel processors in driver-i386.c and builtin_target.c.
5. Detection of AMD processors and older processors in driver-i386.c is
unchanged.

gcc/

	PR target/95843
	* common/config/i386/i386-isas.h: New file.  Extracted from
	gcc/config/i386/i386-builtins.c.
	(_isa_names_table): Add option.
	(ISA_NAMES_TABLE_START): New.
	(ISA_NAMES_TABLE_END): Likewise.
	(ISA_NAMES_TABLE_ENTRY): Likewise.
	(isa_names_table): Defined with ISA_NAMES_TABLE_START,
	ISA_NAMES_TABLE_END and ISA_NAMES_TABLE_ENTRY.  Add more ISAs
	from enum processor_features.
	* config/i386/driver-i386.c: Include
	"common/config/i386/cpuinfo.h" and
	"common/config/i386/i386-isas.h".
	(has_feature): New macro.
	(host_detect_local_cpu): Call cpu_indicator_init to get CPU
	features.  Use has_feature to detect processor features.  Call
	Call get_intel_cpu to get the newer Intel CPU name.  Use
	isa_names_table to generate command-line options.
	* config/i386/i386-builtins.c: Include
	"common/config/i386/i386-isas.h".
	(_arch_names_table): Removed.
	(isa_names_table): Likewise.

gcc/testsuite/

	PR target/95843
	* gcc.target/i386/builtin_target.c: Include <stdlib.h>,
	../../../common/config/i386/i386-cpuinfo.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.
	(ISA_NAMES_TABLE_START): Likewise.
	(ISA_NAMES_TABLE_END): Likewise.
	(ISA_NAMES_TABLE_ENTRY): New.
	(check_features): Include
	"../../../common/config/i386/i386-isas.h".
	(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.
---
 gcc/common/config/i386/i386-isas.h            | 163 +++++
 gcc/config/i386/driver-i386.c                 | 644 +++---------------
 gcc/config/i386/i386-builtins.c               |  52 +-
 .../gcc.target/i386/builtin_target.c          | 355 +---------
 4 files changed, 306 insertions(+), 908 deletions(-)
 create mode 100644 gcc/common/config/i386/i386-isas.h

Comments

Uros Bizjak June 24, 2020, 2:48 p.m. UTC | #1
On Wed, Jun 24, 2020 at 4:38 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Wed, Jun 24, 2020 at 03:46:25PM +0200, Uros Bizjak wrote:
> > On Wed, Jun 24, 2020 at 3:37 PM Uros Bizjak <ubizjak@gmail.com> wrote:
> > >
> > > On Wed, Jun 24, 2020 at 3:06 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > > > On Wed, Jun 24, 2020 at 02:43:43PM +0200, Uros Bizjak wrote:
> > > > > >
> > > > > > Here is the updated patch for x86 backend and libgcc.  driver-i386.c
> > > > > > is unchanged.
> > > > >
> > > > > Thanks. We should change driver-i386.c very carefully and in an
> > > > > independent way from this patch. It is a complex and interwoven web of
> > > > > name, model and features check. I propose that we first convert
> > > > > various has_xxx checks to a new interface, in as trivial way as
> > > > > possible.
> > > > >
> > > >
> > > > Here is the patch to share isa_names_table and use cpuinfo.h to check
> > > > ISAs as well as detect newer Intel/AMD processors.
> > > >
> > > > OK for master?
> > >
> > > No. Don't use get_intel_cpu and get_amd_cpu in driver-i386.c.
> >
> > +      cpu = get_amd_cpu (&cpu_model, &cpu_model2, cpu_features2);
> > +      if (cpu == NULL)
> > +       {
> > +         if (name == signature_NSC_ebx)
> > +           processor = PROCESSOR_GEODE;
> > +         else if (has_feature (FEATURE_SSE2)
> >
> > Here is where your patch fails. AMD part has early bypass for
> > signature_NSC_ebx, so it is detected as NSC processor regardless of
> > what is detected by generic code.
> >
> > Uros.
>
> Here is the updated patch not to use get_amd_cpu in driver-i386.c.
> I believe the usage of get_intel_cpu in driver-i386.c is correct.
>
> OK for master?

OK, let's go with this version, but look out for fallout.

I hope there is some interest from AMD folks to unify and further
improve their part of the detection code.

Thanks,
Uros.

> Thanks.
>
> H.J.
> ---
> Both driver-i386.c and libgcc use CPUID to detect the processor name
> as well as available ISAs.  To detect the same processor or ISAs, the
> same detection logic is duplicated in 2 places.  Sometimes only one place
> was up to date or got it right.  Sometimes both places got it wrong.
>
> 1. Add common/config/i386/i386-isas.h to define _isa_names_table.
> 2. Use isa_names_table to auto-generate ISA command-line options.
> 3. Use isa_names_table to auto-generate __builtin_cpu_supports tests.
> 4. Use common/config/i386/cpuinfo.h to check available ISAs and detect
> newer Intel processors in driver-i386.c and builtin_target.c.
> 5. Detection of AMD processors and older processors in driver-i386.c is
> unchanged.
>
> gcc/
>
>         PR target/95843
>         * common/config/i386/i386-isas.h: New file.  Extracted from
>         gcc/config/i386/i386-builtins.c.
>         (_isa_names_table): Add option.
>         (ISA_NAMES_TABLE_START): New.
>         (ISA_NAMES_TABLE_END): Likewise.
>         (ISA_NAMES_TABLE_ENTRY): Likewise.
>         (isa_names_table): Defined with ISA_NAMES_TABLE_START,
>         ISA_NAMES_TABLE_END and ISA_NAMES_TABLE_ENTRY.  Add more ISAs
>         from enum processor_features.
>         * config/i386/driver-i386.c: Include
>         "common/config/i386/cpuinfo.h" and
>         "common/config/i386/i386-isas.h".
>         (has_feature): New macro.
>         (host_detect_local_cpu): Call cpu_indicator_init to get CPU
>         features.  Use has_feature to detect processor features.  Call
>         Call get_intel_cpu to get the newer Intel CPU name.  Use
>         isa_names_table to generate command-line options.
>         * config/i386/i386-builtins.c: Include
>         "common/config/i386/i386-isas.h".
>         (_arch_names_table): Removed.
>         (isa_names_table): Likewise.
>
> gcc/testsuite/
>
>         PR target/95843
>         * gcc.target/i386/builtin_target.c: Include <stdlib.h>,
>         ../../../common/config/i386/i386-cpuinfo.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.
>         (ISA_NAMES_TABLE_START): Likewise.
>         (ISA_NAMES_TABLE_END): Likewise.
>         (ISA_NAMES_TABLE_ENTRY): New.
>         (check_features): Include
>         "../../../common/config/i386/i386-isas.h".
>         (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.
> ---
>  gcc/common/config/i386/i386-isas.h            | 163 +++++
>  gcc/config/i386/driver-i386.c                 | 644 +++---------------
>  gcc/config/i386/i386-builtins.c               |  52 +-
>  .../gcc.target/i386/builtin_target.c          | 355 +---------
>  4 files changed, 306 insertions(+), 908 deletions(-)
>  create mode 100644 gcc/common/config/i386/i386-isas.h
>
> diff --git a/gcc/common/config/i386/i386-isas.h b/gcc/common/config/i386/i386-isas.h
> new file mode 100644
> index 00000000000..08c9dbecc76
> --- /dev/null
> +++ b/gcc/common/config/i386/i386-isas.h
> @@ -0,0 +1,163 @@
> +/* i386 ISA table.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +
> +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.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +/* These are the target attribute strings for which a dispatcher is
> +   available, from fold_builtin_cpu.  */
> +struct _isa_names_table
> +{
> +  const char *const name;
> +  const enum processor_features feature;
> +  const enum feature_priority priority;
> +  const char *const option;
> +};
> +
> +/* NB: isa_names_table is shared by i386-builtins.c, driver-i386.c and
> +   gcc.target/i386/builtin_target.c.  isa_names_table is a static const
> +   array in i386-builtins.c and driver-i386.c.  But it is a list of
> +   assert statements in gcc.target/i386/builtin_target.c.  */
> +
> +#ifndef ISA_NAMES_TABLE_START
> +# define ISA_NAMES_TABLE_START \
> +    static const struct _isa_names_table isa_names_table[] = {
> +#endif
> +
> +#ifndef ISA_NAMES_TABLE_END
> +# define ISA_NAMES_TABLE_END };
> +#endif
> +
> +#ifndef ISA_NAMES_TABLE_ENTRY
> +# define ISA_NAMES_TABLE_ENTRY(name, feature, priority, option)  \
> +    {name, feature, priority, option},
> +#endif
> +
> +ISA_NAMES_TABLE_START
> +  ISA_NAMES_TABLE_ENTRY("cmov", FEATURE_CMOV, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("mmx", FEATURE_MMX, P_MMX, "-mmmx")
> +  ISA_NAMES_TABLE_ENTRY("popcnt", FEATURE_POPCNT, P_POPCNT, "-mpopcnt")
> +  ISA_NAMES_TABLE_ENTRY("sse", FEATURE_SSE, P_SSE, "-msse")
> +  ISA_NAMES_TABLE_ENTRY("sse2", FEATURE_SSE2, P_SSE2, "-msse2")
> +  ISA_NAMES_TABLE_ENTRY("sse3", FEATURE_SSE3, P_SSE3, "-msse3")
> +  ISA_NAMES_TABLE_ENTRY("ssse3", FEATURE_SSSE3, P_SSSE3, "-mssse3")
> +  ISA_NAMES_TABLE_ENTRY("sse4.1", FEATURE_SSE4_1, P_SSE4_1, "-msse4.1")
> +  ISA_NAMES_TABLE_ENTRY("sse4.2", FEATURE_SSE4_2, P_SSE4_2, "-msse4.2")
> +  ISA_NAMES_TABLE_ENTRY("avx", FEATURE_AVX, P_AVX, "-mavx")
> +  ISA_NAMES_TABLE_ENTRY("avx2", FEATURE_AVX2, P_AVX2, "-mavx2")
> +  ISA_NAMES_TABLE_ENTRY("sse4a", FEATURE_SSE4_A, P_SSE4_A, "-msse4a")
> +  ISA_NAMES_TABLE_ENTRY("fma4", FEATURE_FMA4, P_FMA4, "-mfma4")
> +  ISA_NAMES_TABLE_ENTRY("xop", FEATURE_XOP, P_XOP, "-mxop")
> +  ISA_NAMES_TABLE_ENTRY("fma", FEATURE_FMA, P_FMA, "-mfma")
> +  ISA_NAMES_TABLE_ENTRY("avx512f", FEATURE_AVX512F, P_AVX512F,
> +                       "-mavx512f")
> +  ISA_NAMES_TABLE_ENTRY("bmi", FEATURE_BMI, P_BMI, "-mbmi")
> +  ISA_NAMES_TABLE_ENTRY("bmi2", FEATURE_BMI2, P_BMI2, "-mbmi2")
> +  ISA_NAMES_TABLE_ENTRY("aes", FEATURE_AES, P_AES, "-maes")
> +  ISA_NAMES_TABLE_ENTRY("pclmul", FEATURE_PCLMUL, P_PCLMUL, "-mpclmul")
> +  ISA_NAMES_TABLE_ENTRY("avx512vl", FEATURE_AVX512VL, P_NONE,
> +                       "-mavx512vl")
> +  ISA_NAMES_TABLE_ENTRY("avx512bw", FEATURE_AVX512BW, P_NONE,
> +                       "-mavx512bw")
> +  ISA_NAMES_TABLE_ENTRY("avx512dq", FEATURE_AVX512DQ, P_NONE,
> +                       "-mavx512dq")
> +  ISA_NAMES_TABLE_ENTRY("avx512cd", FEATURE_AVX512CD, P_NONE,
> +                       "-mavx512cd")
> +  ISA_NAMES_TABLE_ENTRY("avx512er", FEATURE_AVX512ER, P_NONE,
> +                       "-mavx512er")
> +  ISA_NAMES_TABLE_ENTRY("avx512pf", FEATURE_AVX512PF, P_NONE,
> +                       "-mavx512pf")
> +  ISA_NAMES_TABLE_ENTRY("avx512vbmi", FEATURE_AVX512VBMI, P_NONE,
> +                       "-mavx512vbmi")
> +  ISA_NAMES_TABLE_ENTRY("avx512ifma", FEATURE_AVX512IFMA, P_NONE,
> +                       "-mavx512ifma")
> +  ISA_NAMES_TABLE_ENTRY("avx5124vnniw", FEATURE_AVX5124VNNIW, P_NONE,
> +                       "-mavx5124vnniw")
> +  ISA_NAMES_TABLE_ENTRY("avx5124fmaps", FEATURE_AVX5124FMAPS, P_NONE,
> +                       "-mavx5124fmaps")
> +  ISA_NAMES_TABLE_ENTRY("avx512vpopcntdq", FEATURE_AVX512VPOPCNTDQ,
> +                       P_NONE, "-mavx512vpopcntdq")
> +  ISA_NAMES_TABLE_ENTRY("avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE,
> +                       "-mavx512vbmi2")
> +  ISA_NAMES_TABLE_ENTRY("gfni", FEATURE_GFNI, P_NONE, "-mgfni")
> +  ISA_NAMES_TABLE_ENTRY("vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE,
> +                       "-mvpclmulqdq")
> +  ISA_NAMES_TABLE_ENTRY("avx512vnni", FEATURE_AVX512VNNI, P_NONE,
> +                       "-mavx512vnni")
> +  ISA_NAMES_TABLE_ENTRY("avx512bitalg", FEATURE_AVX512BITALG, P_NONE,
> +                       "-mavx512bitalg")
> +  ISA_NAMES_TABLE_ENTRY("avx512bf16", FEATURE_AVX512BF16, P_NONE,
> +                       "-mavx512bf16")
> +  ISA_NAMES_TABLE_ENTRY("avx512vp2intersect", FEATURE_AVX512VP2INTERSECT,
> +                       P_NONE, "-mavx512vp2intersect")
> +  ISA_NAMES_TABLE_ENTRY("3dnow", FEATURE_3DNOW, P_NONE, "-m3dnow")
> +  ISA_NAMES_TABLE_ENTRY("3dnowp", FEATURE_3DNOWP, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("adx", FEATURE_ADX, P_NONE, "-madx")
> +  ISA_NAMES_TABLE_ENTRY("abm", FEATURE_ABM, P_NONE, "-mabm")
> +  ISA_NAMES_TABLE_ENTRY("cldemote", FEATURE_CLDEMOTE, P_NONE,
> +                       "-mcldemote")
> +  ISA_NAMES_TABLE_ENTRY("clflushopt", FEATURE_CLFLUSHOPT, P_NONE,
> +                       "-mclflushopt")
> +  ISA_NAMES_TABLE_ENTRY("clwb", FEATURE_CLWB, P_NONE, "-mclwb")
> +  ISA_NAMES_TABLE_ENTRY("clzero", FEATURE_CLZERO, P_NONE, "-mclzero")
> +  ISA_NAMES_TABLE_ENTRY("cmpxchg16b", FEATURE_CMPXCHG16B, P_NONE,
> +                       "-mcx16")
> +  ISA_NAMES_TABLE_ENTRY("cmpxchg8b", FEATURE_CMPXCHG8B, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("enqcmd", FEATURE_ENQCMD, P_NONE, "-menqcmd")
> +  ISA_NAMES_TABLE_ENTRY("f16c", FEATURE_F16C, P_NONE, "-mf16c")
> +  ISA_NAMES_TABLE_ENTRY("fsgsbase", FEATURE_FSGSBASE, P_NONE,
> +                       "-mfsgsbase")
> +  ISA_NAMES_TABLE_ENTRY("fxsave", FEATURE_FXSAVE, P_NONE, "-mfxsr")
> +  ISA_NAMES_TABLE_ENTRY("hle", FEATURE_HLE, P_NONE, "-mhle")
> +  ISA_NAMES_TABLE_ENTRY("ibt", FEATURE_IBT, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("lahf_lm", FEATURE_LAHF_LM, P_NONE, "-msahf")
> +  ISA_NAMES_TABLE_ENTRY("lm", FEATURE_LM, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("lwp", FEATURE_LWP, P_NONE, "-mlwp")
> +  ISA_NAMES_TABLE_ENTRY("lzcnt", FEATURE_LZCNT, P_NONE, "-mlzcnt")
> +  ISA_NAMES_TABLE_ENTRY("movbe", FEATURE_MOVBE, P_NONE, "-mmovbe")
> +  ISA_NAMES_TABLE_ENTRY("movdir64b", FEATURE_MOVDIR64B, P_NONE,
> +                       "-mmovdir64b")
> +  ISA_NAMES_TABLE_ENTRY("movdiri", FEATURE_MOVDIRI, P_NONE, "-mmovdiri")
> +  ISA_NAMES_TABLE_ENTRY("mwaitx", FEATURE_MWAITX, P_NONE, "-mmwaitx")
> +  ISA_NAMES_TABLE_ENTRY("osxsave", FEATURE_OSXSAVE, P_NONE, NULL)
> +  ISA_NAMES_TABLE_ENTRY("pconfig", FEATURE_PCONFIG, P_NONE, "-mpconfig")
> +  ISA_NAMES_TABLE_ENTRY("pku", FEATURE_PKU, P_NONE, "-mpku")
> +  ISA_NAMES_TABLE_ENTRY("prefetchwt1", FEATURE_PREFETCHWT1, P_NONE,
> +                       "-mprefetchwt1")
> +  ISA_NAMES_TABLE_ENTRY("prfchw", FEATURE_PRFCHW, P_NONE, "-mprfchw")
> +  ISA_NAMES_TABLE_ENTRY("ptwrite", FEATURE_PTWRITE, P_NONE, "-mptwrite")
> +  ISA_NAMES_TABLE_ENTRY("rdpid", FEATURE_RDPID, P_NONE, "-mrdpid")
> +  ISA_NAMES_TABLE_ENTRY("rdrnd", FEATURE_RDRND, P_NONE, "-mrdrnd")
> +  ISA_NAMES_TABLE_ENTRY("rdseed", FEATURE_RDSEED, P_NONE, "-mrdseed")
> +  ISA_NAMES_TABLE_ENTRY("rtm", FEATURE_RTM, P_NONE, "-mrtm")
> +  ISA_NAMES_TABLE_ENTRY("serialize", FEATURE_SERIALIZE, P_NONE,
> +                       "-mserialize")
> +  ISA_NAMES_TABLE_ENTRY("sgx", FEATURE_SGX, P_NONE, "-msgx")
> +  ISA_NAMES_TABLE_ENTRY("sha", FEATURE_SHA, P_NONE, "-msha")
> +  ISA_NAMES_TABLE_ENTRY("shstk", FEATURE_SHSTK, P_NONE, "-mshstk")
> +  ISA_NAMES_TABLE_ENTRY("tbm", FEATURE_TBM, P_NONE, "-mtbm")
> +  ISA_NAMES_TABLE_ENTRY("tsxldtrk", FEATURE_TSXLDTRK, P_NONE,
> +                       "-mtsxldtrk")
> +  ISA_NAMES_TABLE_ENTRY("vaes", FEATURE_VAES, P_NONE, "-mvaes")
> +  ISA_NAMES_TABLE_ENTRY("waitpkg", FEATURE_WAITPKG, P_NONE, "-mwaitpkg")
> +  ISA_NAMES_TABLE_ENTRY("wbnoinvd", FEATURE_WBNOINVD, P_NONE,
> +                       "-mwbnoinvd")
> +  ISA_NAMES_TABLE_ENTRY("xsave", FEATURE_XSAVE, P_NONE, "-mxsave")
> +  ISA_NAMES_TABLE_ENTRY("xsavec", FEATURE_XSAVEC, P_NONE, "-mxsavec")
> +  ISA_NAMES_TABLE_ENTRY("xsaveopt", FEATURE_XSAVEOPT, P_NONE,
> +                       "-mxsaveopt")
> +  ISA_NAMES_TABLE_ENTRY("xsaves", FEATURE_XSAVES, P_NONE, "-mxsaves")
> +ISA_NAMES_TABLE_END
> diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
> index 3a816400729..e9e4d6ed023 100644
> --- a/gcc/config/i386/driver-i386.c
> +++ b/gcc/config/i386/driver-i386.c
> @@ -28,6 +28,8 @@ 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"
> +#include "common/config/i386/i386-isas.h"
>
>  struct cache_desc
>  {
> @@ -388,53 +390,13 @@ 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;
>
>    unsigned int vendor;
>    unsigned int model, family;
>
> -  unsigned int has_sse3, has_ssse3, has_cmpxchg16b;
> -  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;
> -
>    bool arch;
>
>    unsigned int l2sizekb = 0;
> @@ -447,210 +409,27 @@ 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);
> +  struct __processor_model cpu_model = { };
> +  struct __processor_model2 cpu_model2 = { };
> +  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { };
>
> -  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;
> -    }
> -
> -  /* 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;
> -
> -  /* 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;
> -    }
> +  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
> +    goto done;
>
> -  /* 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;
> -    }
> +  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;
>
>    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 +437,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>         }
>      }
>
> -  if (vendor == signature_AMD_ebx)
> +  /* Extended features */
> +#define has_feature(f) \
> +  has_cpu_feature (&cpu_model, cpu_features2, f)
> +
> +  if (vendor == VENDOR_AMD)
>      {
>        unsigned int name;
>
> @@ -670,34 +453,36 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>
>        if (name == signature_NSC_ebx)
>         processor = PROCESSOR_GEODE;
> -      else if (has_movbe && family == 22)
> +      else if (has_feature (FEATURE_MOVBE) && family == 22)
>         processor = PROCESSOR_BTVER2;
> -      else if (has_clwb)
> +      else if (has_feature (FEATURE_CLWB))
>         processor = PROCESSOR_ZNVER2;
> -      else if (has_clzero)
> +      else if (has_feature (FEATURE_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)
> +      else if (has_feature (FEATURE_AVX2))
> +       processor = PROCESSOR_BDVER4;
> +      else if (has_feature (FEATURE_XSAVEOPT))
> +       processor = PROCESSOR_BDVER3;
> +      else if (has_feature (FEATURE_BMI))
> +       processor = PROCESSOR_BDVER2;
> +      else if (has_feature (FEATURE_XOP))
>         processor = PROCESSOR_BDVER1;
> -      else if (has_sse4a && has_ssse3)
> -        processor = PROCESSOR_BTVER1;
> -      else if (has_sse4a)
> +      else if (has_feature (FEATURE_SSE4_A)
> +              && has_feature (FEATURE_SSSE3))
> +       processor = PROCESSOR_BTVER1;
> +      else if (has_feature (FEATURE_SSE4_A))
>         processor = PROCESSOR_AMDFAM10;
> -      else if (has_sse2 || has_longmode)
> +      else if (has_feature (FEATURE_SSE2)
> +              || has_feature (FEATURE_LM))
>         processor = PROCESSOR_K8;
> -      else if (has_3dnowp && family == 6)
> +      else if (has_feature (FEATURE_3DNOWP) && family == 6)
>         processor = PROCESSOR_ATHLON;
> -      else if (has_mmx)
> +      else if (has_feature (FEATURE_MMX))
>         processor = PROCESSOR_K6;
>        else
>         processor = PROCESSOR_PENTIUM;
>      }
> -  else if (vendor == signature_CENTAUR_ebx)
> +  else if (vendor == VENDOR_CENTAUR)
>      {
>        processor = PROCESSOR_GENERIC;
>
> @@ -708,12 +493,13 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>           break;
>
>         case 5:
> -         if (has_3dnow || has_mmx)
> +         if (has_feature (FEATURE_3DNOW)
> +             || has_feature (FEATURE_MMX))
>             processor = PROCESSOR_I486;
>           break;
>
>         case 6:
> -         if (has_longmode)
> +         if (has_feature (FEATURE_LM))
>             processor = PROCESSOR_K8;
>           else if (model >= 9)
>             processor = PROCESSOR_PENTIUMPRO;
> @@ -749,11 +535,11 @@ 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";
> -         else if (has_3dnow)
> +         else if (has_feature (FEATURE_3DNOW))
>             cpu = "winchip2";
>           else
>             /* Assume WinChip C6.  */
> @@ -763,226 +549,104 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>         cpu = "i486";
>        break;
>      case PROCESSOR_PENTIUM:
> -      if (arch && has_mmx)
> +      if (arch && has_feature (FEATURE_MMX))
>         cpu = "pentium-mmx";
>        else
>         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";
> +             if (has_feature (FEATURE_AVX))
> +               {
> +                 /* Assume Tiger Lake */
> +                 if (has_feature (FEATURE_AVX512VP2INTERSECT))
> +                   cpu = "tigerlake";
> +                 /* Assume Cooper Lake */
> +                 else if (has_feature (FEATURE_AVX512BF16))
> +                   cpu = "cooperlake";
> +                 /* Assume Ice Lake Server.  */
> +                 else if (has_feature (FEATURE_WBNOINVD))
> +                   cpu = "icelake-server";
>                 /* Assume Ice Lake.  */
> -               else if (has_avx512bitalg)
> +               else if (has_feature (FEATURE_AVX512BITALG))
>                   cpu = "icelake-client";
>                 /* Assume Cannon Lake.  */
> -               else if (has_avx512vbmi)
> +               else if (has_feature (FEATURE_AVX512VBMI))
>                   cpu = "cannonlake";
>                 /* Assume Knights Mill.  */
> -               else if (has_avx5124vnniw)
> +               else if (has_feature (FEATURE_AVX5124VNNIW))
>                   cpu = "knm";
>                 /* Assume Knights Landing.  */
> -               else if (has_avx512er)
> +               else if (has_feature (FEATURE_AVX512ER))
>                   cpu = "knl";
>                 /* Assume Skylake with AVX-512.  */
> -               else if (has_avx512f)
> +               else if (has_feature (FEATURE_AVX512F))
>                   cpu = "skylake-avx512";
>                 /* Assume Skylake.  */
> -               else if (has_clflushopt)
> +               else if (has_feature (FEATURE_CLFLUSHOPT))
>                   cpu = "skylake";
>                 /* Assume Broadwell.  */
> -               else if (has_adx)
> +               else if (has_feature (FEATURE_ADX))
>                   cpu = "broadwell";
> -               else if (has_avx2)
> +               else if (has_feature (FEATURE_AVX2))
>                 /* Assume Haswell.  */
>                   cpu = "haswell";
>                 else
>                 /* Assume Sandy Bridge.  */
>                   cpu = "sandybridge";
>               }
> -             else if (has_sse4_2)
> +             else if (has_feature (FEATURE_SSE4_2))
>                 {
> -                 if (has_gfni)
> +                 if (has_feature (FEATURE_GFNI))
>                     /* Assume Tremont.  */
>                     cpu = "tremont";
> -                 else if (has_sgx)
> +                 else if (has_feature (FEATURE_SGX))
>                     /* Assume Goldmont Plus.  */
>                     cpu = "goldmont-plus";
> -                 else if (has_xsave)
> +                 else if (has_feature (FEATURE_XSAVE))
>                     /* Assume Goldmont.  */
>                     cpu = "goldmont";
> -                 else if (has_movbe)
> +                 else if (has_feature (FEATURE_MOVBE))
>                     /* Assume Silvermont.  */
>                     cpu = "silvermont";
>                   else
>                     /* Assume Nehalem.  */
>                     cpu = "nehalem";
>                 }
> -             else if (has_ssse3)
> +             else if (has_feature (FEATURE_SSSE3))
>                 {
> -                 if (has_movbe)
> +                 if (has_feature (FEATURE_MOVBE))
>                     /* Assume Bonnell.  */
>                     cpu = "bonnell";
>                   else
>                     /* Assume Core 2.  */
>                     cpu = "core2";
>                 }
> -             else if (has_longmode)
> +             else if (has_feature (FEATURE_LM))
>                 /* Perhaps some emulator?  Assume x86-64, otherwise gcc
>                    -march=native would be unusable for 64-bit compilations,
>                    as all the CPUs below are 32-bit only.  */
>                 cpu = "x86-64";
> -             else if (has_sse3)
> +             else if (has_feature (FEATURE_SSE3))
>                 {
> -                 if (vendor == signature_CENTAUR_ebx)
> +                 if (vendor == VENDOR_CENTAUR)
>                     /* C7 / Eden "Esther" */
>                     cpu = "c7";
>                   else
>                     /* It is Core Duo.  */
>                     cpu = "pentium-m";
>                 }
> -             else if (has_sse2)
> +             else if (has_feature (FEATURE_SSE2))
>                 /* It is Pentium M.  */
>                 cpu = "pentium-m";
> -             else if (has_sse)
> +             else if (has_feature (FEATURE_SSE))
>                 {
> -                 if (vendor == signature_CENTAUR_ebx)
> +                 if (vendor == VENDOR_CENTAUR)
>                     {
>                       if (model >= 9)
>                         /* Eden "Nehemiah" */
> @@ -994,7 +658,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>                     /* It is Pentium III.  */
>                     cpu = "pentium3";
>                 }
> -             else if (has_mmx)
> +             else if (has_feature (FEATURE_MMX))
>                 /* It is Pentium II.  */
>                 cpu = "pentium2";
>               else
> @@ -1004,13 +668,12 @@ 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:
> -      if (has_sse3)
> +      if (has_feature (FEATURE_SSE3))
>         {
> -         if (has_longmode)
> +         if (has_feature (FEATURE_LM))
>             cpu = "nocona";
>           else
>             cpu = "prescott";
> @@ -1022,13 +685,13 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>        cpu = "geode";
>        break;
>      case PROCESSOR_K6:
> -      if (arch && has_3dnow)
> +      if (arch && has_feature (FEATURE_3DNOW))
>         cpu = "k6-3";
>        else
>         cpu = "k6";
>        break;
>      case PROCESSOR_ATHLON:
> -      if (arch && has_sse)
> +      if (arch && has_feature (FEATURE_SSE))
>         cpu = "athlon-4";
>        else
>         cpu = "athlon";
> @@ -1036,22 +699,22 @@ 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)
> +             if (has_feature (FEATURE_SSE4_1))
>                 /* Nano 3000 | Nano dual / quad core | Eden X4 */
>                 cpu = "nano-3000";
> -             else if (has_ssse3)
> +             else if (has_feature (FEATURE_SSSE3))
>                 /* Nano 1000 | Nano 2000 */
>                 cpu = "nano";
> -             else if (has_sse3)
> +             else if (has_feature (FEATURE_SSE3))
>                 /* Eden X2 */
>                 cpu = "eden-x2";
>               else
>                 /* Default to k8 */
>                 cpu = "k8";
>             }
> -         else if (has_sse3)
> +         else if (has_feature (FEATURE_SSE3))
>             cpu = "k8-sse3";
>           else
>             cpu = "k8";
> @@ -1092,27 +755,27 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>        /* Use something reasonable.  */
>        if (arch)
>         {
> -         if (has_ssse3)
> +         if (has_feature (FEATURE_SSSE3))
>             cpu = "core2";
> -         else if (has_sse3)
> +         else if (has_feature (FEATURE_SSE3))
>             {
> -             if (has_longmode)
> +             if (has_feature (FEATURE_LM))
>                 cpu = "nocona";
>               else
>                 cpu = "prescott";
>             }
> -         else if (has_longmode)
> +         else if (has_feature (FEATURE_LM))
>             /* Perhaps some emulator?  Assume x86-64, otherwise gcc
>                -march=native would be unusable for 64-bit compilations,
>                as all the CPUs below are 32-bit only.  */
>             cpu = "x86-64";
> -         else if (has_sse2)
> +         else if (has_feature (FEATURE_SSE2))
>             cpu = "pentium4";
> -         else if (has_cmov)
> +         else if (has_feature (FEATURE_CMOV))
>             cpu = "pentiumpro";
> -         else if (has_mmx)
> +         else if (has_feature (FEATURE_MMX))
>             cpu = "pentium-mmx";
> -         else if (has_cmpxchg8b)
> +         else if (has_feature (FEATURE_CMPXCHG8B))
>             cpu = "pentium";
>         }
>        else
> @@ -1121,101 +784,18 @@ const char *host_detect_local_cpu (int argc, const char **argv)
>
>    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";
> -      const char *sse2 = has_sse2 ? " -msse2" : " -mno-sse2";
> -      const char *sse3 = has_sse3 ? " -msse3" : " -mno-sse3";
> -      const char *ssse3 = has_ssse3 ? " -mssse3" : " -mno-ssse3";
> -      const char *sse4a = has_sse4a ? " -msse4a" : " -mno-sse4a";
> -      const char *cx16 = has_cmpxchg16b ? " -mcx16" : " -mno-cx16";
> -      const char *sahf = has_lahf_lm ? " -msahf" : " -mno-sahf";
> -      const char *movbe = has_movbe ? " -mmovbe" : " -mno-movbe";
> -      const char *aes = has_aes ? " -maes" : " -mno-aes";
> -      const char *sha = has_sha ? " -msha" : " -mno-sha";
> -      const char *pclmul = has_pclmul ? " -mpclmul" : " -mno-pclmul";
> -      const char *popcnt = has_popcnt ? " -mpopcnt" : " -mno-popcnt";
> -      const char *abm = has_abm ? " -mabm" : " -mno-abm";
> -      const char *lwp = has_lwp ? " -mlwp" : " -mno-lwp";
> -      const char *fma = has_fma ? " -mfma" : " -mno-fma";
> -      const char *fma4 = has_fma4 ? " -mfma4" : " -mno-fma4";
> -      const char *xop = has_xop ? " -mxop" : " -mno-xop";
> -      const char *bmi = has_bmi ? " -mbmi" : " -mno-bmi";
> -      const char *pconfig = has_pconfig ? " -mpconfig" : " -mno-pconfig";
> -      const char *wbnoinvd = has_wbnoinvd ? " -mwbnoinvd" : " -mno-wbnoinvd";
> -      const char *sgx = has_sgx ? " -msgx" : " -mno-sgx";
> -      const char *bmi2 = has_bmi2 ? " -mbmi2" : " -mno-bmi2";
> -      const char *tbm = has_tbm ? " -mtbm" : " -mno-tbm";
> -      const char *avx = has_avx ? " -mavx" : " -mno-avx";
> -      const char *avx2 = has_avx2 ? " -mavx2" : " -mno-avx2";
> -      const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
> -      const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
> -      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mno-lzcnt";
> -      const char *hle = has_hle ? " -mhle" : " -mno-hle";
> -      const char *rtm = has_rtm ? " -mrtm" : " -mno-rtm";
> -      const char *rdrnd = has_rdrnd ? " -mrdrnd" : " -mno-rdrnd";
> -      const char *f16c = has_f16c ? " -mf16c" : " -mno-f16c";
> -      const char *fsgsbase = has_fsgsbase ? " -mfsgsbase" : " -mno-fsgsbase";
> -      const char *rdseed = has_rdseed ? " -mrdseed" : " -mno-rdseed";
> -      const char *prfchw = has_prfchw ? " -mprfchw" : " -mno-prfchw";
> -      const char *adx = has_adx ? " -madx" : " -mno-adx";
> -      const char *fxsr = has_fxsr ? " -mfxsr" : " -mno-fxsr";
> -      const char *xsave = has_xsave ? " -mxsave" : " -mno-xsave";
> -      const char *xsaveopt = has_xsaveopt ? " -mxsaveopt" : " -mno-xsaveopt";
> -      const char *avx512f = has_avx512f ? " -mavx512f" : " -mno-avx512f";
> -      const char *avx512er = has_avx512er ? " -mavx512er" : " -mno-avx512er";
> -      const char *avx512cd = has_avx512cd ? " -mavx512cd" : " -mno-avx512cd";
> -      const char *avx512pf = has_avx512pf ? " -mavx512pf" : " -mno-avx512pf";
> -      const char *prefetchwt1 = has_prefetchwt1 ? " -mprefetchwt1" : " -mno-prefetchwt1";
> -      const char *clflushopt = has_clflushopt ? " -mclflushopt" : " -mno-clflushopt";
> -      const char *xsavec = has_xsavec ? " -mxsavec" : " -mno-xsavec";
> -      const char *xsaves = has_xsaves ? " -mxsaves" : " -mno-xsaves";
> -      const char *avx512dq = has_avx512dq ? " -mavx512dq" : " -mno-avx512dq";
> -      const char *avx512bw = has_avx512bw ? " -mavx512bw" : " -mno-avx512bw";
> -      const char *avx512vl = has_avx512vl ? " -mavx512vl" : " -mno-avx512vl";
> -      const char *avx512ifma = has_avx512ifma ? " -mavx512ifma" : " -mno-avx512ifma";
> -      const char *avx512vbmi = has_avx512vbmi ? " -mavx512vbmi" : " -mno-avx512vbmi";
> -      const char *avx5124vnniw = has_avx5124vnniw ? " -mavx5124vnniw" : " -mno-avx5124vnniw";
> -      const char *avx512vbmi2 = has_avx512vbmi2 ? " -mavx512vbmi2" : " -mno-avx512vbmi2";
> -      const char *avx512vnni = has_avx512vnni ? " -mavx512vnni" : " -mno-avx512vnni";
> -      const char *avx5124fmaps = has_avx5124fmaps ? " -mavx5124fmaps" : " -mno-avx5124fmaps";
> -      const char *clwb = has_clwb ? " -mclwb" : " -mno-clwb";
> -      const char *mwaitx  = has_mwaitx  ? " -mmwaitx"  : " -mno-mwaitx";
> -      const char *clzero  = has_clzero  ? " -mclzero"  : " -mno-clzero";
> -      const char *pku = has_pku ? " -mpku" : " -mno-pku";
> -      const char *rdpid = has_rdpid ? " -mrdpid" : " -mno-rdpid";
> -      const char *gfni = has_gfni ? " -mgfni" : " -mno-gfni";
> -      const char *shstk = has_shstk ? " -mshstk" : " -mno-shstk";
> -      const char *vaes = has_vaes ? " -mvaes" : " -mno-vaes";
> -      const char *vpclmulqdq = has_vpclmulqdq ? " -mvpclmulqdq" : " -mno-vpclmulqdq";
> -      const char *avx512vp2intersect = has_avx512vp2intersect ? " -mavx512vp2intersect" : " -mno-avx512vp2intersect";
> -      const char *tsxldtrk = has_tsxldtrk ? " -mtsxldtrk " : " -mno-tsxldtrk";
> -      const char *avx512bitalg = has_avx512bitalg ? " -mavx512bitalg" : " -mno-avx512bitalg";
> -      const char *avx512vpopcntdq = has_avx512vpopcntdq ? " -mavx512vpopcntdq" : " -mno-avx512vpopcntdq";
> -      const char *movdiri = has_movdiri ? " -mmovdiri" : " -mno-movdiri";
> -      const char *movdir64b = has_movdir64b ? " -mmovdir64b" : " -mno-movdir64b";
> -      const char *enqcmd = has_enqcmd ? " -menqcmd" : " -mno-enqcmd";
> -      const char *waitpkg = has_waitpkg ? " -mwaitpkg" : " -mno-waitpkg";
> -      const char *cldemote = has_cldemote ? " -mcldemote" : " -mno-cldemote";
> -      const char *serialize = has_serialize ? " -mserialize" : " -mno-serialize";
> -      const char *ptwrite = has_ptwrite ? " -mptwrite" : " -mno-ptwrite";
> -      const char *avx512bf16 = has_avx512bf16 ? " -mavx512bf16" : " -mno-avx512bf16";
> -
> -      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);
> +      unsigned int i;
> +      const char *const neg_option = " -mno-";
> +      for (i = 0; i < ARRAY_SIZE (isa_names_table); i++)
> +       if (isa_names_table[i].option)
> +         {
> +           if (has_feature (isa_names_table[i].feature))
> +             options = concat (options, " ",
> +                               isa_names_table[i].option, NULL);
> +           else
> +             options = concat (options, neg_option,
> +                               isa_names_table[i].option + 2, NULL);
> +         }
>      }
>
>  done:
> diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
> index 57e709d6c43..2246507a8d5 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/i386-isas.h"
>
>  #undef BDESC
>  #undef BDESC_FIRST
> @@ -1835,57 +1836,6 @@ ix86_builtin_reciprocal (tree fndecl)
>      }
>  }
>
> -/* These are the target attribute strings for which a dispatcher is
> -   available, from fold_builtin_cpu.  */
> -struct _isa_names_table
> -{
> -  const char *const name;
> -  const enum processor_features feature;
> -  const enum feature_priority priority;
> -};
> -
> -static const _isa_names_table isa_names_table[] =
> -{
> -  {"cmov",    FEATURE_CMOV,    P_NONE},
> -  {"mmx",     FEATURE_MMX,     P_MMX},
> -  {"popcnt",  FEATURE_POPCNT,  P_POPCNT},
> -  {"sse",     FEATURE_SSE,     P_SSE},
> -  {"sse2",    FEATURE_SSE2,    P_SSE2},
> -  {"sse3",    FEATURE_SSE3,    P_SSE3},
> -  {"ssse3",   FEATURE_SSSE3,   P_SSSE3},
> -  {"sse4a",   FEATURE_SSE4_A,  P_SSE4_A},
> -  {"sse4.1",  FEATURE_SSE4_1,  P_SSE4_1},
> -  {"sse4.2",  FEATURE_SSE4_2,  P_SSE4_2},
> -  {"avx",     FEATURE_AVX,     P_AVX},
> -  {"fma4",    FEATURE_FMA4,    P_FMA4},
> -  {"xop",     FEATURE_XOP,     P_XOP},
> -  {"fma",     FEATURE_FMA,     P_FMA},
> -  {"avx2",    FEATURE_AVX2,    P_AVX2},
> -  {"avx512f", FEATURE_AVX512F, P_AVX512F},
> -  {"bmi",     FEATURE_BMI,     P_BMI},
> -  {"bmi2",    FEATURE_BMI2,    P_BMI2},
> -  {"aes",     FEATURE_AES,     P_AES},
> -  {"pclmul",  FEATURE_PCLMUL,  P_PCLMUL},
> -  {"avx512vl",FEATURE_AVX512VL, P_NONE},
> -  {"avx512bw",FEATURE_AVX512BW, P_NONE},
> -  {"avx512dq",FEATURE_AVX512DQ, P_NONE},
> -  {"avx512cd",FEATURE_AVX512CD, P_NONE},
> -  {"avx512er",FEATURE_AVX512ER, P_NONE},
> -  {"avx512pf",FEATURE_AVX512PF, P_NONE},
> -  {"avx512vbmi",FEATURE_AVX512VBMI, P_NONE},
> -  {"avx512ifma",FEATURE_AVX512IFMA, P_NONE},
> -  {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_NONE},
> -  {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_NONE},
> -  {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ,  P_NONE},
> -  {"avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE},
> -  {"gfni",     FEATURE_GFNI,   P_NONE},
> -  {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE},
> -  {"avx512vnni", FEATURE_AVX512VNNI, P_NONE},
> -  {"avx512bitalg", FEATURE_AVX512BITALG, P_NONE},
> -  {"avx512bf16", FEATURE_AVX512BF16, P_NONE},
> -  {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_NONE}
> -};
> -
>  /* This parses the attribute arguments to target in DECL and determines
>     the right builtin to use to match the platform specification.
>     It returns the priority value for this version decl.  If PREDICATE_LIST
> diff --git a/gcc/testsuite/gcc.target/i386/builtin_target.c b/gcc/testsuite/gcc.target/i386/builtin_target.c
> index 7a8b6e805ed..e87f262a775 100644
> --- a/gcc/testsuite/gcc.target/i386/builtin_target.c
> +++ b/gcc/testsuite/gcc.target/i386/builtin_target.c
> @@ -7,348 +7,53 @@
>  /* { 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/i386-cpuinfo.h"
> +#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;
> -
> -  if (edx & bit_CMOV)
> -    assert (__builtin_cpu_supports ("cmov"));
> -  if (edx & bit_MMX)
> -    assert (__builtin_cpu_supports ("mmx"));
> -  if (edx & bit_SSE)
> -    assert (__builtin_cpu_supports ("sse"));
> -  if (edx & bit_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)
> -    assert (__builtin_cpu_supports ("sse3"));
> -  if (ecx & bit_SSSE3)
> -    assert (__builtin_cpu_supports ("ssse3"));
> -  if (ecx & bit_SSE4_1)
> -    assert (__builtin_cpu_supports ("sse4.1"));
> -  if (ecx & bit_SSE4_2)
> -    assert (__builtin_cpu_supports ("sse4.2"));
> -  if (ecx & bit_AVX)
> -    assert (__builtin_cpu_supports ("avx"));
> -  if (ecx & bit_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);
> +#define has_feature(f) \
> +  has_cpu_feature (cpu_model, cpu_features2, f)
> +#define ISA_NAMES_TABLE_START
> +#define ISA_NAMES_TABLE_END
> +#define ISA_NAMES_TABLE_ENTRY(name, feature, priority, option)  \
> +  assert (!!has_feature (feature) == !!__builtin_cpu_supports (name));
> +#include "../../../common/config/i386/i386-isas.h"
>  }
>
>  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;
> -
> -  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
> -  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
> -    return 0;
> +  struct __processor_model cpu_model = { 0 };
> +  struct __processor_model2 cpu_model2 = { 0 };
> +  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { 0 };
>
> -  vendor = ebx;
> -  max_level = eax;
> -
> -  if (max_level < 1)
> -    return 0;
> -
> -  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
> +  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
>      return 0;
>
> -  model = (eax >> 4) & 0x0f;
> -  family = (eax >> 8) & 0x0f;
> -  brand_id = ebx & 0xff;
> -  extended_model = (eax >> 12) & 0xf0;
> -  extended_family = (eax >> 20) & 0xff;
> +  check_features (&cpu_model, cpu_features2);
>
> -  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;
> --
> 2.26.2
>
diff mbox series

Patch

diff --git a/gcc/common/config/i386/i386-isas.h b/gcc/common/config/i386/i386-isas.h
new file mode 100644
index 00000000000..08c9dbecc76
--- /dev/null
+++ b/gcc/common/config/i386/i386-isas.h
@@ -0,0 +1,163 @@ 
+/* i386 ISA table.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* These are the target attribute strings for which a dispatcher is
+   available, from fold_builtin_cpu.  */
+struct _isa_names_table
+{
+  const char *const name;
+  const enum processor_features feature;
+  const enum feature_priority priority;
+  const char *const option;
+};
+
+/* NB: isa_names_table is shared by i386-builtins.c, driver-i386.c and
+   gcc.target/i386/builtin_target.c.  isa_names_table is a static const
+   array in i386-builtins.c and driver-i386.c.  But it is a list of
+   assert statements in gcc.target/i386/builtin_target.c.  */
+
+#ifndef ISA_NAMES_TABLE_START
+# define ISA_NAMES_TABLE_START \
+    static const struct _isa_names_table isa_names_table[] = {
+#endif
+
+#ifndef ISA_NAMES_TABLE_END
+# define ISA_NAMES_TABLE_END };
+#endif
+
+#ifndef ISA_NAMES_TABLE_ENTRY
+# define ISA_NAMES_TABLE_ENTRY(name, feature, priority, option)  \
+    {name, feature, priority, option},
+#endif
+
+ISA_NAMES_TABLE_START
+  ISA_NAMES_TABLE_ENTRY("cmov", FEATURE_CMOV, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("mmx", FEATURE_MMX, P_MMX, "-mmmx")
+  ISA_NAMES_TABLE_ENTRY("popcnt", FEATURE_POPCNT, P_POPCNT, "-mpopcnt")
+  ISA_NAMES_TABLE_ENTRY("sse", FEATURE_SSE, P_SSE, "-msse")
+  ISA_NAMES_TABLE_ENTRY("sse2", FEATURE_SSE2, P_SSE2, "-msse2")
+  ISA_NAMES_TABLE_ENTRY("sse3", FEATURE_SSE3, P_SSE3, "-msse3")
+  ISA_NAMES_TABLE_ENTRY("ssse3", FEATURE_SSSE3, P_SSSE3, "-mssse3")
+  ISA_NAMES_TABLE_ENTRY("sse4.1", FEATURE_SSE4_1, P_SSE4_1, "-msse4.1")
+  ISA_NAMES_TABLE_ENTRY("sse4.2", FEATURE_SSE4_2, P_SSE4_2, "-msse4.2")
+  ISA_NAMES_TABLE_ENTRY("avx", FEATURE_AVX, P_AVX, "-mavx")
+  ISA_NAMES_TABLE_ENTRY("avx2", FEATURE_AVX2, P_AVX2, "-mavx2")
+  ISA_NAMES_TABLE_ENTRY("sse4a", FEATURE_SSE4_A, P_SSE4_A, "-msse4a")
+  ISA_NAMES_TABLE_ENTRY("fma4", FEATURE_FMA4, P_FMA4, "-mfma4")
+  ISA_NAMES_TABLE_ENTRY("xop", FEATURE_XOP, P_XOP, "-mxop")
+  ISA_NAMES_TABLE_ENTRY("fma", FEATURE_FMA, P_FMA, "-mfma")
+  ISA_NAMES_TABLE_ENTRY("avx512f", FEATURE_AVX512F, P_AVX512F,
+			"-mavx512f")
+  ISA_NAMES_TABLE_ENTRY("bmi", FEATURE_BMI, P_BMI, "-mbmi")
+  ISA_NAMES_TABLE_ENTRY("bmi2", FEATURE_BMI2, P_BMI2, "-mbmi2")
+  ISA_NAMES_TABLE_ENTRY("aes", FEATURE_AES, P_AES, "-maes")
+  ISA_NAMES_TABLE_ENTRY("pclmul", FEATURE_PCLMUL, P_PCLMUL, "-mpclmul")
+  ISA_NAMES_TABLE_ENTRY("avx512vl", FEATURE_AVX512VL, P_NONE,
+			"-mavx512vl")
+  ISA_NAMES_TABLE_ENTRY("avx512bw", FEATURE_AVX512BW, P_NONE,
+			"-mavx512bw")
+  ISA_NAMES_TABLE_ENTRY("avx512dq", FEATURE_AVX512DQ, P_NONE,
+			"-mavx512dq")
+  ISA_NAMES_TABLE_ENTRY("avx512cd", FEATURE_AVX512CD, P_NONE,
+			"-mavx512cd")
+  ISA_NAMES_TABLE_ENTRY("avx512er", FEATURE_AVX512ER, P_NONE,
+			"-mavx512er")
+  ISA_NAMES_TABLE_ENTRY("avx512pf", FEATURE_AVX512PF, P_NONE,
+			"-mavx512pf")
+  ISA_NAMES_TABLE_ENTRY("avx512vbmi", FEATURE_AVX512VBMI, P_NONE,
+			"-mavx512vbmi")
+  ISA_NAMES_TABLE_ENTRY("avx512ifma", FEATURE_AVX512IFMA, P_NONE,
+			"-mavx512ifma")
+  ISA_NAMES_TABLE_ENTRY("avx5124vnniw", FEATURE_AVX5124VNNIW, P_NONE,
+			"-mavx5124vnniw")
+  ISA_NAMES_TABLE_ENTRY("avx5124fmaps", FEATURE_AVX5124FMAPS, P_NONE,
+			"-mavx5124fmaps")
+  ISA_NAMES_TABLE_ENTRY("avx512vpopcntdq", FEATURE_AVX512VPOPCNTDQ,
+			P_NONE, "-mavx512vpopcntdq")
+  ISA_NAMES_TABLE_ENTRY("avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE,
+			"-mavx512vbmi2")
+  ISA_NAMES_TABLE_ENTRY("gfni", FEATURE_GFNI, P_NONE, "-mgfni")
+  ISA_NAMES_TABLE_ENTRY("vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE,
+			"-mvpclmulqdq")
+  ISA_NAMES_TABLE_ENTRY("avx512vnni", FEATURE_AVX512VNNI, P_NONE,
+			"-mavx512vnni")
+  ISA_NAMES_TABLE_ENTRY("avx512bitalg", FEATURE_AVX512BITALG, P_NONE,
+			"-mavx512bitalg")
+  ISA_NAMES_TABLE_ENTRY("avx512bf16", FEATURE_AVX512BF16, P_NONE,
+			"-mavx512bf16")
+  ISA_NAMES_TABLE_ENTRY("avx512vp2intersect", FEATURE_AVX512VP2INTERSECT,
+			P_NONE, "-mavx512vp2intersect")
+  ISA_NAMES_TABLE_ENTRY("3dnow", FEATURE_3DNOW, P_NONE, "-m3dnow")
+  ISA_NAMES_TABLE_ENTRY("3dnowp", FEATURE_3DNOWP, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("adx", FEATURE_ADX, P_NONE, "-madx")
+  ISA_NAMES_TABLE_ENTRY("abm", FEATURE_ABM, P_NONE, "-mabm")
+  ISA_NAMES_TABLE_ENTRY("cldemote", FEATURE_CLDEMOTE, P_NONE,
+			"-mcldemote")
+  ISA_NAMES_TABLE_ENTRY("clflushopt", FEATURE_CLFLUSHOPT, P_NONE,
+			"-mclflushopt")
+  ISA_NAMES_TABLE_ENTRY("clwb", FEATURE_CLWB, P_NONE, "-mclwb")
+  ISA_NAMES_TABLE_ENTRY("clzero", FEATURE_CLZERO, P_NONE, "-mclzero")
+  ISA_NAMES_TABLE_ENTRY("cmpxchg16b", FEATURE_CMPXCHG16B, P_NONE,
+			"-mcx16")
+  ISA_NAMES_TABLE_ENTRY("cmpxchg8b", FEATURE_CMPXCHG8B, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("enqcmd", FEATURE_ENQCMD, P_NONE, "-menqcmd")
+  ISA_NAMES_TABLE_ENTRY("f16c", FEATURE_F16C, P_NONE, "-mf16c")
+  ISA_NAMES_TABLE_ENTRY("fsgsbase", FEATURE_FSGSBASE, P_NONE,
+			"-mfsgsbase")
+  ISA_NAMES_TABLE_ENTRY("fxsave", FEATURE_FXSAVE, P_NONE, "-mfxsr")
+  ISA_NAMES_TABLE_ENTRY("hle", FEATURE_HLE, P_NONE, "-mhle")
+  ISA_NAMES_TABLE_ENTRY("ibt", FEATURE_IBT, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("lahf_lm", FEATURE_LAHF_LM, P_NONE, "-msahf")
+  ISA_NAMES_TABLE_ENTRY("lm", FEATURE_LM, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("lwp", FEATURE_LWP, P_NONE, "-mlwp")
+  ISA_NAMES_TABLE_ENTRY("lzcnt", FEATURE_LZCNT, P_NONE, "-mlzcnt")
+  ISA_NAMES_TABLE_ENTRY("movbe", FEATURE_MOVBE, P_NONE, "-mmovbe")
+  ISA_NAMES_TABLE_ENTRY("movdir64b", FEATURE_MOVDIR64B, P_NONE,
+			"-mmovdir64b")
+  ISA_NAMES_TABLE_ENTRY("movdiri", FEATURE_MOVDIRI, P_NONE, "-mmovdiri")
+  ISA_NAMES_TABLE_ENTRY("mwaitx", FEATURE_MWAITX, P_NONE, "-mmwaitx")
+  ISA_NAMES_TABLE_ENTRY("osxsave", FEATURE_OSXSAVE, P_NONE, NULL)
+  ISA_NAMES_TABLE_ENTRY("pconfig", FEATURE_PCONFIG, P_NONE, "-mpconfig")
+  ISA_NAMES_TABLE_ENTRY("pku", FEATURE_PKU, P_NONE, "-mpku")
+  ISA_NAMES_TABLE_ENTRY("prefetchwt1", FEATURE_PREFETCHWT1, P_NONE,
+			"-mprefetchwt1")
+  ISA_NAMES_TABLE_ENTRY("prfchw", FEATURE_PRFCHW, P_NONE, "-mprfchw")
+  ISA_NAMES_TABLE_ENTRY("ptwrite", FEATURE_PTWRITE, P_NONE, "-mptwrite")
+  ISA_NAMES_TABLE_ENTRY("rdpid", FEATURE_RDPID, P_NONE, "-mrdpid")
+  ISA_NAMES_TABLE_ENTRY("rdrnd", FEATURE_RDRND, P_NONE, "-mrdrnd")
+  ISA_NAMES_TABLE_ENTRY("rdseed", FEATURE_RDSEED, P_NONE, "-mrdseed")
+  ISA_NAMES_TABLE_ENTRY("rtm", FEATURE_RTM, P_NONE, "-mrtm")
+  ISA_NAMES_TABLE_ENTRY("serialize", FEATURE_SERIALIZE, P_NONE,
+			"-mserialize")
+  ISA_NAMES_TABLE_ENTRY("sgx", FEATURE_SGX, P_NONE, "-msgx")
+  ISA_NAMES_TABLE_ENTRY("sha", FEATURE_SHA, P_NONE, "-msha")
+  ISA_NAMES_TABLE_ENTRY("shstk", FEATURE_SHSTK, P_NONE, "-mshstk")
+  ISA_NAMES_TABLE_ENTRY("tbm", FEATURE_TBM, P_NONE, "-mtbm")
+  ISA_NAMES_TABLE_ENTRY("tsxldtrk", FEATURE_TSXLDTRK, P_NONE,
+			"-mtsxldtrk")
+  ISA_NAMES_TABLE_ENTRY("vaes", FEATURE_VAES, P_NONE, "-mvaes")
+  ISA_NAMES_TABLE_ENTRY("waitpkg", FEATURE_WAITPKG, P_NONE, "-mwaitpkg")
+  ISA_NAMES_TABLE_ENTRY("wbnoinvd", FEATURE_WBNOINVD, P_NONE,
+			"-mwbnoinvd")
+  ISA_NAMES_TABLE_ENTRY("xsave", FEATURE_XSAVE, P_NONE, "-mxsave")
+  ISA_NAMES_TABLE_ENTRY("xsavec", FEATURE_XSAVEC, P_NONE, "-mxsavec")
+  ISA_NAMES_TABLE_ENTRY("xsaveopt", FEATURE_XSAVEOPT, P_NONE,
+			"-mxsaveopt")
+  ISA_NAMES_TABLE_ENTRY("xsaves", FEATURE_XSAVES, P_NONE, "-mxsaves")
+ISA_NAMES_TABLE_END
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index 3a816400729..e9e4d6ed023 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -28,6 +28,8 @@  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"
+#include "common/config/i386/i386-isas.h"
 
 struct cache_desc
 {
@@ -388,53 +390,13 @@  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;
 
   unsigned int vendor;
   unsigned int model, family;
 
-  unsigned int has_sse3, has_ssse3, has_cmpxchg16b;
-  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;
-
   bool arch;
 
   unsigned int l2sizekb = 0;
@@ -447,210 +409,27 @@  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);
+  struct __processor_model cpu_model = { };
+  struct __processor_model2 cpu_model2 = { };
+  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { };
 
-  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;
-    }
-
-  /* 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;
-
-  /* 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;
-    }
+  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
+    goto done;
 
-  /* 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;
-    }
+  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;
 
   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 +437,11 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	}
     }
 
-  if (vendor == signature_AMD_ebx)
+  /* Extended features */
+#define has_feature(f) \
+  has_cpu_feature (&cpu_model, cpu_features2, f)
+
+  if (vendor == VENDOR_AMD)
     {
       unsigned int name;
 
@@ -670,34 +453,36 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 
       if (name == signature_NSC_ebx)
 	processor = PROCESSOR_GEODE;
-      else if (has_movbe && family == 22)
+      else if (has_feature (FEATURE_MOVBE) && family == 22)
 	processor = PROCESSOR_BTVER2;
-      else if (has_clwb)
+      else if (has_feature (FEATURE_CLWB))
 	processor = PROCESSOR_ZNVER2;
-      else if (has_clzero)
+      else if (has_feature (FEATURE_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)
+      else if (has_feature (FEATURE_AVX2))
+	processor = PROCESSOR_BDVER4;
+      else if (has_feature (FEATURE_XSAVEOPT))
+	processor = PROCESSOR_BDVER3;
+      else if (has_feature (FEATURE_BMI))
+	processor = PROCESSOR_BDVER2;
+      else if (has_feature (FEATURE_XOP))
 	processor = PROCESSOR_BDVER1;
-      else if (has_sse4a && has_ssse3)
-        processor = PROCESSOR_BTVER1;
-      else if (has_sse4a)
+      else if (has_feature (FEATURE_SSE4_A)
+	       && has_feature (FEATURE_SSSE3))
+	processor = PROCESSOR_BTVER1;
+      else if (has_feature (FEATURE_SSE4_A))
 	processor = PROCESSOR_AMDFAM10;
-      else if (has_sse2 || has_longmode)
+      else if (has_feature (FEATURE_SSE2)
+	       || has_feature (FEATURE_LM))
 	processor = PROCESSOR_K8;
-      else if (has_3dnowp && family == 6)
+      else if (has_feature (FEATURE_3DNOWP) && family == 6)
 	processor = PROCESSOR_ATHLON;
-      else if (has_mmx)
+      else if (has_feature (FEATURE_MMX))
 	processor = PROCESSOR_K6;
       else
 	processor = PROCESSOR_PENTIUM;
     }
-  else if (vendor == signature_CENTAUR_ebx)
+  else if (vendor == VENDOR_CENTAUR)
     {
       processor = PROCESSOR_GENERIC;
 
@@ -708,12 +493,13 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	  break;
 
 	case 5:
-	  if (has_3dnow || has_mmx)
+	  if (has_feature (FEATURE_3DNOW)
+	      || has_feature (FEATURE_MMX))
 	    processor = PROCESSOR_I486;
 	  break;
 
 	case 6:
-	  if (has_longmode)
+	  if (has_feature (FEATURE_LM))
 	    processor = PROCESSOR_K8;
 	  else if (model >= 9)
 	    processor = PROCESSOR_PENTIUMPRO;
@@ -749,11 +535,11 @@  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";
-	  else if (has_3dnow)
+	  else if (has_feature (FEATURE_3DNOW))
 	    cpu = "winchip2";
 	  else
 	    /* Assume WinChip C6.  */
@@ -763,226 +549,104 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 	cpu = "i486";
       break;
     case PROCESSOR_PENTIUM:
-      if (arch && has_mmx)
+      if (arch && has_feature (FEATURE_MMX))
 	cpu = "pentium-mmx";
       else
 	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";
+	      if (has_feature (FEATURE_AVX))
+		{
+		  /* Assume Tiger Lake */
+		  if (has_feature (FEATURE_AVX512VP2INTERSECT))
+		    cpu = "tigerlake";
+		  /* Assume Cooper Lake */
+		  else if (has_feature (FEATURE_AVX512BF16))
+		    cpu = "cooperlake";
+		  /* Assume Ice Lake Server.  */
+		  else if (has_feature (FEATURE_WBNOINVD))
+		    cpu = "icelake-server";
 		/* Assume Ice Lake.  */
-		else if (has_avx512bitalg)
+		else if (has_feature (FEATURE_AVX512BITALG))
 		  cpu = "icelake-client";
 		/* Assume Cannon Lake.  */
-		else if (has_avx512vbmi)
+		else if (has_feature (FEATURE_AVX512VBMI))
 		  cpu = "cannonlake";
 		/* Assume Knights Mill.  */
-		else if (has_avx5124vnniw)
+		else if (has_feature (FEATURE_AVX5124VNNIW))
 		  cpu = "knm";
 		/* Assume Knights Landing.  */
-		else if (has_avx512er)
+		else if (has_feature (FEATURE_AVX512ER))
 		  cpu = "knl";
 		/* Assume Skylake with AVX-512.  */
-		else if (has_avx512f)
+		else if (has_feature (FEATURE_AVX512F))
 		  cpu = "skylake-avx512";
 		/* Assume Skylake.  */
-		else if (has_clflushopt)
+		else if (has_feature (FEATURE_CLFLUSHOPT))
 		  cpu = "skylake";
 		/* Assume Broadwell.  */
-		else if (has_adx)
+		else if (has_feature (FEATURE_ADX))
 		  cpu = "broadwell";
-		else if (has_avx2)
+		else if (has_feature (FEATURE_AVX2))
 		/* Assume Haswell.  */
 		  cpu = "haswell";
 		else
 		/* Assume Sandy Bridge.  */
 		  cpu = "sandybridge";	      
 	      }
-	      else if (has_sse4_2)
+	      else if (has_feature (FEATURE_SSE4_2))
 		{
-		  if (has_gfni)
+		  if (has_feature (FEATURE_GFNI))
 		    /* Assume Tremont.  */
 		    cpu = "tremont";
-		  else if (has_sgx)
+		  else if (has_feature (FEATURE_SGX))
 		    /* Assume Goldmont Plus.  */
 		    cpu = "goldmont-plus";
-		  else if (has_xsave)
+		  else if (has_feature (FEATURE_XSAVE))
 		    /* Assume Goldmont.  */
 		    cpu = "goldmont";
-		  else if (has_movbe)
+		  else if (has_feature (FEATURE_MOVBE))
 		    /* Assume Silvermont.  */
 		    cpu = "silvermont";
 		  else
 		    /* Assume Nehalem.  */
 		    cpu = "nehalem";
 		}
-	      else if (has_ssse3)
+	      else if (has_feature (FEATURE_SSSE3))
 		{
-		  if (has_movbe)
+		  if (has_feature (FEATURE_MOVBE))
 		    /* Assume Bonnell.  */
 		    cpu = "bonnell";
 		  else
 		    /* Assume Core 2.  */
 		    cpu = "core2";
 		}
-	      else if (has_longmode)
+	      else if (has_feature (FEATURE_LM))
 		/* Perhaps some emulator?  Assume x86-64, otherwise gcc
 		   -march=native would be unusable for 64-bit compilations,
 		   as all the CPUs below are 32-bit only.  */
 		cpu = "x86-64";
-	      else if (has_sse3)
+	      else if (has_feature (FEATURE_SSE3))
 		{
-		  if (vendor == signature_CENTAUR_ebx)
+		  if (vendor == VENDOR_CENTAUR)
 		    /* C7 / Eden "Esther" */
 		    cpu = "c7";
 		  else
 		    /* It is Core Duo.  */
 		    cpu = "pentium-m";
 		}
-	      else if (has_sse2)
+	      else if (has_feature (FEATURE_SSE2))
 		/* It is Pentium M.  */
 		cpu = "pentium-m";
-	      else if (has_sse)
+	      else if (has_feature (FEATURE_SSE))
 		{
-		  if (vendor == signature_CENTAUR_ebx)
+		  if (vendor == VENDOR_CENTAUR)
 		    {
 		      if (model >= 9)
 			/* Eden "Nehemiah" */
@@ -994,7 +658,7 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 		    /* It is Pentium III.  */
 		    cpu = "pentium3";
 		}
-	      else if (has_mmx)
+	      else if (has_feature (FEATURE_MMX))
 		/* It is Pentium II.  */
 		cpu = "pentium2";
 	      else
@@ -1004,13 +668,12 @@  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:
-      if (has_sse3)
+      if (has_feature (FEATURE_SSE3))
 	{
-	  if (has_longmode)
+	  if (has_feature (FEATURE_LM))
 	    cpu = "nocona";
 	  else
 	    cpu = "prescott";
@@ -1022,13 +685,13 @@  const char *host_detect_local_cpu (int argc, const char **argv)
       cpu = "geode";
       break;
     case PROCESSOR_K6:
-      if (arch && has_3dnow)
+      if (arch && has_feature (FEATURE_3DNOW))
 	cpu = "k6-3";
       else
 	cpu = "k6";
       break;
     case PROCESSOR_ATHLON:
-      if (arch && has_sse)
+      if (arch && has_feature (FEATURE_SSE))
 	cpu = "athlon-4";
       else
 	cpu = "athlon";
@@ -1036,22 +699,22 @@  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)
+	      if (has_feature (FEATURE_SSE4_1))
 		/* Nano 3000 | Nano dual / quad core | Eden X4 */
 		cpu = "nano-3000";
-	      else if (has_ssse3)
+	      else if (has_feature (FEATURE_SSSE3))
 		/* Nano 1000 | Nano 2000 */
 		cpu = "nano";
-	      else if (has_sse3)
+	      else if (has_feature (FEATURE_SSE3))
 		/* Eden X2 */
 		cpu = "eden-x2";
 	      else
 		/* Default to k8 */
 		cpu = "k8";
 	    }
-	  else if (has_sse3)
+	  else if (has_feature (FEATURE_SSE3))
 	    cpu = "k8-sse3";
 	  else
 	    cpu = "k8";
@@ -1092,27 +755,27 @@  const char *host_detect_local_cpu (int argc, const char **argv)
       /* Use something reasonable.  */
       if (arch)
 	{
-	  if (has_ssse3)
+	  if (has_feature (FEATURE_SSSE3))
 	    cpu = "core2";
-	  else if (has_sse3)
+	  else if (has_feature (FEATURE_SSE3))
 	    {
-	      if (has_longmode)
+	      if (has_feature (FEATURE_LM))
 		cpu = "nocona";
 	      else
 		cpu = "prescott";
 	    }
-	  else if (has_longmode)
+	  else if (has_feature (FEATURE_LM))
 	    /* Perhaps some emulator?  Assume x86-64, otherwise gcc
 	       -march=native would be unusable for 64-bit compilations,
 	       as all the CPUs below are 32-bit only.  */
 	    cpu = "x86-64";
-	  else if (has_sse2)
+	  else if (has_feature (FEATURE_SSE2))
 	    cpu = "pentium4";
-	  else if (has_cmov)
+	  else if (has_feature (FEATURE_CMOV))
 	    cpu = "pentiumpro";
-	  else if (has_mmx)
+	  else if (has_feature (FEATURE_MMX))
 	    cpu = "pentium-mmx";
-	  else if (has_cmpxchg8b)
+	  else if (has_feature (FEATURE_CMPXCHG8B))
 	    cpu = "pentium";
 	}
       else
@@ -1121,101 +784,18 @@  const char *host_detect_local_cpu (int argc, const char **argv)
 
   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";
-      const char *sse2 = has_sse2 ? " -msse2" : " -mno-sse2";
-      const char *sse3 = has_sse3 ? " -msse3" : " -mno-sse3";
-      const char *ssse3 = has_ssse3 ? " -mssse3" : " -mno-ssse3";
-      const char *sse4a = has_sse4a ? " -msse4a" : " -mno-sse4a";
-      const char *cx16 = has_cmpxchg16b ? " -mcx16" : " -mno-cx16";
-      const char *sahf = has_lahf_lm ? " -msahf" : " -mno-sahf";
-      const char *movbe = has_movbe ? " -mmovbe" : " -mno-movbe";
-      const char *aes = has_aes ? " -maes" : " -mno-aes";
-      const char *sha = has_sha ? " -msha" : " -mno-sha";
-      const char *pclmul = has_pclmul ? " -mpclmul" : " -mno-pclmul";
-      const char *popcnt = has_popcnt ? " -mpopcnt" : " -mno-popcnt";
-      const char *abm = has_abm ? " -mabm" : " -mno-abm";
-      const char *lwp = has_lwp ? " -mlwp" : " -mno-lwp";
-      const char *fma = has_fma ? " -mfma" : " -mno-fma";
-      const char *fma4 = has_fma4 ? " -mfma4" : " -mno-fma4";
-      const char *xop = has_xop ? " -mxop" : " -mno-xop";
-      const char *bmi = has_bmi ? " -mbmi" : " -mno-bmi";
-      const char *pconfig = has_pconfig ? " -mpconfig" : " -mno-pconfig";
-      const char *wbnoinvd = has_wbnoinvd ? " -mwbnoinvd" : " -mno-wbnoinvd";
-      const char *sgx = has_sgx ? " -msgx" : " -mno-sgx";
-      const char *bmi2 = has_bmi2 ? " -mbmi2" : " -mno-bmi2";
-      const char *tbm = has_tbm ? " -mtbm" : " -mno-tbm";
-      const char *avx = has_avx ? " -mavx" : " -mno-avx";
-      const char *avx2 = has_avx2 ? " -mavx2" : " -mno-avx2";
-      const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
-      const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
-      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mno-lzcnt";
-      const char *hle = has_hle ? " -mhle" : " -mno-hle";
-      const char *rtm = has_rtm ? " -mrtm" : " -mno-rtm";
-      const char *rdrnd = has_rdrnd ? " -mrdrnd" : " -mno-rdrnd";
-      const char *f16c = has_f16c ? " -mf16c" : " -mno-f16c";
-      const char *fsgsbase = has_fsgsbase ? " -mfsgsbase" : " -mno-fsgsbase";
-      const char *rdseed = has_rdseed ? " -mrdseed" : " -mno-rdseed";
-      const char *prfchw = has_prfchw ? " -mprfchw" : " -mno-prfchw";
-      const char *adx = has_adx ? " -madx" : " -mno-adx";
-      const char *fxsr = has_fxsr ? " -mfxsr" : " -mno-fxsr";
-      const char *xsave = has_xsave ? " -mxsave" : " -mno-xsave";
-      const char *xsaveopt = has_xsaveopt ? " -mxsaveopt" : " -mno-xsaveopt";
-      const char *avx512f = has_avx512f ? " -mavx512f" : " -mno-avx512f";
-      const char *avx512er = has_avx512er ? " -mavx512er" : " -mno-avx512er";
-      const char *avx512cd = has_avx512cd ? " -mavx512cd" : " -mno-avx512cd";
-      const char *avx512pf = has_avx512pf ? " -mavx512pf" : " -mno-avx512pf";
-      const char *prefetchwt1 = has_prefetchwt1 ? " -mprefetchwt1" : " -mno-prefetchwt1";
-      const char *clflushopt = has_clflushopt ? " -mclflushopt" : " -mno-clflushopt";
-      const char *xsavec = has_xsavec ? " -mxsavec" : " -mno-xsavec";
-      const char *xsaves = has_xsaves ? " -mxsaves" : " -mno-xsaves";
-      const char *avx512dq = has_avx512dq ? " -mavx512dq" : " -mno-avx512dq";
-      const char *avx512bw = has_avx512bw ? " -mavx512bw" : " -mno-avx512bw";
-      const char *avx512vl = has_avx512vl ? " -mavx512vl" : " -mno-avx512vl";
-      const char *avx512ifma = has_avx512ifma ? " -mavx512ifma" : " -mno-avx512ifma";
-      const char *avx512vbmi = has_avx512vbmi ? " -mavx512vbmi" : " -mno-avx512vbmi";
-      const char *avx5124vnniw = has_avx5124vnniw ? " -mavx5124vnniw" : " -mno-avx5124vnniw";
-      const char *avx512vbmi2 = has_avx512vbmi2 ? " -mavx512vbmi2" : " -mno-avx512vbmi2";
-      const char *avx512vnni = has_avx512vnni ? " -mavx512vnni" : " -mno-avx512vnni";
-      const char *avx5124fmaps = has_avx5124fmaps ? " -mavx5124fmaps" : " -mno-avx5124fmaps";
-      const char *clwb = has_clwb ? " -mclwb" : " -mno-clwb";
-      const char *mwaitx  = has_mwaitx  ? " -mmwaitx"  : " -mno-mwaitx"; 
-      const char *clzero  = has_clzero  ? " -mclzero"  : " -mno-clzero";
-      const char *pku = has_pku ? " -mpku" : " -mno-pku";
-      const char *rdpid = has_rdpid ? " -mrdpid" : " -mno-rdpid";
-      const char *gfni = has_gfni ? " -mgfni" : " -mno-gfni";
-      const char *shstk = has_shstk ? " -mshstk" : " -mno-shstk";
-      const char *vaes = has_vaes ? " -mvaes" : " -mno-vaes";
-      const char *vpclmulqdq = has_vpclmulqdq ? " -mvpclmulqdq" : " -mno-vpclmulqdq";
-      const char *avx512vp2intersect = has_avx512vp2intersect ? " -mavx512vp2intersect" : " -mno-avx512vp2intersect";
-      const char *tsxldtrk = has_tsxldtrk ? " -mtsxldtrk " : " -mno-tsxldtrk";
-      const char *avx512bitalg = has_avx512bitalg ? " -mavx512bitalg" : " -mno-avx512bitalg";
-      const char *avx512vpopcntdq = has_avx512vpopcntdq ? " -mavx512vpopcntdq" : " -mno-avx512vpopcntdq";
-      const char *movdiri = has_movdiri ? " -mmovdiri" : " -mno-movdiri";
-      const char *movdir64b = has_movdir64b ? " -mmovdir64b" : " -mno-movdir64b";
-      const char *enqcmd = has_enqcmd ? " -menqcmd" : " -mno-enqcmd";
-      const char *waitpkg = has_waitpkg ? " -mwaitpkg" : " -mno-waitpkg";
-      const char *cldemote = has_cldemote ? " -mcldemote" : " -mno-cldemote";
-      const char *serialize = has_serialize ? " -mserialize" : " -mno-serialize";
-      const char *ptwrite = has_ptwrite ? " -mptwrite" : " -mno-ptwrite";
-      const char *avx512bf16 = has_avx512bf16 ? " -mavx512bf16" : " -mno-avx512bf16";
-
-      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);
+      unsigned int i;
+      const char *const neg_option = " -mno-";
+      for (i = 0; i < ARRAY_SIZE (isa_names_table); i++)
+	if (isa_names_table[i].option)
+	  {
+	    if (has_feature (isa_names_table[i].feature))
+	      options = concat (options, " ",
+				isa_names_table[i].option, NULL);
+	    else
+	      options = concat (options, neg_option,
+				isa_names_table[i].option + 2, NULL);
+	  }
     }
 
 done:
diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
index 57e709d6c43..2246507a8d5 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/i386-isas.h"
 
 #undef BDESC
 #undef BDESC_FIRST
@@ -1835,57 +1836,6 @@  ix86_builtin_reciprocal (tree fndecl)
     }
 }
 
-/* These are the target attribute strings for which a dispatcher is
-   available, from fold_builtin_cpu.  */
-struct _isa_names_table
-{
-  const char *const name;
-  const enum processor_features feature;
-  const enum feature_priority priority;
-};
-
-static const _isa_names_table isa_names_table[] =
-{
-  {"cmov",    FEATURE_CMOV,	P_NONE},
-  {"mmx",     FEATURE_MMX,	P_MMX},
-  {"popcnt",  FEATURE_POPCNT,	P_POPCNT},
-  {"sse",     FEATURE_SSE,	P_SSE},
-  {"sse2",    FEATURE_SSE2,	P_SSE2},
-  {"sse3",    FEATURE_SSE3,	P_SSE3},
-  {"ssse3",   FEATURE_SSSE3,	P_SSSE3},
-  {"sse4a",   FEATURE_SSE4_A,	P_SSE4_A},
-  {"sse4.1",  FEATURE_SSE4_1,	P_SSE4_1},
-  {"sse4.2",  FEATURE_SSE4_2,	P_SSE4_2},
-  {"avx",     FEATURE_AVX,	P_AVX},
-  {"fma4",    FEATURE_FMA4,	P_FMA4},
-  {"xop",     FEATURE_XOP,	P_XOP},
-  {"fma",     FEATURE_FMA,	P_FMA},
-  {"avx2",    FEATURE_AVX2,	P_AVX2},
-  {"avx512f", FEATURE_AVX512F, P_AVX512F},
-  {"bmi",     FEATURE_BMI,	P_BMI},
-  {"bmi2",    FEATURE_BMI2,	P_BMI2},
-  {"aes",     FEATURE_AES,	P_AES},
-  {"pclmul",  FEATURE_PCLMUL,	P_PCLMUL},
-  {"avx512vl",FEATURE_AVX512VL, P_NONE},
-  {"avx512bw",FEATURE_AVX512BW, P_NONE},
-  {"avx512dq",FEATURE_AVX512DQ, P_NONE},
-  {"avx512cd",FEATURE_AVX512CD, P_NONE},
-  {"avx512er",FEATURE_AVX512ER, P_NONE},
-  {"avx512pf",FEATURE_AVX512PF, P_NONE},
-  {"avx512vbmi",FEATURE_AVX512VBMI, P_NONE},
-  {"avx512ifma",FEATURE_AVX512IFMA, P_NONE},
-  {"avx5124vnniw",FEATURE_AVX5124VNNIW, P_NONE},
-  {"avx5124fmaps",FEATURE_AVX5124FMAPS, P_NONE},
-  {"avx512vpopcntdq",FEATURE_AVX512VPOPCNTDQ,	P_NONE},
-  {"avx512vbmi2", FEATURE_AVX512VBMI2, P_NONE},
-  {"gfni",	FEATURE_GFNI,	P_NONE},
-  {"vpclmulqdq", FEATURE_VPCLMULQDQ, P_NONE},
-  {"avx512vnni", FEATURE_AVX512VNNI, P_NONE},
-  {"avx512bitalg", FEATURE_AVX512BITALG, P_NONE},
-  {"avx512bf16", FEATURE_AVX512BF16, P_NONE},
-  {"avx512vp2intersect",FEATURE_AVX512VP2INTERSECT, P_NONE}
-};
-
 /* This parses the attribute arguments to target in DECL and determines
    the right builtin to use to match the platform specification.
    It returns the priority value for this version decl.  If PREDICATE_LIST
diff --git a/gcc/testsuite/gcc.target/i386/builtin_target.c b/gcc/testsuite/gcc.target/i386/builtin_target.c
index 7a8b6e805ed..e87f262a775 100644
--- a/gcc/testsuite/gcc.target/i386/builtin_target.c
+++ b/gcc/testsuite/gcc.target/i386/builtin_target.c
@@ -7,348 +7,53 @@ 
 /* { 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/i386-cpuinfo.h"
+#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;
-
-  if (edx & bit_CMOV)
-    assert (__builtin_cpu_supports ("cmov"));
-  if (edx & bit_MMX)
-    assert (__builtin_cpu_supports ("mmx"));
-  if (edx & bit_SSE)
-    assert (__builtin_cpu_supports ("sse"));
-  if (edx & bit_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)
-    assert (__builtin_cpu_supports ("sse3"));
-  if (ecx & bit_SSSE3)
-    assert (__builtin_cpu_supports ("ssse3"));
-  if (ecx & bit_SSE4_1)
-    assert (__builtin_cpu_supports ("sse4.1"));
-  if (ecx & bit_SSE4_2)
-    assert (__builtin_cpu_supports ("sse4.2"));
-  if (ecx & bit_AVX)
-    assert (__builtin_cpu_supports ("avx"));
-  if (ecx & bit_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);
+#define has_feature(f) \
+  has_cpu_feature (cpu_model, cpu_features2, f)
+#define ISA_NAMES_TABLE_START
+#define ISA_NAMES_TABLE_END
+#define ISA_NAMES_TABLE_ENTRY(name, feature, priority, option)  \
+  assert (!!has_feature (feature) == !!__builtin_cpu_supports (name));
+#include "../../../common/config/i386/i386-isas.h"
 }
 
 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;
-
-  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
-  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
-    return 0;
+  struct __processor_model cpu_model = { 0 };
+  struct __processor_model2 cpu_model2 = { 0 };
+  unsigned int cpu_features2[SIZE_OF_CPU_FEATURES] = { 0 };
 
-  vendor = ebx;
-  max_level = eax;
-
-  if (max_level < 1)
-    return 0;
-
-  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
+  if (cpu_indicator_init (&cpu_model, &cpu_model2, cpu_features2) != 0)
     return 0;
 
-  model = (eax >> 4) & 0x0f;
-  family = (eax >> 8) & 0x0f;
-  brand_id = ebx & 0xff;
-  extended_model = (eax >> 12) & 0xf0;
-  extended_family = (eax >> 20) & 0xff;
+  check_features (&cpu_model, cpu_features2);
 
-  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;