ilinpv created this revision.
ilinpv added reviewers: danielkiss, kristof.beyls, nemanjai, arsenm.
Herald added subscribers: Enna1, dberris.
Herald added a project: All.
ilinpv requested review of this revision.
Herald added subscribers: Sanitizers, cfe-commits, wdng.
Herald added projects: clang, Sanitizers.
The patch adds AArch64 target builtin
__builtin_cpu_supports("feature1+...+featureN")
which return true if all specified CPU features in argument are detected.
Also native run aarch64 tests for compiler-rt features detection mechanism
were added.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D153153
Files:
clang/include/clang/Basic/BuiltinsAArch64.def
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Sema/SemaChecking.cpp
clang/test/CodeGen/aarch64-cpu-supports-target.c
clang/test/CodeGen/aarch64-cpu-supports.c
clang/test/Sema/aarch64-cpu-supports.c
compiler-rt/test/builtins/Unit/aarch64_cpu_features_test.c
Index: compiler-rt/test/builtins/Unit/aarch64_cpu_features_test.c
===================================================================
--- /dev/null
+++ compiler-rt/test/builtins/Unit/aarch64_cpu_features_test.c
@@ -0,0 +1,17 @@
+// REQUIRES: aarch64-target-arch
+// REQUIRES: native-run
+// RUN: %clang_builtins %s %librt -o %t && %run %t
+// REQUIRES: librt_has_cpu_model
+int main(void) {
+ if (__builtin_cpu_supports("fp+simd+pmull+sha2+crc")) {
+ if (__builtin_cpu_supports("fp") && __builtin_cpu_supports("simd") &&
+ __builtin_cpu_supports("pmull") && __builtin_cpu_supports("sha2") &&
+ __builtin_cpu_supports("crc")) {
+ return 0;
+ } else {
+ // Something wrong in feature detection
+ return 1;
+ }
+ }
+ return 0;
+}
Index: clang/test/Sema/aarch64-cpu-supports.c
===================================================================
--- /dev/null
+++ clang/test/Sema/aarch64-cpu-supports.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
+
+int test_aarch64_features(void) {
+ char * ssbs2;
+ // expected-error@+1 {{expression is not a string literal}}
+ if (__builtin_cpu_supports(ssbs2))
+ return 1;
+ // expected-error@+1 {{invalid cpu feature string}}
+ if (__builtin_cpu_supports(""))
+ return 2;
+ // expected-error@+1 {{invalid cpu feature string}}
+ if (__builtin_cpu_supports("pmull128"))
+ return 3;
+ // expected-error@+1 {{invalid cpu feature string}}
+ if (__builtin_cpu_supports("sve2,rpres"))
+ return 4;
+ // expected-error@+1 {{invalid cpu feature string}}
+ if (__builtin_cpu_supports("dgh+sve2-pmull"))
+ return 5;
+ // expected-error@+1 {{invalid cpu feature string}}
+ if (__builtin_cpu_supports("default"))
+ return 6;
+ if (__builtin_cpu_supports(" ssbs + bti "))
+ return 7;
+ return 0;
+}
Index: clang/test/CodeGen/aarch64-cpu-supports.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-cpu-supports.c
@@ -0,0 +1,54 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals --version 2
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
+// CHECK-LABEL: define dso_local i32 @main
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70368744177664
+// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70368744177664
+// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+// CHECK: if.then:
+// CHECK-NEXT: store i32 1, ptr [[RETVAL]], align 4
+// CHECK-NEXT: br label [[RETURN:%.*]]
+// CHECK: if.end:
+// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 9070970929152
+// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 9070970929152
+// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]]
+// CHECK-NEXT: br i1 [[TMP7]], label [[IF_THEN1:%.*]], label [[IF_END2:%.*]]
+// CHECK: if.then1:
+// CHECK-NEXT: store i32 2, ptr [[RETVAL]], align 4
+// CHECK-NEXT: br label [[RETURN]]
+// CHECK: if.end2:
+// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 166633186212708352
+// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 166633186212708352
+// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]]
+// CHECK-NEXT: br i1 [[TMP11]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]]
+// CHECK: if.then3:
+// CHECK-NEXT: store i32 3, ptr [[RETVAL]], align 4
+// CHECK-NEXT: br label [[RETURN]]
+// CHECK: if.end4:
+// 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]]
+//
+int main(void) {
+ if (__builtin_cpu_supports("sb"))
+ return 1;
+
+ if (__builtin_cpu_supports("sve2-pmull128+memtag"))
+ return 2;
+
+ if (__builtin_cpu_supports("sme2+ls64_v+wfxt"))
+ return 3;
+
+ return 0;
+}
Index: clang/test/CodeGen/aarch64-cpu-supports-target.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-cpu-supports-target.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+int check_all_feature() {
+ if (__builtin_cpu_supports("rng+flagm+flagm2+fp16fml+dotprod+sm4"))
+ return 1;
+ else if (__builtin_cpu_supports("rdm+lse+fp+simd+crc+sha1+sha2+sha3"))
+ return 2;
+ else if (__builtin_cpu_supports("aes+pmull+fp16+dit+dpb+dpb2+jscvt"))
+ return 3;
+ else if (__builtin_cpu_supports("fcma+rcpc+rcpc2+rcpc3+frintts+dgh"))
+ return 4;
+ else if (__builtin_cpu_supports("i8mm+bf16+ebf16+rpres+sve+sve-bf16"))
+ return 5;
+ else if (__builtin_cpu_supports("sve-ebf16+sve-i8mm+f32mm+f64mm"))
+ return 6;
+ else if (__builtin_cpu_supports("sve2+sve2-aes+sve2-pmull128"))
+ return 7;
+ else if (__builtin_cpu_supports("sve2-bitperm+sve2-sha3+sve2-sm4"))
+ return 8;
+ else if (__builtin_cpu_supports("sme+memtag+memtag2+memtag3+sb"))
+ return 9;
+ else if (__builtin_cpu_supports("predres+ssbs+ssbs2+bti+ls64+ls64_v"))
+ return 10;
+ else if (__builtin_cpu_supports("ls64_accdata+wfxt+sme-f64f64"))
+ return 11;
+ else if (__builtin_cpu_supports("sme-i16i64+sme2"))
+ return 12;
+ else
+ return 0;
+}
+
+// CHECK-LABEL: define dso_local i32 @neon_code() #1
+int __attribute__((target("simd"))) neon_code() { return 1; }
+
+// CHECK-LABEL: define dso_local i32 @sve_code() #2
+int __attribute__((target("sve"))) sve_code() { return 2; }
+
+// CHECK-LABEL: define dso_local i32 @code() #0
+int code() { return 3; }
+
+// CHECK-LABEL: define dso_local i32 @test_versions() #0
+int test_versions() {
+ if (__builtin_cpu_supports("sve"))
+ return sve_code();
+ else if (__builtin_cpu_supports("simd"))
+ return neon_code();
+ else
+ return code();
+}
+// CHECK: attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+// CHECK: attributes #1 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+neon" }
+// CHECK: attributes #2 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -3231,6 +3231,29 @@
return false;
}
+/// SemaBuiltinAArch64CpuSupports - check if __builtin_cpu_supports
+/// argument is valid.
+static bool SemaBuiltinAArch64CpuSupports(Sema &S, const TargetInfo &TI,
+ CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(0);
+ if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+ return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+ << Arg->getSourceRange();
+ StringRef ArgStr =
+ cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+
+ // CPU features are separated by '+', extract them and check
+ llvm::SmallVector<StringRef, 8> Features;
+ ArgStr.split(Features, "+");
+ for (auto &Feature : Features) {
+ Feature = Feature.trim();
+ if (!TI.validateCpuSupports(Feature))
+ return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
+ << Arg->getSourceRange();
+ }
+ return false;
+}
+
bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall) {
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
@@ -3324,6 +3347,10 @@
SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
}
+ if (BuiltinID == AArch64::BI__builtin_cpu_supports) {
+ return SemaBuiltinAArch64CpuSupports(*this, TI, TheCall);
+ }
+
if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4860,10 +4860,10 @@
llvm::Value *EmitAArch64CpuInit();
llvm::Value *
FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
+ llvm::Value *EmitAArch64CpuSupports(const CallExpr *E);
llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
};
-
inline DominatingLLVMValue::saved_type
DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {
if (!needsSaving(value)) return saved_type(value, false);
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -9950,6 +9950,9 @@
BuiltinID <= clang::AArch64::LastSMEBuiltin)
return EmitAArch64SMEBuiltinExpr(BuiltinID, E);
+ if (BuiltinID == clang::AArch64::BI__builtin_cpu_supports)
+ return EmitAArch64CpuSupports(E);
+
unsigned HintID = static_cast<unsigned>(-1);
switch (BuiltinID) {
default: break;
@@ -13288,6 +13291,19 @@
return Builder.CreateCall(Func);
}
+Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
+ const Expr *ArgExpr = E->getArg(0)->IgnoreParenCasts();
+ StringRef ArgStr = cast<StringLiteral>(ArgExpr)->getString();
+ llvm::SmallVector<StringRef, 8> Features;
+ ArgStr.split(Features, "+");
+ for (auto &Feature : Features) {
+ Feature = Feature.trim();
+ if (Feature != "default")
+ Features.push_back(Feature);
+ }
+ return EmitAArch64CpuSupports(Features);
+}
+
llvm::Value *
CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
uint64_t FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs);
Index: clang/include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- clang/include/clang/Basic/BuiltinsAArch64.def
+++ clang/include/clang/Basic/BuiltinsAArch64.def
@@ -76,6 +76,9 @@
TARGET_BUILTIN(__builtin_arm_jcvt, "Zid", "nc", "v8.3a")
+// CPU features detection
+BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
+
// Prefetch
BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc")
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits