Skip to content

[AArch64] Extend FMV support to more features - #229139

Open
Lukacma wants to merge 5 commits into
llvm:mainfrom
Lukacma:fmv-update
Open

Lukacma wants to merge 5 commits into
llvm:mainfrom
Lukacma:fmv-update

Conversation

@Lukacma

@Lukacma Lukacma commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

This patch implements FMV support for new features
added to ACLE.

This required extending __aarch64_cpu_features by
another word and adjusting resolver CodeGen and
runtime accordingly.

This patch is based on #229120 .

Skip unreachable function versions before building their resolver conditions. Update the resolver IR test to omit the unused feature checks.
This patch implements FMV support for neq features
added to ACLE.

This required extending __aarch64_cpu_features by
another word and adjusting resolver CodeGen and
runtime accordingly.
@llvmorg-github-actions

llvmorg-github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-clang-codegen

Author: Lukacma

Changes

This patch implements FMV support for neq features
added to ACLE.

This required extending __aarch64_cpu_features by
another word and adjusting resolver CodeGen and
runtime accordingly.

This patch is based on #229120 .


Patch is 70.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/229139.diff

19 Files Affected:

  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+10-11)
  • (modified) clang/lib/CodeGen/TargetBuiltins/ARM.cpp (+34-1)
  • (modified) clang/test/CodeGen/AArch64/cpu-supports.c (+29-3)
  • (modified) clang/test/CodeGen/AArch64/fmv-dependencies.c (+108)
  • (modified) clang/test/CodeGen/AArch64/fmv-features.c (+108)
  • (modified) clang/test/CodeGen/AArch64/fmv-priority.c (+361-2)
  • (modified) clang/test/CodeGen/AArch64/fmv-unreachable-version.c (+3-15)
  • (modified) compiler-rt/lib/builtins/cpu_model/AArch64CPUFeatures.inc (+29-17)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64.c (+1-1)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/fmv/apple.inc (+7-4)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc (+4-1)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/fmv/fuchsia.inc (+3-1)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc (+62-3)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/fmv/windows.inc (+56-4)
  • (modified) compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc (+87)
  • (modified) llvm/include/llvm/TargetParser/AArch64CPUFeatures.inc (+29-17)
  • (modified) llvm/include/llvm/TargetParser/AArch64FeatPriorities.inc (+27)
  • (modified) llvm/include/llvm/TargetParser/AArch64TargetParser.h (+4-2)
  • (modified) llvm/lib/Target/AArch64/AArch64FMV.td (+27)
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 62dade6cf6f49c..8a2de7f21d39db 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3229,7 +3229,17 @@ void CodeGenFunction::EmitAArch64MultiVersionResolver(
   llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
 
   for (const FMVResolverOption &RO : Options) {
+    // Skip unreachable versions.
+    if (RO.Function == nullptr)
+      continue;
+
     Builder.SetInsertPoint(CurBlock);
+
+    if (!AArch64CpuInitialized && !RO.Features.empty()) {
+      EmitAArch64CpuInit();
+      AArch64CpuInitialized = true;
+    }
+
     llvm::Value *Condition = FormAArch64ResolverCondition(RO);
 
     // The 'default' or 'all features enabled' case.
@@ -3239,17 +3249,6 @@ void CodeGenFunction::EmitAArch64MultiVersionResolver(
       return;
     }
 
-    if (!AArch64CpuInitialized) {
-      Builder.SetInsertPoint(CurBlock->begin());
-      EmitAArch64CpuInit();
-      AArch64CpuInitialized = true;
-      Builder.SetInsertPoint(CurBlock);
-    }
-
-    // Skip unreachable versions.
-    if (RO.Function == nullptr)
-      continue;
-
     llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
     CGBuilderTy RetBuilder(CGM, RetBlock);
     CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function,
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index e20fa60ee132bc..fd0728b5cb6577 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -7389,6 +7389,7 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
     // Get features from structure in runtime library
     // struct {
     //   unsigned long long features;
+    //   unsigned long long features2;
     // } __aarch64_cpu_features;
     llvm::Type *STy = llvm::StructType::get(Int64Ty);
     llvm::Constant *AArch64CPUFeatures =
@@ -7399,10 +7400,42 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
         {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 0)});
     Value *Features = Builder.CreateAlignedLoad(Int64Ty, CpuFeatures,
                                                 CharUnits::fromQuantity(8));
