[clang] 265fb36 - [CIR] Add bit reverse and byte reverse operations (#147200)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 11 21:15:40 PDT 2025
Author: Sirui Mu
Date: 2025-07-12T12:15:36+08:00
New Revision: 265fb3605d1d070a004fd4d9db54ad2ae6f722c7
URL: https://github.com/llvm/llvm-project/commit/265fb3605d1d070a004fd4d9db54ad2ae6f722c7
DIFF: https://github.com/llvm/llvm-project/commit/265fb3605d1d070a004fd4d9db54ad2ae6f722c7.diff
LOG: [CIR] Add bit reverse and byte reverse operations (#147200)
This patch adds support for the following two builtin functions:
- `__builtin_bswap`, represented by the `cir.byte_swap` operation.
- `__builtin_bitreverse`, represented by the `cir.bit.reverse`
operation.
Added:
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
clang/test/CIR/CodeGen/builtin_bit.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 99fcb322a42d5..8058e74968499 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2808,6 +2808,45 @@ def BitPopcountOp : CIR_BitOpBase<"bit.popcnt",
}];
}
+def BitReverseOp : CIR_BitOpBase<"bit.reverse",
+ CIR_UIntOfWidths<[8, 16, 32, 64]>> {
+ let summary = "Reverse the bit pattern of the operand integer";
+ let description = [{
+ The `cir.bit.reverse` operation reverses the bits of the operand integer.
+ Its only argument must be of unsigned integer types of width 8, 16, 32, or
+ 64.
+
+ This operation covers the C/C++ builtin function `__builtin_bitreverse`.
+
+ Example:
+
+ ```mlir
+ %1 = cir.bit.reverse(%0 : !u32i): !u32i
+ ```
+ }];
+}
+
+def ByteSwapOp : CIR_BitOpBase<"byte_swap", CIR_UIntOfWidths<[16, 32, 64]>> {
+ let summary = "Reverse the bytes in the object representation of the operand";
+ let description = [{
+ The `cir.byte_swap` operation takes an integer as operand, reverse the bytes
+ in the object representation of the operand integer, and returns the result.
+
+ The operand integer must be an unsigned integer. Its widths must be either
+ 16, 32, or 64.
+
+ Example:
+
+ ```mlir
+ // %0 = 0x12345678
+ %0 = cir.const #cir.int<305419896> : !u32i
+
+ // %1 should be 0x78563412
+ %1 = cir.byte_swap(%0 : !u32i) : !u32i
+ ```
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Assume Operations
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index c65873209c31d..72e8d71c366d8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -60,15 +60,15 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
+ mlir::Location loc = getLoc(e->getSourceRange());
+
// See if we can constant fold this builtin. If so, don't emit it at all.
// TODO: Extend this handling to all builtin calls that we can constant-fold.
Expr::EvalResult result;
if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) &&
!result.hasSideEffects()) {
- if (result.Val.isInt()) {
- return RValue::get(builder.getConstInt(getLoc(e->getSourceRange()),
- result.Val.getInt()));
- }
+ if (result.Val.isInt())
+ return RValue::get(builder.getConstInt(loc, result.Val.getInt()));
if (result.Val.isFloat()) {
// Note: we are using result type of CallExpr to determine the type of
// the constant. Classic codegen uses the result value to determine the
@@ -76,8 +76,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
// hard to imagine a builtin function evaluates to a value that
// over/underflows its own defined type.
mlir::Type type = convertType(e->getType());
- return RValue::get(builder.getConstFP(getLoc(e->getExprLoc()), type,
- result.Val.getFloat()));
+ return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat()));
}
}
@@ -94,8 +93,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
assert(!cir::MissingFeatures::builtinCallMathErrno());
assert(!cir::MissingFeatures::builtinCall());
- mlir::Location loc = getLoc(e->getExprLoc());
-
switch (builtinIDIfNoAsmLabel) {
default:
break;
@@ -200,11 +197,28 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
probability);
}
- auto result = builder.create<cir::ExpectOp>(getLoc(e->getSourceRange()),
- argValue.getType(), argValue,
- expectedValue, probAttr);
+ auto result = builder.create<cir::ExpectOp>(
+ loc, argValue.getType(), argValue, expectedValue, probAttr);
return RValue::get(result);
}
+
+ case Builtin::BI__builtin_bswap16:
+ case Builtin::BI__builtin_bswap32:
+ case Builtin::BI__builtin_bswap64:
+ case Builtin::BI_byteswap_ushort:
+ case Builtin::BI_byteswap_ulong:
+ case Builtin::BI_byteswap_uint64: {
+ mlir::Value arg = emitScalarExpr(e->getArg(0));
+ return RValue::get(builder.create<cir::ByteSwapOp>(loc, arg));
+ }
+
+ case Builtin::BI__builtin_bitreverse8:
+ case Builtin::BI__builtin_bitreverse16:
+ case Builtin::BI__builtin_bitreverse32:
+ case Builtin::BI__builtin_bitreverse64: {
+ mlir::Value arg = emitScalarExpr(e->getArg(0));
+ return RValue::get(builder.create<cir::BitReverseOp>(loc, arg));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 3446265769a2c..424ff969b3fd4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -535,6 +535,13 @@ mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(
return mlir::LogicalResult::success();
}
+mlir::LogicalResult CIRToLLVMBitReverseOpLowering::matchAndRewrite(
+ cir::BitReverseOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::BitReverseOp>(op, adaptor.getInput());
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
cir::BrCondOp brOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -551,6 +558,13 @@ mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMByteSwapOpLowering::matchAndRewrite(
+ cir::ByteSwapOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ByteSwapOp>(op, adaptor.getInput());
+ return mlir::LogicalResult::success();
+}
+
mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {
return getTypeConverter()->convertType(ty);
}
@@ -2044,8 +2058,10 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMBitCtzOpLowering,
CIRToLLVMBitParityOpLowering,
CIRToLLVMBitPopcountOpLowering,
+ CIRToLLVMBitReverseOpLowering,
CIRToLLVMBrCondOpLowering,
CIRToLLVMBrOpLowering,
+ CIRToLLVMByteSwapOpLowering,
CIRToLLVMCallOpLowering,
CIRToLLVMCmpOpLowering,
CIRToLLVMComplexAddOpLowering,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index ed158eb7289dd..1716015a75882 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -94,6 +94,16 @@ class CIRToLLVMBitPopcountOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMBitReverseOpLowering
+ : public mlir::OpConversionPattern<cir::BitReverseOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitReverseOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitReverseOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMBrCondOpLowering
: public mlir::OpConversionPattern<cir::BrCondOp> {
public:
@@ -104,6 +114,16 @@ class CIRToLLVMBrCondOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMByteSwapOpLowering
+ : public mlir::OpConversionPattern<cir::ByteSwapOp> {
+public:
+ using mlir::OpConversionPattern<cir::ByteSwapOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ByteSwapOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
mlir::DataLayout const &dataLayout;
diff --git a/clang/test/CIR/CodeGen/builtin_bit.cpp b/clang/test/CIR/CodeGen/builtin_bit.cpp
index ba56c91ce7401..8ea7a69b3dd2a 100644
--- a/clang/test/CIR/CodeGen/builtin_bit.cpp
+++ b/clang/test/CIR/CodeGen/builtin_bit.cpp
@@ -325,3 +325,94 @@ int test_builtin_popcountg(unsigned x) {
// OGCG-LABEL: _Z22test_builtin_popcountgj
// OGCG: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})
+
+unsigned char test_builtin_bitreverse8(unsigned char x) {
+ return __builtin_bitreverse8(x);
+}
+
+// CIR-LABEL: @_Z24test_builtin_bitreverse8h
+// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u8i) : !u8i
+
+// LLVM-LABEL: @_Z24test_builtin_bitreverse8h
+// LLVM: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}})
+
+// OGCG-LABEL: @_Z24test_builtin_bitreverse8h
+// OGCG: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}})
+
+unsigned short test_builtin_bitreverse16(unsigned short x) {
+ return __builtin_bitreverse16(x);
+}
+
+// CIR-LABEL: @_Z25test_builtin_bitreverse16t
+// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u16i) : !u16i
+
+// LLVM-LABEL: @_Z25test_builtin_bitreverse16t
+// LLVM: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}})
+
+// OGCG-LABEL: @_Z25test_builtin_bitreverse16t
+// OGCG: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}})
+
+unsigned test_builtin_bitreverse32(unsigned x) {
+ return __builtin_bitreverse32(x);
+}
+
+// CIR-LABEL: @_Z25test_builtin_bitreverse32j
+// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u32i) : !u32i
+
+// LLVM-LABEL: @_Z25test_builtin_bitreverse32j
+// LLVM: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}})
+
+// OGCG-LABEL: @_Z25test_builtin_bitreverse32j
+// OGCG: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}})
+
+unsigned long long test_builtin_bitreverse64(unsigned long long x) {
+ return __builtin_bitreverse64(x);
+}
+
+// CIR-LABEL: @_Z25test_builtin_bitreverse64y
+// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u64i) : !u64i
+
+// LLVM-LABEL: @_Z25test_builtin_bitreverse64y
+// LLVM: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}})
+
+// OGCG-LABEL: @_Z25test_builtin_bitreverse64y
+// OGCG: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}})
+
+unsigned short test_builtin_bswap16(unsigned short x) {
+ return __builtin_bswap16(x);
+}
+
+// CIR-LABEL: @_Z20test_builtin_bswap16t
+// CIR: %{{.+}} = cir.byte_swap(%{{.+}} : !u16i) : !u16i
+
+// LLVM-LABEL: @_Z20test_builtin_bswap16t
+// LLVM: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}})
+
+// OGCG-LABEL: @_Z20test_builtin_bswap16t
+// OGCG: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}})
+
+unsigned test_builtin_bswap32(unsigned x) {
+ return __builtin_bswap32(x);
+}
+
+// CIR-LABEL: @_Z20test_builtin_bswap32j
+// CIR: %{{.+}} = cir.byte_swap(%{{.+}} : !u32i) : !u32i
+
+// LLVM-LABEL: @_Z20test_builtin_bswap32j
+// LLVM: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}})
+
+// OGCG-LABEL: @_Z20test_builtin_bswap32j
+// OGCG: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}})
+
+unsigned long long test_builtin_bswap64(unsigned long long x) {
+ return __builtin_bswap64(x);
+}
+
+// CIR-LABEL: @_Z20test_builtin_bswap64y
+// CIR: %{{.+}} = cir.byte_swap(%{{.+}} : !u64i) : !u64i
+
+// LLVM-LABEL: @_Z20test_builtin_bswap64y
+// LLVM: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}})
+
+// OGCG-LABEL: @_Z20test_builtin_bswap64y
+// OGCG: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}})
More information about the cfe-commits
mailing list