https://github.com/MadhurKumar004 updated https://github.com/llvm/llvm-project/pull/179126
>From 751bb030fb9dec86ae6e19c08cad70ff7015a4e8 Mon Sep 17 00:00:00 2001 From: Madhur Kumar <[email protected]> Date: Mon, 2 Feb 2026 02:50:42 +0530 Subject: [PATCH] Add __builtin_bitreverseg --- clang/docs/ReleaseNotes.rst | 4 + clang/include/clang/Basic/Builtins.td | 6 + clang/lib/AST/ByteCode/InterpBuiltin.cpp | 1 + clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/CodeGen/CGBuiltin.cpp | 10 + clang/lib/Sema/SemaChecking.cpp | 30 +++ clang/test/AST/ByteCode/builtin-functions.cpp | 30 +++ clang/test/CodeGen/builtins.c | 58 +++++ clang/test/CodeGenCXX/builtins.cpp | 56 +++++ clang/test/Sema/constant-builtins-2.c | 27 ++ clang/test/SemaCXX/builtin-bitreverseg.cpp | 232 ++++++++++++++++++ 11 files changed, 455 insertions(+) create mode 100644 clang/test/SemaCXX/builtin-bitreverseg.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3a3d76112a02b..d8d819a4b2522 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -119,6 +119,10 @@ Non-comprehensive list of changes in this release Usable in constant expressions. Implicit conversion is supported for class/struct types with conversion operators. +- A new generaic bit-reverse builtin function ``__builtin_reverseg`` that + extends bit-reversal support to all standard integers type, including + ``_BitInt`` + New Compiler Flags ------------------ - New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index a410a138836eb..5a58c24d7021c 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -767,6 +767,12 @@ def Bitreverse : BitInt8_16_32_64BuiltinsTemplate, Builtin { let Prototype = "T(T)"; } +def Bitreverseg : Builtin { + let Spellings = ["__builtin_bitreverseg"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + def RotateLeft : BitInt8_16_32_64BuiltinsTemplate, Builtin { let Spellings = ["__builtin_rotateleft"]; let Attributes = [NoThrow, Const, Constexpr]; diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 42ed44ff3c3ea..7d18a4e423e84 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -4265,6 +4265,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return APInt(Val.getBitWidth(), Val.getBitWidth() - Val.getSignificantBits()); }); + case Builtin::BI__builtin_bitreverseg: case Builtin::BI__builtin_bitreverse8: case Builtin::BI__builtin_bitreverse16: case Builtin::BI__builtin_bitreverse32: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 73768f7dd612b..80bbd90b9dca2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -16156,6 +16156,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(AlignedVal, E); } + case Builtin::BI__builtin_bitreverseg: case Builtin::BI__builtin_bitreverse8: case Builtin::BI__builtin_bitreverse16: case Builtin::BI__builtin_bitreverse32: diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 339d6cff0a386..c17a025d175e9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3683,6 +3683,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get( emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::bswap)); } + case Builtin::BI__builtin_bitreverseg: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + llvm::IntegerType *IntTy = cast<llvm::IntegerType>(ArgValue->getType()); + assert(IntTy && + "LLVM's __builtin_bitreverseg only support integer variants"); + if (IntTy->getBitWidth() == 1) + return RValue::get(ArgValue); + return RValue::get( + emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::bitreverse)); + } case Builtin::BI__builtin_bitreverse8: case Builtin::BI__builtin_bitreverse16: case Builtin::BI__builtin_bitreverse32: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e2e1b37572364..aeb0812f2eece 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2259,6 +2259,32 @@ static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) { return false; } +/// Checks that __builtin_bitreverseg was called with a single argument, which +/// is an integer +static bool BuiltinBitreverseg(Sema &S, CallExpr *TheCall) { + if (S.checkArgCount(TheCall, 1)) + return true; + ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0)); + if (ArgRes.isInvalid()) + return true; + + Expr *Arg = ArgRes.get(); + TheCall->setArg(0, Arg); + if (Arg->isTypeDependent()) + return false; + + QualType ArgTy = Arg->getType(); + + if (!ArgTy->isIntegerType()) { + S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /*scalar=*/1 << /*unsigned integer*/ 1 << /*float point*/ 0 + << ArgTy; + return true; + } + TheCall->setType(ArgTy); + return false; +} + /// Checks that __builtin_popcountg was called with a single argument, which is /// an unsigned integer. static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { @@ -3666,6 +3692,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (BuiltinBswapg(*this, TheCall)) return ExprError(); break; + case Builtin::BI__builtin_bitreverseg: + if (BuiltinBitreverseg(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_popcountg: if (BuiltinPopcountg(*this, TheCall)) return ExprError(); diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index b2f0213cfea05..125d83e9b8c57 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -553,6 +553,36 @@ namespace bitreverse { char bitreverse2[__builtin_bitreverse16(0x3C48) == 0x123C ? 1 : -1]; char bitreverse3[__builtin_bitreverse32(0x12345678) == 0x1E6A2C48 ? 1 : -1]; char bitreverse4[__builtin_bitreverse64(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 1 : -1]; + char bitreverse5[(char)__builtin_bitreverseg((char)0x01) == (char)0x80 ? 1 : -1]; + char bitreverse6[(short)__builtin_bitreverseg((short)0x3C48) == (short)0x123C ? 1 : -1]; + char bitreverse7[__builtin_bitreverseg(0x12345678) == 0x1E6A2C48 ? 1 : -1]; + char bitreverse8[__builtin_bitreverseg(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 1 : -1]; +#ifndef __AVR__ + char test5[__builtin_bitreverseg((_BitInt(8))0x12) == (_BitInt(8))0x48 ? 1 : -1]; + char test6[__builtin_bitreverseg((_BitInt(16))0x1234) == (_BitInt(16))0x2C48 ? 1 : -1]; + char test7[__builtin_bitreverseg((_BitInt(32))0x00001234) == (_BitInt(32))0x2C480000 ? 1 : -1]; + char test8[__builtin_bitreverseg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x2C48000000000000 ? 1 : -1]; + char test9[__builtin_bitreverseg((_BitInt(128))0x1) == ((_BitInt(128))1 << 127) ? 1 : -1]; +#endif + + constexpr const int const_expr = 0x1234; + + void test_constexpr_reference_bitreverseg() { + const int expr = 0x1234; + const int& ref = expr; // #declare_bitreverseg + + constexpr const int& const_ref = const_expr; + + constexpr auto result2 = __builtin_bitreverseg(ref); + //expected-error@-1 {{constexpr variable 'result2' must be initialized by a constant expression}} + //expected-note@-2 {{initializer of 'ref' is not a constant expression}} + //expected-note@#declare_bitreverseg {{declared here}} + //ref-error@-4 {{constexpr variable 'result2' must be initialized by a constant expression}} + //ref-note@-5 {{initializer of 'ref' is not a constant expression}} + //ref-note@#declare_bitreverseg {{declared here}} + + constexpr auto result3 = __builtin_bitreverseg(const_ref); + } } namespace expect { diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 3545588aec654..fc0e3a482985a 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -152,6 +152,17 @@ int main(void) { // CHECK: @llvm.bitreverse.i16 // CHECK: @llvm.bitreverse.i32 // CHECK: @llvm.bitreverse.i64 + // CHECK: @llvm.bitreverse.i128 + P(bitreverseg, ((char)N)); + P(bitreverseg, ((short)N)); + P(bitreverseg, ((int)N)); + P(bitreverseg, ((unsigned long)N)); + P(bitreverseg, ((_BitInt(8))N)); + P(bitreverseg, ((_BitInt(16))N)); + P(bitreverseg, ((_BitInt(32))N)); + P(bitreverseg, ((_BitInt(64))N)); + P(bitreverseg, ((_BitInt(128))N)); + P(bitreverseg, (N)); P(bitreverse8, (N)); P(bitreverse16, (N)); P(bitreverse32, (N)); @@ -962,3 +973,50 @@ void test_builtin_bswapg(unsigned char uc, unsigned short us, unsigned int ui, bi128 = __builtin_bswapg(bi128); // CHECK: call i128 @llvm.bswap.i128 } +// CHECK-LABEL: define{{.*}} void @test_builtin_bitreverseg +void test_builtin_bitreverseg(unsigned char uc, unsigned short us, unsigned int ui, + unsigned long ul, unsigned long long ull, bool b, +#ifdef __SIZEOF_INT128__ + unsigned __int128 ui128, +#endif + _BitInt(8) bi8, + _BitInt(16) bi16, _BitInt(32) bi32, + _BitInt(64) bi64, _BitInt(128) bi128) { +#if __aarch64__ + int x = 0; + x = x * 2; +#endif + b = __builtin_bitreverseg(b); + // CHECK: %{{.*}} = load i8, ptr %b.addr + // CHECK: %{{.*}} = trunc i8 %{{.*}} to i1 + // CHECK: %{{.*}} = zext i1 %{{.*}} to i8 + // CHECK: store i8 %{{.*}}, ptr %b.addr + uc = __builtin_bitreverseg(uc); + // CHECK: %{{.*}} = load i8, ptr %uc.addr + // CHECK: %{{.*}} = call i8 @llvm.bitreverse.i8(i8 %{{.*}}) + // CHECK: store i8 %{{.*}}, ptr %uc.addr + us = __builtin_bitreverseg(us); + // CHECK: call i16 @llvm.bitreverse.i16 + ui = __builtin_bitreverseg(ui); + // CHECK: call i32 @llvm.bitreverse.i32 + ul = __builtin_bitreverseg(ul); + // CHECK: call [[LONGINTTY]] @llvm.bitreverse.[[LONGINTTY]] + ull = __builtin_bitreverseg(ull); + // CHECK: call i64 @llvm.bitreverse.i64 +#ifdef __SIZEOF_INT128__ + ui128 = __builtin_bitreverseg(ui128); + // I128: call i128 @llvm.bitreverse.i128 +#endif + bi8 = __builtin_bitreverseg(bi8); + // CHECK: %{{.*}} = load i8, ptr %bi8.addr, align 1 + // CHECK: %{{.*}} = call i8 @llvm.bitreverse.i8(i8 %{{.*}}) + // CHECK: store i8 %{{.*}}, ptr %bi8.addr + bi16 = __builtin_bitreverseg(bi16); + // CHECK: call i16 @llvm.bitreverse.i16 + bi32 = __builtin_bitreverseg(bi32); + // CHECK: call i32 @llvm.bitreverse.i32 + bi64 = __builtin_bitreverseg(bi64); + // CHECK: call i64 @llvm.bitreverse.i64 + bi128 = __builtin_bitreverseg(bi128); + // CHECK: call i128 @llvm.bitreverse.i128 +} diff --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp index ef30a25a17922..2248b3800f7bd 100644 --- a/clang/test/CodeGenCXX/builtins.cpp +++ b/clang/test/CodeGenCXX/builtins.cpp @@ -139,3 +139,59 @@ void test_bitint() { // CHECK: call i64 @llvm.bswap.i64 // CHECK: call i128 @llvm.bswap.i128 // CHECK: ret void + +void test_int_reference(int* a) { + __builtin_bitreverseg(*a); +// CHECK-LABEL: @_Z18test_int_referencePi + // CHECK: store ptr %a, ptr + // CHECK: load ptr, ptr + // CHECK: load i32, ptr + // CHECK: call i32 @llvm.bitreverse.i32 +} + +void test_long_reference(long* a) { + __builtin_bitreverseg(*a); +// CHECK-LABEL: @_Z19test_long_referencePl + // CHECK: store ptr %a, ptr + // CHECK: load ptr, ptr + // CHECK: load i64, ptr + // CHECK: call i64 @llvm.bitreverse.i64 +} + +void test_short_reference(short* a) { + __builtin_bitreverseg(*a); +// CHECK-LABEL: @_Z20test_short_referencePs + // CHECK: store ptr %a, ptr + // CHECK: load ptr, ptr + // CHECK: load i16, ptr + // CHECK: call i16 @llvm.bitreverse.i16 +} + +void test_char_reference(char* a) { + __builtin_bitreverseg(*a); +// CHECK-LABEL: @_Z19test_char_referencePc + // CHECK: store ptr %a, ptr + // CHECK: load ptr, ptr + // CHECK: load i8, ptr + // CHECK: call i8 @llvm.bitreverse.i8 + // CHECK: ret void +} + +void test_bitint_reference() { + _BitInt(8) a = 0x12; + __builtin_bitreverseg(a); + _BitInt(16) b = 0x1234; + __builtin_bitreverseg(b); + _BitInt(32) c = 0x00001234; + __builtin_bitreverseg(c); + _BitInt(64) d = 0x0000000000001234; + __builtin_bitreverseg(d); + _BitInt(128) e = ~(_BitInt(128))0; + __builtin_bitreverseg(e); +} +// CHECK-LABEL: @_Z21test_bitint_referencev +// CHECK: call i16 @llvm.bitreverse.i16 +// CHECK: call i32 @llvm.bitreverse.i32 +// CHECK: call i64 @llvm.bitreverse.i64 +// CHECK: call i128 @llvm.bitreverse.i128 +// CHECK: ret void diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index 9579052b1f76b..73d53504d1dc3 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -501,6 +501,33 @@ int h21 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x34 int h22 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); int h23 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f(); // expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} + +char h24[__builtin_bitreverseg((char)0x01) == (char)0x80 ? 1 : -1]; +char h25[__builtin_bitreverseg((short)0x3C48) == (short)0x123C ? 1 : -1]; +char h26[__builtin_bitreverseg(0x12345678) == 0x1E6A2C48 ? 1 : -1]; +char h27[__builtin_bitreverseg(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 1 : -1]; +int h28 = __builtin_bitreverseg((char)(0x12)) == (char)0x48 ? 1 : f(); +int h29 = __builtin_bitreverseg((short)(0x1234)) == (short)0x2C48 ? 1 : f(); +int h30 = __builtin_bitreverseg((__UINT32_TYPE__)0x1234) == (__UINT32_TYPE__)0x2C480000 ? 1 : f(); +int h31 = __builtin_bitreverseg(0x0000000000001234ULL) == 0x2C48000000000000 ? 1 : f(); +float h32 = __builtin_bitreverseg(1.0f); // expected-error {{1st argument must be a scalar integer type (was 'float')}} +double h33 = __builtin_bitreverseg(1.0L); // expected-error {{1st argument must be a scalar integer type (was 'long double')}} +char *h34 = __builtin_bitreverseg("hello"); // expected-error {{1st argument must be a scalar integer type (was 'char[6]')}} +int h35 = __builtin_bitreverseg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}} +int *h36 = __builtin_bitreverseg(&h31); // expected-error {{1st argument must be a scalar integer type (was 'int *')}} +int arr2[4] = {0x12, 0x34, 0x56, 0x78}; +int h37 = __builtin_bitreverseg(arr2); // expected-error {{1st argument must be a scalar integer type (was 'int[4]')}} +enum BitreverseEnum { + BITREVERSE_ENUM_VALUE1 = 0x1234, +}; +int h38 = __builtin_bitreverseg(BITREVERSE_ENUM_VALUE1) == 0x2C480000 ? 1 : f(); +int h39 = __builtin_bitreverseg((_BitInt(8))0x12) == (_BitInt(8))0x48 ? 1 : f(); +int h40 = __builtin_bitreverseg((_BitInt(16))0x1234) == (_BitInt(16))0x2C48 ? 1 : f(); +int h41 = __builtin_bitreverseg((_BitInt(32))0x00001234) == (_BitInt(32))0x2C480000 ? 1 : f(); +int h42 = __builtin_bitreverseg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x2C48000000000000 ? 1 : f(); +int h43 = __builtin_bitreverseg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); + + extern long int bi0; extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/clang/test/SemaCXX/builtin-bitreverseg.cpp b/clang/test/SemaCXX/builtin-bitreverseg.cpp new file mode 100644 index 0000000000000..8e5f747049501 --- /dev/null +++ b/clang/test/SemaCXX/builtin-bitreverseg.cpp @@ -0,0 +1,232 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s + +void test_basic_type_checks() { + static_assert(__is_same(char, decltype(__builtin_bitreverseg((char)0))), ""); + static_assert(__is_same(unsigned char, decltype(__builtin_bitreverseg((unsigned char)0))), ""); + static_assert(__is_same(short, decltype(__builtin_bitreverseg((short)0))), ""); + static_assert(__is_same(unsigned short, decltype(__builtin_bitreverseg((unsigned short)0))), ""); + static_assert(__is_same(int, decltype(__builtin_bitreverseg((int)0))), ""); + static_assert(__is_same(unsigned int, decltype(__builtin_bitreverseg((unsigned int)0))), ""); + static_assert(__is_same(long, decltype(__builtin_bitreverseg((long)0))), ""); + static_assert(__is_same(unsigned long, decltype(__builtin_bitreverseg((unsigned long)0))), ""); + static_assert(__is_same(_BitInt(8), decltype(__builtin_bitreverseg((_BitInt(8))0))), ""); + static_assert(__is_same(_BitInt(16), decltype(__builtin_bitreverseg((_BitInt(16))0))), ""); + static_assert(__is_same(_BitInt(32), decltype(__builtin_bitreverseg((_BitInt(32))0))), ""); + static_assert(__is_same(_BitInt(64), decltype(__builtin_bitreverseg((_BitInt(64))0))), ""); + static_assert(__is_same(_BitInt(128), decltype(__builtin_bitreverseg((_BitInt(128))0))), ""); +} + +template<typename T> +void test_template_type_check() { + static_assert(__is_same(T, decltype(__builtin_bitreverseg(T{}))), + "bitreverseg should return the same type as its argument"); + constexpr T zero{}; + constexpr T max = ~T{}; + constexpr T one = T{1}; + + static_assert(__is_same(T, decltype(__builtin_bitreverseg(zero))), ""); + static_assert(__is_same(T, decltype(__builtin_bitreverseg(max))), ""); + static_assert(__is_same(T, decltype(__builtin_bitreverseg(one))), ""); +} + +template void test_template_type_check<char>(); +template void test_template_type_check<unsigned char>(); +template void test_template_type_check<short>(); +template void test_template_type_check<unsigned short>(); +template void test_template_type_check<int>(); +template void test_template_type_check<unsigned int>(); +template void test_template_type_check<long>(); +template void test_template_type_check<_BitInt(8)>(); +template void test_template_type_check<_BitInt(16)>(); +template void test_template_type_check<_BitInt(32)>(); +template void test_template_type_check<_BitInt(64)>(); +template void test_template_type_check<_BitInt(128)>(); + +void test_lambda_type_checks() { + auto lambda = [](auto x) { + static_assert(__is_same(decltype(x), decltype(__builtin_bitreverseg(x))), + "bitreverseg in lambda should preserve type"); + return __builtin_bitreverseg(x); + }; + auto result_long = lambda(42UL); + static_assert(__is_same(unsigned long, decltype(result_long)), ""); + + auto result_int = lambda(42); + static_assert(__is_same(int, decltype(result_int)), ""); + + auto result_short = lambda(static_cast<short>(42)); + static_assert(__is_same(short, decltype(result_short)), ""); + + auto result_char = lambda(static_cast<char>(42)); + static_assert(__is_same(char, decltype(result_char)), ""); +} + +decltype(auto) test_decltype_auto(int x) { + return __builtin_bitreverseg(x); +} + +void test_decltype_auto_check() { + int x = 42; + auto result = test_decltype_auto(x); + static_assert(__is_same(int, decltype(result)), ""); +} + +template<auto Value> +struct ValueTemplateTypeTest { + using value_type = decltype(Value); + using result_type = decltype(__builtin_bitreverseg(Value)); + + static constexpr bool type_matches = __is_same(value_type, result_type); + static_assert(type_matches, "Value template bitreverseg should preserve type"); + + static constexpr auto reversed_value = __builtin_bitreverseg(Value); +}; + +template<auto... Values> +void test_template_pack_types() { + static_assert((__is_same(decltype(Values), decltype(__builtin_bitreverseg(Values))) && ...), + "All pack elements should preserve type"); +} + +template struct ValueTemplateTypeTest<0x1234>; +template struct ValueTemplateTypeTest<0x12345678UL>; +template struct ValueTemplateTypeTest<(short)0x1234>; +template struct ValueTemplateTypeTest<(char)0x12>; + +template<typename T> +void test_invalid_type() { + __builtin_bitreverseg(T{}); // #invalid_type_use +} + +void test_basic_errors() { + test_invalid_type<float>(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type<float>' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'float')}} + + test_invalid_type<double>(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type<double>' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'double')}} + + test_invalid_type<void*>(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type<void *>' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'void *')}} +} + +template<typename T> +auto test_dependent_context(T value) -> decltype(__builtin_bitreverseg(value)) { // #dependent_use + return __builtin_bitreverseg(value); +} + +void test_dependent_errors() { + test_dependent_context(1.0f); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = float]: 1st argument must be a scalar integer type (was 'float')}} + test_dependent_context(1.0l); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = long double]: 1st argument must be a scalar integer type (was 'long double')}} + test_dependent_context("hello"); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = const char *]: 1st argument must be a scalar integer type (was 'const char *')}} +} + +void test_lambda_errors() { + auto lambda = [](auto x) { + return __builtin_bitreverseg(x); // #lambda_use + }; + + lambda(1.0f); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'float')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<float>' requested here}} + lambda(1.0l); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'long double')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<long double>' requested here}} + lambda("hello"); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'const char *')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<const char *>' requested here}} +} + +template <class... Args> void test_variadic_template_argument_count(Args... args) { + int result = __builtin_bitreverseg(args...); // #arg_use +} + +void test_variadic_template_args() { + test_variadic_template_argument_count(); + // expected-error@#arg_use {{too few arguments to function call, expected 1, have 0}} + // expected-note@-2 {{in instantiation of function template specialization 'test_variadic_template_argument_count<>' requested here}} + test_variadic_template_argument_count(1); + test_variadic_template_argument_count(1, 2); + // expected-error@#arg_use {{too many arguments to function call, expected 1, have 2}} + // expected-note@-2 {{in instantiation of function template specialization 'test_variadic_template_argument_count<int, int>' requested here}} +} + +void test_lvalue_reference(int& a) { + auto result = __builtin_bitreverseg(a); + static_assert(__is_same(int, decltype(result)), "Should decay reference to value type"); +} + +void test_const_lvalue_reference(const int& a) { + auto result = __builtin_bitreverseg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const reference to value type"); +} + +void test_rvalue_reference(int&& a) { + auto result = __builtin_bitreverseg(a); + static_assert(__is_same(int, decltype(result)), "Should decay rvalue reference to value type"); +} + +void test_const_rvalue_reference(const int&& a) { + auto result = __builtin_bitreverseg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const rvalue reference to value type"); +} + +void test_array() { + int arr[4] = {0x12, 0x34, 0x56, 0x78}; + __builtin_bitreverseg(arr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'int[4]')}} +} + +void test_pointer() { + int x = 0x12345678; + int *ptr = &x; + __builtin_bitreverseg(ptr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'int *')}} +} + +enum BasicEnum { + ENUM_VALUE1 = 0x1234, + ENUM_VALUE2 = 0x2C480000 +}; + +void test_enum() { + const BasicEnum e = ENUM_VALUE1; + static_assert(__builtin_bitreverseg(e) == ENUM_VALUE2, ""); +} + +class testClass { +public: + int value; + testClass(int v) : value(v) {} + + int getValue() { return value; } +}; + +void test_class() { + testClass c((int)0x12345678); + __builtin_bitreverseg(c); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'testClass')}} +} + +void test_nullptr() { + __builtin_bitreverseg(nullptr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'std::nullptr_t')}} +} + +void test_bitint() { + static_assert(__builtin_bitreverseg((_BitInt(8))0x12) == (_BitInt(8))0x48, ""); + static_assert(__builtin_bitreverseg((_BitInt(16))0x1234) == (_BitInt(16))0x2C48, ""); + static_assert(__builtin_bitreverseg((_BitInt(32))0x00001234) == (_BitInt(32))0x2C480000, ""); + static_assert(__builtin_bitreverseg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x2C48000000000000, ""); + static_assert(__builtin_bitreverseg((_BitInt(128))0x1) == ((_BitInt(128))1 << 127), ""); + static_assert(__builtin_bitreverseg((_BitInt(24))0x1234) == (_BitInt(24))0x2C4800, ""); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