-    Value *Mask = Builder.getInt(FeaturesMask.trunc(64));
+    llvm::APInt LowerMask = FeaturesMask.trunc(64);
+    llvm::APInt UpperMask = FeaturesMask.lshr(64).trunc(64);
+    if (!UpperMask.isZero())
+      // Require the second feature word to be present.
+      LowerMask.setBit(llvm::AArch64::FEAT_EXT);
+
+    Value *Mask = Builder.getInt(LowerMask);
     Value *Bitset = Builder.CreateAnd(Features, Mask);
     Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
     Result = Builder.CreateAnd(Result, Cmp);
+
+    if (!UpperMask.isZero()) {
+      // Load the second feature word only if present.
+      llvm::BasicBlock *LowerBlock = Builder.GetInsertBlock();
+      llvm::BasicBlock *ExtensionBlock =
+          createBasicBlock("cpu_supports.extension", CurFn);
+      llvm::BasicBlock *EndBlock =
+          createBasicBlock("cpu_supports.end", CurFn);
+      Builder.CreateCondBr(Result, ExtensionBlock, EndBlock);
+
+      Builder.SetInsertPoint(ExtensionBlock);
+      Value *ExtendedFeatures = Builder.CreateGEP(
+          Int8Ty, AArch64CPUFeatures, ConstantInt::get(Int64Ty, 8));
+      Features = Builder.CreateAlignedLoad(Int64Ty, ExtendedFeatures,
+                                           CharUnits::fromQuantity(8));
+      Mask = Builder.getInt(UpperMask);
+      Bitset = Builder.CreateAnd(Features, Mask);
+      Cmp = Builder.CreateICmpEQ(Bitset, Mask);
+      Builder.CreateBr(EndBlock);
+
+      Builder.SetInsertPoint(EndBlock);
+      llvm::PHINode *ResultPhi = Builder.CreatePHI(Builder.getInt1Ty(), 2);
+      ResultPhi->addIncoming(Builder.getFalse(), LowerBlock);
+      ResultPhi->addIncoming(Cmp, ExtensionBlock);
+      Result = ResultPhi;
+    }
   }
   return Result;
 }
diff --git a/clang/test/CodeGen/AArch64/cpu-supports.c b/clang/test/CodeGen/AArch64/cpu-supports.c
index 6a27849b824cb1..a317d0d35d6af1 100644
--- a/clang/test/CodeGen/AArch64/cpu-supports.c
+++ b/clang/test/CodeGen/AArch64/cpu-supports.c
@@ -40,11 +40,28 @@
 // CHECK-NEXT:    store i32 4, ptr [[RETVAL]], align 4
 // CHECK-NEXT:    br label [[RETURN]]
 // CHECK:       if.end6:
+// CHECK-NEXT:    [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT:    [[TMP13:%.*]] = and i64 [[TMP12]], 4611686088220672256
+// CHECK-NEXT:    [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 4611686088220672256
+// CHECK-NEXT:    [[TMP15:%.*]] = and i1 true, [[TMP14]]
+// CHECK-NEXT:    br i1 [[TMP15]], label [[CPU_SUPPORTS_EXTENSION:%.*]], label [[CPU_SUPPORTS_END:%.*]]
+// CHECK:       cpu_supports.extension:
+// CHECK-NEXT:    [[TMP16:%.*]] = load i64, ptr getelementptr inbounds nuw (i8, ptr @__aarch64_cpu_features, i64 8), align 8
+// CHECK-NEXT:    [[TMP17:%.*]] = and i64 [[TMP16]], 1
+// CHECK-NEXT:    [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 1
+// CHECK-NEXT:    br label [[CPU_SUPPORTS_END]]
+// CHECK:       cpu_supports.end:
+// CHECK-NEXT:    [[TMP19:%.*]] = phi i1 [ false, [[IF_END6]] ], [ [[TMP18]], [[CPU_SUPPORTS_EXTENSION]] ]
+// CHECK-NEXT:    br i1 [[TMP19]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
+// CHECK:       if.then7:
+// CHECK-NEXT:    store i32 5, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    br label [[RETURN]]
+// CHECK:       if.end8:
 // CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK-NEXT:    br label [[RETURN]]
 // CHECK:       return:
