summaryrefslogtreecommitdiff
path: root/lib/Analysis/LazyCallGraph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/LazyCallGraph.cpp')
-rw-r--r--lib/Analysis/LazyCallGraph.cpp49
1 files changed, 41 insertions, 8 deletions
diff --git a/lib/Analysis/LazyCallGraph.cpp b/lib/Analysis/LazyCallGraph.cpp
index a4c3e43b4b0c2..d287f81985fd2 100644
--- a/lib/Analysis/LazyCallGraph.cpp
+++ b/lib/Analysis/LazyCallGraph.cpp
@@ -106,6 +106,13 @@ LazyCallGraph::EdgeSequence &LazyCallGraph::Node::populateSlow() {
LazyCallGraph::Edge::Ref);
});
+ // Add implicit reference edges to any defined libcall functions (if we
+ // haven't found an explicit edge).
+ for (auto *F : G->LibFunctions)
+ if (!Visited.count(F))
+ addEdge(Edges->Edges, Edges->EdgeIndexMap, G->get(*F),
+ LazyCallGraph::Edge::Ref);
+
return *Edges;
}
@@ -120,15 +127,34 @@ LLVM_DUMP_METHOD void LazyCallGraph::Node::dump() const {
}
#endif
-LazyCallGraph::LazyCallGraph(Module &M) {
+static bool isKnownLibFunction(Function &F, TargetLibraryInfo &TLI) {
+ LibFunc LF;
+
+ // Either this is a normal library function or a "vectorizable" function.
+ return TLI.getLibFunc(F, LF) || TLI.isFunctionVectorizable(F.getName());
+}
+
+LazyCallGraph::LazyCallGraph(Module &M, TargetLibraryInfo &TLI) {
DEBUG(dbgs() << "Building CG for module: " << M.getModuleIdentifier()
<< "\n");
- for (Function &F : M)
- if (!F.isDeclaration() && !F.hasLocalLinkage()) {
- DEBUG(dbgs() << " Adding '" << F.getName()
- << "' to entry set of the graph.\n");
- addEdge(EntryEdges.Edges, EntryEdges.EdgeIndexMap, get(F), Edge::Ref);
- }
+ for (Function &F : M) {
+ if (F.isDeclaration())
+ continue;
+ // If this function is a known lib function to LLVM then we want to
+ // synthesize reference edges to it to model the fact that LLVM can turn
+ // arbitrary code into a library function call.
+ if (isKnownLibFunction(F, TLI))
+ LibFunctions.insert(&F);
+
+ if (F.hasLocalLinkage())
+ continue;
+
+ // External linkage defined functions have edges to them from other
+ // modules.
+ DEBUG(dbgs() << " Adding '" << F.getName()
+ << "' to entry set of the graph.\n");
+ addEdge(EntryEdges.Edges, EntryEdges.EdgeIndexMap, get(F), Edge::Ref);
+ }
// Now add entry nodes for functions reachable via initializers to globals.
SmallVector<Constant *, 16> Worklist;
@@ -149,7 +175,8 @@ LazyCallGraph::LazyCallGraph(Module &M) {
LazyCallGraph::LazyCallGraph(LazyCallGraph &&G)
: BPA(std::move(G.BPA)), NodeMap(std::move(G.NodeMap)),
EntryEdges(std::move(G.EntryEdges)), SCCBPA(std::move(G.SCCBPA)),
- SCCMap(std::move(G.SCCMap)), LeafRefSCCs(std::move(G.LeafRefSCCs)) {
+ SCCMap(std::move(G.SCCMap)), LeafRefSCCs(std::move(G.LeafRefSCCs)),
+ LibFunctions(std::move(G.LibFunctions)) {
updateGraphPtrs();
}
@@ -160,6 +187,7 @@ LazyCallGraph &LazyCallGraph::operator=(LazyCallGraph &&G) {
SCCBPA = std::move(G.SCCBPA);
SCCMap = std::move(G.SCCMap);
LeafRefSCCs = std::move(G.LeafRefSCCs);
+ LibFunctions = std::move(G.LibFunctions);
updateGraphPtrs();
return *this;
}
@@ -1580,6 +1608,11 @@ void LazyCallGraph::removeDeadFunction(Function &F) {
assert(F.use_empty() &&
"This routine should only be called on trivially dead functions!");
+ // We shouldn't remove library functions as they are never really dead while
+ // the call graph is in use -- every function definition refers to them.
+ assert(!isLibFunction(F) &&
+ "Must not remove lib functions from the call graph!");
+
auto NI = NodeMap.find(&F);
if (NI == NodeMap.end())
// Not in the graph at all!