Description
mlir-opt --allow-unregistered-dialect --canonicalize crashes with an assertion failure in RewriterBase::eraseOp ("expected 'op' to have no uses") when the canonicalizer attempts to fold or erase a builtin.unrealized_conversion_cast op whose result is its own operand (a self-referential cast) inside a test.graph_region. Graph regions allow uses to precede definitions, so a self-referential SSA value is valid IR in this context. The canonicalizer's folder for unrealized_conversion_cast does not account for this case and attempts to erase the op while it still has a use (itself), triggering the assertion.
Reproducer
module {
test.graph_region {
%0 = builtin.unrealized_conversion_cast %0 : i32 to i32
"test.return"() : () -> ()
}
}
Command
mlir-opt --allow-unregistered-dialect --canonicalize reproduce.mlir
Expected behavior
The canonicalizer should detect that the unrealized_conversion_cast op is self-referential and either leave it alone or handle it gracefully without attempting to erase an op that still has uses. It should not crash.
Actual behavior
mlir-opt: mlir/lib/IR/PatternMatch.cpp:156:
virtual void mlir::RewriterBase::eraseOp(mlir::Operation*):
Assertion `op->use_empty() && "expected 'op' to have no uses"' failed.
Aborted (core dumped)
Call chain
--canonicalize
→ Canonicalizer::runOnOperation
→ applyPatternsGreedily
→ GreedyPatternRewriteDriver::processWorklist
→ (unrealized_conversion_cast folder/canonicalization pattern)
→ RewriterBase::eraseOp ← assertion: op still has uses
Root cause
builtin.unrealized_conversion_cast with identical input and output types (i32 to i32) is a candidate for folding — the canonicalizer replaces it with its input operand and erases it. In a normal region this is safe. However, in a graph region the cast's result %0 is also its own operand, so after the folder replaces all uses of %0 with the input (which is %0 itself), the op still has a use through its own operand. The canonicalizer then calls eraseOp without checking use_empty(), triggering the assertion. The fix should add a self-use check in the unrealized_conversion_cast canonicalization pattern, or in eraseOp's caller, to bail out when the op's operands include its own results.
Environment
- Tool:
mlir-opt
- Pass:
--canonicalize (with --allow-unregistered-dialect)
- Affected file:
mlir/lib/IR/PatternMatch.cpp:156 (RewriterBase::eraseOp)
- Triggered by:
builtin.unrealized_conversion_cast folder in --canonicalize
Description
mlir-opt --allow-unregistered-dialect --canonicalizecrashes with an assertion failure inRewriterBase::eraseOp("expected 'op' to have no uses") when the canonicalizer attempts to fold or erase abuiltin.unrealized_conversion_castop whose result is its own operand (a self-referential cast) inside atest.graph_region. Graph regions allow uses to precede definitions, so a self-referential SSA value is valid IR in this context. The canonicalizer's folder forunrealized_conversion_castdoes not account for this case and attempts to erase the op while it still has a use (itself), triggering the assertion.Reproducer
Command
Expected behavior
The canonicalizer should detect that the
unrealized_conversion_castop is self-referential and either leave it alone or handle it gracefully without attempting to erase an op that still has uses. It should not crash.Actual behavior
Call chain
Root cause
builtin.unrealized_conversion_castwith identical input and output types (i32 to i32) is a candidate for folding — the canonicalizer replaces it with its input operand and erases it. In a normal region this is safe. However, in a graph region the cast's result%0is also its own operand, so after the folder replaces all uses of%0with the input (which is%0itself), the op still has a use through its own operand. The canonicalizer then callseraseOpwithout checkinguse_empty(), triggering the assertion. The fix should add a self-use check in theunrealized_conversion_castcanonicalization pattern, or ineraseOp's caller, to bail out when the op's operands include its own results.Environment
mlir-opt--canonicalize(with--allow-unregistered-dialect)mlir/lib/IR/PatternMatch.cpp:156(RewriterBase::eraseOp)builtin.unrealized_conversion_castfolder in--canonicalize