Skip to content

Commit 804d3c4

Browse files
[mlir][IR] Add Block::isReachable helper function (#114928)
Add a new helper function `isReachable` to `Block`. This function traverses all successors of a block to determine if another block is reachable from the current block. This functionality has been reimplemented in multiple places in MLIR. Possibly additional copies in downstream projects. Therefore, moving it to a common place.
1 parent 9991ea2 commit 804d3c4

File tree

4 files changed

+42
-36
lines changed

4 files changed

+42
-36
lines changed

mlir/include/mlir/IR/Block.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "mlir/IR/BlockSupport.h"
1717
#include "mlir/IR/Visitors.h"
1818

19+
#include "llvm/ADT/SmallPtrSet.h"
20+
1921
namespace llvm {
2022
class BitVector;
2123
class raw_ostream;
@@ -264,6 +266,19 @@ class alignas(8) Block : public IRObjectWithUseList<BlockOperand>,
264266
succ_iterator succ_end() { return getSuccessors().end(); }
265267
SuccessorRange getSuccessors() { return SuccessorRange(this); }
266268

269+
/// Return "true" if there is a path from this block to the given block
270+
/// (according to the successors relationship). Both blocks must be in the
271+
/// same region. Paths that contain a block from `except` do not count.
272+
/// This function returns "false" if `other` is in `except`.
273+
///
274+
/// Note: This function performs a block graph traversal and its complexity
275+
/// linear in the number of blocks in the parent region.
276+
///
277+
/// Note: Reachability is a necessary but insufficient condition for
278+
/// dominance. Do not use this function in places where you need to check for
279+
/// dominance.
280+
bool isReachable(Block *other, SmallPtrSet<Block *, 16> &&except = {});
281+
267282
//===--------------------------------------------------------------------===//
268283
// Walkers
269284
//===--------------------------------------------------------------------===//

mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -273,25 +273,6 @@ static bool happensBefore(Operation *a, Operation *b,
273273
return false;
274274
}
275275

276-
static bool isReachable(Block *from, Block *to, ArrayRef<Block *> except) {
277-
DenseSet<Block *> visited;
278-
SmallVector<Block *> worklist;
279-
for (Block *succ : from->getSuccessors())
280-
worklist.push_back(succ);
281-
while (!worklist.empty()) {
282-
Block *next = worklist.pop_back_val();
283-
if (llvm::is_contained(except, next))
284-
continue;
285-
if (next == to)
286-
return true;
287-
if (!visited.insert(next).second)
288-
continue;
289-
for (Block *succ : next->getSuccessors())
290-
worklist.push_back(succ);
291-
}
292-
return false;
293-
}
294-
295276
/// Return `true` if op dominance can be used to rule out a read-after-write
296277
/// conflicts based on the ordering of ops. Returns `false` if op dominance
297278
/// cannot be used to due region-based loops.
@@ -427,8 +408,8 @@ static bool canUseOpDominanceDueToBlocks(OpOperand *uRead, OpOperand *uWrite,
427408
Block *writeBlock = uWrite->getOwner()->getBlock();
428409
for (Value def : definitions) {
429410
Block *defBlock = def.getParentBlock();
430-
if (isReachable(readBlock, writeBlock, {defBlock}) &&
431-
isReachable(writeBlock, readBlock, {defBlock}))
411+
if (readBlock->isReachable(writeBlock, {defBlock}) &&
412+
writeBlock->isReachable(readBlock, {defBlock}))
432413
return false;
433414
}
434415

mlir/lib/Dialect/Vector/Transforms/VectorTransferOpTransforms.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,7 @@ bool TransferOptimization::isReachable(Operation *start, Operation *dest) {
7373
// Simple case where the start op dominate the destination.
7474
if (dominators.dominates(start, dest))
7575
return true;
76-
Block *startBlock = start->getBlock();
77-
Block *destBlock = dest->getBlock();
78-
SmallVector<Block *, 32> worklist(startBlock->succ_begin(),
79-
startBlock->succ_end());
80-
SmallPtrSet<Block *, 32> visited;
81-
while (!worklist.empty()) {
82-
Block *bb = worklist.pop_back_val();
83-
if (!visited.insert(bb).second)
84-
continue;
85-
if (dominators.dominates(bb, destBlock))
86-
return true;
87-
worklist.append(bb->succ_begin(), bb->succ_end());
88-
}
89-
return false;
76+
return start->getBlock()->isReachable(dest->getBlock());
9077
}
9178

9279
/// For transfer_write to overwrite fully another transfer_write must:

mlir/lib/IR/Block.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "mlir/IR/Block.h"
10+
1011
#include "mlir/IR/Builders.h"
1112
#include "mlir/IR/Operation.h"
1213
#include "llvm/ADT/BitVector.h"
14+
#include "llvm/ADT/SmallPtrSet.h"
15+
1316
using namespace mlir;
1417

1518
//===----------------------------------------------------------------------===//
@@ -331,7 +334,7 @@ unsigned PredecessorIterator::getSuccessorIndex() const {
331334
}
332335

333336
//===----------------------------------------------------------------------===//
334-
// SuccessorRange
337+
// Successors
335338
//===----------------------------------------------------------------------===//
336339

337340
SuccessorRange::SuccessorRange() : SuccessorRange(nullptr, 0) {}
@@ -349,6 +352,26 @@ SuccessorRange::SuccessorRange(Operation *term) : SuccessorRange() {
349352
base = term->getBlockOperands().data();
350353
}
351354

355+
bool Block::isReachable(Block *other, SmallPtrSet<Block *, 16> &&except) {
356+
assert(getParent() == other->getParent() && "expected same region");
357+
if (except.contains(other)) {
358+
// Fast path: If `other` is in the `except` set, there can be no path from
359+
// "this" to `other` (that does not pass through an excluded block).
360+
return false;
361+
}
362+
SmallVector<Block *> worklist(succ_begin(), succ_end());
363+
while (!worklist.empty()) {
364+
Block *next = worklist.pop_back_val();
365+
if (next == other)
366+
return true;
367+
// Note: `except` keeps track of already visited blocks.
368+
if (!except.insert(next).second)
369+
continue;
370+
worklist.append(next->succ_begin(), next->succ_end());
371+
}
372+
return false;
373+
}
374+
352375
//===----------------------------------------------------------------------===//
353376
// BlockRange
354377
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)