forked from OSchip/llvm-project
[LCG] In the incremental SCC re-formation, lift the node currently being
processed in the DFS out of the stack completely. Keep it exclusively in a variable. Re-shuffle some code structure to make this easier. This can have a very dramatic effect in some cases because call graphs tend to look like a high fan-out spanning tree. As a consequence, there are a large number of leaf nodes in the graph, and this technique causes leaf nodes to never even go into the stack. While this only reduces the max depth by 1, it may cause the total number of round trips through the stack to drop by a lot. Now, most of this isn't really relevant for the incremental version. =] But I wanted to prototype it first here as this variant is in ways more complex. As long as I can get the code factored well here, I'll next make the primary walk look the same. There are several refactorings this exposes I think. llvm-svn: 207306
This commit is contained in:
parent
a7205b6154
commit
680af7a78c
|
@ -132,6 +132,8 @@ public:
|
|||
: G(&G), NI(Nodes.end()) {}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
bool operator==(const iterator &Arg) const { return NI == Arg.NI; }
|
||||
bool operator!=(const iterator &Arg) const { return !operator==(Arg); }
|
||||
|
||||
|
|
|
@ -217,38 +217,46 @@ LazyCallGraph::SCC::removeInternalEdge(LazyCallGraph &G, Node &Caller,
|
|||
// walk.
|
||||
insert(G, Callee);
|
||||
|
||||
Node *N = nullptr;
|
||||
Node::iterator ChildI;
|
||||
for (;;) {
|
||||
if (DFSStack.empty()) {
|
||||
// Clear off any nodes which have already been visited in the DFS.
|
||||
while (!Worklist.empty() && Worklist.back()->DFSNumber != 0)
|
||||
Worklist.pop_back();
|
||||
if (Worklist.empty())
|
||||
break;
|
||||
Node *N = Worklist.pop_back_val();
|
||||
N->LowLink = N->DFSNumber = 1;
|
||||
NextDFSNumber = 2;
|
||||
DFSStack.push_back(std::make_pair(N, N->begin()));
|
||||
assert(PendingSCCStack.empty() && "Cannot start a fresh DFS walk with "
|
||||
"pending nodes from a prior walk.");
|
||||
if (!N) {
|
||||
if (!DFSStack.empty()) {
|
||||
N = DFSStack.back().first;
|
||||
ChildI = DFSStack.back().second;
|
||||
DFSStack.pop_back();
|
||||
} else {
|
||||
// Clear off any nodes which have already been visited in the DFS.
|
||||
while (!Worklist.empty() && Worklist.back()->DFSNumber != 0)
|
||||
Worklist.pop_back();
|
||||
if (Worklist.empty())
|
||||
break;
|
||||
N = Worklist.pop_back_val();
|
||||
N->LowLink = N->DFSNumber = 1;
|
||||
NextDFSNumber = 2;
|
||||
ChildI = N->begin();
|
||||
assert(PendingSCCStack.empty() && "Cannot start a fresh DFS walk with "
|
||||
"pending nodes from a prior walk.");
|
||||
}
|
||||
}
|
||||
|
||||
Node *N = DFSStack.back().first;
|
||||
assert(N->DFSNumber != 0 && "We should always assign a DFS number "
|
||||
"before placing a node onto the stack.");
|
||||
"before processing a node.");
|
||||
|
||||
// We simulate recursion by popping out of the nested loop and continuing.
|
||||
bool Recurse = false;
|
||||
for (auto I = DFSStack.back().second, E = N->end(); I != E; ++I) {
|
||||
for (auto I = ChildI, E = N->end(); I != E; ++I) {
|
||||
Node &ChildN = *I;
|
||||
if (SCC *ChildSCC = G.SCCMap.lookup(&ChildN)) {
|
||||
// Check if we have reached a node in the new (known connected) set of
|
||||
// this SCC. If so, the entire stack is necessarily in that set and we
|
||||
// can re-start.
|
||||
if (ChildSCC == this) {
|
||||
insert(G, *N);
|
||||
while (!PendingSCCStack.empty())
|
||||
insert(G, *PendingSCCStack.pop_back_val());
|
||||
while (!DFSStack.empty())
|
||||
insert(G, *DFSStack.pop_back_val().first);
|
||||
N = nullptr;
|
||||
Recurse = true;
|
||||
break;
|
||||
}
|
||||
|
@ -263,11 +271,12 @@ LazyCallGraph::SCC::removeInternalEdge(LazyCallGraph &G, Node &Caller,
|
|||
// Mark that we should start at this child when next this node is the
|
||||
// top of the stack. We don't start at the next child to ensure this
|
||||
// child's lowlink is reflected.
|
||||
DFSStack.back().second = I;
|
||||
DFSStack.push_back(std::make_pair(N, I));
|
||||
|
||||
// Recurse onto this node via a tail call.
|
||||
ChildN.LowLink = ChildN.DFSNumber = NextDFSNumber++;
|
||||
DFSStack.push_back(std::make_pair(&ChildN, ChildN.begin()));
|
||||
N = &ChildN;
|
||||
ChildI = ChildN.begin();
|
||||
Recurse = true;
|
||||
break;
|
||||
}
|
||||
|
@ -282,22 +291,21 @@ LazyCallGraph::SCC::removeInternalEdge(LazyCallGraph &G, Node &Caller,
|
|||
if (Recurse)
|
||||
continue;
|
||||
|
||||
// No more children to process, pop it off the core DFS stack.
|
||||
DFSStack.pop_back();
|
||||
if (N->LowLink != N->DFSNumber) {
|
||||
// At this point we know that N cannot ever be an SCC root. Its low-link
|
||||
// is not its dfs-number, and we've processed all of its children. It is
|
||||
// just sitting here waiting until some node further down the stack gets
|
||||
// low-link == dfs-number and pops it off as well. Move it to the pending
|
||||
// stack which is pulled into the next SCC to be formed.
|
||||
PendingSCCStack.push_back(N);
|
||||
|
||||
if (N->LowLink == N->DFSNumber) {
|
||||
ResultSCCs.push_back(G.formSCC(N, PendingSCCStack));
|
||||
assert(!DFSStack.empty() && "We shouldn't have an empty stack!");
|
||||
N = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!DFSStack.empty() && "We shouldn't have an empty stack!");
|
||||
|
||||
// At this point we know that N cannot ever be an SCC root. Its low-link
|
||||
// is not its dfs-number, and we've processed all of its children. It is
|
||||
// just sitting here waiting until some node further down the stack gets
|
||||
// low-link == dfs-number and pops it off as well. Move it to the pending
|
||||
// stack which is pulled into the next SCC to be formed.
|
||||
PendingSCCStack.push_back(N);
|
||||
ResultSCCs.push_back(G.formSCC(N, PendingSCCStack));
|
||||
N = nullptr;
|
||||
}
|
||||
|
||||
// Now we need to reconnect the current SCC to the graph.
|
||||
|
|
Loading…
Reference in New Issue