[Mlir-commits] [mlir] [mlir][scf] Revisit affected loops during range folding (PR #230961)

Ivan Butygin llvmlistbot at llvm.org
Sun Oct 11 09:59:07 PDT 2026


================
@@ -28,86 +30,95 @@ using namespace mlir;
 using namespace mlir::scf;
 
 namespace {
-struct ForLoopRangeFolding
-    : public impl::SCFForLoopRangeFoldingBase<ForLoopRangeFolding> {
-  void runOnOperation() override;
-};
-} // namespace
+struct ForLoopRangeFoldingPattern : public OpRewritePattern<ForOp> {
+  using OpRewritePattern<ForOp>::OpRewritePattern;
 
-void ForLoopRangeFolding::runOnOperation() {
-  getOperation()->walk([&](ForOp op) {
+  void initialize() { setHasBoundedRewriteRecursion(); }
+
+  LogicalResult matchAndRewrite(ForOp op,
+                                PatternRewriter &rewriter) const override {
     Value indVar = op.getInductionVar();
 
     auto canBeFolded = [&](Value value) {
       return op.isDefinedOutsideOfLoop(value) || value == indVar;
     };
 
-    // Fold until a fixed point is reached
-    while (true) {
-
-      // If the induction variable is used by more than one operation, we can't
-      // fold its arith ops into the loop range. Note that a single operation
-      // may use the induction variable several times (e.g. `arith.addi %i,
-      // %i`), so check for a single user rather than a single use.
-      if (indVar.use_empty())
-        break;
-
-      Operation *user = *indVar.getUsers().begin();
-      if (!llvm::all_of(indVar.getUsers(),
-                        [&](Operation *u) { return u == user; }))
-        break;
-
-      if (!isa<arith::AddIOp, arith::MulIOp>(user))
-        break;
-
-      if (!llvm::all_of(user->getOperands(), canBeFolded))
-        break;
-
-      OpBuilder b(op);
-      IRMapping lbMap;
-      lbMap.map(indVar, op.getLowerBound());
-      IRMapping ubMap;
-      ubMap.map(indVar, op.getUpperBound());
-      IRMapping stepMap;
-      stepMap.map(indVar, op.getStep());
-
-      if (auto addOp = dyn_cast<arith::AddIOp>(user)) {
-        Operation *lbFold = b.clone(*user, lbMap);
-        Operation *ubFold = b.clone(*user, ubMap);
-
-        op.setLowerBound(lbFold->getResult(0));
-        op.setUpperBound(ubFold->getResult(0));
-
-        // `arith.addi %i, %i` is `2 * %i`, so the step has to be doubled too.
-        if (addOp.getLhs() == indVar && addOp.getRhs() == indVar) {
-          Operation *stepFold = b.clone(*user, stepMap);
-          op.setStep(stepFold->getResult(0));
-        }
-
-      } else if (auto mulOp = dyn_cast<arith::MulIOp>(user)) {
-        // Only fold if the multiplier is a known strictly positive constant.
-        // Multiplying by zero or a negative value would produce an invalid
-        // step (scf.for requires a strictly positive step).
-        Value multiplier =
-            (mulOp.getLhs() == indVar) ? mulOp.getRhs() : mulOp.getLhs();
-        std::optional<int64_t> multiplierVal = getConstantIntValue(multiplier);
-        if (!multiplierVal || *multiplierVal <= 0)
-          break;
-
-        Operation *lbFold = b.clone(*user, lbMap);
-        Operation *ubFold = b.clone(*user, ubMap);
-        Operation *stepFold = b.clone(*user, stepMap);
-
-        op.setLowerBound(lbFold->getResult(0));
-        op.setUpperBound(ubFold->getResult(0));
-        op.setStep(stepFold->getResult(0));
-      }
+    // If the induction variable is used by more than one operation, we can't
+    // fold its arith ops into the loop range. Note that a single operation
+    // may use the induction variable several times (e.g. `arith.addi %i,
+    // %i`), so check for a single user rather than a single use.
+    if (indVar.use_empty())
+      return failure();
+
+    Operation *user = *indVar.getUsers().begin();
+    if (!llvm::all_of(indVar.getUsers(),
+                      [&](Operation *u) { return u == user; }))
+      return failure();
+
+    if (!isa<arith::AddIOp, arith::MulIOp>(user))
+      return failure();
+
+    if (!llvm::all_of(user->getOperands(), canBeFolded))
+      return failure();
+
+    if (auto mulOp = dyn_cast<arith::MulIOp>(user)) {
+      // Only fold if the multiplier is a known strictly positive constant.
+      // Multiplying by zero or a negative value would produce an invalid
+      // step (scf.for requires a strictly positive step).
+      Value multiplier =
+          (mulOp.getLhs() == indVar) ? mulOp.getRhs() : mulOp.getLhs();
+      std::optional<int64_t> multiplierVal = getConstantIntValue(multiplier);
+      if (!multiplierVal || *multiplierVal <= 0)
+        return failure();
+    }
 
-      ValueRange wrapIndvar(indVar);
-      user->replaceAllUsesWith(wrapIndvar);
-      user->erase();
+    rewriter.setInsertionPoint(op);
+    IRMapping lbMap;
+    lbMap.map(indVar, op.getLowerBound());
+    IRMapping ubMap;
+    ubMap.map(indVar, op.getUpperBound());
+    IRMapping stepMap;
+    stepMap.map(indVar, op.getStep());
+
+    Operation *lbFold = rewriter.clone(*user, lbMap);
+    Operation *ubFold = rewriter.clone(*user, ubMap);
+    Operation *stepFold = nullptr;
+    if (auto addOp = dyn_cast<arith::AddIOp>(user)) {
+      // `arith.addi %i, %i` is `2 * %i`, so the step has to be doubled too.
+      if (addOp.getLhs() == indVar && addOp.getRhs() == indVar)
+        stepFold = rewriter.clone(*user, stepMap);
+    } else {
+      stepFold = rewriter.clone(*user, stepMap);
     }
-  });
+
+    rewriter.modifyOpInPlace(op, [&]() {
+      op.setLowerBound(lbFold->getResult(0));
+      op.setUpperBound(ubFold->getResult(0));
+      if (stepFold)
+        op.setStep(stepFold->getResult(0));
+    });
+    rewriter.replaceOp(user, indVar);
+    return success();
+  }
+};
+
+struct ForLoopRangeFolding
+    : public impl::SCFForLoopRangeFoldingBase<ForLoopRangeFolding> {
+  void runOnOperation() override;
+};
+} // namespace
+
+void ForLoopRangeFolding::runOnOperation() {
+  SmallVector<Operation *> loops;
+  getOperation()->walk<WalkOrder::PreOrder>(
----------------
Hardcode84 wrote:

I think we can remove this now and just run `applyOpPatternsGreedily` on root op.

https://github.com/llvm/llvm-project/pull/230961


More information about the Mlir-commits mailing list