[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 "mlir/Support/LLVM.h"
|
||||||
|
|
||||||
#include "llvm/ADT/DepthFirstIterator.h"
|
#include "llvm/ADT/DepthFirstIterator.h"
|
||||||
|
#include "llvm/ADT/PostOrderIterator.h"
|
||||||
|
|
||||||
namespace mlir {
|
namespace mlir {
|
||||||
/// This iterator enumerates elements in "reverse" order. It is a wrapper around
|
/// 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.
|
/// This iterator enumerates elements according to their dominance relationship.
|
||||||
/// Operations and regions are enumerated in "forward" order. Blocks are
|
/// Operations and regions are enumerated in "forward" order. Blocks are
|
||||||
/// enumerated according to their successor relationship. Unreachable 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
|
/// 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
|
/// visited region has SSA dominance. In either case, the ops in such regions
|
||||||
|
@ -70,6 +71,44 @@ struct ForwardDominanceIterator {
|
||||||
return ForwardIterator::makeIterable(range);
|
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
|
} // namespace mlir
|
||||||
|
|
||||||
#endif // MLIR_IR_ITERATORS_H
|
#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 'regionOp0'
|
||||||
// CHECK: Visiting region 0 from operation 'func.func'
|
// 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-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: Cannot erase block ^bb0 from region 0 from operation 'regionOp0', still has uses
|
// CHECK: Cannot erase block ^bb0 from region 0 from operation 'regionOp0', still has uses
|
||||||
|
|
|
@ -92,6 +92,19 @@ static void testPureCallbacks(Operation *op) {
|
||||||
<< "\n";
|
<< "\n";
|
||||||
funcOp->walk<WalkOrder::PostOrder,
|
funcOp->walk<WalkOrder::PostOrder,
|
||||||
ForwardDominanceIterator</*NoGraphRegions=*/true>>(regionPure);
|
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