https://gcc.gnu.org/g:ec9b7caa3734b613a74aae6f73e50467ac5da955

commit r16-4579-gec9b7caa3734b613a74aae6f73e50467ac5da955
Author: Alfie Richards <[email protected]>
Date:   Tue Oct 7 12:42:41 2025 +0000

    aarch64: testsuite: Add test for supported FMV extensions.
    
    Add tests that check the aarch64 version features are supported, that they
    have the correct priority ordering, and that the generated resolver is 
correct.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/fmv_priority1.c: New test.
            * gcc.target/aarch64/fmv_priority2.c: New test.
            * gcc.target/aarch64/fmv_priority.in: Support file.
    
    Reviewed-by: Wilco Dijkstra <[email protected]>

Diff:
---
 gcc/testsuite/gcc.target/aarch64/fmv_priority.in |  92 ++++++++++++
 gcc/testsuite/gcc.target/aarch64/fmv_priority1.c | 175 +++++++++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/fmv_priority2.c |  29 ++++
 3 files changed, 296 insertions(+)

diff --git a/gcc/testsuite/gcc.target/aarch64/fmv_priority.in 
b/gcc/testsuite/gcc.target/aarch64/fmv_priority.in
new file mode 100644
index 000000000000..93209bce0f23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fmv_priority.in
@@ -0,0 +1,92 @@
+int fn [[gnu::target_version("default")]] (int)                        { 
return 1; }
+int fn_default (int) asm("fn.default");
+int fn [[gnu::target_version("rng")]] (int)                    { return 1; }
+int fn_rng(int) asm("fn._Mrng");
+int fn [[gnu::target_version("flagm")]] (int)                  { return 1; }
+int fn_flagm(int) asm("fn._Mflagm");
+int fn [[gnu::target_version("flagm2")]] (int)                 { return 1; }
+int fn_flagm2(int) asm("fn._Mflagm2");
+int fn [[gnu::target_version("lse")]] (int)                    { return 1; }
+int fn_lse(int) asm("fn._Mlse");
+int fn [[gnu::target_version("fp")]] (int)                     { return 1; }
+int fn_fp(int) asm("fn._Mfp");
+int fn [[gnu::target_version("simd")]] (int)                   { return 1; }
+int fn_simd(int) asm("fn._Msimd");
+int fn [[gnu::target_version("dotprod")]] (int)                        { 
return 1; }
+int fn_dotprod(int) asm("fn._Mdotprod");
+int fn [[gnu::target_version("sm4")]] (int)                    { return 1; }
+int fn_sm4(int) asm("fn._Msm4");
+int fn [[gnu::target_version("rdm")]] (int)                    { return 1; }
+int fn_rdm(int) asm("fn._MrdmaMrdm");
+int fn [[gnu::target_version("crc")]] (int)                    { return 1; }
+int fn_crc(int) asm("fn._Mcrc");
+int fn [[gnu::target_version("sha2")]] (int)                   { return 1; }
+int fn_sha2(int) asm("fn._Msha2");
+int fn [[gnu::target_version("sha3")]] (int)                   { return 1; }
+int fn_sha3(int) asm("fn._Msha3");
+int fn [[gnu::target_version("aes")]] (int)                    { return 1; }
+int fn_aes(int) asm("fn._Maes");
+int fn [[gnu::target_version("fp16")]] (int)                   { return 1; }
+int fn_fp16(int) asm("fn._Mfp16");
+int fn [[gnu::target_version("fp16fml")]] (int)                        { 
return 1; }
+int fn_fp16fml(int) asm("fn._Mfp16fml");
+/* TODO: These FMV features are not yet supported in GCC. */
+// int fn [[gnu::target_version("dit")]] (int)                 { return 1; }
+// int fn [[gnu::target_version("dpb")]] (int)                 { return 1; }
+// int fn [[gnu::target_version("dpb2")]] (int)                        { 
return 1; }
+int fn [[gnu::target_version("jscvt")]] (int)                  { return 1; }
+int fn_jscvt(int) asm("fn._Mjscvt");
+int fn [[gnu::target_version("fcma")]] (int)                   { return 1; }
+int fn_fcma(int) asm("fn._Mfcma");
+int fn [[gnu::target_version("rcpc")]] (int)                   { return 1; }
+int fn_rcpc(int) asm("fn._Mrcpc");
+int fn [[gnu::target_version("rcpc2")]] (int)                  { return 1; }
+int fn_rcpc2(int) asm("fn._Mrcpc2");
+int fn [[gnu::target_version("rcpc3")]] (int)                  { return 1; }
+int fn_rcpc3(int) asm("fn._Mrcpc3");
+int fn [[gnu::target_version("frintts")]] (int)                        { 
return 1; }
+int fn_frintts(int) asm("fn._Mfrintts");
+int fn [[gnu::target_version("i8mm")]] (int)                   { return 1; }
+int fn_i8mm(int) asm("fn._Mi8mm");
+int fn [[gnu::target_version("bf16")]] (int)                   { return 1; }
+int fn_bf16(int) asm("fn._Mbf16");
+int fn [[gnu::target_version("sve")]] (int)                    { return 1; }
+int fn_sve(int) asm("fn._Msve");
+int fn [[gnu::target_version("f32mm")]] (int)                  { return 1; }
+int fn_f32mm(int) asm("fn._Mf32mm");
+int fn [[gnu::target_version("f64mm")]] (int)                  { return 1; }
+int fn_f64mm(int) asm("fn._Mf64mm");
+int fn [[gnu::target_version("sve2")]] (int)                   { return 1; }
+int fn_sve2(int) asm("fn._Msve2");
+int fn [[gnu::target_version("sve2-aes")]] (int)               { return 1; }
+int fn_sve2_aes(int) asm("fn._Msve2_aes");
+int fn [[gnu::target_version("sve2-bitperm")]] (int)           { return 1; }
+int fn_sve2_bitperm(int) asm("fn._Msve2_bitperm");
+int fn [[gnu::target_version("sve2-sha3")]] (int)              { return 1; }
+int fn_sve2_sha3(int) asm("fn._Msve2_sha3");
+int fn [[gnu::target_version("sve2-sm4")]] (int)               { return 1; }
+int fn_sve2_sm4(int) asm("fn._Msve2_sm4");
+int fn [[gnu::target_version("sve2+sme")]] (int)               { return 1; }
+int fn_sve2_sme(int) asm("fn._Msve2Msme");
+/* TODO: This FMV features is not yet supported in GCC. */
+// int fn [[gnu::target_version("memtag")]] (int)              { return 1; }
+int fn [[gnu::target_version("sb")]] (int)                     { return 1; }
+int fn_sb(int) asm("fn._Msb");
+/* TODO: This FMV feature is not yet supported in GCC. */
+// int fn [[gnu::target_version("ssbs")]] (int)                        { 
return 1; }
+// int fn_ssbs(int) asm("fn._Mssbs");
+/* TODO: This FMV feature is not yet supported in GCC. */
+// int fn [[gnu::target_version("bti")]] (int)                 { return 1; }
+int fn [[gnu::target_version("wfxt")]] (int)                   { return 1; }
+int fn_wfxt(int) asm("fn._Mwfxt");
+int fn [[gnu::target_version("sve2+sme-f64f64")]] (int)                { 
return 1; }
+int fn_sve2_sme_f64f64(int) asm("fn._Msve2Msme_f64f64");
+int fn [[gnu::target_version("sve2+sme-i16i64")]] (int)                { 
return 1; }
+int fn_sve2_sme_i16i64(int) asm("fn._Msve2Msme_i16i64");
+int fn [[gnu::target_version("sve2+sme2")]] (int)              { return 1; }
+int fn_sve2_sme2(int) asm("fn._Msve2Msme2");
+int fn [[gnu::target_version("mops")]] (int)                   { return 1; }
+int fn_mops(int) asm("fn._Mmops");
+int fn [[gnu::target_version("cssc")]] (int)                   { return 1; }
+int fn_cssc(int) asm("fn._Mcssc");
+
diff --git a/gcc/testsuite/gcc.target/aarch64/fmv_priority1.c 
b/gcc/testsuite/gcc.target/aarch64/fmv_priority1.c
new file mode 100644
index 000000000000..942b7a71c3a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fmv_priority1.c
@@ -0,0 +1,175 @@
+/* { dg-do run { target { aarch64_asm_sme2_ok } } }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0 -march=armv8-a" } */
+
+#include <sys/auxv.h>
+#include "../../../common/config/aarch64/cpuinfo.h"
+
+/* This test has a FMV function set with one version per feature we support.
+   Each version is turned on incrementally and the generated resolver is
+   checked to show the correct version is chosen.  */
+
+/* The resolver does actually take arguments, but ignores them and uses
+   __aarch64_cpu_features global instead to establish what features are
+   present.  */
+int (*(resolver)(void)) (int) asm("fn.resolver");
+
+extern struct {
+  unsigned long long features;
+} aarch64_cpu_features asm("__aarch64_cpu_features");
+
+#include "fmv_priority.in"
+
+#define setCPUFeature(F) aarch64_cpu_features.features |= 1UL << F
+
+int main () {
+  aarch64_cpu_features.features = 0;
+
+  /* Initialize the CPU features, so the resolver doesn't try fetch it.  */
+  setCPUFeature(FEAT_INIT);
+
+  /* Go through features in order and assure the priorities are correct.
+     By checking the correct versions are resolved.  */
+
+  /* Some are missing as they are defined in the ACLE but are not yet
+     implemented.  */
+  if (resolver() != &fn_default) return 1;
+
+  setCPUFeature(FEAT_RNG);
+  if (resolver() != &fn_rng) return 1;
+
+  setCPUFeature(FEAT_FLAGM);
+ if (resolver() != &fn_flagm) return 1;
+
+  setCPUFeature(FEAT_FLAGM2);
+  if (resolver() != &fn_flagm2) return 1;
+
+  setCPUFeature (FEAT_LSE);
+  if (resolver () != &fn_lse) return 1;
+
+  setCPUFeature (FEAT_FP);
+  if (resolver () != &fn_fp) return 1;
+
+  setCPUFeature (FEAT_SIMD);
+  if (resolver () != &fn_simd) return 1;
+
+  setCPUFeature (FEAT_DOTPROD);
+  if (resolver () != &fn_dotprod) return 1;
+
+  setCPUFeature (FEAT_SM4);
+  if(resolver() != &fn_sm4) return 1;
+
+  setCPUFeature (FEAT_RDM);
+  if(resolver() != &fn_rdm) return 1;
+
+  setCPUFeature (FEAT_CRC);
+  if (resolver () != &fn_crc) return 1;
+
+  setCPUFeature (FEAT_SHA2);
+  if (resolver () != &fn_sha2) return 1;
+
+  setCPUFeature (FEAT_SHA3);
+  if (resolver () != &fn_sha3) return 1;
+
+  setCPUFeature(FEAT_PMULL);
+  if(resolver() != &fn_aes) return 1;
+
+  setCPUFeature (FEAT_FP16);
+  if (resolver () != &fn_fp16) return 1;
+
+  setCPUFeature (FEAT_FP16FML);
+  if(resolver() != &fn_fp16fml) return 1;
+
+  setCPUFeature (FEAT_DIT);
+  // if(resolver() != &fn_dit) return 1;
+  // 
+  setCPUFeature (FEAT_DPB);
+  // if(resolver() != &fn_dpb) return 1;
+  // 
+  setCPUFeature (FEAT_DPB2);
+  // if(resolver() != &fn_dpb2) return 1;
+  // 
+  setCPUFeature (FEAT_JSCVT);
+  if (resolver () != &fn_jscvt) return 1;
+
+  setCPUFeature (FEAT_FCMA);
+  if (resolver () != &fn_fcma) return 1;
+
+  setCPUFeature (FEAT_RCPC);
+  if (resolver () != &fn_rcpc) return 1;
+
+  setCPUFeature (FEAT_RCPC2);
+  if (resolver () != &fn_rcpc2) return 1;
+
+  setCPUFeature (FEAT_RCPC3);
+  // if(resolver() != &fn_rcpc3) return 1;
+  // 
+  setCPUFeature (FEAT_FRINTTS);
+  if (resolver () != &fn_frintts) return 1;
+
+  setCPUFeature (FEAT_I8MM);
+  if (resolver () != &fn_i8mm) return 1;
+
+  setCPUFeature (FEAT_BF16);
+  if (resolver () != &fn_bf16) return 1;
+
+  setCPUFeature (FEAT_SVE);
+  if (resolver () != &fn_sve) return 1;
+
+  setCPUFeature (FEAT_SVE_F32MM);
+  if(resolver() != &fn_f32mm) return 1;
+
+  setCPUFeature (FEAT_SVE_F64MM);
+  if(resolver() != &fn_f64mm) return 1;
+
+  setCPUFeature (FEAT_SVE2);
+  if (resolver () != &fn_sve2) return 1;
+
+  setCPUFeature(FEAT_SVE_PMULL128);
+  if(resolver() != &fn_sve2_aes) return 1;
+
+  setCPUFeature (FEAT_SVE_BITPERM);
+  if (resolver () != &fn_sve2_bitperm) return 1;
+
+  setCPUFeature (FEAT_SVE_SHA3);
+  if (resolver () != &fn_sve2_sha3) return 1;
+
+  setCPUFeature (FEAT_SVE_SM4);
+  if (resolver () != &fn_sve2_sm4) return 1;
+
+  setCPUFeature (FEAT_SME);
+  if (resolver () != &fn_sve2_sme) return 1;
+
+  setCPUFeature(FEAT_MEMTAG2);
+  // if(resolver() != &fn_memtag) return 1;
+
+  setCPUFeature (FEAT_SB);
+  if (resolver () != &fn_sb) return 1;
+
+  setCPUFeature(FEAT_SSBS2);
+  // if(resolver() != &fn_ssbs) return 1;
+ 
+  setCPUFeature(FEAT_BTI);
+  // if(resolver() != &fn_bti) return 1;
+
+  setCPUFeature (FEAT_WFXT);
+  if (resolver () != &fn_wfxt) return 1;
+
+  setCPUFeature (FEAT_SME_F64);
+  if (resolver () != &fn_sve2_sme_f64f64) return 1;
+
+  setCPUFeature (FEAT_SME_I64);
+  if (resolver () != &fn_sve2_sme_i16i64) return 1;
+
+  setCPUFeature (FEAT_SME2);
+  if (resolver () != &fn_sve2_sme2) return 1;
+
+  setCPUFeature (FEAT_MOPS);
+  if (resolver () != &fn_mops) return 1;
+
+  setCPUFeature (FEAT_CSSC);
+  if (resolver () != &fn_cssc) return 1;
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/aarch64/fmv_priority2.c 
b/gcc/testsuite/gcc.target/aarch64/fmv_priority2.c
new file mode 100644
index 000000000000..dbeb15e4f62d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fmv_priority2.c
@@ -0,0 +1,29 @@
+/* { dg-do compile }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0 -march=armv8-a -fdump-ipa-targetclone1-details" } */
+
+#include "fmv_priority.in"
+
+// Checks that the versions are in the correct order
+// Each of these lines checks 3 consecutive versions in the list with one 
overlap
+/* { dg-final { scan-ipa-dump-times "Version order for 
fn/\[0-9\]+:\\nfn\.default/\[0-9\]+\\n" 1 "targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\.default/\[0-9\]+\\nfn\._Mrng/\[0-9\]+\\nfn\._Mflagm/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mflagm/\[0-9\]+\\nfn\._Mflagm2/\[0-9\]+\\nfn\._Mlse/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mlse/\[0-9\]+\\nfn\._Mfp/\[0-9\]+\\nfn\._Msimd/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msimd/\[0-9\]+\\nfn\._Mdotprod/\[0-9\]+\\nfn\._Msm4/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msm4/\[0-9\]+\\nfn\._MrdmaMrdm/\[0-9\]+\\nfn\._Mcrc/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mcrc/\[0-9\]+\\nfn\._Msha2/\[0-9\]+\\nfn\._Msha3/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msha3/\[0-9\]+\\nfn\._Maes/\[0-9\]+\\nfn\._Mfp16/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mfp16/\[0-9\]+\\nfn\._Mfp16fml/\[0-9\]+\\nfn\._Mjscvt/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mjscvt/\[0-9\]+\\nfn\._Mfcma/\[0-9\]+\\nfn\._Mrcpc/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mrcpc/\[0-9\]+\\nfn\._Mrcpc2/\[0-9\]+\\nfn\._Mrcpc3/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mrcpc3/\[0-9\]+\\nfn\._Mfrintts/\[0-9\]+\\nfn\._Mi8mm/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mi8mm/\[0-9\]+\\nfn\._Mbf16/\[0-9\]+\\nfn\._Msve/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msve/\[0-9\]+\\nfn\._Mf32mm/\[0-9\]+\\nfn\._Mf64mm/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mf64mm/\[0-9\]+\\nfn\._Msve2/\[0-9\]+\\nfn\._Msve2_aes/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msve2_aes/\[0-9\]+\\nfn\._Msve2_bitperm/\[0-9\]+\\nfn\._Msve2_sha3/\[0-9\]+\\n"
 1 "targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msve2_sha3/\[0-9\]+\\nfn\._Msve2_sm4/\[0-9\]+\\nfn\._Msve2Msme/\[0-9\]+\\n"
 1 "targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msve2Msme/\[0-9\]+\\nfn\._Msb/\[0-9\]+\\nfn\._Mwfxt/\[0-9\]+\\n" 1 
"targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mwfxt/\[0-9\]+\\nfn\._Msve2Msme_f64f64/\[0-9\]+\\nfn\._Msve2Msme_i16i64/\[0-9\]+\\n"
 1 "targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Msve2Msme_i16i64/\[0-9\]+\\nfn\._Msve2Msme2/\[0-9\]+\\nfn\._Mmops/\[0-9\]+\\n"
 1 "targetclone1" } } */
+/* { dg-final { scan-ipa-dump-times 
"fn\._Mmops/\[0-9\]+\\nfn\._Mcssc/\[0-9\]+\\n" 1 "targetclone1" } } */

Reply via email to