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/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3237,6 +3237,9 @@ case Builtin::BI__builtin_elementwise_pow: { return RValue::get(emitBinaryBuiltin(*this, E, llvm::Intrinsic::pow)); } + case Builtin::BI__builtin_elementwise_bitreverse: + return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::bitreverse, + "elt.bitreverse")); case Builtin::BI__builtin_elementwise_cos: return RValue::get( emitUnaryBuiltin(*this, E, llvm::Intrinsic::cos, "elt.cos")); 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,42 @@ int_as_one = __builtin_elementwise_min(int_as_one, b); } +void test_builtin_elementwise_bitreverse(si8 vi1, si8 vi2, + long long int i1, long long int i2, short si, + _BitInt(31) bi1, _BitInt(31) bi2) { + + + // CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8 + // CHECK-NEXT: call i64 @llvm.bitreverse.i64(i64 [[I1]]) + i2 = __builtin_elementwise_bitreverse(i1); + + // CHECK: [[VI1:%.+]] = load <8 x i16>, ptr %vi1.addr, align 16 + // CHECK-NEXT: call <8 x i16> @llvm.bitreverse.v8i16(<8 x i16> [[VI1]]) + vi2 = __builtin_elementwise_bitreverse(vi1); + + // CHECK: [[CVI2:%.+]] = load <8 x i16>, ptr %cvi2, align 16 + // CHECK-NEXT: call <8 x i16> @llvm.bitreverse.v8i16(<8 x i16> [[CVI2]]) + const si8 cvi2 = vi2; + vi2 = __builtin_elementwise_bitreverse(cvi2); + + // CHECK: [[BI1:%.+]] = load i31, ptr %bi1.addr, align 4 + // CHECK-NEXT: call i31 @llvm.bitreverse.i31(i31 [[BI1]]) + bi2 = __builtin_elementwise_bitreverse(bi1); + + // CHECK: [[IA1:%.+]] = load i32, ptr addrspace(1) @int_as_one, align 4 + // CHECK-NEXT: call i32 @llvm.bitreverse.i32(i32 [[IA1]]) + b = __builtin_elementwise_bitreverse(int_as_one); + + // CHECK: call i32 @llvm.bitreverse.i32(i32 -10) + b = __builtin_elementwise_bitreverse(-10); + + // CHECK: [[SI:%.+]] = load i16, ptr %si.addr, align 2 + // CHECK-NEXT: [[SI_EXT:%.+]] = sext i16 [[SI]] to i32 + // CHECK-NEXT: [[RES:%.+]] = call i32 @llvm.bitreverse.i32(i32 [[SI_EXT]]) + // CHECK-NEXT: = trunc i32 [[RES]] to i16 + si = __builtin_elementwise_bitreverse(si); +} + 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/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/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); +}