[llvm] [Support] Use block numbers for DomTree construction (PR #101706)
Alexis Engelke via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 6 00:50:54 PDT 2024
https://github.com/aengelke updated https://github.com/llvm/llvm-project/pull/101706
>From fb0dda6448136cd9eb30ad0cb7efd36aa9eda7bc Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Thu, 1 Aug 2024 17:47:46 +0200
Subject: [PATCH 1/2] [Support] Use block numbers for DomTree construction
---
.../llvm/Support/GenericDomTreeConstruction.h | 65 +++++++++++++------
1 file changed, 45 insertions(+), 20 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index af7ac04a5ab29..143087ed193f5 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -60,6 +60,10 @@ struct SemiNCAInfo {
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
+ template <typename T>
+ using has_number_t =
+ decltype(GraphTraits<T *>::getNumber(std::declval<T *>()));
+
// Information record used by Semi-NCA during tree construction.
struct InfoRec {
unsigned DFSNum = 0;
@@ -73,7 +77,11 @@ struct SemiNCAInfo {
// Number to node mapping is 1-based. Initialize the mapping to start with
// a dummy element.
SmallVector<NodePtr, 64> NumToNode = {nullptr};
- DenseMap<NodePtr, InfoRec> NodeToInfo;
+ // If blocks have numbers (e.g., BasicBlock, MachineBasicBlock), store node
+ // infos in a vector.
+ SmallVector<InfoRec, 64> NodeInfos;
+ // For blocks without numbers, store InfoRec in a map.
+ DenseMap<NodePtr, InfoRec> NodeInfoMap;
using UpdateT = typename DomTreeT::UpdateType;
using UpdateKind = typename DomTreeT::UpdateKind;
@@ -99,7 +107,8 @@ struct SemiNCAInfo {
void clear() {
NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
- NodeToInfo.clear();
+ NodeInfos.clear();
+ NodeInfoMap.clear();
// Don't reset the pointer to BatchUpdateInfo here -- if there's an update
// in progress, we need this information to continue it.
}
@@ -123,13 +132,29 @@ struct SemiNCAInfo {
return Res;
}
- NodePtr getIDom(NodePtr BB) const {
- auto InfoIt = NodeToInfo.find(BB);
- if (InfoIt == NodeToInfo.end()) return nullptr;
+ template <class T_ = NodeT>
+ std::enable_if_t<is_detected<has_number_t, T_>::value, InfoRec *>
+ getNodeInfo(NodePtr BB) {
+ unsigned Idx = BB ? GraphTraits<NodePtr>::getNumber(BB) + 1 : 0;
+ if (Idx >= NodeInfos.size()) {
+ unsigned Max = 0;
+ if (BB)
+ Max = GraphTraits<decltype(BB->getParent())>::getMaxNumber(
+ BB->getParent());
+ // Max might be zero, graphs might not support getMaxNumber().
+ NodeInfos.resize(Max ? Max + 1 : Idx + 1);
+ }
+ return &NodeInfos[Idx];
+ }
- return InfoIt->second.IDom;
+ template <class T_ = NodeT>
+ std::enable_if_t<!is_detected<has_number_t, T_>::value, InfoRec *>
+ getNodeInfo(NodePtr BB) {
+ return &NodeInfoMap[BB];
}
+ NodePtr getIDom(NodePtr BB) { return getNodeInfo(BB)->IDom; }
+
TreeNodePtr getNodeForBlock(NodePtr BB, DomTreeT &DT) {
if (TreeNodePtr Node = DT.getNode(BB)) return Node;
@@ -181,11 +206,11 @@ struct SemiNCAInfo {
const NodeOrderMap *SuccOrder = nullptr) {
assert(V);
SmallVector<std::pair<NodePtr, unsigned>, 64> WorkList = {{V, AttachToNum}};
- NodeToInfo[V].Parent = AttachToNum;
+ getNodeInfo(V)->Parent = AttachToNum;
while (!WorkList.empty()) {
const auto [BB, ParentNum] = WorkList.pop_back_val();
- auto &BBInfo = NodeToInfo[BB];
+ auto &BBInfo = *getNodeInfo(BB);
BBInfo.ReverseChildren.push_back(ParentNum);
// Visited nodes always have positive DFS numbers.
@@ -264,7 +289,7 @@ struct SemiNCAInfo {
// Initialize IDoms to spanning tree parents.
for (unsigned i = 1; i < NextDFSNum; ++i) {
const NodePtr V = NumToNode[i];
- auto &VInfo = NodeToInfo[V];
+ auto &VInfo = *getNodeInfo(V);
VInfo.IDom = NumToNode[VInfo.Parent];
NumToInfo.push_back(&VInfo);
}
@@ -292,7 +317,7 @@ struct SemiNCAInfo {
const unsigned SDomNum = NumToInfo[WInfo.Semi]->DFSNum;
NodePtr WIDomCandidate = WInfo.IDom;
while (true) {
- auto &WIDomCandidateInfo = NodeToInfo.find(WIDomCandidate)->second;
+ auto &WIDomCandidateInfo = *getNodeInfo(WIDomCandidate);
if (WIDomCandidateInfo.DFSNum <= SDomNum)
break;
WIDomCandidate = WIDomCandidateInfo.IDom;
@@ -311,7 +336,7 @@ struct SemiNCAInfo {
assert(IsPostDom && "Only postdominators have a virtual root");
assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
- auto &BBInfo = NodeToInfo[nullptr];
+ auto &BBInfo = *getNodeInfo(nullptr);
BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = 1;
NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
@@ -393,7 +418,7 @@ struct SemiNCAInfo {
auto InitSuccOrderOnce = [&]() {
SuccOrder = NodeOrderMap();
for (const auto Node : nodes(DT.Parent))
- if (SNCA.NodeToInfo.count(Node) == 0)
+ if (SNCA.getNodeInfo(Node)->DFSNum == 0)
for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
SuccOrder->try_emplace(Succ, 0);
@@ -417,7 +442,7 @@ 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.NodeToInfo.count(I) == 0) {
+ if (SNCA.getNodeInfo(I)->DFSNum == 0) {
LLVM_DEBUG(dbgs()
<< "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
// Find the furthest away we can get by following successors, then
@@ -449,7 +474,7 @@ struct SemiNCAInfo {
const NodePtr N = SNCA.NumToNode[i];
LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
<< BlockNamePrinter(N) << "\n");
- SNCA.NodeToInfo.erase(N);
+ *SNCA.getNodeInfo(N) = {};
SNCA.NumToNode.pop_back();
}
const unsigned PrevNum = Num;
@@ -582,7 +607,7 @@ struct SemiNCAInfo {
void attachNewSubtree(DomTreeT& DT, const TreeNodePtr AttachTo) {
// Attach the first unreachable block to AttachTo.
- NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
+ getNodeInfo(NumToNode[1])->IDom = AttachTo->getBlock();
// Loop over all of the discovered blocks in the function...
for (NodePtr W : llvm::drop_begin(NumToNode)) {
if (DT.getNode(W))
@@ -600,11 +625,11 @@ struct SemiNCAInfo {
}
void reattachExistingSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
- NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
+ getNodeInfo(NumToNode[1])->IDom = AttachTo->getBlock();
for (const NodePtr N : llvm::drop_begin(NumToNode)) {
const TreeNodePtr TN = DT.getNode(N);
assert(TN);
- const TreeNodePtr NewIDom = DT.getNode(NodeToInfo[N].IDom);
+ const TreeNodePtr NewIDom = DT.getNode(getNodeInfo(N)->IDom);
TN->setIDom(NewIDom);
}
}
@@ -1237,7 +1262,7 @@ struct SemiNCAInfo {
// Virtual root has a corresponding virtual CFG node.
if (DT.isVirtualRoot(TN)) continue;
- if (NodeToInfo.count(BB) == 0) {
+ if (getNodeInfo(BB)->DFSNum == 0) {
errs() << "DomTree node " << BlockNamePrinter(BB)
<< " not found by DFS walk!\n";
errs().flush();
@@ -1445,7 +1470,7 @@ struct SemiNCAInfo {
});
for (TreeNodePtr Child : TN->children())
- if (NodeToInfo.count(Child->getBlock()) != 0) {
+ if (getNodeInfo(Child->getBlock())->DFSNum != 0) {
errs() << "Child " << BlockNamePrinter(Child)
<< " reachable after its parent " << BlockNamePrinter(BB)
<< " is removed!\n";
@@ -1481,7 +1506,7 @@ struct SemiNCAInfo {
for (const TreeNodePtr S : TN->children()) {
if (S == N) continue;
- if (NodeToInfo.count(S->getBlock()) == 0) {
+ if (getNodeInfo(S->getBlock())->DFSNum == 0) {
errs() << "Node " << BlockNamePrinter(S)
<< " not reachable when its sibling " << BlockNamePrinter(N)
<< " is removed!\n";
>From a65756c2f24d2dba731f44630a6d6cceb6353f68 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 6 Aug 2024 07:47:43 +0000
Subject: [PATCH 2/2] Use if-constexpr + move number check to GraphTraits
---
llvm/include/llvm/ADT/GraphTraits.h | 11 ++++
.../llvm/Support/GenericDomTreeConstruction.h | 66 ++++++++-----------
2 files changed, 40 insertions(+), 37 deletions(-)
diff --git a/llvm/include/llvm/ADT/GraphTraits.h b/llvm/include/llvm/ADT/GraphTraits.h
index 3a7773592af3d..c5a1cdbfd7cf0 100644
--- a/llvm/include/llvm/ADT/GraphTraits.h
+++ b/llvm/include/llvm/ADT/GraphTraits.h
@@ -19,6 +19,7 @@
#ifndef LLVM_ADT_GRAPHTRAITS_H
#define LLVM_ADT_GRAPHTRAITS_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
namespace llvm {
@@ -80,6 +81,16 @@ struct GraphTraits {
using NodeRef = typename GraphType::UnknownGraphTypeError;
};
+namespace detail {
+template <typename T>
+using has_number_t = decltype(GraphTraits<T>::getNumber(std::declval<T>()));
+} // namespace detail
+
+/// Indicate whether a GraphTraits<NodeT>::getNumber() is supported.
+template <typename NodeT>
+constexpr bool GraphHasNodeNumbers =
+ is_detected<detail::has_number_t, NodeT>::value;
+
// Inverse - This class is used as a little marker class to tell the graph
// iterator to iterate over the graph in a graph defined "Inverse" ordering.
// Not all graphs define an inverse ordering, and if they do, it depends on
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 143087ed193f5..3cced8c1bfa28 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -60,10 +60,6 @@ struct SemiNCAInfo {
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
- template <typename T>
- using has_number_t =
- decltype(GraphTraits<T *>::getNumber(std::declval<T *>()));
-
// Information record used by Semi-NCA during tree construction.
struct InfoRec {
unsigned DFSNum = 0;
@@ -132,28 +128,24 @@ struct SemiNCAInfo {
return Res;
}
- template <class T_ = NodeT>
- std::enable_if_t<is_detected<has_number_t, T_>::value, InfoRec *>
- getNodeInfo(NodePtr BB) {
- unsigned Idx = BB ? GraphTraits<NodePtr>::getNumber(BB) + 1 : 0;
- if (Idx >= NodeInfos.size()) {
- unsigned Max = 0;
- if (BB)
- Max = GraphTraits<decltype(BB->getParent())>::getMaxNumber(
- BB->getParent());
- // Max might be zero, graphs might not support getMaxNumber().
- NodeInfos.resize(Max ? Max + 1 : Idx + 1);
+ InfoRec &getNodeInfo(NodePtr BB) {
+ if constexpr (GraphHasNodeNumbers<NodePtr>) {
+ unsigned Idx = BB ? GraphTraits<NodePtr>::getNumber(BB) + 1 : 0;
+ if (Idx >= NodeInfos.size()) {
+ unsigned Max = 0;
+ if (BB)
+ Max = GraphTraits<decltype(BB->getParent())>::getMaxNumber(
+ BB->getParent());
+ // Max might be zero, graphs might not support getMaxNumber().
+ NodeInfos.resize(Max ? Max + 1 : Idx + 1);
+ }
+ return NodeInfos[Idx];
+ } else {
+ return NodeInfoMap[BB];
}
- return &NodeInfos[Idx];
- }
-
- template <class T_ = NodeT>
- std::enable_if_t<!is_detected<has_number_t, T_>::value, InfoRec *>
- getNodeInfo(NodePtr BB) {
- return &NodeInfoMap[BB];
}
- NodePtr getIDom(NodePtr BB) { return getNodeInfo(BB)->IDom; }
+ NodePtr getIDom(NodePtr BB) { return getNodeInfo(BB).IDom; }
TreeNodePtr getNodeForBlock(NodePtr BB, DomTreeT &DT) {
if (TreeNodePtr Node = DT.getNode(BB)) return Node;
@@ -206,11 +198,11 @@ struct SemiNCAInfo {
const NodeOrderMap *SuccOrder = nullptr) {
assert(V);
SmallVector<std::pair<NodePtr, unsigned>, 64> WorkList = {{V, AttachToNum}};
- getNodeInfo(V)->Parent = AttachToNum;
+ getNodeInfo(V).Parent = AttachToNum;
while (!WorkList.empty()) {
const auto [BB, ParentNum] = WorkList.pop_back_val();
- auto &BBInfo = *getNodeInfo(BB);
+ auto &BBInfo = getNodeInfo(BB);
BBInfo.ReverseChildren.push_back(ParentNum);
// Visited nodes always have positive DFS numbers.
@@ -289,7 +281,7 @@ struct SemiNCAInfo {
// Initialize IDoms to spanning tree parents.
for (unsigned i = 1; i < NextDFSNum; ++i) {
const NodePtr V = NumToNode[i];
- auto &VInfo = *getNodeInfo(V);
+ auto &VInfo = getNodeInfo(V);
VInfo.IDom = NumToNode[VInfo.Parent];
NumToInfo.push_back(&VInfo);
}
@@ -317,7 +309,7 @@ struct SemiNCAInfo {
const unsigned SDomNum = NumToInfo[WInfo.Semi]->DFSNum;
NodePtr WIDomCandidate = WInfo.IDom;
while (true) {
- auto &WIDomCandidateInfo = *getNodeInfo(WIDomCandidate);
+ auto &WIDomCandidateInfo = getNodeInfo(WIDomCandidate);
if (WIDomCandidateInfo.DFSNum <= SDomNum)
break;
WIDomCandidate = WIDomCandidateInfo.IDom;
@@ -336,7 +328,7 @@ struct SemiNCAInfo {
assert(IsPostDom && "Only postdominators have a virtual root");
assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
- auto &BBInfo = *getNodeInfo(nullptr);
+ auto &BBInfo = getNodeInfo(nullptr);
BBInfo.DFSNum = BBInfo.Semi = BBInfo.Label = 1;
NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
@@ -418,7 +410,7 @@ struct SemiNCAInfo {
auto InitSuccOrderOnce = [&]() {
SuccOrder = NodeOrderMap();
for (const auto Node : nodes(DT.Parent))
- if (SNCA.getNodeInfo(Node)->DFSNum == 0)
+ if (SNCA.getNodeInfo(Node).DFSNum == 0)
for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
SuccOrder->try_emplace(Succ, 0);
@@ -442,7 +434,7 @@ 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 == 0) {
LLVM_DEBUG(dbgs()
<< "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
// Find the furthest away we can get by following successors, then
@@ -474,7 +466,7 @@ struct SemiNCAInfo {
const NodePtr N = SNCA.NumToNode[i];
LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
<< BlockNamePrinter(N) << "\n");
- *SNCA.getNodeInfo(N) = {};
+ SNCA.getNodeInfo(N) = {};
SNCA.NumToNode.pop_back();
}
const unsigned PrevNum = Num;
@@ -607,7 +599,7 @@ struct SemiNCAInfo {
void attachNewSubtree(DomTreeT& DT, const TreeNodePtr AttachTo) {
// Attach the first unreachable block to AttachTo.
- getNodeInfo(NumToNode[1])->IDom = AttachTo->getBlock();
+ getNodeInfo(NumToNode[1]).IDom = AttachTo->getBlock();
// Loop over all of the discovered blocks in the function...
for (NodePtr W : llvm::drop_begin(NumToNode)) {
if (DT.getNode(W))
@@ -625,11 +617,11 @@ struct SemiNCAInfo {
}
void reattachExistingSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
- getNodeInfo(NumToNode[1])->IDom = AttachTo->getBlock();
+ getNodeInfo(NumToNode[1]).IDom = AttachTo->getBlock();
for (const NodePtr N : llvm::drop_begin(NumToNode)) {
const TreeNodePtr TN = DT.getNode(N);
assert(TN);
- const TreeNodePtr NewIDom = DT.getNode(getNodeInfo(N)->IDom);
+ const TreeNodePtr NewIDom = DT.getNode(getNodeInfo(N).IDom);
TN->setIDom(NewIDom);
}
}
@@ -1262,7 +1254,7 @@ struct SemiNCAInfo {
// Virtual root has a corresponding virtual CFG node.
if (DT.isVirtualRoot(TN)) continue;
- if (getNodeInfo(BB)->DFSNum == 0) {
+ if (getNodeInfo(BB).DFSNum == 0) {
errs() << "DomTree node " << BlockNamePrinter(BB)
<< " not found by DFS walk!\n";
errs().flush();
@@ -1470,7 +1462,7 @@ struct SemiNCAInfo {
});
for (TreeNodePtr Child : TN->children())
- if (getNodeInfo(Child->getBlock())->DFSNum != 0) {
+ if (getNodeInfo(Child->getBlock()).DFSNum != 0) {
errs() << "Child " << BlockNamePrinter(Child)
<< " reachable after its parent " << BlockNamePrinter(BB)
<< " is removed!\n";
@@ -1506,7 +1498,7 @@ struct SemiNCAInfo {
for (const TreeNodePtr S : TN->children()) {
if (S == N) continue;
- if (getNodeInfo(S->getBlock())->DFSNum == 0) {
+ if (getNodeInfo(S->getBlock()).DFSNum == 0) {
errs() << "Node " << BlockNamePrinter(S)
<< " not reachable when its sibling " << BlockNamePrinter(N)
<< " is removed!\n";
More information about the llvm-commits
mailing list