summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/LazyCallGraph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/LazyCallGraph.cpp')
-rw-r--r--llvm/lib/Analysis/LazyCallGraph.cpp122
1 files changed, 118 insertions, 4 deletions
diff --git a/llvm/lib/Analysis/LazyCallGraph.cpp b/llvm/lib/Analysis/LazyCallGraph.cpp
index 8a0d00ac49f..dd5c7df7848 100644
--- a/llvm/lib/Analysis/LazyCallGraph.cpp
+++ b/llvm/lib/Analysis/LazyCallGraph.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/LazyCallGraph.h"
-#include "llvm/ADT/SCCIterator.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/Instructions.h"
@@ -46,7 +46,8 @@ static void findCallees(
}
}
-LazyCallGraph::Node::Node(LazyCallGraph &G, Function &F) : G(&G), F(F) {
+LazyCallGraph::Node::Node(LazyCallGraph &G, Function &F)
+ : G(&G), F(F), DFSNumber(0), LowLink(0) {
SmallVector<Constant *, 16> Worklist;
SmallPtrSet<Constant *, 16> Visited;
// Find all the potential callees in this function. First walk the
@@ -65,7 +66,7 @@ LazyCallGraph::Node::Node(LazyCallGraph &G, Function &F) : G(&G), F(F) {
}
LazyCallGraph::Node::Node(LazyCallGraph &G, const Node &OtherN)
- : G(&G), F(OtherN.F), CalleeSet(OtherN.CalleeSet) {
+ : G(&G), F(OtherN.F), DFSNumber(0), LowLink(0), CalleeSet(OtherN.CalleeSet) {
// Loop over the other node's callees, adding the Function*s to our list
// directly, and recursing to add the Node*s.
Callees.reserve(OtherN.Callees.size());
@@ -91,6 +92,12 @@ LazyCallGraph::LazyCallGraph(Module &M) {
Worklist.push_back(GV.getInitializer());
findCallees(Worklist, Visited, EntryNodes, EntryNodeSet);
+
+ for (auto &Entry : EntryNodes)
+ if (Function *F = Entry.dyn_cast<Function *>())
+ SCCEntryNodes.insert(F);
+ else
+ SCCEntryNodes.insert(&Entry.get<Node *>()->getFunction());
}
LazyCallGraph::LazyCallGraph(const LazyCallGraph &G)
@@ -101,11 +108,22 @@ LazyCallGraph::LazyCallGraph(const LazyCallGraph &G)
EntryNodes.push_back(Callee);
else
EntryNodes.push_back(copyInto(*EntryNode.get<Node *>()));
+
+ // Just re-populate the SCCEntryNodes structure so we recompute the SCCs if
+ // needed.
+ for (auto &Entry : EntryNodes)
+ if (Function *F = Entry.dyn_cast<Function *>())
+ SCCEntryNodes.insert(F);
+ else
+ SCCEntryNodes.insert(&Entry.get<Node *>()->getFunction());
}
LazyCallGraph::LazyCallGraph(LazyCallGraph &&G)
: BPA(std::move(G.BPA)), EntryNodes(std::move(G.EntryNodes)),
- EntryNodeSet(std::move(G.EntryNodeSet)) {
+ EntryNodeSet(std::move(G.EntryNodeSet)), SCCBPA(std::move(G.SCCBPA)),
+ SCCMap(std::move(G.SCCMap)), LeafSCCs(std::move(G.LeafSCCs)),
+ DFSStack(std::move(G.DFSStack)),
+ SCCEntryNodes(std::move(G.SCCEntryNodes)) {
// Process all nodes updating the graph pointers.
SmallVector<Node *, 16> Worklist;
for (auto &Entry : EntryNodes)
@@ -133,6 +151,88 @@ LazyCallGraph::Node *LazyCallGraph::copyInto(const Node &OtherN) {
return new (N = BPA.Allocate()) Node(*this, OtherN);
}
+LazyCallGraph::SCC *LazyCallGraph::getNextSCCInPostOrder() {
+ // When the stack is empty, there are no more SCCs to walk in this graph.
+ if (DFSStack.empty()) {
+ // If we've handled all candidate entry nodes to the SCC forest, we're done.
+ if (SCCEntryNodes.empty())
+ return nullptr;
+
+ Node *N = get(*SCCEntryNodes.pop_back_val());
+ DFSStack.push_back(std::make_pair(N, N->begin()));
+ }
+
+ Node *N = DFSStack.back().first;
+ if (N->DFSNumber == 0) {
+ // This node hasn't been visited before, assign it a DFS number and remove
+ // it from the entry set.
+ N->LowLink = N->DFSNumber = NextDFSNumber++;
+ SCCEntryNodes.remove(&N->getFunction());
+ }
+
+ for (auto I = DFSStack.back().second, E = N->end(); I != E; ++I) {
+ Node *ChildN = *I;
+ if (ChildN->DFSNumber == 0) {
+ // 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.
+ // FIXME: I don't actually think this is required, and we could start
+ // at the next child.
+ DFSStack.back().second = I;
+
+ // Recurse onto this node via a tail call.
+ DFSStack.push_back(std::make_pair(ChildN, ChildN->begin()));
+ return LazyCallGraph::getNextSCCInPostOrder();
+ }
+
+ // Track the lowest link of the childen, if any are still in the stack.
+ if (ChildN->LowLink < N->LowLink && !SCCMap.count(&ChildN->getFunction()))
+ N->LowLink = ChildN->LowLink;
+ }
+
+ // The tail of the stack is the new SCC. Allocate the SCC and pop the stack
+ // into it.
+ SCC *NewSCC = new (SCCBPA.Allocate()) SCC();
+
+ // Because we don't follow the strict Tarjan recursive formulation, walk
+ // from the top of the stack down, propagating the lowest link and stopping
+ // when the DFS number is the lowest link.
+ int LowestLink = N->LowLink;
+ do {
+ Node *SCCN = DFSStack.pop_back_val().first;
+ SCCMap.insert(std::make_pair(&SCCN->getFunction(), NewSCC));
+ NewSCC->Nodes.push_back(SCCN);
+ LowestLink = std::min(LowestLink, SCCN->LowLink);
+ bool Inserted =
+ NewSCC->NodeSet.insert(&SCCN->getFunction());
+ (void)Inserted;
+ assert(Inserted && "Cannot have duplicates in the DFSStack!");
+ } while (!DFSStack.empty() && LowestLink <= DFSStack.back().first->DFSNumber);
+ assert(LowestLink == NewSCC->Nodes.back()->DFSNumber &&
+ "Cannot stop with a DFS number greater than the lowest link!");
+
+ // A final pass over all edges in the SCC (this remains linear as we only
+ // do this once when we build the SCC) to connect it to the parent sets of
+ // its children.
+ bool IsLeafSCC = true;
+ for (Node *SCCN : NewSCC->Nodes)
+ for (Node *SCCChildN : *SCCN) {
+ if (NewSCC->NodeSet.count(&SCCChildN->getFunction()))
+ continue;
+ SCC *ChildSCC = SCCMap.lookup(&SCCChildN->getFunction());
+ assert(ChildSCC &&
+ "Must have all child SCCs processed when building a new SCC!");
+ ChildSCC->ParentSCCs.insert(NewSCC);
+ IsLeafSCC = false;
+ }
+
+ // For the SCCs where we fine no child SCCs, add them to the leaf list.
+ if (IsLeafSCC)
+ LeafSCCs.push_back(NewSCC);
+
+ return NewSCC;
+}
+
char LazyCallGraphAnalysis::PassID;
LazyCallGraphPrinterPass::LazyCallGraphPrinterPass(raw_ostream &OS) : OS(OS) {}
@@ -151,6 +251,16 @@ static void printNodes(raw_ostream &OS, LazyCallGraph::Node &N,
OS << "\n";
}
+static void printSCC(raw_ostream &OS, LazyCallGraph::SCC &SCC) {
+ ptrdiff_t SCCSize = std::distance(SCC.begin(), SCC.end());
+ OS << " SCC with " << SCCSize << " functions:\n";
+
+ for (LazyCallGraph::Node *N : SCC)
+ OS << " " << N->getFunction().getName() << "\n";
+
+ OS << "\n";
+}
+
PreservedAnalyses LazyCallGraphPrinterPass::run(Module *M,
ModuleAnalysisManager *AM) {
LazyCallGraph &G = AM->getResult<LazyCallGraphAnalysis>(M);
@@ -163,5 +273,9 @@ PreservedAnalyses LazyCallGraphPrinterPass::run(Module *M,
if (Printed.insert(N))
printNodes(OS, *N, Printed);
+ for (LazyCallGraph::SCC *SCC : G.postorder_sccs())
+ printSCC(OS, *SCC);
+
return PreservedAnalyses::all();
+
}
OpenPOWER on IntegriCloud