[Mlir-commits] [mlir] [mlir][test-ir-visitors] Fix noSkipBlockErasure for blocks providing global context (PR #181320)
Prathamesh Tagore
llvmlistbot at llvm.org
Mon Feb 16 12:40:40 PST 2026
https://github.com/meshtag updated https://github.com/llvm/llvm-project/pull/181320
>From d158e2ba458610139a9489c853f8434dd049fa0b Mon Sep 17 00:00:00 2001
From: Prathamesh Tagore <prathameshtagore at gmail.com>
Date: Mon, 16 Feb 2026 21:09:14 +0100
Subject: [PATCH 1/2] [NFC][test-ir-visitors] Remove unregistered dialect uses
from tests
Use the already registered test dialect in tests which is explicitly intended
to allow arbitrary ops.
---
mlir/test/IR/visitors.mlir | 236 ++++++++++++++++++-------------------
1 file changed, 118 insertions(+), 118 deletions(-)
diff --git a/mlir/test/IR/visitors.mlir b/mlir/test/IR/visitors.mlir
index ec7712a45d388..a60f9e0afa0d8 100644
--- a/mlir/test/IR/visitors.mlir
+++ b/mlir/test/IR/visitors.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt -test-ir-visitors -allow-unregistered-dialect -split-input-file %s | FileCheck %s
+// RUN: mlir-opt -test-ir-visitors -split-input-file %s | FileCheck %s
// Verify the different configurations of IR visitors.
// Constant, yield and other terminator ops are not matched for simplicity.
@@ -10,13 +10,13 @@ func.func @structured_cfg() {
%c1 = arith.constant 1 : index
%c10 = arith.constant 10 : index
scf.for %i = %c1 to %c10 step %c1 {
- %cond = "use0"(%i) : (index) -> (i1)
+ %cond = "test.zero"(%i) : (index) -> (i1)
scf.if %cond {
- "use1"(%i) : (index) -> ()
+ "test.one"(%i) : (index) -> ()
} else {
- "use2"(%i) : (index) -> ()
+ "test.two"(%i) : (index) -> ()
}
- "use3"(%i) : (index) -> ()
+ "test.three"(%i) : (index) -> ()
} {walk_blocks, walk_regions}
return
}
@@ -25,11 +25,11 @@ func.func @structured_cfg() {
// CHECK: Visiting op 'builtin.module'
// CHECK: Visiting op 'func.func'
// CHECK: Visiting op 'scf.for'
-// CHECK: Visiting op 'use0'
+// CHECK: Visiting op 'test.zero'
// CHECK: Visiting op 'scf.if'
-// CHECK: Visiting op 'use1'
-// CHECK: Visiting op 'use2'
-// CHECK: Visiting op 'use3'
+// CHECK: Visiting op 'test.one'
+// CHECK: Visiting op 'test.two'
+// CHECK: Visiting op 'test.three'
// CHECK: Visiting op 'func.return'
// CHECK-LABEL: Block pre-order visits
@@ -47,11 +47,11 @@ func.func @structured_cfg() {
// CHECK: Visiting region 1 from operation 'scf.if'
// CHECK-LABEL: Op post-order visits
-// CHECK: Visiting op 'use0'
-// CHECK: Visiting op 'use1'
-// CHECK: Visiting op 'use2'
+// CHECK: Visiting op 'test.zero'
+// CHECK: Visiting op 'test.one'
+// CHECK: Visiting op 'test.two'
// CHECK: Visiting op 'scf.if'
-// CHECK: Visiting op 'use3'
+// CHECK: Visiting op 'test.three'
// CHECK: Visiting op 'scf.for'
// CHECK: Visiting op 'func.return'
// CHECK: Visiting op 'func.func'
@@ -74,13 +74,13 @@ func.func @structured_cfg() {
// CHECK-LABEL: Op reverse post-order visits
// CHECK: Visiting op 'func.return'
// CHECK: Visiting op 'scf.yield'
-// CHECK: Visiting op 'use3'
+// CHECK: Visiting op 'test.three'
// CHECK: Visiting op 'scf.yield'
-// CHECK: Visiting op 'use2'
+// CHECK: Visiting op 'test.two'
// CHECK: Visiting op 'scf.yield'
-// CHECK: Visiting op 'use1'
+// CHECK: Visiting op 'test.one'
// CHECK: Visiting op 'scf.if'
-// CHECK: Visiting op 'use0'
+// CHECK: Visiting op 'test.zero'
// CHECK: Visiting op 'scf.for'
// CHECK: Visiting op 'arith.constant'
// CHECK: Visiting op 'arith.constant'
@@ -116,11 +116,11 @@ func.func @structured_cfg() {
// CHECK: Erasing block ^bb0 from region 0 from operation 'scf.for'
// CHECK-LABEL: Op post-order erasures (skip)
-// CHECK: Erasing op 'use0'
-// CHECK: Erasing op 'use1'
-// CHECK: Erasing op 'use2'
+// CHECK: Erasing op 'test.zero'
+// CHECK: Erasing op 'test.one'
+// CHECK: Erasing op 'test.two'
// CHECK: Erasing op 'scf.if'
-// CHECK: Erasing op 'use3'
+// CHECK: Erasing op 'test.three'
// CHECK: Erasing op 'scf.for'
// CHECK: Erasing op 'func.return'
@@ -130,11 +130,11 @@ func.func @structured_cfg() {
// CHECK: Erasing block ^bb0 from region 0 from operation 'scf.for'
// CHECK-LABEL: Op post-order erasures (no skip)
-// CHECK: Erasing op 'use0'
-// CHECK: Erasing op 'use1'
-// CHECK: Erasing op 'use2'
+// CHECK: Erasing op 'test.zero'
+// CHECK: Erasing op 'test.one'
+// CHECK: Erasing op 'test.two'
// CHECK: Erasing op 'scf.if'
-// CHECK: Erasing op 'use3'
+// CHECK: Erasing op 'test.three'
// CHECK: Erasing op 'scf.for'
// CHECK: Erasing op 'func.return'
// CHECK: Erasing op 'func.func'
@@ -150,15 +150,15 @@ func.func @structured_cfg() {
// -----
func.func @unstructured_cfg() {
- "regionOp0"() ({
+ "test.regiontest.op0"() ({
^bb0:
- "op0"() : () -> ()
+ "test.op0"() : () -> ()
cf.br ^bb2
^bb1:
- "op1"() : () -> ()
+ "test.op1"() : () -> ()
cf.br ^bb2
^bb2:
- "op2"() : () -> ()
+ "test.op2"() : () -> ()
}) : () -> ()
return
}
@@ -166,138 +166,138 @@ func.func @unstructured_cfg() {
// CHECK-LABEL: Op pre-order visits
// CHECK: Visiting op 'builtin.module'
// CHECK: Visiting op 'func.func'
-// CHECK: Visiting op 'regionOp0'
-// CHECK: Visiting op 'op0'
+// CHECK: Visiting op 'test.regiontest.op0'
+// CHECK: Visiting op 'test.op0'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op1'
+// CHECK: Visiting op 'test.op1'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op2'
+// CHECK: Visiting op 'test.op2'
// CHECK: Visiting op 'func.return'
// CHECK-LABEL: Block pre-order visits
// CHECK: Visiting block ^bb0 from region 0 from operation 'builtin.module'
// CHECK: Visiting block ^bb0 from region 0 from operation 'func.func'
-// CHECK: Visiting block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb1 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb2 from region 0 from operation 'regionOp0'
+// CHECK: Visiting block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb1 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb2 from region 0 from operation 'test.regiontest.op0'
// CHECK-LABEL: Region pre-order visits
// CHECK: Visiting region 0 from operation 'builtin.module'
// CHECK: Visiting region 0 from operation 'func.func'
-// CHECK: Visiting region 0 from operation 'regionOp0'
+// CHECK: Visiting region 0 from operation 'test.regiontest.op0'
// CHECK-LABEL: Op post-order visits
-// CHECK: Visiting op 'op0'
+// CHECK: Visiting op 'test.op0'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op1'
+// CHECK: Visiting op 'test.op1'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op2'
-// CHECK: Visiting op 'regionOp0'
+// CHECK: Visiting op 'test.op2'
+// CHECK: Visiting op 'test.regiontest.op0'
// CHECK: Visiting op 'func.return'
// CHECK: Visiting op 'func.func'
// CHECK: Visiting op 'builtin.module'
// CHECK-LABEL: Block post-order visits
-// CHECK: Visiting block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb1 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb2 from region 0 from operation 'regionOp0'
+// CHECK: Visiting block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb1 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb2 from region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting block ^bb0 from region 0 from operation 'func.func'
// CHECK: Visiting block ^bb0 from region 0 from operation 'builtin.module'
// CHECK-LABEL: Region post-order visits
-// CHECK: Visiting region 0 from operation 'regionOp0'
+// CHECK: Visiting region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting region 0 from operation 'func.func'
// CHECK: Visiting region 0 from operation 'builtin.module'
// CHECK-LABEL: Op reverse post-order visits
// CHECK: Visiting op 'func.return'
-// CHECK: Visiting op 'op2'
+// CHECK: Visiting op 'test.op2'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op1'
+// CHECK: Visiting op 'test.op1'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op0'
-// CHECK: Visiting op 'regionOp0'
+// CHECK: Visiting op 'test.op0'
+// CHECK: Visiting op 'test.regiontest.op0'
// CHECK: Visiting op 'func.func'
// CHECK: Visiting op 'builtin.module'
// CHECK-LABEL: Block reverse post-order visits
-// CHECK: Visiting block ^bb2 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb1 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb0 from region 0 from operation 'regionOp0'
+// CHECK: Visiting block ^bb2 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb1 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb0 from region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting block ^bb0 from region 0 from operation 'func.func'
// CHECK: Visiting block ^bb0 from region 0 from operation 'builtin.module'
// CHECK-LABEL: Region reverse post-order visits
-// CHECK: Visiting region 0 from operation 'regionOp0'
+// CHECK: Visiting region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting region 0 from operation 'func.func'
// CHECK: Visiting region 0 from operation 'builtin.module'
// CHECK-LABEL: Op pre-order erasures (skip)
-// CHECK: Erasing op 'regionOp0'
+// CHECK: Erasing op 'test.regiontest.op0'
// CHECK: Erasing op 'func.return'
// CHECK-LABEL: Block pre-order erasures (skip)
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
// CHECK-LABEL: Op post-order erasures (skip)
-// CHECK: Erasing op 'op0'
+// CHECK: Erasing op 'test.op0'
// CHECK: Erasing op 'cf.br'
-// CHECK: Erasing op 'op1'
+// CHECK: Erasing op 'test.op1'
// CHECK: Erasing op 'cf.br'
-// CHECK: Erasing op 'op2'
-// CHECK: Erasing op 'regionOp0'
+// CHECK: Erasing op 'test.op2'
+// CHECK: Erasing op 'test.regiontest.op0'
// CHECK: Erasing op 'func.return'
// CHECK-LABEL: Block post-order erasures (skip)
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
// CHECK-LABEL: Op post-order erasures (no skip)
-// CHECK: Erasing op 'op0'
+// CHECK: Erasing op 'test.op0'
// CHECK: Erasing op 'cf.br'
-// CHECK: Erasing op 'op1'
+// CHECK: Erasing op 'test.op1'
// CHECK: Erasing op 'cf.br'
-// CHECK: Erasing op 'op2'
-// CHECK: Erasing op 'regionOp0'
+// CHECK: Erasing op 'test.op2'
+// CHECK: Erasing op 'test.regiontest.op0'
// CHECK: Erasing op 'func.return'
// CHECK-LABEL: Block post-order erasures (no skip)
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
// CHECK: Erasing block ^bb0 from region 0 from operation 'func.func'
// CHECK: Erasing block ^bb0 from region 0 from operation 'builtin.module'
// -----
func.func @unordered_cfg_with_loop() {
- "regionOp0"() ({
+ "test.regiontest.op0"() ({
^bb0:
- %c = "op0"() : () -> (i1)
+ %c = "test.op0"() : () -> (i1)
cf.cond_br %c, ^bb2, ^bb3
^bb1:
- "op1"(%val) : (i32) -> ()
+ "test.op1"(%val) : (i32) -> ()
cf.br ^bb5
^bb2:
- %val = "op2"() : () -> (i32)
+ %val = "test.op2"() : () -> (i32)
cf.br ^bb1
^bb3:
- "op3"() : () -> ()
+ "test.op3"() : () -> ()
cf.br ^bb2
^bb4:
- "op4"() : () -> ()
+ "test.op4"() : () -> ()
cf.br ^bb2
^bb5:
- "op5"() : () -> ()
+ "test.op5"() : () -> ()
cf.br ^bb7
^bb6:
- "op6"() : () -> ()
+ "test.op6"() : () -> ()
cf.br ^bb6
^bb7:
- "op7"() : () -> ()
+ "test.op7"() : () -> ()
}) : () -> ()
return
}
@@ -314,71 +314,71 @@ func.func @unordered_cfg_with_loop() {
// 3
// CHECK-LABEL: Op forward dominance post-order visits
-// CHECK: Visiting op 'op0'
+// CHECK: Visiting op 'test.op0'
// CHECK: Visiting op 'cf.cond_br'
-// CHECK: Visiting op 'op2'
+// CHECK: Visiting op 'test.op2'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op1'
+// CHECK: Visiting op 'test.op1'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op5'
+// CHECK: Visiting op 'test.op5'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op7'
-// CHECK: Visiting op 'op3'
+// CHECK: Visiting op 'test.op7'
+// CHECK: Visiting op 'test.op3'
// CHECK: Visiting op 'cf.br'
-// CHECK-NOT: Visiting op 'op6'
-// CHECK: Visiting op 'regionOp0'
+// CHECK-NOT: Visiting op 'test.op6'
+// CHECK: Visiting op 'test.regiontest.op0'
// CHECK: Visiting op 'func.return'
// CHECK: Visiting op 'func.func'
// CHECK-LABEL: Block forward dominance post-order visits
-// CHECK: Visiting block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb2 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb1 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb5 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb7 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb3 from region 0 from operation 'regionOp0'
+// CHECK: Visiting block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb2 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb1 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb5 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb7 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb3 from region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting block ^bb0 from region 0 from operation 'func.func'
// CHECK-LABEL: Region forward dominance post-order visits
-// CHECK: Visiting region 0 from operation 'regionOp0'
+// CHECK: Visiting region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting region 0 from operation 'func.func'
// CHECK-LABEL: Op reverse dominance post-order visits
// CHECK: Visiting op 'func.return'
-// CHECK-NOT: Visiting op 'op6'
-// CHECK: Visiting op 'op7'
+// CHECK-NOT: Visiting op 'test.op6'
+// CHECK: Visiting op 'test.op7'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op5'
+// CHECK: Visiting op 'test.op5'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op1'
+// CHECK: Visiting op 'test.op1'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op2'
+// CHECK: Visiting op 'test.op2'
// CHECK: Visiting op 'cf.br'
-// CHECK: Visiting op 'op3'
+// CHECK: Visiting op 'test.op3'
// CHECK: Visiting op 'cf.cond_br'
-// CHECK: Visiting op 'op0'
-// CHECK: Visiting op 'regionOp0'
+// CHECK: Visiting op 'test.op0'
+// CHECK: Visiting op 'test.regiontest.op0'
// CHECK: Visiting op 'func.func'
// CHECK-LABEL: Block reverse dominance post-order visits
-// CHECK: Visiting block ^bb7 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb5 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb1 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb2 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb3 from region 0 from operation 'regionOp0'
-// CHECK: Visiting block ^bb0 from region 0 from operation 'regionOp0'
+// CHECK: Visiting block ^bb7 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb5 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb1 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb2 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb3 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Visiting block ^bb0 from region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting block ^bb0 from region 0 from operation 'func.func'
// CHECK-LABEL: Region reverse dominance post-order visits
-// CHECK: Visiting region 0 from operation 'regionOp0'
+// CHECK: Visiting region 0 from operation 'test.regiontest.op0'
// CHECK: Visiting region 0 from operation 'func.func'
// CHECK-LABEL: Block pre-order erasures (skip)
-// CHECK: Erasing block ^bb0 from region 0 from operation 'regionOp0'
-// CHECK: Cannot erase block ^bb0 from region 0 from operation 'regionOp0', still has uses
-// CHECK: Cannot erase block ^bb1 from region 0 from operation 'regionOp0', still has uses
-// CHECK: Erasing block ^bb2 from region 0 from operation 'regionOp0'
-// CHECK: Erasing block ^bb2 from region 0 from operation 'regionOp0'
-// CHECK: Cannot erase block ^bb2 from region 0 from operation 'regionOp0', still has uses
-// CHECK: Cannot erase block ^bb3 from region 0 from operation 'regionOp0', still has uses
-// CHECK: Cannot erase block ^bb4 from region 0 from operation 'regionOp0', still has uses
+// CHECK: Erasing block ^bb0 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Cannot erase block ^bb0 from region 0 from operation 'test.regiontest.op0', still has uses
+// CHECK: Cannot erase block ^bb1 from region 0 from operation 'test.regiontest.op0', still has uses
+// CHECK: Erasing block ^bb2 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Erasing block ^bb2 from region 0 from operation 'test.regiontest.op0'
+// CHECK: Cannot erase block ^bb2 from region 0 from operation 'test.regiontest.op0', still has uses
+// CHECK: Cannot erase block ^bb3 from region 0 from operation 'test.regiontest.op0', still has uses
+// CHECK: Cannot erase block ^bb4 from region 0 from operation 'test.regiontest.op0', still has uses
>From afa61dd86fffbeec537e963cc180d6e778cfedfd Mon Sep 17 00:00:00 2001
From: Prathamesh Tagore <prathameshtagore at gmail.com>
Date: Mon, 16 Feb 2026 21:31:09 +0100
Subject: [PATCH 2/2] [mlir][test-ir-visitors] Fix erasure of operations with
intact uses
The pass checks if something is pointing to the current block in
testNoSkipErasureCallbacks() inside noSkipBlockErasure() callback and erases
it if no one is pointing to it. However, it doesn't consider the fact that
the current block might be providing global context to other blocks in the
same parent op even if no one is pointing to it (see the attached test for an
example of this). Erasing this block would then lead to invalid IR. We solve
this by dropping uses from operations within the same parent block holding
operation. This way, we can safely erase the block if nothing outside the
surrounding region still needs it.
---
mlir/test/IR/visitors.mlir | 17 +++++++++++++++++
mlir/test/lib/IR/TestVisitors.cpp | 18 ++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/mlir/test/IR/visitors.mlir b/mlir/test/IR/visitors.mlir
index a60f9e0afa0d8..e8efe327d9810 100644
--- a/mlir/test/IR/visitors.mlir
+++ b/mlir/test/IR/visitors.mlir
@@ -382,3 +382,20 @@ func.func @unordered_cfg_with_loop() {
// CHECK: Cannot erase block ^bb2 from region 0 from operation 'test.regiontest.op0', still has uses
// CHECK: Cannot erase block ^bb3 from region 0 from operation 'test.regiontest.op0', still has uses
// CHECK: Cannot erase block ^bb4 from region 0 from operation 'test.regiontest.op0', still has uses
+
+// -----
+
+// The following test should not crash while visiting the intra-op blocks (inside the top level
+// function in this case). We are testing that the intra-block ops are erased after dropping their
+// uses from the parent block holding op.
+// CHECK-LABEL: func.func @test_no_skip_block_erasure
+func.func @test_no_skip_block_erasure() {
+ %c0 = arith.constant 0 : index
+ %c3 = arith.constant 3 : index
+ cf.br ^bb1
+^bb1:
+ %cond = arith.cmpi eq, %c0, %c3 : index
+ cf.br ^bb4
+^bb4:
+ return
+}
diff --git a/mlir/test/lib/IR/TestVisitors.cpp b/mlir/test/lib/IR/TestVisitors.cpp
index 7df0ddb7ca27e..4a2a3fb5f8632 100644
--- a/mlir/test/lib/IR/TestVisitors.cpp
+++ b/mlir/test/lib/IR/TestVisitors.cpp
@@ -184,6 +184,24 @@ static void testNoSkipErasureCallbacks(Operation *op) {
llvm::outs() << "Erasing ";
printBlock(block);
llvm::outs() << "\n";
+
+ // Only drop uses from operations within the same parent block holding
+ // operation. This avoids erasing operations with their uses still intact
+ // and eliminates such crashes.
+ // Note: We do not drop uses when the parent block holder operation is
+ // different for the use, because this means that this op is a child of
+ // the current blockParentOp and was expected to be visited and erased
+ // first - we should correctly fail here.
+ Operation *blockParentOp = block->getParentOp();
+ for (Operation &op : *block) {
+ for (OpOperand &use : llvm::make_early_inc_range(op.getUses())) {
+ // Early continue if the parent block holding ops are not same.
+ if (blockParentOp != use.getOwner()->getParentOp())
+ continue;
+ use.drop();
+ }
+ }
+
block->erase();
} else {
llvm::outs() << "Cannot erase ";
More information about the Mlir-commits
mailing list