[PM/LCG] Teach the LazyCallGraph to maintain reference edges from every

function to every defined function known to LLVM as a library function.

LLVM can introduce calls to these functions either by replacing other
library calls or by recognizing patterns (such as memset_pattern or
vector math patterns) and replacing those with calls. When these library
functions are actually defined in the module, we need to have reference
edges to them initially so that we visit them during the CGSCC walk in
the right order and can effectively rebuild the call graph afterward.

This was discovered when building code with Fortify enabled as that is
a common case of both inline definitions of library calls and
simplifications of code into calling them.

This can in extreme cases of LTO-ing with libc introduce *many* more
reference edges. I discussed a bunch of different options with folks but
all of them are unsatisfying. They either make the graph operations
substantially more complex even when there are *no* defined libfuncs, or
they introduce some other complexity into the callgraph. So this patch
goes with the simplest possible solution of actual synthetic reference
edges. If this proves to be a memory problem, I'm happy to implement one
of the clever techniques to save memory here.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth
2017-07-15 08:08:19 +00:00
parent b515119244
commit ed504111e8
7 changed files with 124 additions and 33 deletions
+36 -8
View File
@@ -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.push_back(&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;
}