[llvm] [GenericDomTreeConstruction] Use 0-based DFS numbering and a trivial InfoRec (PR #207524)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 4 15:54:20 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/207524
>From 5b99dcd1f6ea1871e17af1e53049f518336e0995 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 4 Jul 2026 09:11:06 -0700
Subject: [PATCH 1/4] [GenericDomTreeConstruction] Switch to 0-based DFS
numbering
... and drop the unused index-0 sentinel from NumToNote/NumToInfo/IDoms.
`Unvisited` (-1u) marks unvisited nodes by DFS. 0 is now the DFS root,
or the virtual root for postdominators.
---
.../llvm/Support/GenericDomTreeConstruction.h | 83 ++++++++++---------
1 file changed, 42 insertions(+), 41 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 869087cda219a..8aff074d6a2a4 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -59,9 +59,12 @@ template <typename DomTreeT> struct SemiNCAInfo {
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
+ // Marks a node that hasn't been visited by DFS.
+ static constexpr unsigned Unvisited = -1u;
+
// Information record used by Semi-NCA during tree construction.
struct InfoRec {
- unsigned DFSNum = 0;
+ unsigned DFSNum = Unvisited;
unsigned Parent = 0;
unsigned Semi = 0;
unsigned Label = 0;
@@ -69,9 +72,9 @@ template <typename DomTreeT> struct SemiNCAInfo {
SmallVector<unsigned, 4> ReverseChildren;
};
- // Number to node mapping is 1-based. Initialize the mapping to start with
- // a dummy element.
- SmallVector<NodePtr, 64> NumToNode = {nullptr};
+ // Map a 0-based DFS number to the node. 0 is the DFS root, or the virtual
+ // root for postdominators.
+ SmallVector<NodePtr, 64> NumToNode;
// If blocks have numbers (e.g., BasicBlock, MachineBasicBlock), store node
// infos in a vector. Otherwise, store them in a map.
std::conditional_t<GraphHasNodeNumbers<NodePtr>, SmallVector<InfoRec, 64>,
@@ -101,7 +104,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {}
void clear() {
- NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
+ NumToNode.clear();
NodeInfos.clear();
// Don't reset the pointer to BatchUpdateInfo here -- if there's an update
// in progress, we need this information to continue it.
@@ -211,11 +214,11 @@ template <typename DomTreeT> struct SemiNCAInfo {
auto &BBInfo = getNodeInfo(BB);
BBInfo.ReverseChildren.push_back(ParentNum);
- // Visited nodes always have positive DFS numbers.
- if (BBInfo.DFSNum != 0)
+ if (BBInfo.DFSNum != Unvisited)
continue;
BBInfo.Parent = ParentNum;
- BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = ++LastNum;
+ unsigned Num = LastNum++;
+ BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = Num;
NumToNode.push_back(BB);
constexpr bool Direction = IsReverse != IsPostDom; // XOR.
@@ -225,7 +228,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (!SuccOrder && !BatchUpdates) {
for (const NodePtr Succ : getChildren<Direction>(BB))
if (Condition(BB, Succ))
- WorkList.push_back({Succ, LastNum});
+ WorkList.push_back({Succ, Num});
continue;
}
@@ -240,7 +243,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (!Condition(BB, Succ))
continue;
- WorkList.push_back({Succ, LastNum});
+ WorkList.push_back({Succ, Num});
}
}
@@ -294,14 +297,14 @@ template <typename DomTreeT> struct SemiNCAInfo {
// This function requires DFS to be run before calling it.
void runSemiNCA() {
const unsigned NextDFSNum(NumToNode.size());
- // NumToInfo and IDoms are indexed by DFS number; index 0 is an unused
- // sentinel. IDoms holds immediate dominators in DFS-number space,
- // initialized below to spanning tree parents.
+ // NumToInfo and IDoms are indexed by DFS number; 0 is the root. IDoms holds
+ // immediate dominators in DFS-number space, initialized below to spanning
+ // tree parents.
SmallVector<InfoRec *, 32> NumToInfo;
NumToInfo.resize_for_overwrite(NextDFSNum);
SmallVector<unsigned, 32> IDoms;
IDoms.resize_for_overwrite(NextDFSNum);
- for (unsigned i = 1; i < NextDFSNum; ++i) {
+ for (unsigned i = 0; i < NextDFSNum; ++i) {
auto &VInfo = getNodeInfo(NumToNode[i]);
IDoms[i] = VInfo.Parent;
NumToInfo[i] = &VInfo;
@@ -309,7 +312,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Step #1: Calculate the semidominators of all vertices.
SmallVector<InfoRec *, 32> EvalStack;
- for (unsigned i = NextDFSNum - 1; i >= 2; --i) {
+ for (unsigned i = NextDFSNum; --i;) {
auto &WInfo = *NumToInfo[i];
// Initialize the semi dominator to point to the parent node.
@@ -324,9 +327,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Step #2: Explicitly define the immediate dominator of each vertex.
// IDom[i] = NCA(SDom[i], SpanningTreeParent(i)).
// SDom[i]'s DFS number is just Semi.
- for (unsigned i = 2; i < NextDFSNum; ++i) {
+ for (unsigned i = 1; i < NextDFSNum; ++i) {
auto &WInfo = *NumToInfo[i];
- assert(WInfo.Semi != 0);
unsigned WIDom = IDoms[i];
while (WIDom > WInfo.Semi)
WIDom = IDoms[WIDom];
@@ -342,12 +344,12 @@ template <typename DomTreeT> struct SemiNCAInfo {
// This functions maps a nullptr CFG node to the virtual root tree node.
void addVirtualRoot() {
assert(IsPostDom && "Only postdominators have a virtual root");
- assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
+ assert(NumToNode.empty() && "SNCAInfo must be freshly constructed");
auto &BBInfo = getNodeInfo(nullptr);
- BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = 1;
+ BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = 0;
- NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
+ NumToNode.push_back(nullptr); // NumToNode[0] = nullptr;
}
// For postdominators, nodes with no forward successors are trivial roots that
@@ -398,11 +400,11 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (!HasForwardSuccessors(N, BUI)) {
Roots.push_back(N);
// Run DFS not to walk this part of CFG later.
- Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
+ Num = SNCA.runDFS(N, Num, AlwaysDescend, 0);
LLVM_DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
<< "\n");
LLVM_DEBUG(dbgs() << "Last visited node: "
- << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
+ << BlockNamePrinter(SNCA.NumToNode[Num - 1]) << "\n");
}
}
@@ -426,7 +428,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
auto InitSuccOrderOnce = [&]() {
SuccOrder = NodeOrderMap();
for (const auto Node : nodes(DT.Parent))
- if (SNCA.getNodeInfo(Node).DFSNum == 0)
+ if (SNCA.getNodeInfo(Node).DFSNum == Unvisited)
for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
SuccOrder->try_emplace(Succ, 0);
@@ -450,7 +452,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
// unreachable node once, we may just visit it in two directions,
// depending on how lucky we get.
for (const NodePtr I : nodes(DT.Parent)) {
- if (SNCA.getNodeInfo(I).DFSNum == 0) {
+ if (SNCA.getNodeInfo(I).DFSNum == Unvisited) {
LLVM_DEBUG(dbgs()
<< "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
// Find the furthest away we can get by following successors, then
@@ -471,14 +473,14 @@ template <typename DomTreeT> struct SemiNCAInfo {
const unsigned NewNum =
SNCA.runDFS<true>(I, Num, AlwaysDescend, Num, &*SuccOrder);
- const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
+ const NodePtr FurthestAway = SNCA.NumToNode[NewNum - 1];
LLVM_DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
<< "(non-trivial root): "
<< BlockNamePrinter(FurthestAway) << "\n");
Roots.push_back(FurthestAway);
LLVM_DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
<< NewNum << "\n\t\t\tRemoving DFS info\n");
- for (unsigned i = NewNum; i > Num; --i) {
+ for (unsigned i = NewNum; i-- > Num;) {
const NodePtr N = SNCA.NumToNode[i];
LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
<< BlockNamePrinter(N) << "\n");
@@ -487,8 +489,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
}
const unsigned PrevNum = Num;
LLVM_DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
- Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
- for (unsigned i = PrevNum + 1; i <= Num; ++i)
+ Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 0);
+ for (unsigned i = PrevNum; i < Num; ++i)
LLVM_DEBUG(dbgs() << "\t\t\t\tfound node "
<< BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
}
@@ -497,7 +499,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
LLVM_DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
LLVM_DEBUG(dbgs() << "Discovered CFG nodes:\n");
- LLVM_DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
+ LLVM_DEBUG(for (size_t i = 0; i < Num; ++i) dbgs()
<< i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
assert((Total + 1 == Num) && "Everything should have been visited");
@@ -539,9 +541,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
SNCA.clear();
// Do a forward walk looking for the other roots.
const unsigned Num = SNCA.runDFS<true>(Root, 0, AlwaysDescend, 0);
- // Skip the start node and begin from the second one (note that DFS uses
- // 1-based indexing).
- for (unsigned x = 2; x <= Num; ++x) {
+ // Skip the start node (DFS number 0).
+ for (unsigned x = 1; x < Num; ++x) {
const NodePtr N = SNCA.NumToNode[x];
// If we wound another root in a (forward) DFS walk, remove the current
// root from the set of roots, as it is reverse-reachable from the other
@@ -573,7 +574,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
addVirtualRoot();
unsigned Num = 1;
for (const NodePtr Root : DT.Roots)
- Num = runDFS(Root, Num, DC, 1);
+ Num = runDFS(Root, Num, DC, 0);
}
static void CalculateFromScratch(DomTreeT &DT, BatchUpdatePtr BUI) {
@@ -618,9 +619,9 @@ template <typename DomTreeT> struct SemiNCAInfo {
void attachNewSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
// Attach the first unreachable block to AttachTo.
- getNodeInfo(NumToNode[1]).IDom = AttachTo->getBlock();
+ getNodeInfo(NumToNode[0]).IDom = AttachTo->getBlock();
// Loop over all of the discovered blocks in the function...
- for (NodePtr W : llvm::drop_begin(NumToNode)) {
+ for (NodePtr W : NumToNode) {
if (DT.getNode(W))
continue; // Already calculated the node before
@@ -636,8 +637,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
}
void reattachExistingSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
- getNodeInfo(NumToNode[1]).IDom = AttachTo->getBlock();
- for (const NodePtr N : llvm::drop_begin(NumToNode)) {
+ getNodeInfo(NumToNode[0]).IDom = AttachTo->getBlock();
+ for (const NodePtr N : NumToNode) {
const TreeNodePtr TN = DT.getNode(N);
assert(TN);
const TreeNodePtr NewIDom = DT.getNode(getNodeInfo(N).IDom);
@@ -1122,7 +1123,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Erase the unreachable subtree in reverse preorder to process all children
// before deleting their parent.
- for (unsigned i = LastDFSNum; i > 0; --i) {
+ for (unsigned i = LastDFSNum; i-- > 0;) {
const NodePtr N = SNCA.NumToNode[i];
LLVM_DEBUG(dbgs() << "Erasing node " << BlockNamePrinter(DT.getNode(N))
<< "\n");
@@ -1290,7 +1291,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (DT.isVirtualRoot(TN))
continue;
- if (getNodeInfo(BB).DFSNum == 0) {
+ if (getNodeInfo(BB).DFSNum == Unvisited) {
errs() << "DomTree node " << BlockNamePrinter(BB)
<< " not found by DFS walk!\n";
errs().flush();
@@ -1503,7 +1504,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
});
for (TreeNodePtr Child : TN->children())
- if (getNodeInfo(Child->getBlock()).DFSNum != 0) {
+ if (getNodeInfo(Child->getBlock()).DFSNum != Unvisited) {
errs() << "Child " << BlockNamePrinter(Child)
<< " reachable after its parent " << BlockNamePrinter(BB)
<< " is removed!\n";
@@ -1541,7 +1542,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (S == N)
continue;
- if (getNodeInfo(S->getBlock()).DFSNum == 0) {
+ if (getNodeInfo(S->getBlock()).DFSNum == Unvisited) {
errs() << "Node " << BlockNamePrinter(S)
<< " not reachable when its sibling " << BlockNamePrinter(N)
<< " is removed!\n";
>From d5799da9b8f86d1e1c7634dbeaae659b29901081 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 4 Jul 2026 13:30:20 -0700
Subject: [PATCH 2/4] use Chain Forward Star
---
.../llvm/Support/GenericDomTreeConstruction.h | 44 ++++++++++++-------
1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 8aff074d6a2a4..8ed8a781bca30 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -60,16 +60,18 @@ template <typename DomTreeT> struct SemiNCAInfo {
using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
// Marks a node that hasn't been visited by DFS.
- static constexpr unsigned Unvisited = -1u;
+ static constexpr unsigned Unvisited = 0;
- // Information record used by Semi-NCA during tree construction.
+ // std::is_trivial information used by Semi-NCA during tree construction.
+ // DFSNum is the DFS number + 1, so a zero-initialized InfoRec is unvisited.
struct InfoRec {
- unsigned DFSNum = Unvisited;
- unsigned Parent = 0;
- unsigned Semi = 0;
- unsigned Label = 0;
- NodePtr IDom = nullptr;
- SmallVector<unsigned, 4> ReverseChildren;
+ unsigned DFSNum;
+ unsigned Parent;
+ unsigned Semi;
+ unsigned Label;
+ NodePtr IDom;
+ // Head index + 1 into ReverseChildren; 0 = empty.
+ unsigned ReverseChildrenHead;
};
// Map a 0-based DFS number to the node. 0 is the DFS root, or the virtual
@@ -80,6 +82,9 @@ template <typename DomTreeT> struct SemiNCAInfo {
std::conditional_t<GraphHasNodeNumbers<NodePtr>, SmallVector<InfoRec, 64>,
DenseMap<NodePtr, InfoRec>>
NodeInfos;
+ // Reverse children of nodes; pairs of (DFSNum (predecessor), next-or-zero);
+ // forms a linked list in this vector.
+ SmallVector<std::pair<unsigned, unsigned>> ReverseChildren;
using UpdateT = typename DomTreeT::UpdateType;
using UpdateKind = typename DomTreeT::UpdateKind;
@@ -106,6 +111,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
void clear() {
NumToNode.clear();
NodeInfos.clear();
+ ReverseChildren.clear();
// Don't reset the pointer to BatchUpdateInfo here -- if there's an update
// in progress, we need this information to continue it.
}
@@ -192,8 +198,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
using NodeOrderMap = DenseMap<NodePtr, unsigned>;
// Custom DFS implementation which can skip nodes based on a provided
- // predicate. It also collects ReverseChildren so that we don't have to spend
- // time getting predecessors in SemiNCA.
+ // predicate. It also builds the ReverseChildren lists to avoid re-fetching
+ // predecessors in SemiNCA.
//
// If IsReverse is set to true, the DFS walk will be performed backwards
// relative to IsPostDom -- using reverse edges for dominators and forward
@@ -212,13 +218,16 @@ template <typename DomTreeT> struct SemiNCAInfo {
while (!WorkList.empty()) {
const auto [BB, ParentNum] = WorkList.pop_back_val();
auto &BBInfo = getNodeInfo(BB);
- BBInfo.ReverseChildren.push_back(ParentNum);
+ // Prepend the reverse edge (predecessor ParentNum) to BB's list.
+ ReverseChildren.emplace_back(ParentNum, BBInfo.ReverseChildrenHead);
+ BBInfo.ReverseChildrenHead = ReverseChildren.size();
if (BBInfo.DFSNum != Unvisited)
continue;
BBInfo.Parent = ParentNum;
unsigned Num = LastNum++;
- BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = Num;
+ BBInfo.Semi = BBInfo.Label = Num;
+ BBInfo.DFSNum = Num + 1; // stored as Num+1
NumToNode.push_back(BB);
constexpr bool Direction = IsReverse != IsPostDom; // XOR.
@@ -297,6 +306,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
// This function requires DFS to be run before calling it.
void runSemiNCA() {
const unsigned NextDFSNum(NumToNode.size());
+
// NumToInfo and IDoms are indexed by DFS number; 0 is the root. IDoms holds
// immediate dominators in DFS-number space, initialized below to spanning
// tree parents.
@@ -317,10 +327,13 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Initialize the semi dominator to point to the parent node.
WInfo.Semi = WInfo.Parent;
- for (unsigned N : WInfo.ReverseChildren) {
- unsigned SemiU = NumToInfo[eval(N, i + 1, EvalStack, NumToInfo)]->Semi;
+ for (unsigned RCIdx = WInfo.ReverseChildrenHead; RCIdx != 0;) {
+ auto [Pred, NextIdx] = ReverseChildren[RCIdx - 1];
+ unsigned SemiU =
+ NumToInfo[eval(Pred, i + 1, EvalStack, NumToInfo)]->Semi;
if (SemiU < WInfo.Semi)
WInfo.Semi = SemiU;
+ RCIdx = NextIdx;
}
}
@@ -347,7 +360,8 @@ template <typename DomTreeT> struct SemiNCAInfo {
assert(NumToNode.empty() && "SNCAInfo must be freshly constructed");
auto &BBInfo = getNodeInfo(nullptr);
- BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = 0;
+ BBInfo.Semi = BBInfo.Label = 0;
+ BBInfo.DFSNum = 1; // DFS number 0, stored as 1.
NumToNode.push_back(nullptr); // NumToNode[0] = nullptr;
}
>From b08062cf568a334a3c6e2064c8a91ff98a3a9f55 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 4 Jul 2026 13:51:21 -0700
Subject: [PATCH 3/4] Use more accurate DFSNumPlus1
---
.../llvm/Support/GenericDomTreeConstruction.h | 25 ++++++++++---------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 8ed8a781bca30..408202e97ca7d 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -62,15 +62,16 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Marks a node that hasn't been visited by DFS.
static constexpr unsigned Unvisited = 0;
- // std::is_trivial information used by Semi-NCA during tree construction.
- // DFSNum is the DFS number + 1, so a zero-initialized InfoRec is unvisited.
+ // Information used by Semi-NCA during tree construction; trivial type for
+ // resize efficiency. DFSNumPlus1 is the DFS number + 1, so a zeroed InfoRec
+ // is unvisited.
struct InfoRec {
- unsigned DFSNum;
+ unsigned DFSNumPlus1;
unsigned Parent;
unsigned Semi;
unsigned Label;
NodePtr IDom;
- // Head index + 1 into ReverseChildren; 0 = empty.
+ // Head index + 1 into ReverseChildren; 0: empty list.
unsigned ReverseChildrenHead;
};
@@ -222,12 +223,12 @@ template <typename DomTreeT> struct SemiNCAInfo {
ReverseChildren.emplace_back(ParentNum, BBInfo.ReverseChildrenHead);
BBInfo.ReverseChildrenHead = ReverseChildren.size();
- if (BBInfo.DFSNum != Unvisited)
+ if (BBInfo.DFSNumPlus1 != Unvisited)
continue;
BBInfo.Parent = ParentNum;
unsigned Num = LastNum++;
BBInfo.Semi = BBInfo.Label = Num;
- BBInfo.DFSNum = Num + 1; // stored as Num+1
+ BBInfo.DFSNumPlus1 = Num + 1;
NumToNode.push_back(BB);
constexpr bool Direction = IsReverse != IsPostDom; // XOR.
@@ -361,7 +362,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
auto &BBInfo = getNodeInfo(nullptr);
BBInfo.Semi = BBInfo.Label = 0;
- BBInfo.DFSNum = 1; // DFS number 0, stored as 1.
+ BBInfo.DFSNumPlus1 = 1;
NumToNode.push_back(nullptr); // NumToNode[0] = nullptr;
}
@@ -442,7 +443,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
auto InitSuccOrderOnce = [&]() {
SuccOrder = NodeOrderMap();
for (const auto Node : nodes(DT.Parent))
- if (SNCA.getNodeInfo(Node).DFSNum == Unvisited)
+ if (SNCA.getNodeInfo(Node).DFSNumPlus1 == Unvisited)
for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
SuccOrder->try_emplace(Succ, 0);
@@ -466,7 +467,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
// unreachable node once, we may just visit it in two directions,
// depending on how lucky we get.
for (const NodePtr I : nodes(DT.Parent)) {
- if (SNCA.getNodeInfo(I).DFSNum == Unvisited) {
+ if (SNCA.getNodeInfo(I).DFSNumPlus1 == Unvisited) {
LLVM_DEBUG(dbgs()
<< "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
// Find the furthest away we can get by following successors, then
@@ -1305,7 +1306,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (DT.isVirtualRoot(TN))
continue;
- if (getNodeInfo(BB).DFSNum == Unvisited) {
+ if (getNodeInfo(BB).DFSNumPlus1 == Unvisited) {
errs() << "DomTree node " << BlockNamePrinter(BB)
<< " not found by DFS walk!\n";
errs().flush();
@@ -1518,7 +1519,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
});
for (TreeNodePtr Child : TN->children())
- if (getNodeInfo(Child->getBlock()).DFSNum != Unvisited) {
+ if (getNodeInfo(Child->getBlock()).DFSNumPlus1 != Unvisited) {
errs() << "Child " << BlockNamePrinter(Child)
<< " reachable after its parent " << BlockNamePrinter(BB)
<< " is removed!\n";
@@ -1556,7 +1557,7 @@ template <typename DomTreeT> struct SemiNCAInfo {
if (S == N)
continue;
- if (getNodeInfo(S->getBlock()).DFSNum == Unvisited) {
+ if (getNodeInfo(S->getBlock()).DFSNumPlus1 == Unvisited) {
errs() << "Node " << BlockNamePrinter(S)
<< " not reachable when its sibling " << BlockNamePrinter(N)
<< " is removed!\n";
>From a8b04c17e58f9636646a1dc7e8e3c90100220587 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 4 Jul 2026 15:54:08 -0700
Subject: [PATCH 4/4] inline capacity 32
---
llvm/include/llvm/Support/GenericDomTreeConstruction.h | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 408202e97ca7d..94ca2fb6c2f4b 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -77,15 +77,15 @@ template <typename DomTreeT> struct SemiNCAInfo {
// Map a 0-based DFS number to the node. 0 is the DFS root, or the virtual
// root for postdominators.
- SmallVector<NodePtr, 64> NumToNode;
+ SmallVector<NodePtr, 32> NumToNode;
// If blocks have numbers (e.g., BasicBlock, MachineBasicBlock), store node
// infos in a vector. Otherwise, store them in a map.
- std::conditional_t<GraphHasNodeNumbers<NodePtr>, SmallVector<InfoRec, 64>,
+ std::conditional_t<GraphHasNodeNumbers<NodePtr>, SmallVector<InfoRec, 32>,
DenseMap<NodePtr, InfoRec>>
NodeInfos;
// Reverse children of nodes; pairs of (DFSNum (predecessor), next-or-zero);
// forms a linked list in this vector.
- SmallVector<std::pair<unsigned, unsigned>> ReverseChildren;
+ SmallVector<std::pair<unsigned, unsigned>, 32> ReverseChildren;
using UpdateT = typename DomTreeT::UpdateType;
using UpdateKind = typename DomTreeT::UpdateKind;
@@ -307,7 +307,6 @@ template <typename DomTreeT> struct SemiNCAInfo {
// This function requires DFS to be run before calling it.
void runSemiNCA() {
const unsigned NextDFSNum(NumToNode.size());
-
// NumToInfo and IDoms are indexed by DFS number; 0 is the root. IDoms holds
// immediate dominators in DFS-number space, initialized below to spanning
// tree parents.
More information about the llvm-commits
mailing list