Skip to content

Commit

Permalink
[CIR] Add support for byteswap intrinsic (#523)
Browse files Browse the repository at this point in the history
This PR adds support for the following intrinsic functions:
- `__builtin_bswap{16, 32, 64}`
- `_byteswap_{ushort, ulong, uint64}`

This PR adds a new `cir.bswap` operation to represent such an intrinsic
call. CIRGen and LLVMIR lowering for the new operation is included in
this PR.
  • Loading branch information
Lancern authored and lanza committed Apr 6, 2024
1 parent e58a597 commit 84851f8
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 1 deletion.
34 changes: 34 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,40 @@ def BitPopcountOp : CIR_BitOp<"bit.popcount", UIntOfWidths<[16, 32, 64]>> {
}];
}

//===----------------------------------------------------------------------===//
// ByteswapOp
//===----------------------------------------------------------------------===//

def ByteswapOp : CIR_Op<"bswap", [Pure, SameOperandsAndResultType]> {
let summary = "Reverse the bytes that constitute the operand integer";
let description = [{
The `cir.bswap` operation takes an integer as operand, and returns it with
the order of bytes that constitute the operand reversed.

The operand integer must be an unsigned integer. Its widths must be either
16, 32, or 64.

Example:

```mlir
!u32i = !cir.int<u, 32>

// %0 = 0x12345678
%0 = cir.const(#cir.int<305419896> : !u32i) : !u32i

// %1 should be 0x78563412
%1 = cir.bswap(%0 : !u32i) : !u32i
```
}];

let results = (outs CIR_IntType:$result);
let arguments = (ins UIntOfWidths<[16, 32, 64]>:$input);

let assemblyFormat = [{
`(` $input `:` type($input) `)` `:` type($result) attr-dict
}];
}

//===----------------------------------------------------------------------===//
// CmpThreeWayOp
//===----------------------------------------------------------------------===//
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,17 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_popcountll:
return buildBuiltinBitOp<mlir::cir::BitPopcountOp>(*this, E, std::nullopt);

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: {
auto arg = buildScalarExpr(E->getArg(0));
return RValue::get(builder.create<mlir::cir::ByteswapOp>(
getLoc(E->getSourceRange()), arg));
}

case Builtin::BI__builtin_constant_p: {
mlir::Type ResultType = ConvertType(E->getType());

Expand Down
28 changes: 27 additions & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,32 @@ class CIRAtomicFetchLowering
}
};

class CIRByteswapOpLowering
: public mlir::OpConversionPattern<mlir::cir::ByteswapOp> {
public:
using OpConversionPattern<mlir::cir::ByteswapOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(mlir::cir::ByteswapOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
// Note that LLVM intrinsic calls to @llvm.bswap.i* have the same type as
// the operand.

auto resTy =
getTypeConverter()->convertType(op.getType()).cast<mlir::IntegerType>();

std::string llvmIntrinName = "llvm.bswap.i";
llvmIntrinName.append(std::to_string(resTy.getWidth()));
auto llvmIntrinNameAttr =
mlir::StringAttr::get(rewriter.getContext(), llvmIntrinName);

rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
op, resTy, llvmIntrinNameAttr, adaptor.getInput());

return mlir::LogicalResult::success();
}
};

class CIRBrOpLowering : public mlir::OpConversionPattern<mlir::cir::BrOp> {
public:
using OpConversionPattern<mlir::cir::BrOp>::OpConversionPattern;
Expand Down Expand Up @@ -2903,7 +2929,7 @@ void populateCIRToLLVMConversionPatterns(mlir::RewritePatternSet &patterns,
patterns.add<
CIRCmpOpLowering, CIRBitClrsbOpLowering, CIRBitClzOpLowering,
CIRBitCtzOpLowering, CIRBitFfsOpLowering, CIRBitParityOpLowering,
CIRBitPopcountOpLowering, CIRAtomicFetchLowering,
CIRBitPopcountOpLowering, CIRAtomicFetchLowering, CIRByteswapOpLowering,
CIRLoopOpInterfaceLowering, CIRBrCondOpLowering, CIRPtrStrideOpLowering,
CIRCallLowering, CIRUnaryOpLowering, CIRBinOpLowering, CIRShiftOpLowering,
CIRLoadLowering, CIRConstantLowering, CIRStoreLowering, CIRAllocaLowering,
Expand Down
30 changes: 30 additions & 0 deletions clang/test/CIR/CodeGen/bswap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s

using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;

u16 bswap_u16(u16 x) {
return __builtin_bswap16(x);
}

// CHECK: cir.func @_Z9bswap_u16t
// CHECK: %{{.+}} = cir.bswap(%{{.+}} : !u16i) : !u16i
// CHECK: }

u32 bswap_u32(u32 x) {
return __builtin_bswap32(x);
}

// CHECK: cir.func @_Z9bswap_u32j
// CHECK: %{{.+}} = cir.bswap(%{{.+}} : !u32i) : !u32i
// CHECK: }

u64 bswap_u64(u64 x) {
return __builtin_bswap64(x);
}

// CHECK: cir.func @_Z9bswap_u64y
// CHECK: %{{.+}} = cir.bswap(%{{.+}} : !u64i) : !u64i
// CHECK: }
19 changes: 19 additions & 0 deletions clang/test/CIR/Lowering/bswap.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR
// RUN: cir-translate %s -cir-to-llvmir | FileCheck %s -check-prefix=LLVM

!u32i = !cir.int<u, 32>

cir.func @test(%arg0: !u32i) -> !u32i {
%0 = cir.bswap(%arg0 : !u32i) : !u32i
cir.return %0 : !u32i
}

// MLIR: llvm.func @test(%arg0: i32) -> i32
// MLIR-NEXT: %0 = llvm.call_intrinsic "llvm.bswap.i32"(%arg0) : (i32) -> i32
// MLIR-NEXT: llvm.return %0 : i32
// MLIR-NEXT: }

// LLVM: define i32 @test(i32 %0)
// LLVM-NEXT: %2 = call i32 @llvm.bswap.i32(i32 %0)
// LLVM-NEXT: ret i32 %2
// LLVM-NEXT: }

0 comments on commit 84851f8

Please sign in to comment.