[clang] Add __builtin_bitreverseg (PR #179126)
Simon Pilgrim via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 12 09:05:37 PST 2026
https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/179126
>From 19de62f54a5e374454aa05833a22ce2703e720d3 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
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 | 64 +++++
clang/test/CodeGenCXX/builtins.cpp | 56 +++++
clang/test/Sema/constant-builtins-2.c | 27 ++
clang/test/SemaCXX/builtin-bitreverseg.cpp | 233 ++++++++++++++++++
11 files changed, 462 insertions(+)
create mode 100644 clang/test/SemaCXX/builtin-bitreverseg.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 24d4e07ca68b3..02b1618dc7f28 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -126,6 +126,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 generic bit-reverse builtin function ``__builtin_bitreverseg`` 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 05e3af4a0e96f..d6a89c46bcf69 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 e47fc43ee8638..19fb522f5d390 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4288,6 +4288,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 ff433ed729a28..cc685fb16107e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16041,6 +16041,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 cf686581240a5..01346a4dd1f30 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3685,6 +3685,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 d1c46a875208a..7c74f59e85bf3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2288,6 +2288,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) {
@@ -3697,6 +3723,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 10f7ff294ae00..d293b133e42ef 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 at -1 {{constexpr variable 'result2' must be initialized by a constant expression}}
+ //expected-note at -2 {{initializer of 'ref' is not a constant expression}}
+ //expected-note@#declare_bitreverseg {{declared here}}
+ //ref-error at -4 {{constexpr variable 'result2' must be initialized by a constant expression}}
+ //ref-note at -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 0d0104515235c..6bb568fe61dc4 100644
--- a/clang/test/CodeGen/builtins.c
+++ b/clang/test/CodeGen/builtins.c
@@ -153,6 +153,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));
@@ -963,3 +974,56 @@ 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,
+ unsigned _BitInt(1) bi1,
+#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
+ bi1 = __builtin_bitreverseg(bi1);
+ // CHECK: %{{.*}} = load i8, ptr %bi1.addr
+ // CHECK: %{{.*}} = trunc i8 %{{.*}} to i1
+ // CHECK: %{{.*}} = zext i1 %{{.*}} to i8
+ // CHECK: store i8 %{{.*}}, ptr %bi1.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 ad0d06cdb2637..a6c4d6b7dedb1 100644
--- a/clang/test/CodeGenCXX/builtins.cpp
+++ b/clang/test/CodeGenCXX/builtins.cpp
@@ -150,3 +150,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 e875863e7fa91..bb005981b6daf 100644
--- a/clang/test/Sema/constant-builtins-2.c
+++ b/clang/test/Sema/constant-builtins-2.c
@@ -502,6 +502,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 at -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..cacfe4f7b4456
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-bitreverseg.cpp
@@ -0,0 +1,233 @@
+// 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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -1 {{1st argument must be a scalar integer type (was 'testClass')}}
+}
+
+void test_nullptr() {
+ __builtin_bitreverseg(nullptr);
+ // expected-error at -1 {{1st argument must be a scalar integer type (was 'std::nullptr_t')}}
+}
+
+void test_bitint() {
+ static_assert(__builtin_bitreverseg((unsigned _BitInt(1))1) == (unsigned _BitInt(1))1, "");
+ 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, "");
+}
More information about the cfe-commits
mailing list