================
@@ -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

Reply via email to