Repository navigation
Conversation
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.
|
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-clang-codegen Author: Lukacma ChangesThis patch implements FMV support for neq features This required extending __aarch64_cpu_features by 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:
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]
|
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
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);
}
|
| 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); |
There was a problem hiding this comment.
There was a problem hiding this comment.
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 ?
| FEAT_SVE_F16F32MM, | ||
| FEAT_SME_MOP4, | ||
| FEAT_MAX | ||
| }; |
There was a problem hiding this comment.
I think we should pre-reserve FEAT_EXT2.
There was a problem hiding this comment.
And perhaps document it in ARM-software/abi-aa#431 ?
CarolineConcatto
left a comment
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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} );
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
Should we check also features2
There was a problem hiding this comment.
With current implementation this is not necessary as first word contains FEAT_INIT, which can be used to signal initialization of the variable.
| {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}, |
There was a problem hiding this comment.
Should this set dependent features too, like FEAT_F8 in this case?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
It would be good to also add end-to-end tests for these to llvm-test-suite
https://github.com/llvm/llvm-test-suite/blob/13fa6366c1cd5c8db5e7a72b6808b4ad4320794c/SingleSource/UnitTests/AArch64/acle-fmv-features.c
There was a problem hiding this comment.
Good catch @tommat01 I agree we need a patch for the llvm test suite to cover those.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I have created #231912 to fix dependencies for existing features.
|
@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 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 .