[MLIR] Stop visiting unreachable blocks in the walkAndApplyPatterns driver (#154038)
This is similar to the fix to the greedy driver in #153957 ; except that instead of removing unreachable code, we just ignore it. Operations like: ``` %add = arith.addi %add, %add : i64 ``` are legal in unreachable code. Unfortunately many patterns would be unsafe to apply on such IR and can lead to crashes or infinite loops.
This commit is contained in:
parent
624b724ca6
commit
191e7eba93
@ -27,6 +27,8 @@ namespace mlir {
|
||||
/// This is intended as the simplest and most lightweight pattern rewriter in
|
||||
/// cases when a simple walk gets the job done.
|
||||
///
|
||||
/// The driver will skip unreachable blocks.
|
||||
///
|
||||
/// Note: Does not apply patterns to the given operation itself.
|
||||
void walkAndApplyPatterns(Operation *op,
|
||||
const FrozenRewritePatternSet &patterns,
|
||||
|
@ -27,6 +27,26 @@
|
||||
|
||||
namespace mlir {
|
||||
|
||||
// Find all reachable blocks in the region and add them to the visitedBlocks
|
||||
// set.
|
||||
static void findReachableBlocks(Region ®ion,
|
||||
DenseSet<Block *> &reachableBlocks) {
|
||||
Block *entryBlock = ®ion.front();
|
||||
reachableBlocks.insert(entryBlock);
|
||||
// Traverse the CFG and add all reachable blocks to the blockList.
|
||||
SmallVector<Block *> worklist({entryBlock});
|
||||
while (!worklist.empty()) {
|
||||
Block *block = worklist.pop_back_val();
|
||||
Operation *terminator = &block->back();
|
||||
for (Block *successor : terminator->getSuccessors()) {
|
||||
if (reachableBlocks.contains(successor))
|
||||
continue;
|
||||
worklist.push_back(successor);
|
||||
reachableBlocks.insert(successor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct WalkAndApplyPatternsAction final
|
||||
: tracing::ActionImpl<WalkAndApplyPatternsAction> {
|
||||
@ -98,6 +118,8 @@ void walkAndApplyPatterns(Operation *op,
|
||||
regionIt = region->begin();
|
||||
if (regionIt != region->end())
|
||||
blockIt = regionIt->begin();
|
||||
if (!llvm::hasSingleElement(*region))
|
||||
findReachableBlocks(*region, reachableBlocks);
|
||||
}
|
||||
// Advance the iterator to the next reachable operation.
|
||||
void advance() {
|
||||
@ -105,6 +127,9 @@ void walkAndApplyPatterns(Operation *op,
|
||||
hasVisitedRegions = false;
|
||||
if (blockIt == regionIt->end()) {
|
||||
++regionIt;
|
||||
while (regionIt != region->end() &&
|
||||
!reachableBlocks.contains(&*regionIt))
|
||||
++regionIt;
|
||||
if (regionIt != region->end())
|
||||
blockIt = regionIt->begin();
|
||||
return;
|
||||
@ -121,6 +146,8 @@ void walkAndApplyPatterns(Operation *op,
|
||||
Region::iterator regionIt;
|
||||
// The Operation currently being iterated over.
|
||||
Block::iterator blockIt;
|
||||
// The set of blocks that are reachable in the current region.
|
||||
DenseSet<Block *> reachableBlocks;
|
||||
// Whether we've visited the nested regions of the current op already.
|
||||
bool hasVisitedRegions = false;
|
||||
};
|
||||
|
@ -119,3 +119,23 @@ func.func @erase_nested_block() -> i32 {
|
||||
}): () -> (i32)
|
||||
return %a : i32
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: func.func @unreachable_replace_with_new_op
|
||||
// CHECK: "test.new_op"
|
||||
// CHECK: "test.replace_with_new_op"
|
||||
// CHECK-SAME: unreachable
|
||||
// CHECK: "test.new_op"
|
||||
func.func @unreachable_replace_with_new_op() {
|
||||
"test.br"()[^bb1] : () -> ()
|
||||
^bb1:
|
||||
%a = "test.replace_with_new_op"() : () -> (i32)
|
||||
"test.br"()[^end] : () -> () // Test jumping over the unreachable block is visited as well.
|
||||
^unreachable:
|
||||
%b = "test.replace_with_new_op"() {test.unreachable} : () -> (i32)
|
||||
return
|
||||
^end:
|
||||
%c = "test.replace_with_new_op"() : () -> (i32)
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user