================ @@ -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()) { ---------------- Lancern wrote:
I'm not sure I get your point, but the idea here is that we could fold `cir.rotate` away even if one of its two operands is not a constant: - `cir.rotate left %0, 0` could be folded into simply `%0` even if `%0` is not a constant. - `cir.rotate left 0, %0` could be folded into constant 0 even if `%0` is not a constant. The two branches here are specifically dealing with such cases where only `input` or `amount` is a constant known at compile time. The invocation to `APInt::rotl` and `APInt::rotr` later is dealing with the case where both of `input` and `amount` are constants. 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