Skip to content

Commit 2dc9775

Browse files
committed
[CIR] Add bit reverse and byte reverse operations
1 parent ba7d78a commit 2dc9775

File tree

5 files changed

+201
-11
lines changed

5 files changed

+201
-11
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,6 +2661,55 @@ def BitPopcountOp : CIR_BitOpBase<"bit.popcnt",
26612661
}];
26622662
}
26632663

2664+
def BitReverseOp : CIR_BitOpBase<"bit.reverse", CIR_UIntOfWidths<[8, 16, 32, 64]>> {
2665+
let summary = "Reverse the bit pattern of the operand integer";
2666+
let description = [{
2667+
The `cir.bit.reverse` operation reverses the bits of the operand integer.
2668+
Its only argument must be of unsigned integer types of width 8, 16, 32, or
2669+
64.
2670+
2671+
This operation covers the C/C++ builtin function `__builtin_bitreverse`.
2672+
2673+
Example:
2674+
2675+
```mlir
2676+
%1 = cir.bit.reverse(%0 : !u32i): !u32i
2677+
```
2678+
}];
2679+
}
2680+
2681+
//===----------------------------------------------------------------------===//
2682+
// ByteSwapOp
2683+
//===----------------------------------------------------------------------===//
2684+
2685+
def ByteSwapOp : CIR_Op<"bswap", [Pure, SameOperandsAndResultType]> {
2686+
let summary = "Reverse the bytes in the object representation of the operand";
2687+
let description = [{
2688+
The `cir.bswap` operation takes an integer as operand, reverse the bytes in
2689+
the object representation of the operand integer, and returns the result.
2690+
2691+
The operand integer must be an unsigned integer. Its widths must be either
2692+
16, 32, or 64.
2693+
2694+
Example:
2695+
2696+
```mlir
2697+
// %0 = 0x12345678
2698+
%0 = cir.const #cir.int<305419896> : !u32i
2699+
2700+
// %1 should be 0x78563412
2701+
%1 = cir.bswap(%0 : !u32i) : !u32i
2702+
```
2703+
}];
2704+
2705+
let results = (outs CIR_IntType:$result);
2706+
let arguments = (ins CIR_UIntOfWidths<[16, 32, 64]>:$input);
2707+
2708+
let assemblyFormat = [{
2709+
`(` $input `:` type($input) `)` `:` type($result) attr-dict
2710+
}];
2711+
}
2712+
26642713
//===----------------------------------------------------------------------===//
26652714
// Assume Operations
26662715
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,23 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
6060
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
6161
const CallExpr *e,
6262
ReturnValueSlot returnValue) {
63+
mlir::Location loc = getLoc(e->getSourceRange());
64+
6365
// See if we can constant fold this builtin. If so, don't emit it at all.
6466
// TODO: Extend this handling to all builtin calls that we can constant-fold.
6567
Expr::EvalResult result;
6668
if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) &&
6769
!result.hasSideEffects()) {
68-
if (result.Val.isInt()) {
69-
return RValue::get(builder.getConstInt(getLoc(e->getSourceRange()),
70-
result.Val.getInt()));
71-
}
70+
if (result.Val.isInt())
71+
return RValue::get(builder.getConstInt(loc, result.Val.getInt()));
7272
if (result.Val.isFloat()) {
7373
// Note: we are using result type of CallExpr to determine the type of
7474
// the constant. Classic codegen uses the result value to determine the
7575
// type. We feel it should be Ok to use expression type because it is
7676
// hard to imagine a builtin function evaluates to a value that
7777
// over/underflows its own defined type.
7878
mlir::Type type = convertType(e->getType());
79-
return RValue::get(builder.getConstFP(getLoc(e->getExprLoc()), type,
80-
result.Val.getFloat()));
79+
return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat()));
8180
}
8281
}
8382

@@ -101,8 +100,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
101100
assert(!cir::MissingFeatures::builtinCallMathErrno());
102101
assert(!cir::MissingFeatures::builtinCall());
103102

104-
mlir::Location loc = getLoc(e->getExprLoc());
105-
106103
switch (builtinIDIfNoAsmLabel) {
107104
default:
108105
break;
@@ -185,11 +182,28 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
185182
probability);
186183
}
187184

