diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -631,7 +631,7 @@ =========================================== ================================================================ ========================================= T __builtin_elementwise_abs(T x) return the absolute value of a number x; the absolute value of signed integer and floating point types the most negative integer remains the most negative integer - T __builtin_elementwise_fma(T x, T y, T z) fused multiply add, (x * y) + z. floating point types + T __builtin_elementwise_fma(T x, T y, T z) fused multiply add, (x * y) + z. floating point types T __builtin_elementwise_ceil(T x) return the smallest integral value greater than or equal to x floating point types T __builtin_elementwise_sin(T x) return the sine of x interpreted as an angle in radians floating point types T __builtin_elementwise_cos(T x) return the cosine of x interpreted as an angle in radians floating point types @@ -640,6 +640,7 @@ T __builtin_elementwise_log2(T x) return the base 2 logarithm of x floating point types T __builtin_elementwise_log10(T x) return the base 10 logarithm of x floating point types T __builtin_elementwise_pow(T x, T y) return x raised to the power of y floating point types + T __builtin_elementwise_bitreverse(T x) return the integer represented after reversing the bits of x integer types T __builtin_elementwise_exp(T x) returns the base-e exponential, e^x, of the specified value floating point types T __builtin_elementwise_exp2(T x) returns the base-2 exponential, 2^x, of the specified value floating point types T __builtin_elementwise_roundeven(T x) round x to the nearest integer value in floating point format, floating point types diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -962,6 +962,7 @@ - Add ``__builtin_elementwise_exp2`` builtin for floating point types only. - Add ``__builtin_set_flt_rounds`` builtin for X86, x86_64, Arm and AArch64 only. - Add ``__builtin_elementwise_pow`` builtin for floating point types only. +- Add ``__builtin_elementwise_bitreverse`` builtin for integer types only. AST Matchers ------------ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -677,6 +677,7 @@ BUILTIN(__builtin_nondeterministic_value, "v.", "nt") BUILTIN(__builtin_elementwise_abs, "v.", "nct") +BUILTIN(__builtin_elementwise_bitreverse, "v.", "nct") BUILTIN(__builtin_elementwise_max, "v.", "nct") BUILTIN(__builtin_elementwise_min, "v.", "nct") BUILTIN(__builtin_elementwise_ceil, "v.", "nct") diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2700,6 +2700,26 @@ if (SemaBuiltinElementwiseMath(TheCall)) return ExprError(); break; + + case Builtin::BI__builtin_elementwise_bitreverse: { + if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return ExprError(); + + const Expr *Arg = TheCall->getArg(0); + QualType ArgTy = Arg->getType(); + QualType EltTy = ArgTy; + + if (auto *VecTy = EltTy->getAs()) + EltTy = VecTy->getElementType(); + + if (!EltTy->isIntegerType()) { + Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /* integer ty */ 6 << ArgTy; + return ExprError(); + } + break; + } + case Builtin::BI__builtin_elementwise_copysign: { if (checkArgCount(*this, TheCall, 2)) return ExprError(); diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -323,6 +323,55 @@ int_as_one = __builtin_elementwise_min(int_as_one, b); } +void test_builtin_elementwise_bitreverse(long long int i1, + si8 vi1, + unsigned u1, + u4 vu1, + _BitInt(31) bi1, + unsigned _BitInt(55) bu1) { + + // CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8 + // CHECK-NEXT: [[I2:%.+]] = load i64, ptr %i2.addr, align 8 + // CHECK-NEXT: call i64 @llvm.sbitreverse.i64(i64 [[I1]], i64 [[I2]]) + i1 = __builtin_elementwise_bitreverse(i1); + + // CHECK: [[VI1:%.+]] = load <8 x i16>, ptr %vi1.addr, align 16 + // CHECK-NEXT: [[VI2:%.+]] = load <8 x i16>, ptr %vi2.addr, align 16 + // CHECK-NEXT: call <8 x i16> @llvm.sbitreverse.v8i16(<8 x i16> [[VI1]], <8 x i16> [[VI2]]) + vi1 = __builtin_elementwise_bitreverse(vi1); + + // CHECK: [[U1:%.+]] = load i32, ptr %u1.addr, align 4 + // CHECK-NEXT: [[U2:%.+]] = load i32, ptr %u2.addr, align 4 + // CHECK-NEXT: call i32 @llvm.ubitreverse.i32(i32 [[U1]], i32 [[U2]]) + u1 = __builtin_elementwise_bitreverse(u1); + + // CHECK: [[U1:%.+]] = load i32, ptr %u1.addr, align 4 + // CHECK-NEXT: [[ZEXT_U1:%.+]] = zext i32 [[U1]] to i64 + // CHECK-NEXT: [[I2:%.+]] = load i64, ptr %i2.addr, align 8 + // CHECK-NEXT: call i64 @llvm.sbitreverse.i64(i64 [[ZEXT_U1]], i64 [[I2]]) + u1 = __builtin_elementwise_bitreverse(u1); + + // CHECK: [[VU1:%.+]] = load <4 x i32>, ptr %vu1.addr, align 16 + // CHECK-NEXT: [[VU2:%.+]] = load <4 x i32>, ptr %vu2.addr, align 16 + // CHECK-NEXT: call <4 x i32> @llvm.ubitreverse.v4i32(<4 x i32> [[VU1]], <4 x i32> [[VU2]]) + vu1 = __builtin_elementwise_bitreverse(vu1); + + // CHECK: [[BI1:%.+]] = load i31, ptr %bi1.addr, align 4 + // CHECK-NEXT: [[BI2:%.+]] = load i31, ptr %bi2.addr, align 4 + // CHECK-NEXT: call i31 @llvm.sbitreverse.i31(i31 [[BI1]], i31 [[BI2]]) + bi1 = __builtin_elementwise_bitreverse(bi1); + + // CHECK: [[BU1:%.+]] = load i55, ptr %bu1.addr, align 8 + // CHECK-NEXT: [[BU2:%.+]] = load i55, ptr %bu2.addr, align 8 + // CHECK-NEXT: call i55 @llvm.ubitreverse.i55(i55 [[BU1]], i55 [[BU2]]) + bu1 = __builtin_elementwise_bitreverse(bu1); + + // CHECK: [[IAS1:%.+]] = load i32, ptr addrspace(1) @int_as_one, align 4 + // CHECK-NEXT: [[B:%.+]] = load i32, ptr @b, align 4 + // CHECK-NEXT: call i32 @llvm.sbitreverse.i32(i32 [[IAS1]], i32 [[B]]) + int_as_one = __builtin_elementwise_bitreverse(int_as_one, b); +} + void test_builtin_elementwise_ceil(float f1, float f2, double d1, double d2, float4 vf1, float4 vf2) { // CHECK-LABEL: define void @test_builtin_elementwise_ceil( diff --git a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp --- a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp +++ b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp @@ -47,6 +47,16 @@ return __builtin_elementwise_min(a, b); } +// CHECK-LABEL: define dso_local noundef <4 x float> @_Z22strict_elementwise_bitreverseDv4_fS_ +// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x float> @llvm.bitreverse.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]] +// CHECK-NEXT: ret <4 x float> [[TMP0]] +// +float4 strict_elementwise_bitreverse(float4 a, float4 b) { + return __builtin_elementwise_bitreverse(a, b); +} + // CHECK-LABEL: define dso_local noundef <4 x float> @_Z23strict_elementwise_ceilDv4_f // CHECK-SAME: (<4 x float> noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: entry: diff --git a/clang/test/Sema/aarch64-sve-vector-bitreverse-ops.c b/clang/test/Sema/aarch64-sve-vector-bitreverse-ops.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/aarch64-sve-vector-bitreverse-ops.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple aarch64 -target-feature +f -target-feature +d \ +// RUN: -target-feature +v -target-feature +zfh -target-feature +sve -target-feature +experimental-zvfh \ +// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify +// REQUIRES: aarch64-registered-target + +#include + +svfloat32_t test_bitreverse_vv_i8mf8(svfloat32_t v) { + + return __builtin_elementwise_bitreverse(v, v); + // expected-error@-1 {{1st argument must be a vector, integer or floating point type}} +} diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -269,6 +269,24 @@ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}} } +void test_builtin_elementwise_bitreverse(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { + + struct Foo s = __builtin_elementwise_ceil(f); + // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}} + + i = __builtin_elementwise_bitreverse(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} + + i = __builtin_elementwise_bitreverse(f); + // expected-error@-1 {{1st argument must be a vector of integers (was 'float')}} + + i = __builtin_elementwise_bitreverse(f, f); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} + + u = __builtin_elementwise_bitreverse(d); + // expected-error@-1 {{1st argument must be a vector of integers (was 'double')}} +} + void test_builtin_elementwise_ceil(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { struct Foo s = __builtin_elementwise_ceil(f); diff --git a/clang/test/Sema/riscv-sve-vector-bitreverse-ops.c b/clang/test/Sema/riscv-sve-vector-bitreverse-ops.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/riscv-sve-vector-bitreverse-ops.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d \ +// RUN: -target-feature +v -target-feature +zfh -target-feature +experimental-zvfh \ +// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify +// REQUIRES: riscv-registered-target + +#include + + +vfloat32mf2_t test_bitreverse_vv_i8mf8(vfloat32mf2_t v) { + + return __builtin_elementwise_bitreverse(v, v); + // expected-error@-1 {{1st argument must be a vector, integer or floating point type}} +} diff --git a/clang/test/SemaCXX/builtins-elementwise-math.cpp b/clang/test/SemaCXX/builtins-elementwise-math.cpp --- a/clang/test/SemaCXX/builtins-elementwise-math.cpp +++ b/clang/test/SemaCXX/builtins-elementwise-math.cpp @@ -206,3 +206,10 @@ static_assert(!is_const::value); static_assert(!is_const::value); } + +void test_builtin_elementwise_bitreverse() { + const int a = 2; + int b = 1; + static_assert(!is_const::value); + static_assert(!is_const::value); +}