Sorry for the slow review.
Andrew Carlotti <[email protected]> writes:
> These new flags (+fcma, +jscvt, +rcpc2, +jscvt, +frintts, +wfxt and +xs)
> were only recently added to the assembler. To improve compatibility
> with older assemblers, we try to avoid passing these new flags to the
> assembler if we can express the targetted architecture without them. We
> do so by using an almost-equivalent architecture string with a higher
> architecture version.
>
> This should never reduce the set of instructions accepted by the
> assembler. It will make it more lenient in two cases:
>
> 1. Many system registers are currently gated behind architecture
> versions instead of specific feature flags. Increasing the base
> architecture version may cause more system register accesses to be
> accepted.
>
> 2. FEAT_XS doesn't have an HWCAP bit or cpuinfo entry. We still want to
> avoid passing +wfxt or +noxs to the assembler if possible, so we'll
> instruct the assembler to accept FEAT_XS instructions as well whenever
> the rest of the new features are enabled.
>
> gcc/ChangeLog:
>
> * common/config/aarch64/aarch64-common.cc
> (aarch64_get_arch_string_for_assembler): New.
> (aarch64_rewrite_march): New.
> (aarch64_rewrite_selected_cpu): Call new function.
> * config/aarch64/aarch64-elf.h (ASM_SPEC): Remove identity mapping.
> * config/aarch64/aarch64-protos.h
> (aarch64_get_arch_string_for_assembler): New.
> * config/aarch64/aarch64.cc
> (aarch64_declare_function_name): Call new function.
> (aarch64_start_file): Ditto.
> * config/aarch64/aarch64.h
> * config/aarch64/aarch64.h
> (EXTRA_SPEC_FUNCTIONS): Use new macro name.
> (MCPU_TO_MARCH_SPEC): Rename to...
> (MARCH_REWRITE_SPEC): ...this, and add new spec rule.
> (aarch64_rewrite_march): New declaration.
> (MCPU_TO_MARCH_SPEC_FUNCTIONS): Rename to...
> (MARCH_REWRITE_SPEC_FUNCTIONS): ...this, and add new function.
> (ASM_CPU_SPEC): Use new macro name.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/cpunative/native_cpu_21.c: Update check.
> * gcc.target/aarch64/cpunative/native_cpu_22.c: Update check.
> * gcc.target/aarch64/cpunative/info_27: New test.
> * gcc.target/aarch64/cpunative/info_28: New test.
> * gcc.target/aarch64/cpunative/info_29: New test.
> * gcc.target/aarch64/cpunative/native_cpu_27.c: New test.
> * gcc.target/aarch64/cpunative/native_cpu_28.c: New test.
> * gcc.target/aarch64/cpunative/native_cpu_29.c: New test.
>
>
> diff --git a/gcc/common/config/aarch64/aarch64-common.cc
> b/gcc/common/config/aarch64/aarch64-common.cc
> index
> 2bfc597e333b6018970a9ee6e370a66b6d0960ef..717b3238be16f39a6fd1b4143662eb540ccf292d
> 100644
> --- a/gcc/common/config/aarch64/aarch64-common.cc
> +++ b/gcc/common/config/aarch64/aarch64-common.cc
> @@ -371,6 +371,119 @@ aarch64_get_extension_string_for_isa_flags
> return outstr;
> }
>
> +/* Generate an arch string to be passed to the assembler.
> +
> + Several flags were added retrospectively for features that were previously
> + enabled only by specifying an architecture version. We want to avoid
> + passing these flags to the assembler if possible, to improve compatibility
> + with older assemblers. */
> +
> +std::string
> +aarch64_get_arch_string_for_assembler (aarch64_arch arch,
> + aarch64_feature_flags flags)
> +{
> + if (!(flags & AARCH64_FL_FCMA) || !(flags & AARCH64_FL_JSCVT))
> + goto done;
> +
> + if (arch == AARCH64_ARCH_V8A
> + || arch == AARCH64_ARCH_V8_1A
> + || arch == AARCH64_ARCH_V8_2A)
> + arch = AARCH64_ARCH_V8_3A;
> +
> + if (!(flags & AARCH64_FL_RCPC2))
> + goto done;
> +
> + if (arch == AARCH64_ARCH_V8_3A)
> + arch = AARCH64_ARCH_V8_4A;
> +
> + if (!(flags & AARCH64_FL_FRINTTS) || !(flags & AARCH64_FL_FLAGM2))
> + goto done;
> +
> + if (arch == AARCH64_ARCH_V8_4A)
> + arch = AARCH64_ARCH_V8_5A;
> +
> + if (!(flags & AARCH64_FL_WFXT))
> + goto done;
> +
> + if (arch == AARCH64_ARCH_V8_5A || arch == AARCH64_ARCH_V8_6A)
> + {
> + arch = AARCH64_ARCH_V8_7A;
> + /* We don't support native detection for FEAT_XS, so we'll assume it's
> + present if the rest of these features are also present. If we don't
> + do this, then we would end up passing +noxs to the assembler. */
> + flags |= AARCH64_FL_XS;
> + }
> +done:
> +
> + const struct arch_to_arch_name* a_to_an;
> + for (a_to_an = all_architectures;
> + a_to_an->arch != aarch64_no_arch;
> + a_to_an++)
> + {
> + if (a_to_an->arch == arch)
> + break;
> + }
> +
> + std::string outstr = a_to_an->arch_name
> + + aarch64_get_extension_string_for_isa_flags (flags, a_to_an->flags);
> +
> + return outstr;
> +}
I was hoping we could do this in a table-driven way. Experimenting
a bit locally (but only lightly tested), the following seems to work:
aarch64.h:
/* The set of all architecture flags. */
constexpr auto AARCH64_FL_ARCHES ATTRIBUTE_UNUSED = aarch64_feature_flags (0)
#define AARCH64_ARCH(A, B, ARCH_IDENT, D, E) \
| feature_deps::ARCH_IDENT ().flag
#include "config/aarch64/aarch64-arches.def"
;
aarch64-common.cc:
...
const struct arch_to_arch_name *best = nullptr;
for (auto *a_to_an = all_architectures;
a_to_an->arch != aarch64_no_arch;
a_to_an++)
{
/* Require the architecture to have all architecture flags in FLAGS. */
if ((~a_to_an->flags & flags & AARCH64_FL_ARCHES) != 0)
continue;
/* Skip architectures that add no new mandatory features. */
if (best && (a_to_an->flags & ~best->flags & ~AARCH64_FL_ARCHES) == 0)
continue;
/* Require FLAGS to include all mandatory extensions. */
if ((a_to_an->flags & ~flags & ~AARCH64_FL_ARCHES) != 0)
continue;
best = a_to_an;
}
> +
> +/* Called by the driver to rewrite a name passed to the -march
> + argument in preparation to be passed to the assembler. The
> + names passed from the commend line will be in ARGV, we want
> + to use the right-most argument, which should be in
> + ARGV[ARGC - 1]. ARGC should always be greater than 0. */
> +
> +const char *
> +aarch64_rewrite_march (int argc, const char **argv)
> +{
> + gcc_assert (argc);
> + const char *name = argv[argc - 1];
> + std::string original_string (name);
> + std::string extension_str;
> + std::string base_name;
> + size_t extension_pos = original_string.find_first_of ('+');
> +
> + /* Strip and save the extension string. */
> + if (extension_pos != std::string::npos)
> + {
> + base_name = original_string.substr (0, extension_pos);
> + extension_str = original_string.substr (extension_pos,
> + std::string::npos);
> + }
> + else
> + {
> + /* No extensions. */
> + base_name = original_string;
> + }
> +
> + const struct arch_to_arch_name* a_to_an;
> + for (a_to_an = all_architectures;
> + a_to_an->arch != aarch64_no_arch;
> + a_to_an++)
> + {
> + if (a_to_an->arch_name == base_name)
> + break;
> + }
> +
> + /* We couldn't find that architecture name. */
> + if (a_to_an->arch == aarch64_no_arch)
> + fatal_error (input_location, "unknown value %qs for %<-march%>", name);
> +
> + aarch64_feature_flags flags = a_to_an->flags;
> + aarch64_parse_extension (extension_str.c_str (), &flags, NULL);
> +
> + std::string outstr = aarch64_get_arch_string_for_assembler (a_to_an->arch,
> + flags);
> +
> + /* We are going to memory leak here, nobody elsewhere
> + in the callchain is going to clean up after us. The alternative is
> + to allocate a static buffer, and assert that it is big enough for our
> + modified string, which seems much worse! */
> + return xstrdup (outstr.c_str ());
> +}
This is going to seem like feature creep, sorry, but: rather than
duplicate the architecture parsing, could we instead move the march
and mcpu processing from aarch64.cc to here? Specifically:
- aarch64_parse_arch
- aarch64_parse_cpu
- aarch64_validate_mcpu
- aarch64_validate_march
- aarch64_print_hint_for_*
This would mean making "struct processor" public, and so giving it
an aarch64_ name (or putting it in a namespace). We'd also need to
remove the tuning information and use a separate table for that.
Still, I think it would be more robust than having two pieces of code
doing the same parsing. It should also give a better UI, since the
driver parsing would give the same hints as the compiler proper.
(Only tested to the point of moving the code and linking the driver.)
Thanks,
Richard
> /* Attempt to rewrite NAME, which has been passed on the command line
> as a -mcpu option to an equivalent -march value. If we can do so,
> return the new string, otherwise return an error. */
> @@ -414,7 +527,7 @@ aarch64_rewrite_selected_cpu (const char *name)
> break;
> }
>
> - /* We couldn't find that proceesor name, or the processor name we
> + /* We couldn't find that processor name, or the processor name we
> found does not map to an architecture we understand. */
> if (p_to_a->arch == aarch64_no_arch
> || a_to_an->arch == aarch64_no_arch)
> @@ -423,9 +536,8 @@ aarch64_rewrite_selected_cpu (const char *name)
> aarch64_feature_flags extensions = p_to_a->flags;
> aarch64_parse_extension (extension_str.c_str (), &extensions, NULL);
>
> - std::string outstr = a_to_an->arch_name
> - + aarch64_get_extension_string_for_isa_flags (extensions,
> - a_to_an->flags);
> + std::string outstr = aarch64_get_arch_string_for_assembler (a_to_an->arch,
> + extensions);
>
> /* We are going to memory leak here, nobody elsewhere
> in the callchain is going to clean up after us. The alternative is
> diff --git a/gcc/config/aarch64/aarch64-elf.h
> b/gcc/config/aarch64/aarch64-elf.h
> index
> b6fb7936789fed7fc07d61c6e10301f0c451ac5c..1e210ce3b8beacb0ded7b482694df10368b9a50b
> 100644
> --- a/gcc/config/aarch64/aarch64-elf.h
> +++ b/gcc/config/aarch64/aarch64-elf.h
> @@ -136,7 +136,6 @@
> #define ASM_SPEC "\
> %{mbig-endian:-EB} \
> %{mlittle-endian:-EL} \
> -%{march=*:-march=%*} \
> %(asm_cpu_spec)" \
> ASM_MABI_SPEC
> #endif
> diff --git a/gcc/config/aarch64/aarch64-protos.h
> b/gcc/config/aarch64/aarch64-protos.h
> index
> 6ab41a21c75dbdb6bba7875408bc1aa6959c9033..6cf09b41e88cb4d029e4d38f722a4247b9f84328
> 100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -1165,6 +1165,8 @@ enum aarch_parse_opt_result aarch64_parse_extension
> (const char *,
> void aarch64_get_all_extension_candidates (auto_vec<const char *>
> *candidates);
> std::string aarch64_get_extension_string_for_isa_flags
> (aarch64_feature_flags,
> aarch64_feature_flags);
> +std::string aarch64_get_arch_string_for_assembler (aarch64_arch,
> + aarch64_feature_flags);
>
> rtl_opt_pass *make_pass_aarch64_early_ra (gcc::context *);
> rtl_opt_pass *make_pass_fma_steering (gcc::context *);
> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
> index
> e50bd43f3908916903fe724ec39ae137bc68dfad..9287329a76392034725080ae79060dcd16cfd753
> 100644
> --- a/gcc/config/aarch64/aarch64.h
> +++ b/gcc/config/aarch64/aarch64.h
> @@ -1417,7 +1417,7 @@ extern const char *host_detect_local_cpu (int argc,
> const char **argv);
> #define HAVE_LOCAL_CPU_DETECT
> # define EXTRA_SPEC_FUNCTIONS \
> { "local_cpu_detect", host_detect_local_cpu }, \
> - MCPU_TO_MARCH_SPEC_FUNCTIONS
> + MARCH_REWRITE_SPEC_FUNCTIONS
>
> /* Rewrite -m{arch,cpu,tune}=native based on the host system information.
> When rewriting -march=native convert it into an -mcpu option if no other
> @@ -1434,7 +1434,7 @@ extern const char *host_detect_local_cpu (int argc,
> const char **argv);
> { "tune", "%{!mcpu=*:%{!mtune=*:%{!march=native:-mtune=%(VALUE)}}}" },
> #else
> # define MCPU_MTUNE_NATIVE_SPECS ""
> -# define EXTRA_SPEC_FUNCTIONS MCPU_TO_MARCH_SPEC_FUNCTIONS
> +# define EXTRA_SPEC_FUNCTIONS MARCH_REWRITE_SPEC_FUNCTIONS
> # define CONFIG_TUNE_SPEC \
> {"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}"},
> #endif
> @@ -1449,15 +1449,18 @@ extern const char *host_detect_local_cpu (int argc,
> const char **argv);
> {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
> CONFIG_TUNE_SPEC
>
> -#define MCPU_TO_MARCH_SPEC \
> - " %{mcpu=*:-march=%:rewrite_mcpu(%{mcpu=*:%*})}"
> +#define MARCH_REWRITE_SPEC \
> + " %{mcpu=*:-march=%:rewrite_mcpu(%{mcpu=*:%*})}" \
> + " %{march=*:-march=%:rewrite_march(%{march=*:%*})}"
>
> extern const char *aarch64_rewrite_mcpu (int argc, const char **argv);
> -#define MCPU_TO_MARCH_SPEC_FUNCTIONS \
> - { "rewrite_mcpu", aarch64_rewrite_mcpu },
> +extern const char *aarch64_rewrite_march (int argc, const char **argv);
> +#define MARCH_REWRITE_SPEC_FUNCTIONS \
> + { "rewrite_mcpu", aarch64_rewrite_mcpu }, \
> + { "rewrite_march", aarch64_rewrite_march },
>
> #define ASM_CPU_SPEC \
> - MCPU_TO_MARCH_SPEC
> + MARCH_REWRITE_SPEC
>
> #define EXTRA_SPECS \
> { "asm_cpu_spec", ASM_CPU_SPEC }
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index
> 81885d442ed3e7008aacc937c1a9305b7824bc7c..f32b90c188228fe980e247b4448ee3c1f3e7ddfc
> 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -24846,16 +24846,12 @@ aarch64_declare_function_name (FILE *stream, const
> char* name,
> targ_options = TREE_TARGET_OPTION (target_option_current_node);
> gcc_assert (targ_options);
>
> - const struct processor *this_arch
> - = aarch64_get_arch (targ_options->x_selected_arch);
> -
> auto isa_flags = aarch64_get_asm_isa_flags (targ_options);
> - std::string extension
> - = aarch64_get_extension_string_for_isa_flags (isa_flags,
> - this_arch->flags);
> + aarch64_arch arch = targ_options->x_selected_arch;
> + std::string to_print
> + = aarch64_get_arch_string_for_assembler (arch, isa_flags);
> /* Only update the assembler .arch string if it is distinct from the last
> such string we printed. */
> - std::string to_print = this_arch->name + extension;
> if (to_print != aarch64_last_printed_arch_string)
> {
> asm_fprintf (asm_out_file, "\t.arch %s\n", to_print.c_str ());
> @@ -24977,19 +24973,16 @@ aarch64_start_file (void)
> struct cl_target_option *default_options
> = TREE_TARGET_OPTION (target_option_default_node);
>
> - const struct processor *default_arch
> - = aarch64_get_arch (default_options->x_selected_arch);
> + aarch64_arch default_arch = default_options->x_selected_arch;
> auto default_isa_flags = aarch64_get_asm_isa_flags (default_options);
> - std::string extension
> - = aarch64_get_extension_string_for_isa_flags (default_isa_flags,
> - default_arch->flags);
> -
> - aarch64_last_printed_arch_string = default_arch->name + extension;
> - aarch64_last_printed_tune_string = "";
> - asm_fprintf (asm_out_file, "\t.arch %s\n",
> - aarch64_last_printed_arch_string.c_str ());
> -
> - default_file_start ();
> + std::string arch_string
> + = aarch64_get_arch_string_for_assembler (default_arch,
> default_isa_flags);
> + aarch64_last_printed_arch_string = arch_string;
> + aarch64_last_printed_tune_string = "";
> + asm_fprintf (asm_out_file, "\t.arch %s\n",
> + arch_string.c_str ());
> +
> + default_file_start ();
> }
>
> /* Emit load exclusive. */
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/info_27
> b/gcc/testsuite/gcc.target/aarch64/cpunative/info_27
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..1ca9354579f0b7fdd77e31857d744476529cd301
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/info_27
> @@ -0,0 +1,8 @@
> +processor : 0
> +BogoMIPS : 100.00
> +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp
> asimdhp cpuid asimdrdm fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve
> asimdfhm dit uscat ilrcpc flagm ssbs sb dcpodp sve2 sveaes svepmull
> svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh bti paca
> pacg
> +CPU implementer : 0x41
> +CPU architecture: 8
> +CPU variant : 0x0
> +CPU part : 0xd08
> +CPU revision : 2
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/info_28
> b/gcc/testsuite/gcc.target/aarch64/cpunative/info_28
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..0c216abbb9e4d5c0273eaeb1824dc16e66b09c6c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/info_28
> @@ -0,0 +1,8 @@
> +processor : 0
> +BogoMIPS : 100.00
> +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp
> asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve
> asimdfhm dit uscat flagm ssbs sb dcpodp sve2 sveaes svepmull svebitperm
> svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh bti paca pacg
> +CPU implementer : 0x41
> +CPU architecture: 8
> +CPU variant : 0x0
> +CPU part : 0xd08
> +CPU revision : 2
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/info_29
> b/gcc/testsuite/gcc.target/aarch64/cpunative/info_29
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..308c06710902507fcf274aa61e2244937d4e227b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/info_29
> @@ -0,0 +1,8 @@
> +processor : 0
> +BogoMIPS : 100.00
> +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp
> asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve
> asimdfhm dit uscat ilrcpc flagm ssbs sb dcpodp sve2 sveaes svepmull
> svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh bti paca
> pacg wfxt
> +CPU implementer : 0x41
> +CPU architecture: 8
> +CPU variant : 0x0
> +CPU part : 0xd08
> +CPU revision : 2
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_21.c
> b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_21.c
> index
> 904cdf452263961442f3ecc31cd1b6563130f9c7..e56b9164024c7535d6b10f451b7bc0796e7bd161
> 100644
> --- a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_21.c
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_21.c
> @@ -7,7 +7,7 @@ int main()
> return 0;
> }
>
> -/* { dg-final { scan-assembler {\.arch
> armv8-a\+flagm2\+lse\+dotprod\+rdma\+crc\+fp16fml\+jscvt\+rcpc2\+frintts\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+sb\+ssbs\n}
> } } */
> +/* { dg-final { scan-assembler {\.arch
> armv8\.5-a\+crc\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+nopredres\+nopauth\n}
> } } */
>
> /* Check that an Armv8-A core doesn't fall apart on extensions without midr
> values. */
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_22.c
> b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_22.c
> index
> feb959b11b0e383a5e1f3214d55f80f56d2605d4..db3df27a22ea9275ca303e911061f2c35d3ba722
> 100644
> --- a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_22.c
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_22.c
> @@ -7,7 +7,7 @@ int main()
> return 0;
> }
>
> -/* { dg-final { scan-assembler {\.arch
> armv8-a\+flagm2\+lse\+dotprod\+rdma\+crc\+fp16fml\+jscvt\+rcpc2\+frintts\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+sb\+ssbs\+pauth\n}
> } } */
> +/* { dg-final { scan-assembler {\.arch
> armv8\.5-a\+crc\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+nopredres\n}
> } } */
>
> /* Check that an Armv8-A core doesn't fall apart on extensions without midr
> values and that it enables optional features. */
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_27.c
> b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_27.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..43df6a50706df8855d2e960e508778542d81e643
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_27.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile { target { { aarch64*-*-linux*} && native } } } */
> +/* { dg-set-compiler-env-var GCC_CPUINFO
> "$srcdir/gcc.target/aarch64/cpunative/info_27" } */
> +/* { dg-additional-options "-mcpu=native" } */
> +
> +int main()
> +{
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler {\.arch
> armv8-a\+flagm2\+lse\+dotprod\+rdma\+crc\+fp16fml\+rcpc2\+frintts\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+sb\+ssbs\+pauth\n}
> } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_28.c
> b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_28.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..0e0e56f539433ea02c5c71c8c0bae5ddb256e962
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_28.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile { target { { aarch64*-*-linux*} && native } } } */
> +/* { dg-set-compiler-env-var GCC_CPUINFO
> "$srcdir/gcc.target/aarch64/cpunative/info_28" } */
> +/* { dg-additional-options "-mcpu=native" } */
> +
> +int main()
> +{
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler {\.arch
> armv8\.3-a\+flagm2\+dotprod\+crc\+fp16fml\+frintts\+i8mm\+bf16\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+sb\+ssbs\n}
> } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_29.c
> b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_29.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..9b07161b77d75cfec19aea01fcf2eb5ece91853a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_29.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile { target { { aarch64*-*-linux*} && native } } } */
> +/* { dg-set-compiler-env-var GCC_CPUINFO
> "$srcdir/gcc.target/aarch64/cpunative/info_29" } */
> +/* { dg-additional-options "-mcpu=native" } */
> +
> +int main()
> +{
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler {\.arch
> armv8\.7-a\+crc\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\+nopredres\n} }
> } */