llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Sirui Mu (Lancern) <details> <summary>Changes</summary> This patch adds folders for the bit manipulation operations, namely: `clrsb`, `clz`, `ctz`, `parity`, `popcount`, `bitreverse`, `byte_swap`, and `rotate`. --- Full diff: https://github.com/llvm/llvm-project/pull/150235.diff 4 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+4) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+112) - (modified) clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp (+2-1) - (added) clang/test/CIR/Transforms/bit.cir (+129) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 694e3691c9361..8d5d34782c9a8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2773,6 +2773,8 @@ class CIR_BitOpBase<string mnemonic, TypeConstraint operandTy> let assemblyFormat = [{ $input `:` type($result) attr-dict }]; + + let hasFolder = 1; } class CIR_BitZeroCountOpBase<string mnemonic, TypeConstraint operandTy> @@ -2980,6 +2982,8 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> { bool isRotateLeft() { return getRotateLeft(); } bool isRotateRight() { return !getRotateLeft(); } }]; + + let hasFolder = 1; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index f0416b6aba6e4..8e13900043108 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -17,6 +17,7 @@ #include "mlir/Interfaces/ControlFlowInterfaces.h" #include "mlir/Interfaces/FunctionImplementation.h" +#include "mlir/Support/LLVM.h" #include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc" #include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc" @@ -2132,6 +2133,117 @@ LogicalResult cir::ComplexImagPtrOp::verify() { return success(); } +//===----------------------------------------------------------------------===// +// Bit manipulation operations +//===----------------------------------------------------------------------===// + +template <typename F> +static OpFoldResult foldUnaryBitOp(mlir::Attribute inputAttr, F func, + bool poisonZero = false) { + auto input = mlir::dyn_cast_if_present<IntAttr>(inputAttr); + if (!input) + return nullptr; + + llvm::APInt inputValue = input.getValue(); + if (poisonZero && inputValue.isZero()) { + // TODO(cir): maybe we should return a poison value here? + return nullptr; + } + + auto resultValue = func(inputValue); + if constexpr (std::is_integral_v<decltype(resultValue)>) + return IntAttr::get(input.getType(), resultValue); + else + return IntAttr::get(input.getContext(), input.getType(), resultValue); +} + +OpFoldResult BitClrsbOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + return inputValue.getBitWidth() - inputValue.getSignificantBits(); + }); +} + +OpFoldResult BitClzOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp( + adaptor.getInput(), + [](const llvm::APInt &inputValue) { + return inputValue.countLeadingZeros(); + }, + getPoisonZero()); +} + +OpFoldResult BitCtzOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp( + adaptor.getInput(), + [](const llvm::APInt &inputValue) { + return inputValue.countTrailingZeros(); + }, + getPoisonZero()); +} + +OpFoldResult BitParityOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + return inputValue.popcount() % 2; + }); +} + +OpFoldResult BitPopcountOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + return inputValue.popcount(); + }); +} + +OpFoldResult BitReverseOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + return inputValue.reverseBits(); + }); +} + +OpFoldResult ByteSwapOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + return inputValue.byteSwap(); + }); +} + +OpFoldResult RotateOp::fold(FoldAdaptor adaptor) { + auto input = mlir::dyn_cast_if_present<IntAttr>(adaptor.getInput()); + auto amount = mlir::dyn_cast_if_present<IntAttr>(adaptor.getAmount()); + if (!input && !amount) + return nullptr; + + llvm::APInt inputValue; + if (input) { + inputValue = input.getValue(); + if (inputValue.isZero() || inputValue.isAllOnes()) { + // An input value of all 0s or all 1s will not change after rotation + return input; + } + } + + uint64_t amountValue; + if (amount) { + amountValue = amount.getValue().urem(getInput().getType().getWidth()); + if (amountValue == 0) { + // A shift amount of 0 will not change the input value + return getInput(); + } + } + + if (!input || !amount) + return nullptr; + + assert(inputValue.getBitWidth() == getInput().getType().getWidth() && + "input value must have the same bit width as the input type"); + + llvm::APInt resultValue; + if (isRotateLeft()) + resultValue = inputValue.rotl(amountValue); + else + resultValue = inputValue.rotr(amountValue); + + return IntAttr::get(input.getContext(), input.getType(), resultValue); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp index e505db50d3609..2143f167ba2c8 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp @@ -143,7 +143,8 @@ void CIRCanonicalizePass::runOnOperation() { if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp, ComplexCreateOp, ComplexImagOp, ComplexRealOp, VecCmpOp, VecCreateOp, VecExtractOp, VecShuffleOp, VecShuffleDynamicOp, - VecTernaryOp>(op)) + VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp, BitParityOp, + BitPopcountOp, BitReverseOp, ByteSwapOp, RotateOp>(op)) ops.push_back(op); }); diff --git a/clang/test/CIR/Transforms/bit.cir b/clang/test/CIR/Transforms/bit.cir new file mode 100644 index 0000000000000..df804fbef8981 --- /dev/null +++ b/clang/test/CIR/Transforms/bit.cir @@ -0,0 +1,129 @@ +// RUN: cir-opt -cir-canonicalize -cir-simplify -o %t.cir %s +// RUN: FileCheck --input-file=%t.cir %s + +!s32i = !cir.int<s, 32> +!u32i = !cir.int<u, 32> + +module { + cir.func @fold_clrsb() -> !s32i { + %0 = cir.const #cir.int<114514> : !s32i + %1 = cir.clrsb %0 : !s32i + cir.return %1 : !s32i + } + // CHECK-LABEL: @fold_clrsb + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<14> : !s32i + // CHECK-NEXT: cir.return %[[R]] : !s32i + // CHECK-NEXT: } + + cir.func @fold_clz() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.clz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_clz + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<15> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_ctz() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.ctz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_ctz + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<1> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_parity() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.parity %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_parity + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<1> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_popcount() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.popcount %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_popcount + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<11> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_bitreverse() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.bitreverse %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_bitreverse + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<1258127360> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_byte_swap() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.byte_swap %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_byte_swap + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<1388249344> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_input_all_zeros(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.rotate left %0, %arg0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_input_all_zeros + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<0> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_input_all_ones(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.int<4294967295> : !u32i + %1 = cir.rotate left %0, %arg0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_input_all_ones + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4294967295> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_zero_amount(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.int<32> : !u32i + %1 = cir.rotate left %arg0, %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_zero_amount + // CHECK-SAME: (%[[R:.+]]: !u32i) + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_left() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.const #cir.int<7> : !u32i + %2 = cir.rotate left %0, %1 : !u32i + cir.return %2 : !u32i + } + // CHECK-LABEL: @fold_rotate_left + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<14657792> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_right() -> !u32i { + %0 = cir.const #cir.int<114514> : !u32i + %1 = cir.const #cir.int<7> : !u32i + %2 = cir.rotate right %0, %1 : !u32i + cir.return %2 : !u32i + } + // CHECK-LABEL: @fold_rotate_right + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<2751464318> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } +} `````````` </details> https://github.com/llvm/llvm-project/pull/150235 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits