[clang] Add __builtin_bitreverseg (PR #179126)
Madhur Kumar via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 1 10:34:06 PST 2026
https://github.com/MadhurKumar004 created https://github.com/llvm/llvm-project/pull/179126
None
>From 5f50666196c5e121f66cd34163b555fa325790a6 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
Date: Mon, 2 Feb 2026 00:03:08 +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 | 9 +++
clang/lib/Sema/SemaChecking.cpp | 30 ++++++++++
clang/test/AST/ByteCode/builtin-functions.cpp | 30 ++++++++++
clang/test/CodeGen/builtins.c | 58 +++++++++++++++++++
8 files changed, 139 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fe573afc99422..342dd91d7cdc3 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..340b00832b511 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3683,6 +3683,15 @@ 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..86b1c7adc321e 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.DefaultFunctionArrayLvalueConversion(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*/ 0<< /*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..49757e6c1222c 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 bitreverseg_char[(char)__builtin_bitreverseg((char)0x01) == (char)0x80 ? 1 : -1];
+ char bitreverseg_short[(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 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
+}
More information about the cfe-commits
mailing list