[mlir][IR] Add ReverseDominanceIterator for IR walkers
Blocks are enumerated depth-first, but post-order. I.e., a block is enumerated when its successors have been enumerated. This iteration style is suitable when deleting blocks in a regions: in the absence of cycles, uses are deleted before their definitions. Differential Revision: https://reviews.llvm.org/D146125
This commit is contained in:
parent
558b46fde2
commit
9c16eef1ec
|
@ -21,6 +21,7 @@
|
|||
#include "mlir/Support/LLVM.h"
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
|
||||
namespace mlir {
|
||||
/// This iterator enumerates elements in "reverse" order. It is a wrapper around
|
||||
|
@ -37,7 +38,7 @@ struct ReverseIterator {
|
|||
/// This iterator enumerates elements according to their dominance relationship.
|
||||
/// Operations and regions are enumerated in "forward" order. Blocks are
|
||||
/// enumerated according to their successor relationship. Unreachable blocks are
|
||||
/// not enumerated.
|
||||
/// not enumerated. Blocks may not be erased during the traversal.
|
||||
///
|
||||
/// Note: If `NoGraphRegions` is set to "true", this iterator asserts that each
|
||||
/// visited region has SSA dominance. In either case, the ops in such regions
|
||||
|
@ -70,6 +71,44 @@ struct ForwardDominanceIterator {
|
|||
return ForwardIterator::makeIterable(range);
|
||||
}
|
||||
};
|
||||
|
||||
/// This iterator enumerates elements according to their reverse dominance
|
||||
/// relationship. Operations and regions are enumerated in "reverse" order.
|
||||
/// Blocks are enumerated according to their successor relationship, but
|
||||
/// post-order. I.e., a block is visited after its successors have been visited.
|
||||
/// Cycles in the block graph are broken in an unspecified way. Unreachable
|
||||
/// blocks are not enumerated. Blocks may not be erased during the traversal.
|
||||
///
|
||||
/// Note: If `NoGraphRegions` is set to "true", this iterator asserts that each
|
||||
/// visited region has SSA dominance.
|
||||
template <bool NoGraphRegions = false>
|
||||
struct ReverseDominanceIterator {
|
||||
// llvm::reverse uses RangeT::rbegin and RangeT::rend.
|
||||
static constexpr auto makeIterable(Block &range) {
|
||||
return llvm::reverse(ForwardIterator::makeIterable(range));
|
||||
}
|
||||
|
||||
static constexpr auto makeIterable(Operation &range) {
|
||||
return llvm::reverse(ForwardIterator::makeIterable(range));
|
||||
}
|
||||
|
||||
static auto makeIterable(Region ®ion) {
|
||||
if (NoGraphRegions) {
|
||||
// Only regions with SSA dominance are allowed.
|
||||
assert(mayHaveSSADominance(region) && "graph regions are not allowed");
|
||||
}
|
||||
|
||||
// Create post-order iterator. Blocks are enumerated according to their
|
||||
// successor relationship.
|
||||
Block *null = nullptr;
|
||||
auto it = region.empty()
|
||||
? llvm::make_range(llvm::po_end(null), llvm::po_end(null))
|
||||
: llvm::post_order(®ion.front());
|
||||
|
||||
// Walk API expects Block references instead of pointers.
|
||||
return llvm::make_pointee_range(it);
|
||||
}
|
||||
};
|
||||
} // namespace mlir
|
||||
|
||||
#endif // MLIR_IR_ITERATORS_H
|
||||
|
|
|
@ -323,6 +323,36 @@ func.func @unordered_cfg_with_loop() {
|
|||
// CHECK: Visiting region 0 from operation 'regionOp0'
|
||||
// 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: Visiting op 'cf.br'
|
||||
// CHECK: Visiting op 'op5'
|
||||
// CHECK: Visiting op 'cf.br'
|
||||
// CHECK: Visiting op 'op1'
|
||||
// CHECK: Visiting op 'cf.br'
|
||||
// CHECK: Visiting op 'op2'
|
||||
// CHECK: Visiting op 'cf.br'
|
||||
// CHECK: Visiting op 'op3'
|
||||
// CHECK: Visiting op 'cf.cond_br'
|
||||
// CHECK: Visiting op 'op0'
|
||||
// CHECK: Visiting op 'regionOp0'
|
||||
// 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 ^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 '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
|
||||
|
|
|
@ -92,6 +92,19 @@ static void testPureCallbacks(Operation *op) {
|
|||
<< "\n";
|
||||
funcOp->walk<WalkOrder::PostOrder,
|
||||
ForwardDominanceIterator</*NoGraphRegions=*/true>>(regionPure);
|
||||
|
||||
llvm::outs() << "Op reverse dominance post-order visits"
|
||||
<< "\n";
|
||||
funcOp->walk<WalkOrder::PostOrder,
|
||||
ReverseDominanceIterator</*NoGraphRegions=*/true>>(opPure);
|
||||
llvm::outs() << "Block reverse dominance post-order visits"
|
||||
<< "\n";
|
||||
funcOp->walk<WalkOrder::PostOrder,
|
||||
ReverseDominanceIterator</*NoGraphRegions=*/true>>(blockPure);
|
||||
llvm::outs() << "Region reverse dominance post-order visits"
|
||||
<< "\n";
|
||||
funcOp->walk<WalkOrder::PostOrder,
|
||||
ReverseDominanceIterator</*NoGraphRegions=*/true>>(regionPure);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user