--- /dev/null
+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");
+
--- /dev/null
+/* { 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;
+}
+
--- /dev/null
+/* { 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" } } */