188-
auto result = builder.create<cir::ExpectOp>(getLoc(e->getSourceRange()),
189-
argValue.getType(), argValue,
190-
expectedValue, probAttr);
185+
auto result = builder.create<cir::ExpectOp>(
186+
loc, argValue.getType(), argValue, expectedValue, probAttr);
191187
return RValue::get(result);
192188
}
189+
190+
case Builtin::BI__builtin_bswap16:
191+
case Builtin::BI__builtin_bswap32:
192+
case Builtin::BI__builtin_bswap64:
193+
case Builtin::BI_byteswap_ushort:
194+
case Builtin::BI_byteswap_ulong:
195+
case Builtin::BI_byteswap_uint64: {
196+
mlir::Value arg = emitScalarExpr(e->getArg(0));
197+
return RValue::get(builder.create<cir::ByteSwapOp>(loc, arg));
198+
}
199+
200+
case Builtin::BI__builtin_bitreverse8:
201+
case Builtin::BI__builtin_bitreverse16:
202+
case Builtin::BI__builtin_bitreverse32:
203+
case Builtin::BI__builtin_bitreverse64: {
204+
mlir::Value arg = emitScalarExpr(e->getArg(0));
205+
return RValue::get(builder.create<cir::BitReverseOp>(loc, arg));
206+
}
193207
}
194208

195209
cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call");

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,13 @@ mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(
535535
return mlir::LogicalResult::success();
536536
}
537537

538+
mlir::LogicalResult CIRToLLVMBitReverseOpLowering::matchAndRewrite(
539+
cir::BitReverseOp op, OpAdaptor adaptor,
540+
mlir::ConversionPatternRewriter &rewriter) const {
541+
rewriter.replaceOpWithNewOp<mlir::LLVM::BitReverseOp>(op, adaptor.getInput());
542+
return mlir::success();
543+
}
544+
538545
mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
539546
cir::BrCondOp brOp, OpAdaptor adaptor,
540547
mlir::ConversionPatternRewriter &rewriter) const {
@@ -551,6 +558,13 @@ mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
551558
return mlir::success();
552559
}
553560

561+
mlir::LogicalResult CIRToLLVMByteSwapOpLowering::matchAndRewrite(
562+
cir::ByteSwapOp op, OpAdaptor adaptor,
563+
mlir::ConversionPatternRewriter &rewriter) const {
564+
rewriter.replaceOpWithNewOp<mlir::LLVM::ByteSwapOp>(op, adaptor.getInput());
565+
return mlir::LogicalResult::success();
566+
}
567+
554568
mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {
555569
return getTypeConverter()->convertType(ty);
556570
}
@@ -2035,8 +2049,10 @@ void ConvertCIRToLLVMPass::runOnOperation() {
20352049
CIRToLLVMBitCtzOpLowering,
20362050
CIRToLLVMBitParityOpLowering,
20372051
CIRToLLVMBitPopcountOpLowering,
2052+
CIRToLLVMBitReverseOpLowering,
20382053
CIRToLLVMBrCondOpLowering,
20392054
CIRToLLVMBrOpLowering,
2055+
CIRToLLVMByteSwapOpLowering,
20402056
CIRToLLVMCallOpLowering,
20412057
CIRToLLVMCmpOpLowering,
20422058
CIRToLLVMComplexCreateOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ class CIRToLLVMBitPopcountOpLowering
9494
mlir::ConversionPatternRewriter &) const override;
9595
};
9696

97+
class CIRToLLVMBitReverseOpLowering
98+
: public mlir::OpConversionPattern<cir::BitReverseOp> {
99+
public:
100+
using mlir::OpConversionPattern<cir::BitReverseOp>::OpConversionPattern;
101+
102+
mlir::LogicalResult
103+
matchAndRewrite(cir::BitReverseOp op, OpAdaptor,
104+
mlir::ConversionPatternRewriter &) const override;
105+
};
106+
97107
class CIRToLLVMBrCondOpLowering
98108
: public mlir::OpConversionPattern<cir::BrCondOp> {
99109
public:
@@ -104,6 +114,16 @@ class CIRToLLVMBrCondOpLowering
104114
mlir::ConversionPatternRewriter &) const override;
105115
};
106116

117+
class CIRToLLVMByteSwapOpLowering
118+
: public mlir::OpConversionPattern<cir::ByteSwapOp> {
119+
public:
120+
using mlir::OpConversionPattern<cir::ByteSwapOp>::OpConversionPattern;
121+
122+
mlir::LogicalResult
123+
matchAndRewrite(cir::ByteSwapOp op, OpAdaptor,
124+
mlir::ConversionPatternRewriter &) const override;
125+
};
126+
107127
class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
108128
mlir::DataLayout const &dataLayout;
109129