-// CHECK-NEXT:    [[TMP12:%.*]] = load i32, ptr [[RETVAL]], align 4
-// CHECK-NEXT:    ret i32 [[TMP12]]
+// CHECK-NEXT:    [[TMP20:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    ret i32 [[TMP20]]
 //
 int main(void) {
   if (__builtin_cpu_supports("sb"))
@@ -59,8 +76,17 @@ int main(void) {
   if (__builtin_cpu_supports("avx2"))
     return 4;
 
+  if (__builtin_cpu_supports("sve2p1"))
+    return 5;
+
   return 0;
 }
 //.
-// CHECK: [[META0:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"ptrauth-elf-got", i32 0}
+// CHECK: [[META1:![0-9]+]] = !{i32 1, !"ptrauth-init-fini", i32 0}
+// CHECK: [[META2:![0-9]+]] = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0}
+// CHECK: [[META3:![0-9]+]] = !{i32 1, !"ptrauth-sign-personality", i32 0}
+// CHECK: [[META4:![0-9]+]] = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
+// CHECK: [[META5:![0-9]+]] = !{i32 1, !"aarch64-elf-pauthabi-version", i32 0}
+// CHECK: [[META6:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
 //.
diff --git a/clang/test/CodeGen/AArch64/fmv-dependencies.c b/clang/test/CodeGen/AArch64/fmv-dependencies.c
index 8f7f23f93dfeaf..b6e267346466bf 100644
--- a/clang/test/CodeGen/AArch64/fmv-dependencies.c
+++ b/clang/test/CodeGen/AArch64/fmv-dependencies.c
@@ -138,6 +138,87 @@ __attribute__((target_version("wfxt"))) int fmv(void) { return 0; }
 // CHECK: define dso_local i32 @fmv._Mcssc() #[[cssc:[0-9]+]] {
 __attribute__((target_version("cssc"))) int fmv(void) { return 0; }
 
+// CHECK: define dso_local i32 @fmv._Mfp8() #[[fp8:[0-9]+]] {
+__attribute__((target_version("fp8"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mf8f32mm() #[[f8f32mm:[0-9]+]] {
+__attribute__((target_version("f8f32mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8dot4() #[[fp8dot4:[0-9]+]] {
+__attribute__((target_version("fp8dot4"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8dot2() #[[fp8dot2:[0-9]+]] {
+__attribute__((target_version("fp8dot2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8fma() #[[fp8fma:[0-9]+]] {
+__attribute__((target_version("fp8fma"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f8f32() #[[sme_f8f32:[0-9]+]] {
+__attribute__((target_version("sme-f8f32"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8dot4() #[[ssve_fp8dot4:[0-9]+]] {
+__attribute__((target_version("ssve-fp8dot4"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8fma() #[[ssve_fp8fma:[0-9]+]] {
+__attribute__((target_version("ssve-fp8fma"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-bitperm() #[[ssve_bitperm:[0-9]+]] {
+__attribute__((target_version("ssve-bitperm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8dot2() #[[ssve_fp8dot2:[0-9]+]] {
+__attribute__((target_version("ssve-fp8dot2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-aes() #[[ssve_aes:[0-9]+]] {
+__attribute__((target_version("ssve-aes"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fexpa() #[[ssve_fexpa:[0-9]+]] {
+__attribute__((target_version("ssve-fexpa"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mlut() #[[lut:[0-9]+]] {
+__attribute__((target_version("lut"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfaminmax() #[[faminmax:[0-9]+]] {
+__attribute__((target_version("faminmax"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-lutv2() #[[sme_lutv2:[0-9]+]] {
+__attribute__((target_version("sme-lutv2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme2p1() #[[sme2p1:[0-9]+]] {
+__attribute__((target_version("sme2p1"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme2p2() #[[sme2p2:[0-9]+]] {
+__attribute__((target_version("sme2p2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve2p1() #[[sve2p1:[0-9]+]] {
+__attribute__((target_version("sve2p1"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve2p2() #[[sve2p2:[0-9]+]] {
+__attribute__((target_version("sve2p2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f16f16() #[[sme_f16f16:[0-9]+]] {
+__attribute__((target_version("sme-f16f16"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mgcs() #[[gcs:[0-9]+]] {
+__attribute__((target_version("gcs"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f8f16() #[[sme_f8f16:[0-9]+]] {
+__attribute__((target_version("sme-f8f16"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mf8f16mm() #[[f8f16mm:[0-9]+]] {
+__attribute__((target_version("f8f16mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-aes2() #[[sve_aes2:[0-9]+]] {
+__attribute__((target_version("sve-aes2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-bfscale() #[[sve_bfscale:[0-9]+]] {
+__attribute__((target_version("sve-bfscale"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-f16f32mm() #[[sve_f16f32mm:[0-9]+]] {
+__attribute__((target_version("sve-f16f32mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-mop4() #[[sme_mop4:[0-9]+]] {
+__attribute__((target_version("sme-mop4"))) int fmv(void) { return 0; }
+
 // CHECK-NOT: define dso_local i32 @fmv._M{{.*}}
 __attribute__((target_version("non_existent_extension"))) int fmv(void);
 
@@ -192,3 +273,30 @@ int caller() {
 // CHECK: attributes #[[sve2_sm4]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sm4,+sve,+sve-sm4,+sve2,+sve2-sm4,+v8a"
 // CHECK: attributes #[[wfxt]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,+wfxt"
 // CHECK: attributes #[[cssc]] = { {{.*}} "target-features"="+cssc,+fp-armv8,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[fp8]] = { {{.*}} "target-features"="+fp-armv8,+fp8,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[f8f32mm]] = { {{.*}} "target-features"="+f8f32mm,+fp-armv8,+fp8,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[fp8dot4]] = { {{.*}} "target-features"="+fp-armv8,+fp8,+fp8dot4,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[fp8dot2]] = { {{.*}} "target-features"="+fp-armv8,+fp8,+fp8dot2,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[fp8fma]] = { {{.*}} "target-features"="+fp-armv8,+fp8,+fp8fma,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[sme_f8f32]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fp8,+fullfp16,+neon,+outline-atomics,+sme,+sme-f8f32,+sme2,+v8a"
+// CHECK: attributes #[[ssve_fp8dot4]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fp8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-fp8dot4,+v8a"
+// CHECK: attributes #[[ssve_fp8fma]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fp8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-fp8fma,+v8a"
+// CHECK: attributes #[[ssve_bitperm]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-bitperm,+sve-bitperm,+v8a"
+// CHECK: attributes #[[ssve_fp8dot2]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fp8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-fp8dot2,+v8a"
+// CHECK: attributes #[[ssve_aes]] = { {{.*}} "target-features"="+aes,+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-aes,+sve-aes,+v8a"
+// CHECK: attributes #[[ssve_fexpa]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+ssve-fexpa,+v8a"
+// CHECK: attributes #[[lut]] = { {{.*}} "target-features"="+fp-armv8,+lut,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[faminmax]] = { {{.*}} "target-features"="+faminmax,+fp-armv8,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[sme_lutv2]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme-lutv2,+sme2,+v8a"
+// CHECK: attributes #[[sme2p1]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+sme2p1,+v8a"
+// CHECK: attributes #[[sme2p2]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+sme2p1,+sme2p2,+v8a"
+// CHECK: attributes #[[sve2p1]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2p1,+v8a"
+// CHECK: attributes #[[sve2p2]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2p1,+sve2p2,+v8a"
+// CHECK: attributes #[[sme_f16f16]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme-f16f16,+sme2,+v8a"
+// CHECK: attributes #[[gcs]] = { {{.*}} "target-features"="+chk,+fp-armv8,+gcs,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[sme_f8f16]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fp8,+fullfp16,+neon,+outline-atomics,+sme,+sme-f8f16,+sme2,+v8a"
+// CHECK: attributes #[[f8f16mm]] = { {{.*}} "target-features"="+f8f16mm,+fp-armv8,+fp8,+neon,+outline-atomics,+v8a"
+// CHECK: attributes #[[sve_aes2]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sve-aes2,+v8a"
+// CHECK: attributes #[[sve_bfscale]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sve-bfscale,+v8a"
+// CHECK: attributes #[[sve_f16f32mm]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve-f16f32mm,+v8a"
+// CHECK: attributes #[[sme_mop4]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme-mop4,+sme2,+v8a"
diff --git a/clang/test/CodeGen/AArch64/fmv-features.c b/clang/test/CodeGen/AArch64/fmv-features.c
index f8b5a9b15456f7..aa1e9da3201eda 100644
--- a/clang/test/CodeGen/AArch64/fmv-features.c
+++ b/clang/test/CodeGen/AArch64/fmv-features.c
@@ -133,6 +133,87 @@ __attribute__((target_version("sve2-sm4"))) int fmv(void) { return 0; }
 // CHECK: define dso_local i32 @fmv._Mwfxt() #[[wfxt:[0-9]+]] {
 __attribute__((target_version("wfxt"))) int fmv(void) { return 0; }
 
+// CHECK: define dso_local i32 @fmv._Mfp8() #[[fp8:[0-9]+]] {
+__attribute__((target_version("fp8"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mf8f32mm() #[[f8f32mm:[0-9]+]] {
+__attribute__((target_version("f8f32mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8dot4() #[[fp8dot4:[0-9]+]] {
+__attribute__((target_version("fp8dot4"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8dot2() #[[fp8dot2:[0-9]+]] {
+__attribute__((target_version("fp8dot2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfp8fma() #[[fp8fma:[0-9]+]] {
+__attribute__((target_version("fp8fma"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f8f32() #[[sme_f8f32:[0-9]+]] {
+__attribute__((target_version("sme-f8f32"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8dot4() #[[ssve_fp8dot4:[0-9]+]] {
+__attribute__((target_version("ssve-fp8dot4"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8fma() #[[ssve_fp8fma:[0-9]+]] {
+__attribute__((target_version("ssve-fp8fma"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-bitperm() #[[ssve_bitperm:[0-9]+]] {
+__attribute__((target_version("ssve-bitperm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fp8dot2() #[[ssve_fp8dot2:[0-9]+]] {
+__attribute__((target_version("ssve-fp8dot2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-aes() #[[ssve_aes:[0-9]+]] {
+__attribute__((target_version("ssve-aes"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mssve-fexpa() #[[ssve_fexpa:[0-9]+]] {
+__attribute__((target_version("ssve-fexpa"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mlut() #[[lut:[0-9]+]] {
+__attribute__((target_version("lut"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mfaminmax() #[[faminmax:[0-9]+]] {
+__attribute__((target_version("faminmax"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-lutv2() #[[sme_lutv2:[0-9]+]] {
+__attribute__((target_version("sme-lutv2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme2p1() #[[sme2p1:[0-9]+]] {
+__attribute__((target_version("sme2p1"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme2p2() #[[sme2p2:[0-9]+]] {
+__attribute__((target_version("sme2p2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve2p1() #[[sve2p1:[0-9]+]] {
+__attribute__((target_version("sve2p1"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve2p2() #[[sve2p2:[0-9]+]] {
+__attribute__((target_version("sve2p2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f16f16() #[[sme_f16f16:[0-9]+]] {
+__attribute__((target_version("sme-f16f16"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mgcs() #[[gcs:[0-9]+]] {
+__attribute__((target_version("gcs"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-f8f16() #[[sme_f8f16:[0-9]+]] {
+__attribute__((target_version("sme-f8f16"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Mf8f16mm() #[[f8f16mm:[0-9]+]] {
+__attribute__((target_version("f8f16mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-aes2() #[[sve_aes2:[0-9]+]] {
+__attribute__((target_version("sve-aes2"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-bfscale() #[[sve_bfscale:[0-9]+]] {
+__attribute__((target_version("sve-bfscale"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msve-f16f32mm() #[[sve_f16f32mm:[0-9]+]] {
+__attribute__((target_version("sve-f16f32mm"))) int fmv(void) { return 0; }
+
+// CHECK: define dso_local i32 @fmv._Msme-mop4() #[[sme_mop4:[0-9]+]] {
+__attribute__((target_version("sme-mop4"))) int fmv(void) { return 0; }
+
 // CHECK: define dso_local i32 @fmv._MaesMbf16MbtiMcrc() #[[unordered_features_with_duplicates:[0-9]+]] {
 __attribute__((target_version("crc+bti+bti+bti+aes+aes+bf16"))) int fmv(void) { return 0; }
 
@@ -190,5 +271,32 @@ int caller() {
 // CHECK: attributes #[[sve2_sha3]] = {{.*}} "fmv-features"="sve2-sha3"
 // CHECK: attributes #[[sve2_sm4]] = {{.*}} "fmv-features"="sve2-sm4"
 // CHECK: attributes #[[wfxt]] = {{.*}} "fmv-features"="wfxt"
+// CHECK: attributes #[[fp8]] = {{.*}} "fmv-features"="fp8"
+// CHECK: attributes #[[f8f32mm]] = {{.*}} "fmv-features"="f8f32mm"
+// CHECK: attributes #[[fp8dot4]] = {{.*}} "fmv-features"="fp8dot4"
+// CHECK: attributes #[[fp8dot2]] = {{.*}} "fmv-featu...
[truncated]

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions cpp,inc,c,h -- clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/TargetBuiltins/ARM.cpp clang/test/CodeGen/AArch64/cpu-supports.c clang/test/CodeGen/AArch64/fmv-dependencies.c clang/test/CodeGen/AArch64/fmv-features.c clang/test/CodeGen/AArch64/fmv-priority.c clang/test/CodeGen/AArch64/fmv-unreachable-version.c compiler-rt/lib/builtins/cpu_model/AArch64CPUFeatures.inc compiler-rt/lib/builtins/cpu_model/aarch64.c compiler-rt/lib/builtins/cpu_model/aarch64/fmv/apple.inc compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc compiler-rt/lib/builtins/cpu_model/aarch64/fmv/fuchsia.inc compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc compiler-rt/lib/builtins/cpu_model/aarch64/fmv/windows.inc compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc llvm/include/llvm/TargetParser/AArch64CPUFeatures.inc llvm/include/llvm/TargetParser/AArch64FeatPriorities.inc llvm/include/llvm/TargetParser/AArch64TargetParser.h --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc
index 29b0a570a..e7fcf9b8f 100644
--- a/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc
+++ b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/hwcap.inc
@@ -161,6 +161,5 @@ static void __init_cpu_features_constructor(unsigned long hwcap,
 
   __atomic_store_n(&__aarch64_cpu_features.features2, feat[1],
                    __ATOMIC_RELAXED);
-  __atomic_store_n(&__aarch64_cpu_features.features, feat[0],
-                   __ATOMIC_RELEASE);
+  __atomic_store_n(&__aarch64_cpu_features.features, feat[0], __ATOMIC_RELEASE);
 }

Comment thread llvm/include/llvm/TargetParser/AArch64CPUFeatures.inc
CHECK_BIT(CAP_BIT_FEAT_SME, FEAT_SME);
CHECK_BIT(CAP_BIT_FEAT_SME2, FEAT_SME2);
CHECK_BIT(CAP_BIT_FEAT_SME_F64F64, FEAT_SME_F64);
CHECK_BIT(CAP_BIT_FEAT_SME_I16I64, FEAT_SME_I64);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing those out! I was looking at the wrong branch of the repo for them. I assume that when adding these features check I would also need to add corresponding #ifndef CAP_BIT_* #define CAP_BIT_* lines to make it compatible with older versions of XNU ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread compiler-rt/lib/builtins/cpu_model/aarch64.c
FEAT_SVE_F16F32MM,
FEAT_SME_MOP4,
FEAT_MAX
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should pre-reserve FEAT_EXT2.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And perhaps document it in ARM-software/abi-aa#431 ?

@CarolineConcatto CarolineConcatto left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add test in :
clang/test/CodeGen/AArch64/fmv-detection.c.

// unsigned long long features;
// unsigned long long features2;
// } __aarch64_cpu_features;
llvm::Type *STy = llvm::StructType::get(Int64Ty);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the struct now 2 values, should we change this to be changed to be something like:
llvm::Type *STy = llvm::StructType::get({Int64Ty,Int64Ty} );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wouldn't be backwards compatible. Compiler cannot assume __aarch64_cpu_features has 16bytes for the new code works with older runtime.

// ELF platforms, where IFuncs are resolved serially at load time). This
// function's effect on __aarch64_cpu_features must be idempotent.

if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check also features2

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With current implementation this is not necessary as first word contains FEAT_INIT, which can be used to signal initialization of the variable.

Comment thread compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc
Comment thread clang/test/CodeGen/AArch64/cpu-supports.c
{PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE, FEAT_SSVE_FP8DOT2},
{PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE, FEAT_SSVE_FP8DOT4},
{PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE, FEAT_SSVE_FP8FMA},
{PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE, FEAT_SME_F8F32},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this set dependent features too, like FEAT_F8 in this case?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated checks fmv-priority.c are checking for FP8 (I think) and therefore the sme-f8f32 case will never be selected at runtime (because the checks will always fail).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch @tommat01 I agree we need a patch for the llvm test suite to cover those.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... This is an existing problem with windows and other runtimes. It seems like they are not adding detection for all dependencies of the features they add. Fixing this for windows would require rewriting the initializer and since it already an existing issue, I will solve it in a separate patch, before fixing it here.

I will also update the tests in test-suite with the new feature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created #231912 to fix dependencies for existing features.

@CarolineConcatto

Copy link
Copy Markdown
Contributor

@Lukacma is safe to assume this is blocked until we choose a solution for features in the ABI change here: https://github.com/ARM-software/abi-aa/pull/431/changes

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants