[Dominators] Move helper functions into SemiNCAInfo

Summary: Helper functions (DFSPass, ReverseDFSPass, Eval) need SemiNCAInfo anyway, so it's simpler to have them there as member functions. This also makes them simpler by removing template boilerplate.

Reviewers: dberlin, sanjoy, chandlerc

Reviewed By: dberlin

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D34427

llvm-svn: 306579
This commit is contained in:
Jakub Kuderski 2017-06-28 18:15:45 +00:00
parent 64d182d36f
commit f01cd723a8
2 changed files with 208 additions and 215 deletions

View File

@ -76,47 +76,42 @@ struct SemiNCAInfo {
llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))) llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode)))
.get(); .get();
} }
};
} // namespace DomTreeBuilder
// External storage for depth first iterator that reuses the info lookup map // External storage for depth first iterator that reuses the info lookup map
// domtree already has. We don't have a set, but a map instead, so we are // SemiNCAInfo already has. We don't have a set, but a map instead, so we are
// converting the one argument insert calls. // converting the one argument insert calls.
template <class NodeRef, class InfoType> struct df_iterator_dom_storage { struct df_iterator_dom_storage {
public: public:
using BaseSet = DenseMap<NodeRef, InfoType>; using BaseSet = decltype(NodeToInfo);
df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {} df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {}
using iterator = typename BaseSet::iterator; using iterator = typename BaseSet::iterator;
std::pair<iterator, bool> insert(NodeRef N) { std::pair<iterator, bool> insert(NodePtr N) {
return Storage.insert({N, InfoType()}); return Storage.insert({N, InfoRec()});
} }
void completed(NodeRef) {} void completed(NodePtr) {}
private: private:
BaseSet &Storage; BaseSet &Storage;
}; };
template <class NodePtr, df_iterator_dom_storage getStorage() { return {NodeToInfo}; }
class NodeT = typename std::remove_pointer<NodePtr>::type>
unsigned ReverseDFSPass(NodePtr V, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA, unsigned runReverseDFS(NodePtr V, unsigned N) {
unsigned N) { auto DFStorage = getStorage();
using SNCAInfoTy = DomTreeBuilder::SemiNCAInfo<NodeT>;
df_iterator_dom_storage<NodePtr, typename SNCAInfoTy::InfoRec> DFStorage(
SNCA.NodeToInfo);
bool IsChildOfArtificialExit = (N != 0); bool IsChildOfArtificialExit = (N != 0);
for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage); for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage);
I != E; ++I) { I != E; ++I) {
NodePtr BB = *I; NodePtr BB = *I;
auto &BBInfo = SNCA.NodeToInfo[BB]; auto &BBInfo = NodeToInfo[BB];
BBInfo.DFSNum = BBInfo.Semi = ++N; BBInfo.DFSNum = BBInfo.Semi = ++N;
BBInfo.Label = BB; BBInfo.Label = BB;
// Set the parent to the top of the visited stack. The stack includes us, // Set the parent to the top of the visited stack. The stack includes us,
// and is 1 based, so we subtract to account for both of these. // and is 1 based, so we subtract to account for both of these.
if (I.getPathLength() > 1) if (I.getPathLength() > 1)
BBInfo.Parent = SNCA.NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum; BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
SNCA.NumToNode.push_back(BB); // NumToNode[n] = V; NumToNode.push_back(BB); // NumToNode[n] = V;
if (IsChildOfArtificialExit) if (IsChildOfArtificialExit)
BBInfo.Parent = 1; BBInfo.Parent = 1;
@ -126,33 +121,26 @@ unsigned ReverseDFSPass(NodePtr V, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA,
return N; return N;
} }
template <class NodePtr, unsigned runDFS(NodePtr V, unsigned N) {
class NodeT = typename std::remove_pointer<NodePtr>::type> auto DFStorage = getStorage();
unsigned DFSPass(NodePtr V, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA, unsigned N) {
using SNCAInfoTy = DomTreeBuilder::SemiNCAInfo<NodeT>;
df_iterator_dom_storage<NodePtr, typename SNCAInfoTy::InfoRec> DFStorage(
SNCA.NodeToInfo);
for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage); for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage);
I != E; ++I) { I != E; ++I) {
NodePtr BB = *I; NodePtr BB = *I;
auto &BBInfo = SNCA.NodeToInfo[BB]; auto &BBInfo = NodeToInfo[BB];
BBInfo.DFSNum = BBInfo.Semi = ++N; BBInfo.DFSNum = BBInfo.Semi = ++N;
BBInfo.Label = BB; BBInfo.Label = BB;
// Set the parent to the top of the visited stack. The stack includes us, // Set the parent to the top of the visited stack. The stack includes us,
// and is 1 based, so we subtract to account for both of these. // and is 1 based, so we subtract to account for both of these.
if (I.getPathLength() > 1) if (I.getPathLength() > 1)
BBInfo.Parent = SNCA.NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum; BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
SNCA.NumToNode.push_back(BB); // NumToNode[n] = V; NumToNode.push_back(BB); // NumToNode[n] = V;
} }
return N; return N;
} }
template <class NodePtr, NodePtr eval(NodePtr VIn, unsigned LastLinked) {
class NodeT = typename std::remove_pointer<NodePtr>::type> auto &VInInfo = NodeToInfo[VIn];
NodePtr Eval(NodePtr VIn, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA,
unsigned LastLinked) {
auto &VInInfo = SNCA.NodeToInfo[VIn];
if (VInInfo.DFSNum < LastLinked) if (VInInfo.DFSNum < LastLinked)
return VIn; return VIn;
@ -164,8 +152,8 @@ NodePtr Eval(NodePtr VIn, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA,
while (!Work.empty()) { while (!Work.empty()) {
NodePtr V = Work.back(); NodePtr V = Work.back();
auto &VInfo = SNCA.NodeToInfo[V]; auto &VInfo = NodeToInfo[V];
NodePtr VAncestor = SNCA.NumToNode[VInfo.Parent]; NodePtr VAncestor = NumToNode[VInfo.Parent];
// Process Ancestor first // Process Ancestor first
if (Visited.insert(VAncestor).second && VInfo.Parent >= LastLinked) { if (Visited.insert(VAncestor).second && VInfo.Parent >= LastLinked) {
@ -178,10 +166,10 @@ NodePtr Eval(NodePtr VIn, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA,
if (VInfo.Parent < LastLinked) if (VInfo.Parent < LastLinked)
continue; continue;
auto &VAInfo = SNCA.NodeToInfo[VAncestor]; auto &VAInfo = NodeToInfo[VAncestor];
NodePtr VAncestorLabel = VAInfo.Label; NodePtr VAncestorLabel = VAInfo.Label;
NodePtr VLabel = VInfo.Label; NodePtr VLabel = VInfo.Label;
if (SNCA.NodeToInfo[VAncestorLabel].Semi < SNCA.NodeToInfo[VLabel].Semi) if (NodeToInfo[VAncestorLabel].Semi < NodeToInfo[VLabel].Semi)
VInfo.Label = VAncestorLabel; VInfo.Label = VAncestorLabel;
VInfo.Parent = VAInfo.Parent; VInfo.Parent = VAInfo.Parent;
} }
@ -189,26 +177,18 @@ NodePtr Eval(NodePtr VIn, DomTreeBuilder::SemiNCAInfo<NodeT> &SNCA,
return VInInfo.Label; return VInInfo.Label;
} }
template <class FuncT, class NodeT> template <typename NodeType>
void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT, void runSemiNCA(unsigned NumBlocks) {
FuncT &F) {
using GraphT = GraphTraits<NodeT>;
using NodePtr = typename GraphT::NodeRef;
static_assert(std::is_pointer<NodePtr>::value,
"NodePtr should be a pointer type");
using NodeType = typename std::remove_pointer<NodePtr>::type;
unsigned N = 0; unsigned N = 0;
DomTreeBuilder::SemiNCAInfo<NodeType> SNCA(DT); NumToNode.push_back(nullptr);
SNCA.NumToNode.push_back(nullptr);
bool MultipleRoots = (DT.Roots.size() > 1); bool MultipleRoots = (DT.Roots.size() > 1);
if (MultipleRoots) { if (MultipleRoots) {
auto &BBInfo = SNCA.NodeToInfo[nullptr]; auto &BBInfo = NodeToInfo[nullptr];
BBInfo.DFSNum = BBInfo.Semi = ++N; BBInfo.DFSNum = BBInfo.Semi = ++N;
BBInfo.Label = nullptr; BBInfo.Label = nullptr;
SNCA.NumToNode.push_back(nullptr); // NumToNode[n] = V; NumToNode.push_back(nullptr); // NumToNode[n] = V;
} }
// Step #1: Number blocks in depth-first order and initialize variables used // Step #1: Number blocks in depth-first order and initialize variables used
@ -216,49 +196,48 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT,
if (DT.isPostDominator()){ if (DT.isPostDominator()){
for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size()); for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size());
i != e; ++i) i != e; ++i)
N = ReverseDFSPass<NodePtr>(DT.Roots[i], SNCA, N); N = runReverseDFS(DT.Roots[i], N);
} else { } else {
N = DFSPass<NodePtr>(DT.Roots[0], SNCA, N); N = runDFS(DT.Roots[0], N);
} }
// It might be that some blocks did not get a DFS number (e.g., blocks of // It might be that some blocks did not get a DFS number (e.g., blocks of
// infinite loops). In these cases an artificial exit node is required. // infinite loops). In these cases an artificial exit node is required.
MultipleRoots |= (DT.isPostDominator() && N != GraphTraits<FuncT*>::size(&F)); MultipleRoots |= (DT.isPostDominator() && N != NumBlocks);
// Initialize IDoms to spanning tree parents. // Initialize IDoms to spanning tree parents.
for (unsigned i = 1; i <= N; ++i) { for (unsigned i = 1; i <= N; ++i) {
const NodePtr V = SNCA.NumToNode[i]; const NodePtr V = NumToNode[i];
auto &VInfo = SNCA.NodeToInfo[V]; auto &VInfo = NodeToInfo[V];
VInfo.IDom = SNCA.NumToNode[VInfo.Parent]; VInfo.IDom = NumToNode[VInfo.Parent];
} }
// Step #2: Calculate the semidominators of all vertices. // Step #2: Calculate the semidominators of all vertices.
for (unsigned i = N; i >= 2; --i) { for (unsigned i = N; i >= 2; --i) {
NodePtr W = SNCA.NumToNode[i]; NodePtr W = NumToNode[i];
auto &WInfo = SNCA.NodeToInfo[W]; auto &WInfo = NodeToInfo[W];
// Initialize the semi dominator to point to the parent node. // Initialize the semi dominator to point to the parent node.
WInfo.Semi = WInfo.Parent; WInfo.Semi = WInfo.Parent;
for (const auto &N : inverse_children<NodeT>(W)) for (const auto &N : inverse_children<NodeType>(W))
if (SNCA.NodeToInfo.count(N)) { // Only if this predecessor is reachable! if (NodeToInfo.count(N)) { // Only if this predecessor is reachable!
unsigned SemiU = SNCA.NodeToInfo[Eval<NodePtr>(N, SNCA, i + 1)].Semi; unsigned SemiU = NodeToInfo[eval(N, i + 1)].Semi;
if (SemiU < WInfo.Semi) if (SemiU < WInfo.Semi)
WInfo.Semi = SemiU; WInfo.Semi = SemiU;
} }
} }
// Step #3: Explicitly define the immediate dominator of each vertex. // Step #3: Explicitly define the immediate dominator of each vertex.
// IDom[i] = NCA(SDom[i], SpanningTreeParent(i)). // IDom[i] = NCA(SDom[i], SpanningTreeParent(i)).
// Note that the parents were stored in IDoms and later got invalidated during // Note that the parents were stored in IDoms and later got invalidated
// path compression in Eval. // during path compression in Eval.
for (unsigned i = 2; i <= N; ++i) { for (unsigned i = 2; i <= N; ++i) {
const NodePtr W = SNCA.NumToNode[i]; const NodePtr W = NumToNode[i];
auto &WInfo = SNCA.NodeToInfo[W]; auto &WInfo = NodeToInfo[W];
const unsigned SDomNum = SNCA.NodeToInfo[SNCA.NumToNode[WInfo.Semi]].DFSNum; const unsigned SDomNum = NodeToInfo[NumToNode[WInfo.Semi]].DFSNum;
NodePtr WIDomCandidate = WInfo.IDom; NodePtr WIDomCandidate = WInfo.IDom;
while (SNCA.NodeToInfo[WIDomCandidate].DFSNum > SDomNum) while (NodeToInfo[WIDomCandidate].DFSNum > SDomNum)
WIDomCandidate = SNCA.NodeToInfo[WIDomCandidate].IDom; WIDomCandidate = NodeToInfo[WIDomCandidate].IDom;
WInfo.IDom = WIDomCandidate; WInfo.IDom = WIDomCandidate;
} }
@ -266,39 +245,53 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT,
if (DT.Roots.empty()) return; if (DT.Roots.empty()) return;
// Add a node for the root. This node might be the actual root, if there is // Add a node for the root. This node might be the actual root, if there is
// one exit block, or it may be the virtual exit (denoted by (BasicBlock *)0) // one exit block, or it may be the virtual exit (denoted by
// which postdominates all real exits if there are multiple exit blocks, or // (BasicBlock *)0) which postdominates all real exits if there are multiple
// an infinite loop. // exit blocks, or an infinite loop.
NodePtr Root = !MultipleRoots ? DT.Roots[0] : nullptr; NodePtr Root = !MultipleRoots ? DT.Roots[0] : nullptr;
DT.RootNode = DT.RootNode =
(DT.DomTreeNodes[Root] = (DT.DomTreeNodes[Root] =
llvm::make_unique<DomTreeNodeBase<NodeType>>(Root, nullptr)) llvm::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr))
.get(); .get();
// Loop over all of the reachable blocks in the function... // Loop over all of the reachable blocks in the function...
for (unsigned i = 2; i <= N; ++i) { for (unsigned i = 2; i <= N; ++i) {
NodePtr W = SNCA.NumToNode[i]; NodePtr W = NumToNode[i];
// Don't replace this with 'count', the insertion side effect is important // Don't replace this with 'count', the insertion side effect is important
if (DT.DomTreeNodes[W]) if (DT.DomTreeNodes[W])
continue; // Haven't calculated this node yet? continue; // Haven't calculated this node yet?
NodePtr ImmDom = SNCA.getIDom(W); NodePtr ImmDom = getIDom(W);
assert(ImmDom || DT.DomTreeNodes[nullptr]); assert(ImmDom || DT.DomTreeNodes[nullptr]);
// Get or calculate the node for the immediate dominator // Get or calculate the node for the immediate dominator
DomTreeNodeBase<NodeType> *IDomNode = SNCA.getNodeForBlock(ImmDom); TreeNodePtr IDomNode = getNodeForBlock(ImmDom);
// Add a new tree node for this BasicBlock, and link it as a child of // Add a new tree node for this BasicBlock, and link it as a child of
// IDomNode // IDomNode
DT.DomTreeNodes[W] = IDomNode->addChild( DT.DomTreeNodes[W] = IDomNode->addChild(
llvm::make_unique<DomTreeNodeBase<NodeType>>(W, IDomNode)); llvm::make_unique<DomTreeNodeBase<NodeT>>(W, IDomNode));
} }
DT.updateDFSNumbers(); DT.updateDFSNumbers();
} }
};
} // namespace DomTreeBuilder } // namespace DomTreeBuilder
template <class FuncT, class NodeT>
void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT,
FuncT &F) {
using NodePtr = typename GraphTraits<NodeT>::NodeRef;
static_assert(std::is_pointer<NodePtr>::value,
"NodePtr should be a pointer type");
DomTreeBuilder::SemiNCAInfo<typename std::remove_pointer<NodePtr>::type>
SNCA(DT);
SNCA.template runSemiNCA<NodeT>(GraphTraits<FuncT *>::size(&F));
}
} // namespace llvm
#endif #endif