[llvm] [VPlan] Generalize `VPAllSuccessorsIterator` to support predecessors (PR #178724)
Andrei Elovikov via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 3 07:13:59 PST 2026
https://github.com/eas updated https://github.com/llvm/llvm-project/pull/178724
>From cdbcde8d7fed719d3eb958756183a827f5572193 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Thu, 29 Jan 2026 10:45:12 -0800
Subject: [PATCH 1/9] [VPlan] Generalize `VPAllSuccessorsIterator` to support
predecessors
To be used in Mel's https://github.com/llvm/llvm-project/pull/173265.
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 162 +++++++++++-------
.../Transforms/Vectorize/VPlanTest.cpp | 36 +++-
2 files changed, 136 insertions(+), 62 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index c79485c4cea71..c96a8cf687531 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -25,90 +25,132 @@ namespace llvm {
// GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs //
//===----------------------------------------------------------------------===//
-/// 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. Region blocks themselves traverse only their entries
-// directly and not their successors. Those will be traversed when a region's
-// exiting block is traversed
-template <typename BlockPtrTy>
-class VPAllSuccessorsIterator
- : public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>,
- std::bidirectional_iterator_tag,
- VPBlockBase> {
+/// Iterator to traverse all successors/predecessors of a VPBlockBase node, such
+/// that:
+///
+/// A
+/// |
+/// +-----+ <- Region R
+/// | b |
+/// | |
+/// | ... |
+/// | |
+/// | e |
+/// +-----+
+/// |
+/// B
+///
+/// children(A) == {R} ; Forward == true
+/// children(R) == {b} ; Forward == true
+/// children(e) == {B} ; Forward == true
+///
+/// children(B) == {R} ; Forward == false
+/// children(R) == {e} ; Forward == false
+/// children(b) == {A} ; Forward == false
+///
+/// This ensures that all blocks of the region are visited before continuing
+/// traversal outside the region when doing a reverse post-order traversal of
+/// the VPlan.
+///
+template <typename BlockPtrTy, bool Forward = true>
+class VPImmediateHierarchicalChildrenIterator
+ : public iterator_facade_base<
+ VPImmediateHierarchicalChildrenIterator<BlockPtrTy, Forward>,
+ std::bidirectional_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)
+ /// Index of the current successor/predecessor.
+ ///
+ /// For VPBasicBlock nodes, this simply is the index for the
+ /// successors/predecessors array. For VPRegionBlock, EdgeIdx == 0 is used for
+ /// the region's entry/exiting block, and EdgeIdx - 1 are the indices for the
+ /// successors/predecessors array.
+ size_t EdgeIdx;
+
+ static auto getNumOutgoingEdges(BlockPtrTy Current) {
+ if constexpr (Forward)
+ return Current->getNumSuccessors();
+ else
+ return Current->getNumPredecessors();
+ }
+
+ static decltype(auto) getOutgoingEdges(BlockPtrTy Current) {
+ if constexpr (Forward)
+ return Current->getSuccessors();
+ else
+ return Current->getPredecessors();
+ }
+
+ static BlockPtrTy getBlockWithOutgoingEdges(BlockPtrTy Current) {
+ while (Current && getNumOutgoingEdges(Current) == 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) {
+ template <typename T1> static T1 deref(T1 Block, unsigned EdgeIdx) {
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
- assert(SuccIdx == 0);
- return R->getEntry();
+ assert(EdgeIdx == 0);
+ if constexpr (Forward)
+ return R->getEntry();
+ else
+ return R->getExiting();
}
// For exit blocks, use the next parent region with successors.
- return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx];
+ return getOutgoingEdges(getBlockWithOutgoingEdges(Block))[EdgeIdx];
}
public:
/// Used by iterator_facade_base with bidirectional_iterator_tag.
using reference = BlockPtrTy;
- VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0)
- : Block(Block), SuccessorIdx(Idx) {}
- VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other)
- : Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {}
+ VPImmediateHierarchicalChildrenIterator(BlockPtrTy Block, size_t Idx = 0)
+ : Block(Block), EdgeIdx(Idx) {}
+ VPImmediateHierarchicalChildrenIterator(
+ const VPImmediateHierarchicalChildrenIterator &Other)
+ : Block(Other.Block), EdgeIdx(Other.EdgeIdx) {}
- VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) {
+ VPImmediateHierarchicalChildrenIterator &
+ operator=(const VPImmediateHierarchicalChildrenIterator &R) {
Block = R.Block;
- SuccessorIdx = R.SuccessorIdx;
+ EdgeIdx = R.EdgeIdx;
return *this;
}
- static VPAllSuccessorsIterator end(BlockPtrTy Block) {
+ static VPImmediateHierarchicalChildrenIterator end(BlockPtrTy Block) {
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
- // Traverse through the region's entry node.
+ // Traverse through the region's entry/exiting (based on Forward) node.
return {R, 1};
}
- BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block);
- unsigned NumSuccessors =
- ParentWithSuccs ? ParentWithSuccs->getNumSuccessors() : 0;
- return {Block, NumSuccessors};
+ BlockPtrTy ParentWithOutgoingEdges = getBlockWithOutgoingEdges(Block);
+ unsigned NumOutgoingEdges =
+ ParentWithOutgoingEdges ? getNumOutgoingEdges(ParentWithOutgoingEdges)
+ : 0;
+ return {Block, NumOutgoingEdges};
}
- bool operator==(const VPAllSuccessorsIterator &R) const {
- return Block == R.Block && SuccessorIdx == R.SuccessorIdx;
+ bool operator==(const VPImmediateHierarchicalChildrenIterator &R) const {
+ return Block == R.Block && EdgeIdx == R.EdgeIdx;
}
- const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); }
+ const VPBlockBase *operator*() const { return deref(Block, EdgeIdx); }
- BlockPtrTy operator*() { return deref(Block, SuccessorIdx); }
+ BlockPtrTy operator*() { return deref(Block, EdgeIdx); }
- VPAllSuccessorsIterator &operator++() {
- SuccessorIdx++;
+ VPImmediateHierarchicalChildrenIterator &operator++() {
+ EdgeIdx++;
return *this;
}
- VPAllSuccessorsIterator &operator--() {
- SuccessorIdx--;
+ VPImmediateHierarchicalChildrenIterator &operator--() {
+ EdgeIdx--;
return *this;
}
- VPAllSuccessorsIterator operator++(int X) {
- VPAllSuccessorsIterator Orig = *this;
- SuccessorIdx++;
+ VPImmediateHierarchicalChildrenIterator operator++(int X) {
+ VPImmediateHierarchicalChildrenIterator Orig = *this;
+ EdgeIdx++;
return Orig;
}
};
@@ -129,7 +171,8 @@ template <typename BlockTy> class VPBlockDeepTraversalWrapper {
/// reverse post-order traversal of the graph.
template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
- using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
+ using ChildIteratorType =
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *>;
static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<VPBlockBase *> N) {
return N.getEntry();
@@ -147,7 +190,8 @@ template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> {
template <>
struct GraphTraits<VPBlockDeepTraversalWrapper<const VPBlockBase *>> {
using NodeRef = const VPBlockBase *;
- using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
+ using ChildIteratorType =
+ VPImmediateHierarchicalChildrenIterator<const VPBlockBase *>;
static NodeRef
getEntryNode(VPBlockDeepTraversalWrapper<const VPBlockBase *> N) {
@@ -257,7 +301,8 @@ vp_depth_first_deep(const VPBlockBase *G) {
template <> struct GraphTraits<VPBlockBase *> {
using NodeRef = VPBlockBase *;
- using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
+ using ChildIteratorType =
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -272,7 +317,8 @@ template <> struct GraphTraits<VPBlockBase *> {
template <> struct GraphTraits<const VPBlockBase *> {
using NodeRef = const VPBlockBase *;
- using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
+ using ChildIteratorType =
+ VPImmediateHierarchicalChildrenIterator<const VPBlockBase *>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -285,23 +331,19 @@ template <> struct GraphTraits<const VPBlockBase *> {
}
};
-/// Inverse graph traits are not implemented yet.
-/// TODO: Implement a version of VPBlockNonRecursiveTraversalWrapper to traverse
-/// predecessors recursively through regions.
template <> struct GraphTraits<Inverse<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
- using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator;
+ using ChildIteratorType =
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *, /*Forward=*/false>;
- static NodeRef getEntryNode(Inverse<NodeRef> B) {
- llvm_unreachable("not implemented");
- }
+ static NodeRef getEntryNode(Inverse<NodeRef> B) { return B.Graph; }
static inline ChildIteratorType child_begin(NodeRef N) {
- llvm_unreachable("not implemented");
+ return ChildIteratorType{N};
}
static inline ChildIteratorType child_end(NodeRef N) {
- llvm_unreachable("not implemented");
+ return ChildIteratorType::end(N);
}
};
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index 9b1e7c0af7c8c..a93ca45772460 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -388,11 +388,28 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
// Successors of R1.
SmallVector<const VPBlockBase *> FromIterator(
- VPAllSuccessorsIterator<VPBlockBase *>(R1),
- VPAllSuccessorsIterator<VPBlockBase *>::end(R1));
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *>(R1),
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *>::end(R1));
EXPECT_EQ(1u, FromIterator.size());
EXPECT_EQ(R1BB1, FromIterator[0]);
+ // Predecessors of R1.
+ FromIterator.clear();
+ copy(VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>(R1),
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>::end(R1),
+ std::back_inserter(FromIterator));
+ EXPECT_EQ(1u, FromIterator.size());
+ EXPECT_EQ(R1BB4, FromIterator[0]);
+
+ // Predecessors of R1BB1.
+ FromIterator.clear();
+ copy(VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>(R1BB1),
+ VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>::end(
+ R1BB1),
+ std::back_inserter(FromIterator));
+ EXPECT_EQ(1u, FromIterator.size());
+ EXPECT_EQ(VPBB0, FromIterator[0]);
+
// Depth-first.
VPBlockDeepTraversalWrapper<VPBlockBase *> Start(R1);
FromIterator.clear();
@@ -407,6 +424,21 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
EXPECT_EQ(R2BB2, FromIterator[6]);
EXPECT_EQ(R1BB3, FromIterator[7]);
+ // Depth-first on the inverse graph (traverse predecessors).
+ FromIterator.clear();
+ copy(depth_first<Inverse<VPBlockBase *>>(R2),
+ std::back_inserter(FromIterator));
+ EXPECT_EQ(9u, FromIterator.size());
+ EXPECT_EQ(R2, FromIterator[0]);
+ EXPECT_EQ(R2BB2, FromIterator[1]);
+ EXPECT_EQ(R2BB1, FromIterator[2]);
+ EXPECT_EQ(R1, FromIterator[3]);
+ EXPECT_EQ(R1BB4, FromIterator[4]);
+ EXPECT_EQ(R1BB2, FromIterator[5]);
+ EXPECT_EQ(R1BB1, FromIterator[6]);
+ EXPECT_EQ(VPBB0, FromIterator[7]);
+ EXPECT_EQ(R1BB3, FromIterator[8]);
+
// const VPBasicBlocks only.
FromIterator.clear();
copy(VPBlockUtils::blocksOnly<const VPBasicBlock>(depth_first(Start)),
>From b14e7a4728ebf4075b7f263a9dc55b3067e5ff37 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <a.elovikov at gmail.com>
Date: Mon, 2 Feb 2026 08:08:49 -0800
Subject: [PATCH 2/9] Apply suggestions from code review
Co-authored-by: Florian Hahn <flo at fhahn.com>
Co-authored-by: Luke Lau <luke_lau at icloud.com>
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index c96a8cf687531..a48ae48416be9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -25,7 +25,7 @@ namespace llvm {
// GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs //
//===----------------------------------------------------------------------===//
-/// Iterator to traverse all successors/predecessors of a VPBlockBase node, such
+/// Iterator to traverse all successors/predecessors of a VPBlockBase node, including its hierarchical successors/predecessors. For example:
/// that:
///
/// A
@@ -66,14 +66,14 @@ class VPImmediateHierarchicalChildrenIterator
/// successors/predecessors array.
size_t EdgeIdx;
- static auto getNumOutgoingEdges(BlockPtrTy Current) {
+ static size_t getNumOutgoingEdges(BlockPtrTy Current) {
if constexpr (Forward)
return Current->getNumSuccessors();
else
return Current->getNumPredecessors();
}
- static decltype(auto) getOutgoingEdges(BlockPtrTy Current) {
+ static SmallVectorImpl<BlockPtrTy> &getOutgoingEdges(BlockPtrTy Current) {
if constexpr (Forward)
return Current->getSuccessors();
else
@@ -339,7 +339,7 @@ template <> struct GraphTraits<Inverse<VPBlockBase *>> {
static NodeRef getEntryNode(Inverse<NodeRef> B) { return B.Graph; }
static inline ChildIteratorType child_begin(NodeRef N) {
- return ChildIteratorType{N};
+ return ChildIteratorType(N);
}
static inline ChildIteratorType child_end(NodeRef N) {
>From 319c6ed6c6f03b8190de42406e7debe47bb9dc67 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 08:25:17 -0800
Subject: [PATCH 3/9] Update comments per code-review suggestions
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index a48ae48416be9..124c5f3f50754 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -25,8 +25,8 @@ namespace llvm {
// GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs //
//===----------------------------------------------------------------------===//
-/// Iterator to traverse all successors/predecessors of a VPBlockBase node, including its hierarchical successors/predecessors. For example:
-/// that:
+/// Iterator to traverse all successors/predecessors of a VPBlockBase node,
+/// including its hierarchical successors/predecessors. For example: that:
///
/// A
/// |
@@ -40,18 +40,23 @@ namespace llvm {
/// |
/// B
///
-/// children(A) == {R} ; Forward == true
-/// children(R) == {b} ; Forward == true
-/// children(e) == {B} ; Forward == true
+/// Forward == true:
+/// Region blocks themselves traverse only their entries directly:
+/// Region's successor is traversed when processing its exiting block:
+/// children(A) == {R}
+/// children(R) == {b}
+/// children(e) == {B}
///
-/// children(B) == {R} ; Forward == false
-/// children(R) == {e} ; Forward == false
-/// children(b) == {A} ; Forward == false
+/// Forward == false:
+/// Region blocks themselves traverse only their exiting blocks directly:
+/// Region's predecessor is traversed when processing its entry block:
+/// children(B) == {R}
+/// children(R) == {e}
+/// children(b) == {A}
///
/// This ensures that all blocks of the region are visited before continuing
/// traversal outside the region when doing a reverse post-order traversal of
/// the VPlan.
-///
template <typename BlockPtrTy, bool Forward = true>
class VPImmediateHierarchicalChildrenIterator
: public iterator_facade_base<
>From 631b7501ecc2b232e6a435e3bcd82b4489ad0bf2 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 08:31:15 -0800
Subject: [PATCH 4/9] Drop "For example: that:"
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index 124c5f3f50754..e6e2f9fd23953 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -26,7 +26,7 @@ namespace llvm {
//===----------------------------------------------------------------------===//
/// Iterator to traverse all successors/predecessors of a VPBlockBase node,
-/// including its hierarchical successors/predecessors. For example: that:
+/// including its hierarchical successors/predecessors:
///
/// A
/// |
>From a857ea7737eb436c3ec9a3866e95286baccb8991 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 08:45:46 -0800
Subject: [PATCH 5/9] Restore `decltype(auto)` return type to fix the build
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index e6e2f9fd23953..9c9ed6666f011 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -78,7 +78,10 @@ class VPImmediateHierarchicalChildrenIterator
return Current->getNumPredecessors();
}
- static SmallVectorImpl<BlockPtrTy> &getOutgoingEdges(BlockPtrTy Current) {
+ /// Auto-deduce resulting type depending on the constness of the template type
+ /// parameter BlockPtrTy. Use `decltype(auto)` instead of just `auto` to
+ /// preserve reference and avoid copies.
+ static decltype(auto) getOutgoingEdges(BlockPtrTy Current) {
if constexpr (Forward)
return Current->getSuccessors();
else
>From b8f912c9bd0a25a97a2ebfbeca85d4bac99c1a41 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 15:08:22 -0800
Subject: [PATCH 6/9] Rename
VPImmediateHierarchicalChildrenIterator->VPHierarchicalChildrenIterator
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 39 ++++++++-----------
.../Transforms/Vectorize/VPlanTest.cpp | 13 +++----
2 files changed, 23 insertions(+), 29 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index 9c9ed6666f011..c40faa7bebde9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -58,9 +58,9 @@ namespace llvm {
/// traversal outside the region when doing a reverse post-order traversal of
/// the VPlan.
template <typename BlockPtrTy, bool Forward = true>
-class VPImmediateHierarchicalChildrenIterator
+class VPHierarchicalChildrenIterator
: public iterator_facade_base<
- VPImmediateHierarchicalChildrenIterator<BlockPtrTy, Forward>,
+ VPHierarchicalChildrenIterator<BlockPtrTy, Forward>,
std::bidirectional_iterator_tag, VPBlockBase> {
BlockPtrTy Block;
/// Index of the current successor/predecessor.
@@ -113,20 +113,19 @@ class VPImmediateHierarchicalChildrenIterator
/// Used by iterator_facade_base with bidirectional_iterator_tag.
using reference = BlockPtrTy;
- VPImmediateHierarchicalChildrenIterator(BlockPtrTy Block, size_t Idx = 0)
+ VPHierarchicalChildrenIterator(BlockPtrTy Block, size_t Idx = 0)
: Block(Block), EdgeIdx(Idx) {}
- VPImmediateHierarchicalChildrenIterator(
- const VPImmediateHierarchicalChildrenIterator &Other)
+ VPHierarchicalChildrenIterator(const VPHierarchicalChildrenIterator &Other)
: Block(Other.Block), EdgeIdx(Other.EdgeIdx) {}
- VPImmediateHierarchicalChildrenIterator &
- operator=(const VPImmediateHierarchicalChildrenIterator &R) {
+ VPHierarchicalChildrenIterator &
+ operator=(const VPHierarchicalChildrenIterator &R) {
Block = R.Block;
EdgeIdx = R.EdgeIdx;
return *this;
}
- static VPImmediateHierarchicalChildrenIterator end(BlockPtrTy Block) {
+ static VPHierarchicalChildrenIterator end(BlockPtrTy Block) {
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
// Traverse through the region's entry/exiting (based on Forward) node.
return {R, 1};
@@ -138,7 +137,7 @@ class VPImmediateHierarchicalChildrenIterator
return {Block, NumOutgoingEdges};
}
- bool operator==(const VPImmediateHierarchicalChildrenIterator &R) const {
+ bool operator==(const VPHierarchicalChildrenIterator &R) const {
return Block == R.Block && EdgeIdx == R.EdgeIdx;
}
@@ -146,18 +145,18 @@ class VPImmediateHierarchicalChildrenIterator
BlockPtrTy operator*() { return deref(Block, EdgeIdx); }
- VPImmediateHierarchicalChildrenIterator &operator++() {
+ VPHierarchicalChildrenIterator &operator++() {
EdgeIdx++;
return *this;
}
- VPImmediateHierarchicalChildrenIterator &operator--() {
+ VPHierarchicalChildrenIterator &operator--() {
EdgeIdx--;
return *this;
}
- VPImmediateHierarchicalChildrenIterator operator++(int X) {
- VPImmediateHierarchicalChildrenIterator Orig = *this;
+ VPHierarchicalChildrenIterator operator++(int X) {
+ VPHierarchicalChildrenIterator Orig = *this;
EdgeIdx++;
return Orig;
}
@@ -179,8 +178,7 @@ template <typename BlockTy> class VPBlockDeepTraversalWrapper {
/// reverse post-order traversal of the graph.
template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
- using ChildIteratorType =
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *>;
+ using ChildIteratorType = VPHierarchicalChildrenIterator<VPBlockBase *>;
static NodeRef getEntryNode(VPBlockDeepTraversalWrapper<VPBlockBase *> N) {
return N.getEntry();
@@ -198,8 +196,7 @@ template <> struct GraphTraits<VPBlockDeepTraversalWrapper<VPBlockBase *>> {
template <>
struct GraphTraits<VPBlockDeepTraversalWrapper<const VPBlockBase *>> {
using NodeRef = const VPBlockBase *;
- using ChildIteratorType =
- VPImmediateHierarchicalChildrenIterator<const VPBlockBase *>;
+ using ChildIteratorType = VPHierarchicalChildrenIterator<const VPBlockBase *>;
static NodeRef
getEntryNode(VPBlockDeepTraversalWrapper<const VPBlockBase *> N) {
@@ -309,8 +306,7 @@ vp_depth_first_deep(const VPBlockBase *G) {
template <> struct GraphTraits<VPBlockBase *> {
using NodeRef = VPBlockBase *;
- using ChildIteratorType =
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *>;
+ using ChildIteratorType = VPHierarchicalChildrenIterator<VPBlockBase *>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -325,8 +321,7 @@ template <> struct GraphTraits<VPBlockBase *> {
template <> struct GraphTraits<const VPBlockBase *> {
using NodeRef = const VPBlockBase *;
- using ChildIteratorType =
- VPImmediateHierarchicalChildrenIterator<const VPBlockBase *>;
+ using ChildIteratorType = VPHierarchicalChildrenIterator<const VPBlockBase *>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -342,7 +337,7 @@ template <> struct GraphTraits<const VPBlockBase *> {
template <> struct GraphTraits<Inverse<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
using ChildIteratorType =
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *, /*Forward=*/false>;
+ VPHierarchicalChildrenIterator<VPBlockBase *, /*Forward=*/false>;
static NodeRef getEntryNode(Inverse<NodeRef> B) { return B.Graph; }
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index a93ca45772460..12ab48e598269 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -388,24 +388,23 @@ TEST_F(VPBasicBlockTest, TraversingIteratorTest) {
// Successors of R1.
SmallVector<const VPBlockBase *> FromIterator(
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *>(R1),
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *>::end(R1));
+ VPHierarchicalChildrenIterator<VPBlockBase *>(R1),
+ VPHierarchicalChildrenIterator<VPBlockBase *>::end(R1));
EXPECT_EQ(1u, FromIterator.size());
EXPECT_EQ(R1BB1, FromIterator[0]);
// Predecessors of R1.
FromIterator.clear();
- copy(VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>(R1),
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>::end(R1),
+ copy(VPHierarchicalChildrenIterator<VPBlockBase *, false>(R1),
+ VPHierarchicalChildrenIterator<VPBlockBase *, false>::end(R1),
std::back_inserter(FromIterator));
EXPECT_EQ(1u, FromIterator.size());
EXPECT_EQ(R1BB4, FromIterator[0]);
// Predecessors of R1BB1.
FromIterator.clear();
- copy(VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>(R1BB1),
- VPImmediateHierarchicalChildrenIterator<VPBlockBase *, false>::end(
- R1BB1),
+ copy(VPHierarchicalChildrenIterator<VPBlockBase *, false>(R1BB1),
+ VPHierarchicalChildrenIterator<VPBlockBase *, false>::end(R1BB1),
std::back_inserter(FromIterator));
EXPECT_EQ(1u, FromIterator.size());
EXPECT_EQ(VPBB0, FromIterator[0]);
>From ab6810035f771e9ba7edc754c9b02fad9a48dfc9 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 15:14:56 -0800
Subject: [PATCH 7/9] Some changes to the comments, hopefully to address CR
feedback
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 26 ++++++++++++------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index c40faa7bebde9..becb6804e85cd 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -41,34 +41,34 @@ namespace llvm {
/// B
///
/// Forward == true:
-/// Region blocks themselves traverse only their entries directly:
-/// Region's successor is traversed when processing its exiting block:
+/// Region blocks themselves traverse only their entries directly.
+/// Region's successor is implictly traversed when processing its exiting
+/// block.
/// children(A) == {R}
/// children(R) == {b}
/// children(e) == {B}
///
/// Forward == false:
-/// Region blocks themselves traverse only their exiting blocks directly:
-/// Region's predecessor is traversed when processing its entry block:
+/// Region blocks themselves traverse only their exiting blocks directly.
+/// Region's predecessor is implicitly traversed when processing its entry
+/// block.
/// children(B) == {R}
/// children(R) == {e}
/// children(b) == {A}
///
-/// This ensures that all blocks of the region are visited before continuing
-/// traversal outside the region when doing a reverse post-order traversal of
-/// the VPlan.
+/// The scheme described above ensures that all blocks of the region are visited
+/// before continuing traversal outside the region when doing a reverse
+/// post-order traversal of the VPlan.
template <typename BlockPtrTy, bool Forward = true>
class VPHierarchicalChildrenIterator
: public iterator_facade_base<
VPHierarchicalChildrenIterator<BlockPtrTy, Forward>,
std::bidirectional_iterator_tag, VPBlockBase> {
BlockPtrTy Block;
- /// Index of the current successor/predecessor.
- ///
- /// For VPBasicBlock nodes, this simply is the index for the
- /// successors/predecessors array. For VPRegionBlock, EdgeIdx == 0 is used for
- /// the region's entry/exiting block, and EdgeIdx - 1 are the indices for the
- /// successors/predecessors array.
+ /// Index of the current successor/predecessor. For VPBasicBlock nodes, this
+ /// simply is the index for the successors/predecessors array. For
+ /// VPRegionBlock, EdgeIdx == 0 is used for the region's entry/exiting block,
+ /// and EdgeIdx - 1 are the indices for the successors/predecessors array.
size_t EdgeIdx;
static size_t getNumOutgoingEdges(BlockPtrTy Current) {
>From 428c2987c98a8762c177b3841ee99d3e3f56c502 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 2 Feb 2026 15:16:49 -0800
Subject: [PATCH 8/9] ArrayRef instead of decltype(auto) return type
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index becb6804e85cd..cc497e1a6034f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -78,10 +78,7 @@ class VPHierarchicalChildrenIterator
return Current->getNumPredecessors();
}
- /// Auto-deduce resulting type depending on the constness of the template type
- /// parameter BlockPtrTy. Use `decltype(auto)` instead of just `auto` to
- /// preserve reference and avoid copies.
- static decltype(auto) getOutgoingEdges(BlockPtrTy Current) {
+ static ArrayRef<BlockPtrTy> getOutgoingEdges(BlockPtrTy Current) {
if constexpr (Forward)
return Current->getSuccessors();
else
>From 9294b97e84f347b1d79c068c68a8c0534b892484 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Tue, 3 Feb 2026 07:13:34 -0800
Subject: [PATCH 9/9] Update comment for `deref`
---
llvm/lib/Transforms/Vectorize/VPlanCFG.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index cc497e1a6034f..ec3016f700fc2 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -91,8 +91,8 @@ class VPHierarchicalChildrenIterator
return Current;
}
- /// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
- /// both the const and non-const operator* implementations.
+ /// Templated helper to dereference successor/predecessor \p EdgeIdx of \p
+ /// Block. Used by both the const and non-const operator* implementations.
template <typename T1> static T1 deref(T1 Block, unsigned EdgeIdx) {
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
assert(EdgeIdx == 0);
More information about the llvm-commits
mailing list