mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[VPlan] Add GraphTraits impl to traverse through VPRegionBlock.
This patch adds a new iterator to traverse through VPRegionBlocks and a GraphTraits specialization using the iterator to traverse through VPRegionBlocks. Because there is already a GraphTraits specialization for VPBlockBase * and co, a new VPBlockRecursiveTraversalWrapper helper is introduced. This allows us to provide a new GraphTraits specialization for that type. Users can use the new recursive traversal by using this wrapper. The graph trait visits both the entry block of a region, as well as all its successors. Exit blocks of a region implicitly have their parent region's successors. This ensures all blocks in a region are visited before any blocks in a successor region when doing a reverse post-order traversal of the graph. Reviewed By: a.elovikov Differential Revision: https://reviews.llvm.org/D100175
This commit is contained in:
parent
1f0605d432
commit
4b94f2fec6
@ -1748,6 +1748,136 @@ struct GraphTraits<Inverse<VPRegionBlock *>>
|
||||
}
|
||||
};
|
||||
|
||||
/// Iterator to traverse all successors of a VPBlockBase node. This includes the
|
||||
/// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their
|
||||
/// parent region's successors. This ensures all blocks in a region are visited
|
||||
/// before any blocks in a successor region when doing a reverse post-order
|
||||
// traversal of the graph.
|
||||
template <typename BlockPtrTy>
|
||||
class VPAllSuccessorsIterator
|
||||
: public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>,
|
||||
std::forward_iterator_tag, VPBlockBase> {
|
||||
BlockPtrTy Block;
|
||||
/// Index of the current successor. For VPBasicBlock nodes, this simply is the
|
||||
/// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is
|
||||
/// used for the region's entry block, and SuccessorIdx - 1 are the indices
|
||||
/// for the successor array.
|
||||
size_t SuccessorIdx;
|
||||
|
||||
static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) {
|
||||
while (Current && Current->getNumSuccessors() == 0)
|
||||
Current = Current->getParent();
|
||||
return Current;
|
||||
}
|
||||
|
||||
/// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
|
||||
/// both the const and non-const operator* implementations.
|
||||
template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) {
|
||||
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
|
||||
if (SuccIdx == 0)
|
||||
return R->getEntry();
|
||||
SuccIdx--;
|
||||
}
|
||||
|
||||
// For exit blocks, use the next parent region with successors.
|
||||
return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx];
|
||||
}
|
||||
|
||||
public:
|
||||
VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0)
|
||||
: Block(Block), SuccessorIdx(Idx) {}
|
||||
VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other)
|
||||
: Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {}
|
||||
|
||||
VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) {
|
||||
Block = R.Block;
|
||||
SuccessorIdx = R.SuccessorIdx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static VPAllSuccessorsIterator end(BlockPtrTy Block) {
|
||||
BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block);
|
||||
unsigned NumSuccessors = ParentWithSuccs
|
||||
? ParentWithSuccs->getNumSuccessors()
|
||||
: Block->getNumSuccessors();
|
||||
|
||||
if (auto *R = dyn_cast<VPRegionBlock>(Block))
|
||||
return {R, NumSuccessors + 1};
|
||||
return {Block, NumSuccessors};
|
||||
}
|
||||
|
||||
bool operator==(const VPAllSuccessorsIterator &R) const {
|
||||
return Block == R.Block && SuccessorIdx == R.SuccessorIdx;
|
||||
}
|
||||
|
||||
const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); }
|
||||
|
||||
BlockPtrTy operator*() { return deref(Block, SuccessorIdx); }
|
||||
|
||||
VPAllSuccessorsIterator &operator++() {
|
||||
SuccessorIdx++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VPAllSuccessorsIterator operator++(int X) {
|
||||
VPAllSuccessorsIterator Orig = *this;
|
||||
SuccessorIdx++;
|
||||
return Orig;
|
||||
}
|
||||
};
|
||||
|
||||
/// Helper for GraphTraits specialization that traverses through VPRegionBlocks.
|
||||
template <typename BlockTy> class VPBlockRecursiveTraversalWrapper {
|
||||
BlockTy Entry;
|
||||
|
||||
public:
|
||||
VPBlockRecursiveTraversalWrapper(BlockTy Entry) : Entry(Entry) {}
|
||||
BlockTy getEntry() { return Entry; }
|
||||
};
|
||||
|
||||
/// GraphTraits specialization to recursively traverse VPBlockBase nodes,
|
||||
/// including traversing through VPRegionBlocks. Exit blocks of a region
|
||||
/// implicitly have their parent region's successors. This ensures all blocks in
|
||||
/// a region are visited before any blocks in a successor region when doing a
|
||||
/// reverse post-order traversal of the graph.
|
||||
template <>
|
||||
struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> {
|
||||
using NodeRef = VPBlockBase *;
|
||||
using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
|
||||
|
||||
static NodeRef
|
||||
getEntryNode(VPBlockRecursiveTraversalWrapper<VPBlockBase *> N) {
|
||||
return N.getEntry();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeRef N) {
|
||||
return ChildIteratorType(N);
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeRef N) {
|
||||
return ChildIteratorType::end(N);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GraphTraits<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> {
|
||||
using NodeRef = const VPBlockBase *;
|
||||
using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
|
||||
|
||||
static NodeRef
|
||||
getEntryNode(VPBlockRecursiveTraversalWrapper<const VPBlockBase *> N) {
|
||||
return N.getEntry();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeRef N) {
|
||||
return ChildIteratorType(N);
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeRef N) {
|
||||
return ChildIteratorType::end(N);
|
||||
}
|
||||
};
|
||||
|
||||
/// VPlan models a candidate for vectorization, encoding various decisions take
|
||||
/// to produce efficient output IR, including which branches, basic-blocks and
|
||||
/// output IR instructions to generate, and their cost. VPlan holds a
|
||||
|
@ -324,6 +324,299 @@ TEST(VPBasicBlockTest, getPlan) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VPBasicBlockTest, TraversingIteratorTest) {
|
||||
{
|
||||
// VPBasicBlocks only
|
||||
// VPBB1
|
||||
// / \
|
||||
// VPBB2 VPBB3
|
||||
// \ /
|
||||
// VPBB4
|
||||
//
|
||||
VPBasicBlock *VPBB1 = new VPBasicBlock();
|
||||
VPBasicBlock *VPBB2 = new VPBasicBlock();
|
||||
VPBasicBlock *VPBB3 = new VPBasicBlock();
|
||||
VPBasicBlock *VPBB4 = new VPBasicBlock();
|
||||
|
||||
VPBlockUtils::connectBlocks(VPBB1, VPBB2);
|
||||
VPBlockUtils::connectBlocks(VPBB1, VPBB3);
|
||||
VPBlockUtils::connectBlocks(VPBB2, VPBB4);
|
||||
VPBlockUtils::connectBlocks(VPBB3, VPBB4);
|
||||
|
||||
VPBlockRecursiveTraversalWrapper<const VPBlockBase *> Start(VPBB1);
|
||||
SmallVector<const VPBlockBase *> FromIterator(depth_first(Start));
|
||||
EXPECT_EQ(4u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB1, FromIterator[0]);
|
||||
EXPECT_EQ(VPBB2, FromIterator[1]);
|
||||
|
||||
// Use Plan to properly clean up created blocks.
|
||||
VPlan Plan;
|
||||
Plan.setEntry(VPBB1);
|
||||
}
|
||||
|
||||
{
|
||||
// 2 consecutive regions.
|
||||
// R1 {
|
||||
// \
|
||||
// R1BB1
|
||||
// / \ |--|
|
||||
// R1BB2 R1BB3 -|
|
||||
// \ /
|
||||
// R1BB4
|
||||
// }
|
||||
// |
|
||||
// R2 {
|
||||
// \
|
||||
// R2BB1
|
||||
// |
|
||||
// R2BB2
|
||||
//
|
||||
VPBasicBlock *R1BB1 = new VPBasicBlock();
|
||||
VPBasicBlock *R1BB2 = new VPBasicBlock();
|
||||
VPBasicBlock *R1BB3 = new VPBasicBlock();
|
||||
VPBasicBlock *R1BB4 = new VPBasicBlock();
|
||||
VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB4, "R1");
|
||||
R1BB2->setParent(R1);
|
||||
R1BB3->setParent(R1);
|
||||
VPBlockUtils::connectBlocks(R1BB1, R1BB2);
|
||||
VPBlockUtils::connectBlocks(R1BB1, R1BB3);
|
||||
VPBlockUtils::connectBlocks(R1BB2, R1BB4);
|
||||
VPBlockUtils::connectBlocks(R1BB3, R1BB4);
|
||||
// Cycle.
|
||||
VPBlockUtils::connectBlocks(R1BB3, R1BB3);
|
||||
|
||||
VPBasicBlock *R2BB1 = new VPBasicBlock();
|
||||
VPBasicBlock *R2BB2 = new VPBasicBlock();
|
||||
VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
|
||||
VPBlockUtils::connectBlocks(R2BB1, R2BB2);
|
||||
VPBlockUtils::connectBlocks(R1, R2);
|
||||
|
||||
// Depth-first.
|
||||
VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(R1);
|
||||
SmallVector<const VPBlockBase *> FromIterator(df_begin(Start),
|
||||
df_end(Start));
|
||||
EXPECT_EQ(8u, FromIterator.size());
|
||||
EXPECT_EQ(R1, FromIterator[0]);
|
||||
EXPECT_EQ(R1BB1, FromIterator[1]);
|
||||
EXPECT_EQ(R1BB2, FromIterator[2]);
|
||||
EXPECT_EQ(R1BB4, FromIterator[3]);
|
||||
EXPECT_EQ(R2, FromIterator[4]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[5]);
|
||||
EXPECT_EQ(R2BB2, FromIterator[6]);
|
||||
EXPECT_EQ(R1BB3, FromIterator[7]);
|
||||
|
||||
// Post-order.
|
||||
FromIterator.clear();
|
||||
copy(post_order(Start), std::back_inserter(FromIterator));
|
||||
EXPECT_EQ(8u, FromIterator.size());
|
||||
EXPECT_EQ(R2BB2, FromIterator[0]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[1]);
|
||||
EXPECT_EQ(R2, FromIterator[2]);
|
||||
EXPECT_EQ(R1BB4, FromIterator[3]);
|
||||
EXPECT_EQ(R1BB2, FromIterator[4]);
|
||||
EXPECT_EQ(R1BB3, FromIterator[5]);
|
||||
EXPECT_EQ(R1BB1, FromIterator[6]);
|
||||
EXPECT_EQ(R1, FromIterator[7]);
|
||||
|
||||
// Use Plan to properly clean up created blocks.
|
||||
VPlan Plan;
|
||||
Plan.setEntry(R1);
|
||||
}
|
||||
|
||||
{
|
||||
// 2 nested regions.
|
||||
// VPBB1
|
||||
// |
|
||||
// R1 {
|
||||
// R1BB1
|
||||
// / \
|
||||
// R2 { |
|
||||
// \ |
|
||||
// R2BB1 |
|
||||
// | \ R1BB2
|
||||
// R2BB2-| |
|
||||
// \ |
|
||||
// R2BB3 |
|
||||
// } /
|
||||
// \ /
|
||||
// R1BB3
|
||||
// }
|
||||
// |
|
||||
// VPBB2
|
||||
//
|
||||
VPBasicBlock *R1BB1 = new VPBasicBlock("R1BB1");
|
||||
VPBasicBlock *R1BB2 = new VPBasicBlock("R1BB2");
|
||||
VPBasicBlock *R1BB3 = new VPBasicBlock("R1BB3");
|
||||
VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB3, "R1");
|
||||
|
||||
VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
|
||||
VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
|
||||
VPBasicBlock *R2BB3 = new VPBasicBlock("R2BB3");
|
||||
VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB3, "R2");
|
||||
R2BB2->setParent(R2);
|
||||
VPBlockUtils::connectBlocks(R2BB1, R2BB2);
|
||||
VPBlockUtils::connectBlocks(R2BB2, R2BB1);
|
||||
VPBlockUtils::connectBlocks(R2BB2, R2BB3);
|
||||
|
||||
R2->setParent(R1);
|
||||
VPBlockUtils::connectBlocks(R1BB1, R2);
|
||||
R1BB2->setParent(R1);
|
||||
VPBlockUtils::connectBlocks(R1BB1, R1BB2);
|
||||
VPBlockUtils::connectBlocks(R1BB2, R1BB3);
|
||||
VPBlockUtils::connectBlocks(R2, R1BB3);
|
||||
|
||||
VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
|
||||
VPBlockUtils::connectBlocks(VPBB1, R1);
|
||||
VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
|
||||
VPBlockUtils::connectBlocks(R1, VPBB2);
|
||||
|
||||
// Depth-first.
|
||||
VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
|
||||
SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
|
||||
EXPECT_EQ(10u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB1, FromIterator[0]);
|
||||
EXPECT_EQ(R1, FromIterator[1]);
|
||||
EXPECT_EQ(R1BB1, FromIterator[2]);
|
||||
EXPECT_EQ(R2, FromIterator[3]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[4]);
|
||||
EXPECT_EQ(R2BB2, FromIterator[5]);
|
||||
EXPECT_EQ(R2BB3, FromIterator[6]);
|
||||
EXPECT_EQ(R1BB3, FromIterator[7]);
|
||||
EXPECT_EQ(VPBB2, FromIterator[8]);
|
||||
EXPECT_EQ(R1BB2, FromIterator[9]);
|
||||
|
||||
// Post-order.
|
||||
FromIterator.clear();
|
||||
FromIterator.append(po_begin(Start), po_end(Start));
|
||||
EXPECT_EQ(10u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB2, FromIterator[0]);
|
||||
EXPECT_EQ(R1BB3, FromIterator[1]);
|
||||
EXPECT_EQ(R2BB3, FromIterator[2]);
|
||||
EXPECT_EQ(R2BB2, FromIterator[3]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[4]);
|
||||
EXPECT_EQ(R2, FromIterator[5]);
|
||||
EXPECT_EQ(R1BB2, FromIterator[6]);
|
||||
EXPECT_EQ(R1BB1, FromIterator[7]);
|
||||
EXPECT_EQ(R1, FromIterator[8]);
|
||||
EXPECT_EQ(VPBB1, FromIterator[9]);
|
||||
|
||||
// Use Plan to properly clean up created blocks.
|
||||
VPlan Plan;
|
||||
Plan.setEntry(VPBB1);
|
||||
}
|
||||
|
||||
{
|
||||
// VPBB1
|
||||
// |
|
||||
// R1 {
|
||||
// \
|
||||
// R2 {
|
||||
// R2BB1
|
||||
// |
|
||||
// R2BB2
|
||||
// }
|
||||
//
|
||||
VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
|
||||
VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
|
||||
VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
|
||||
VPBlockUtils::connectBlocks(R2BB1, R2BB2);
|
||||
|
||||
VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
|
||||
R2->setParent(R1);
|
||||
|
||||
VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
|
||||
VPBlockUtils::connectBlocks(VPBB1, R1);
|
||||
|
||||
// Depth-first.
|
||||
VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
|
||||
SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
|
||||
EXPECT_EQ(5u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB1, FromIterator[0]);
|
||||
EXPECT_EQ(R1, FromIterator[1]);
|
||||
EXPECT_EQ(R2, FromIterator[2]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[3]);
|
||||
EXPECT_EQ(R2BB2, FromIterator[4]);
|
||||
|
||||
// Post-order.
|
||||
FromIterator.clear();
|
||||
FromIterator.append(po_begin(Start), po_end(Start));
|
||||
EXPECT_EQ(5u, FromIterator.size());
|
||||
EXPECT_EQ(R2BB2, FromIterator[0]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[1]);
|
||||
EXPECT_EQ(R2, FromIterator[2]);
|
||||
EXPECT_EQ(R1, FromIterator[3]);
|
||||
EXPECT_EQ(VPBB1, FromIterator[4]);
|
||||
|
||||
// Use Plan to properly clean up created blocks.
|
||||
VPlan Plan;
|
||||
Plan.setEntry(VPBB1);
|
||||
}
|
||||
|
||||
{
|
||||
// Nested regions with both R3 and R2 being exit nodes without successors.
|
||||
// The successors of R1 should be used.
|
||||
//
|
||||
// VPBB1
|
||||
// |
|
||||
// R1 {
|
||||
// \
|
||||
// R2 {
|
||||
// \
|
||||
// R2BB1
|
||||
// |
|
||||
// R3 {
|
||||
// R3BB1
|
||||
// }
|
||||
// }
|
||||
// |
|
||||
// VPBB2
|
||||
//
|
||||
VPBasicBlock *R3BB1 = new VPBasicBlock("R3BB1");
|
||||
VPRegionBlock *R3 = new VPRegionBlock(R3BB1, R3BB1, "R3");
|
||||
|
||||
VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
|
||||
VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R3, "R2");
|
||||
R3->setParent(R2);
|
||||
VPBlockUtils::connectBlocks(R2BB1, R3);
|
||||
|
||||
VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
|
||||
R2->setParent(R1);
|
||||
|
||||
VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
|
||||
VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
|
||||
VPBlockUtils::connectBlocks(VPBB1, R1);
|
||||
VPBlockUtils::connectBlocks(R1, VPBB2);
|
||||
|
||||
// Depth-first.
|
||||
VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
|
||||
SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
|
||||
EXPECT_EQ(7u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB1, FromIterator[0]);
|
||||
EXPECT_EQ(R1, FromIterator[1]);
|
||||
EXPECT_EQ(R2, FromIterator[2]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[3]);
|
||||
EXPECT_EQ(R3, FromIterator[4]);
|
||||
EXPECT_EQ(R3BB1, FromIterator[5]);
|
||||
EXPECT_EQ(VPBB2, FromIterator[6]);
|
||||
|
||||
// Post-order.
|
||||
FromIterator.clear();
|
||||
copy(post_order(Start), std::back_inserter(FromIterator));
|
||||
EXPECT_EQ(7u, FromIterator.size());
|
||||
EXPECT_EQ(VPBB2, FromIterator[0]);
|
||||
EXPECT_EQ(R3BB1, FromIterator[1]);
|
||||
EXPECT_EQ(R3, FromIterator[2]);
|
||||
EXPECT_EQ(R2BB1, FromIterator[3]);
|
||||
EXPECT_EQ(R2, FromIterator[4]);
|
||||
EXPECT_EQ(R1, FromIterator[5]);
|
||||
EXPECT_EQ(VPBB1, FromIterator[6]);
|
||||
|
||||
// Use Plan to properly clean up created blocks.
|
||||
VPlan Plan;
|
||||
Plan.setEntry(VPBB1);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
TEST(VPBasicBlockTest, print) {
|
||||
VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
|
||||
|
Loading…
Reference in New Issue
Block a user