[clang] [CIR] Add folders for bit manipulation operations (PR #150235)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 24 08:06:38 PDT 2025
================
@@ -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
More information about the cfe-commits
mailing list