[Mlir-commits] [mlir] [mlir] Fix non-termination when a block becomes unreachable during rewriting (PR #221152)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Sep 4 00:08:21 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir
Author: Vijay Kandiah (VijayKandiah)
<details>
<summary>Changes</summary>
`GreedyPatternRewriteDriver` erases unreachable blocks at the top of each iteration here https://github.com/llvm/llvm-project/blob/85081add2d8b401e5f5ee67cf4af11531560f3bf/mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp#L892-L899
This handles blocks that are unreachable in the input, but not a block that becomes unreachable *during* `processWorklist()`, which then never returns to give `eraseUnreachableBlocks` another turn.
Here's a reproducer:
```mlir
// test.mlir
func.func @<!-- -->loop(%cond: i1, %init: i32) {
%true = arith.constant true
%c1 = arith.constant 1 : i32
cf.cond_br %true, ^exit, ^header(%init : i32)
^header(%iv: i32):
cf.cond_br %cond, ^exit, ^latch
^latch:
%next = arith.addi %iv, %c1 : i32
cf.br ^header(%next : i32)
^exit:
return
}
```
`mlir-opt test.mlir -canonicalize` never terminates: folding `%true` removes the only entry edge into `^header`, so the loop becomes unreachable while the worklist is still running.
This PR skips operations that use their own result, leaving them to hit `eraseUnreachableBlocks` on the next iteration. Such operations are legal in unreachable code.
Assisted-by: Claude Opus 5 (Cursor)
---
Full diff: https://github.com/llvm/llvm-project/pull/221152.diff
2 Files Affected:
- (modified) mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp (+9)
- (modified) mlir/test/Transforms/canonicalize-dce.mlir (+20)
``````````diff
diff --git a/mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp b/mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp
index b71194e783ba0..8c5c39992d512 100644
--- a/mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp
+++ b/mlir/lib/Transforms/Utils/GreedyPatternRewriteDriver.cpp
@@ -482,6 +482,15 @@ bool GreedyPatternRewriteDriver::processWorklist() {
}
});
+ // Folding an operation that uses its own result can loop forever, so
+ // skip it. Such operations are legal in unreachable code.
+ if (llvm::any_of(op->getOperands(), [op](Value operand) {
+ return operand.getDefiningOp() == op;
+ })) {
+ LLVM_DEBUG(logResultWithLine("failure", "operation uses its own result"));
+ continue;
+ }
+
// If the operation is trivially dead - remove it.
if (isOpTriviallyDead(op)) {
rewriter.eraseOp(op);
diff --git a/mlir/test/Transforms/canonicalize-dce.mlir b/mlir/test/Transforms/canonicalize-dce.mlir
index 84631947970de..57b5832c71dbd 100644
--- a/mlir/test/Transforms/canonicalize-dce.mlir
+++ b/mlir/test/Transforms/canonicalize-dce.mlir
@@ -187,3 +187,23 @@ func.func @f() {
%0 = "test.test_effects_result"() : () -> i32
return
}
+
+// -----
+
+// Test case: Terminate when a block becomes unreachable while patterns run.
+
+// CHECK: func @f
+// CHECK-NEXT: return
+
+func.func @f(%cond: i1, %init: i32) {
+ %true = arith.constant true
+ %c1 = arith.constant 1 : i32
+ cf.cond_br %true, ^exit, ^header(%init : i32)
+^header(%iv: i32):
+ cf.cond_br %cond, ^exit, ^latch
+^latch:
+ %next = arith.addi %iv, %c1 : i32
+ cf.br ^header(%next : i32)
+^exit:
+ return
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/221152
More information about the Mlir-commits
mailing list