clang/test/CIR/CodeGen/builtin_bit.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,94 @@ int test_builtin_popcountg(unsigned x) {
325325

326326
// OGCG-LABEL: _Z22test_builtin_popcountgj
327327
// OGCG: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})
328+
329+
unsigned char test_builtin_bitreverse8(unsigned char x) {
330+
return __builtin_bitreverse8(x);
331+
}
332+
333+
// CIR-LABEL: @_Z24test_builtin_bitreverse8h
334+
// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u8i) : !u8i
335+
336+
// LLVM-LABEL: @_Z24test_builtin_bitreverse8h
337+
// LLVM: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}})
338+
339+
// OGCG-LABEL: @_Z24test_builtin_bitreverse8h
340+
// OGCG: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}})
341+
342+
unsigned short test_builtin_bitreverse16(unsigned short x) {
343+
return __builtin_bitreverse16(x);
344+
}
345+
346+
// CIR-LABEL: @_Z25test_builtin_bitreverse16t
347+
// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u16i) : !u16i
348+
349+
// LLVM-LABEL: @_Z25test_builtin_bitreverse16t
350+
// LLVM: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}})
351+
352+
// OGCG-LABEL: @_Z25test_builtin_bitreverse16t
353+
// OGCG: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}})
354+
355+
unsigned test_builtin_bitreverse32(unsigned x) {
356+
return __builtin_bitreverse32(x);
357+
}
358+
359+
// CIR-LABEL: @_Z25test_builtin_bitreverse32j
360+
// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u32i) : !u32i
361+
362+
// LLVM-LABEL: @_Z25test_builtin_bitreverse32j
363+
// LLVM: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}})
364+
365+
// OGCG-LABEL: @_Z25test_builtin_bitreverse32j
366+
// OGCG: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}})
367+
368+
unsigned long long test_builtin_bitreverse64(unsigned long long x) {
369+
return __builtin_bitreverse64(x);
370+
}
371+
372+
// CIR-LABEL: @_Z25test_builtin_bitreverse64y
373+
// CIR: %{{.+}} = cir.bit.reverse(%{{.+}} : !u64i) : !u64i
374+
375+
// LLVM-LABEL: @_Z25test_builtin_bitreverse64y
376+
// LLVM: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}})
377+
378+
// OGCG-LABEL: @_Z25test_builtin_bitreverse64y
379+
// OGCG: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}})
380+
381+
unsigned short test_builtin_bswap16(unsigned short x) {
382+
return __builtin_bswap16(x);
383+
}
384+
385+
// CIR-LABEL: @_Z20test_builtin_bswap16t
386+
// CIR: %{{.+}} = cir.bswap(%{{.+}} : !u16i) : !u16i
387+
388+
// LLVM-LABEL: @_Z20test_builtin_bswap16t
389+
// LLVM: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}})
390+
391+
// OGCG-LABEL: @_Z20test_builtin_bswap16t
392+
// OGCG: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}})
393+
394+
unsigned test_builtin_bswap32(unsigned x) {
395+
return __builtin_bswap32(x);
396+
}
397+
398+
// CIR-LABEL: @_Z20test_builtin_bswap32j
399+
// CIR: %{{.+}} = cir.bswap(%{{.+}} : !u32i) : !u32i
400+
401+
// LLVM-LABEL: @_Z20test_builtin_bswap32j
402+
// LLVM: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}})
403+
404+
// OGCG-LABEL: @_Z20test_builtin_bswap32j
405+
// OGCG: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}})
406+
407+
unsigned long long test_builtin_bswap64(unsigned long long x) {
408+
return __builtin_bswap64(x);
409+
}
410+
411+
// CIR-LABEL: @_Z20test_builtin_bswap64y
412+
// CIR: %{{.+}} = cir.bswap(%{{.+}} : !u64i) : !u64i
413+
414+
// LLVM-LABEL: @_Z20test_builtin_bswap64y
415+
// LLVM: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}})
416+
417+
// OGCG-LABEL: @_Z20test_builtin_bswap64y
418+
// OGCG: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}})

0 commit comments

Comments
 (0)