[llvm] [DominanceFrontier] Support multiple root nodes for post-dom (PR #181257)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 14:06:35 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Andrei Elovikov (eas)
<details>
<summary>Changes</summary>
Post-dominator tree has a notion of a single virtual root node, use that in the dominance-frontier implementation to support multiple root nodes.
Originally part of https://github.com/llvm/llvm-project/pull/179336 but split up into a separate later PR to ease review.
---
Full diff: https://github.com/llvm/llvm-project/pull/181257.diff
3 Files Affected:
- (modified) llvm/include/llvm/Analysis/DominanceFrontier.h (+3-8)
- (modified) llvm/include/llvm/Analysis/DominanceFrontierImpl.h (+29-13)
- (modified) llvm/unittests/Transforms/Vectorize/VPPostDomFrontierTest.cpp (+64)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DominanceFrontier.h b/llvm/include/llvm/Analysis/DominanceFrontier.h
index 4af1ce46b6ae2..038731f2ca94e 100644
--- a/llvm/include/llvm/Analysis/DominanceFrontier.h
+++ b/llvm/include/llvm/Analysis/DominanceFrontier.h
@@ -101,16 +101,11 @@ class DominanceFrontierBase {
#endif
void analyze(DomTreeT &DT) {
- assert(IsPostDom || DT.root_size() == 1 &&
- "Only one entry block for forward domfronts!");
- assert(DT.root_size() == 1 &&
- "Support for post-dom frontiers with multiple roots hasn't been "
- "implemented yet!");
- this->Roots = {DT.getRoot()};
- calculate(DT, DT[this->Roots[0]]);
+ copy(DT.roots(), std::back_inserter(Roots));
+ calculate(DT);
}
- void calculate(const DomTreeT &DT, const DomTreeNodeT *Node);
+ void calculate(const DomTreeT &DT);
};
class DominanceFrontier : public DominanceFrontierBase<BasicBlock, false> {
diff --git a/llvm/include/llvm/Analysis/DominanceFrontierImpl.h b/llvm/include/llvm/Analysis/DominanceFrontierImpl.h
index 9919f5432fb16..1973adc36cfc5 100644
--- a/llvm/include/llvm/Analysis/DominanceFrontierImpl.h
+++ b/llvm/include/llvm/Analysis/DominanceFrontierImpl.h
@@ -74,14 +74,16 @@ void DominanceFrontierBase<BlockT, IsPostDom>::dump() const {
#endif
template <class BlockT, bool IsPostDom>
-void DominanceFrontierBase<BlockT, IsPostDom>::calculate(
- const DomTreeT &DT, const DomTreeNodeT *Node) {
- BlockT *BB = Node->getBlock();
+void DominanceFrontierBase<BlockT, IsPostDom>::calculate(const DomTreeT &DT) {
+ // NOTE: RootNode might be virtual for `IsPostDom == true`.
+ const DomTreeNodeT *RootNode = DT.getRootNode();
+ BlockT *BB = RootNode->getBlock();
std::vector<DFCalculateWorkObject<BlockT>> workList;
SmallPtrSet<BlockT *, 32> visited;
- workList.push_back(DFCalculateWorkObject<BlockT>(BB, nullptr, Node, nullptr));
+ workList.push_back(
+ DFCalculateWorkObject<BlockT>(BB, nullptr, RootNode, nullptr));
do {
DFCalculateWorkObject<BlockT> *currentW = &workList.back();
assert(currentW && "Missing work object.");
@@ -90,17 +92,22 @@ void DominanceFrontierBase<BlockT, IsPostDom>::calculate(
BlockT *parentBB = currentW->parentBB;
const DomTreeNodeT *currentNode = currentW->Node;
const DomTreeNodeT *parentNode = currentW->parentNode;
- assert(currentBB && "Invalid work object. Missing current Basic Block");
assert(currentNode && "Invalid work object. Missing current Node");
- DomSetType &S = this->Frontiers[currentBB];
// Visit each block only once.
if (visited.insert(currentBB).second) {
- // Loop over CFG successors to calculate DFlocal[currentNode]
- for (const auto Child : children<GraphTy>(currentBB)) {
- // Does Node immediately dominate this successor?
- if (DT[Child]->getIDom() != currentNode)
- S.insert(Child);
+ // Loop over CFG successors to calculate DFlocal[currentNode].
+ //
+ // Note that for `IsPostDom == true`, virtual root node (empty currentBB)
+ // is an immediate post-dominator for all the exit nodes (which are
+ // virtual node's CFG successors).
+ if (currentBB) {
+ DomSetType &S = this->Frontiers[currentBB];
+ for (const auto Child : children<GraphTy>(currentBB)) {
+ // Does Node immediately dominate this successor?
+ if (DT[Child]->getIDom() != currentNode)
+ S.insert(Child);
+ }
}
}
@@ -123,17 +130,26 @@ void DominanceFrontierBase<BlockT, IsPostDom>::calculate(
// If all children are visited or there is any child then pop this block
// from the workList.
if (!visitChild) {
- if (!parentBB) {
+ if (RootNode == currentNode) {
break;
}
+ workList.pop_back();
+ if (!parentBB) {
+ assert(IsPostDom && "For forward frontiers only root node (processed "
+ "above) might not have a parent.");
+ // Processing below isn't necessary for the virtual root node in case
+ // of post-dominance frontier.
+ continue;
+ }
+
+ DomSetType &S = this->Frontiers[currentBB];
typename DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
DomSetType &parentSet = this->Frontiers[parentBB];
for (; CDFI != CDFE; ++CDFI) {
if (!DT.properlyDominates(parentNode, DT[*CDFI]))
parentSet.insert(*CDFI);
}
- workList.pop_back();
}
} while (!workList.empty());
diff --git a/llvm/unittests/Transforms/Vectorize/VPPostDomFrontierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPPostDomFrontierTest.cpp
index a8097a4e1d5ca..f15f078c3a419 100644
--- a/llvm/unittests/Transforms/Vectorize/VPPostDomFrontierTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPPostDomFrontierTest.cpp
@@ -90,5 +90,69 @@ TEST_F(VPPostDomFrontierTest, SingleExitTest) {
EXPECT_EQ(F7.size(), 0u);
}
+TEST_F(VPPostDomFrontierTest, MultipleExitsTest) {
+ // VPBB0
+ // / \
+ // VBBB1 VBB2->VPBB3
+ // / \ |
+ // VPBB4 VPBB5
+ // \ /
+ // VPBB6
+ VPlan &Plan = getPlan();
+ VPBasicBlock *VPBB0 = Plan.getEntry();
+ VPBasicBlock *VPBB1 = Plan.createVPBasicBlock("VPBB1");
+ VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("VPBB2");
+ VPBasicBlock *VPBB3 = Plan.createVPBasicBlock("VPBB3");
+ VPBasicBlock *VPBB4 = Plan.createVPBasicBlock("VPBB4");
+ VPBasicBlock *VPBB5 = Plan.createVPBasicBlock("VPBB5");
+ VPBasicBlock *VPBB6 = Plan.createVPBasicBlock("VPBB6");
+
+ VPBlockUtils::connectBlocks(VPBB0, VPBB1);
+ VPBlockUtils::connectBlocks(VPBB0, VPBB2);
+ VPBlockUtils::connectBlocks(VPBB1, VPBB4);
+ VPBlockUtils::connectBlocks(VPBB1, VPBB5);
+ VPBlockUtils::connectBlocks(VPBB2, VPBB5);
+ VPBlockUtils::connectBlocks(VPBB2, VPBB3);
+ VPBlockUtils::connectBlocks(VPBB4, VPBB6);
+ VPBlockUtils::connectBlocks(VPBB5, VPBB6);
+
+ PostDomTreeBase<VPBlockBase> VPPDT;
+ VPPDT.recalculate(Plan);
+ DominanceFrontierBase<VPBlockBase, true> VPPDF;
+ VPPDF.analyze(VPPDT);
+
+ EXPECT_TRUE(VPPDF.find(VPBB0) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB1) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB2) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB3) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB4) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB5) != VPPDF.end());
+ EXPECT_TRUE(VPPDF.find(VPBB6) != VPPDF.end());
+
+ auto F0 = VPPDF.find(VPBB0)->second;
+ auto F1 = VPPDF.find(VPBB1)->second;
+ auto F2 = VPPDF.find(VPBB2)->second;
+ auto F3 = VPPDF.find(VPBB3)->second;
+ auto F4 = VPPDF.find(VPBB4)->second;
+ auto F5 = VPPDF.find(VPBB5)->second;
+ auto F6 = VPPDF.find(VPBB6)->second;
+
+ EXPECT_EQ(F0.size(), 0u);
+ EXPECT_EQ(F1.size(), 1u);
+ EXPECT_TRUE(is_contained(F1, VPBB0));
+ EXPECT_EQ(F2.size(), 1u);
+ EXPECT_TRUE(is_contained(F2, VPBB0));
+ EXPECT_EQ(F3.size(), 1u);
+ EXPECT_TRUE(is_contained(F3, VPBB2));
+ EXPECT_EQ(F4.size(), 1u);
+ EXPECT_TRUE(is_contained(F4, VPBB1));
+ EXPECT_EQ(F5.size(), 2u);
+ EXPECT_TRUE(is_contained(F5, VPBB1));
+ EXPECT_TRUE(is_contained(F5, VPBB2));
+ EXPECT_EQ(F6.size(), 2u);
+ EXPECT_TRUE(is_contained(F6, VPBB0));
+ EXPECT_TRUE(is_contained(F6, VPBB2));
+}
+
} // namespace
} // namespace llvm
``````````
</details>
https://github.com/llvm/llvm-project/pull/181257
More information about the llvm-commits
mailing list