109467b48Spatrick //===- CallGraph.cpp - Build a Module's call graph ------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
909467b48Spatrick #include "llvm/Analysis/CallGraph.h"
10*d415bd75Srobert #include "llvm/ADT/SCCIterator.h"
1109467b48Spatrick #include "llvm/ADT/STLExtras.h"
1209467b48Spatrick #include "llvm/ADT/SmallVector.h"
1309467b48Spatrick #include "llvm/Config/llvm-config.h"
14097a140dSpatrick #include "llvm/IR/AbstractCallSite.h"
1509467b48Spatrick #include "llvm/IR/Function.h"
16097a140dSpatrick #include "llvm/IR/IntrinsicInst.h"
1709467b48Spatrick #include "llvm/IR/Module.h"
1809467b48Spatrick #include "llvm/IR/PassManager.h"
1909467b48Spatrick #include "llvm/InitializePasses.h"
2009467b48Spatrick #include "llvm/Pass.h"
2109467b48Spatrick #include "llvm/Support/Compiler.h"
2209467b48Spatrick #include "llvm/Support/Debug.h"
2309467b48Spatrick #include "llvm/Support/raw_ostream.h"
2409467b48Spatrick #include <cassert>
2509467b48Spatrick
2609467b48Spatrick using namespace llvm;
2709467b48Spatrick
2809467b48Spatrick //===----------------------------------------------------------------------===//
2909467b48Spatrick // Implementations of the CallGraph class methods.
3009467b48Spatrick //
3109467b48Spatrick
CallGraph(Module & M)3209467b48Spatrick CallGraph::CallGraph(Module &M)
3309467b48Spatrick : M(M), ExternalCallingNode(getOrInsertFunction(nullptr)),
34097a140dSpatrick CallsExternalNode(std::make_unique<CallGraphNode>(this, nullptr)) {
35097a140dSpatrick // Add every interesting function to the call graph.
3609467b48Spatrick for (Function &F : M)
37097a140dSpatrick if (!isDbgInfoIntrinsic(F.getIntrinsicID()))
3809467b48Spatrick addToCallGraph(&F);
3909467b48Spatrick }
4009467b48Spatrick
CallGraph(CallGraph && Arg)4109467b48Spatrick CallGraph::CallGraph(CallGraph &&Arg)
4209467b48Spatrick : M(Arg.M), FunctionMap(std::move(Arg.FunctionMap)),
4309467b48Spatrick ExternalCallingNode(Arg.ExternalCallingNode),
4409467b48Spatrick CallsExternalNode(std::move(Arg.CallsExternalNode)) {
4509467b48Spatrick Arg.FunctionMap.clear();
4609467b48Spatrick Arg.ExternalCallingNode = nullptr;
47097a140dSpatrick
48097a140dSpatrick // Update parent CG for all call graph's nodes.
49097a140dSpatrick CallsExternalNode->CG = this;
50097a140dSpatrick for (auto &P : FunctionMap)
51097a140dSpatrick P.second->CG = this;
5209467b48Spatrick }
5309467b48Spatrick
~CallGraph()5409467b48Spatrick CallGraph::~CallGraph() {
5509467b48Spatrick // CallsExternalNode is not in the function map, delete it explicitly.
5609467b48Spatrick if (CallsExternalNode)
5709467b48Spatrick CallsExternalNode->allReferencesDropped();
5809467b48Spatrick
5909467b48Spatrick // Reset all node's use counts to zero before deleting them to prevent an
6009467b48Spatrick // assertion from firing.
6109467b48Spatrick #ifndef NDEBUG
6209467b48Spatrick for (auto &I : FunctionMap)
6309467b48Spatrick I.second->allReferencesDropped();
6409467b48Spatrick #endif
6509467b48Spatrick }
6609467b48Spatrick
invalidate(Module &,const PreservedAnalyses & PA,ModuleAnalysisManager::Invalidator &)67097a140dSpatrick bool CallGraph::invalidate(Module &, const PreservedAnalyses &PA,
68097a140dSpatrick ModuleAnalysisManager::Invalidator &) {
69097a140dSpatrick // Check whether the analysis, all analyses on functions, or the function's
70097a140dSpatrick // CFG have been preserved.
71097a140dSpatrick auto PAC = PA.getChecker<CallGraphAnalysis>();
72*d415bd75Srobert return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>());
73097a140dSpatrick }
74097a140dSpatrick
addToCallGraph(Function * F)7509467b48Spatrick void CallGraph::addToCallGraph(Function *F) {
7609467b48Spatrick CallGraphNode *Node = getOrInsertFunction(F);
7709467b48Spatrick
78097a140dSpatrick // If this function has external linkage or has its address taken and
79097a140dSpatrick // it is not a callback, then anything could call it.
80097a140dSpatrick if (!F->hasLocalLinkage() ||
8173471bf0Spatrick F->hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
8273471bf0Spatrick /* IgnoreAssumeLikeCalls */ true,
8373471bf0Spatrick /* IgnoreLLVMUsed */ false))
8409467b48Spatrick ExternalCallingNode->addCalledFunction(nullptr, Node);
8509467b48Spatrick
86097a140dSpatrick populateCallGraphNode(Node);
87097a140dSpatrick }
88097a140dSpatrick
populateCallGraphNode(CallGraphNode * Node)89097a140dSpatrick void CallGraph::populateCallGraphNode(CallGraphNode *Node) {
90097a140dSpatrick Function *F = Node->getFunction();
91097a140dSpatrick
9209467b48Spatrick // If this function is not defined in this translation unit, it could call
9309467b48Spatrick // anything.
94*d415bd75Srobert if (F->isDeclaration() && !F->hasFnAttribute(Attribute::NoCallback))
9509467b48Spatrick Node->addCalledFunction(nullptr, CallsExternalNode.get());
9609467b48Spatrick
9709467b48Spatrick // Look for calls by this function.
9809467b48Spatrick for (BasicBlock &BB : *F)
9909467b48Spatrick for (Instruction &I : BB) {
10009467b48Spatrick if (auto *Call = dyn_cast<CallBase>(&I)) {
10109467b48Spatrick const Function *Callee = Call->getCalledFunction();
102*d415bd75Srobert if (!Callee)
10309467b48Spatrick Node->addCalledFunction(Call, CallsExternalNode.get());
104*d415bd75Srobert else if (!isDbgInfoIntrinsic(Callee->getIntrinsicID()))
10509467b48Spatrick Node->addCalledFunction(Call, getOrInsertFunction(Callee));
106097a140dSpatrick
107097a140dSpatrick // Add reference to callback functions.
108097a140dSpatrick forEachCallbackFunction(*Call, [=](Function *CB) {
109097a140dSpatrick Node->addCalledFunction(nullptr, getOrInsertFunction(CB));
110097a140dSpatrick });
11109467b48Spatrick }
11209467b48Spatrick }
11309467b48Spatrick }
11409467b48Spatrick
print(raw_ostream & OS) const11509467b48Spatrick void CallGraph::print(raw_ostream &OS) const {
11609467b48Spatrick // Print in a deterministic order by sorting CallGraphNodes by name. We do
11709467b48Spatrick // this here to avoid slowing down the non-printing fast path.
11809467b48Spatrick
11909467b48Spatrick SmallVector<CallGraphNode *, 16> Nodes;
12009467b48Spatrick Nodes.reserve(FunctionMap.size());
12109467b48Spatrick
12209467b48Spatrick for (const auto &I : *this)
12309467b48Spatrick Nodes.push_back(I.second.get());
12409467b48Spatrick
12509467b48Spatrick llvm::sort(Nodes, [](CallGraphNode *LHS, CallGraphNode *RHS) {
12609467b48Spatrick if (Function *LF = LHS->getFunction())
12709467b48Spatrick if (Function *RF = RHS->getFunction())
12809467b48Spatrick return LF->getName() < RF->getName();
12909467b48Spatrick
13009467b48Spatrick return RHS->getFunction() != nullptr;
13109467b48Spatrick });
13209467b48Spatrick
13309467b48Spatrick for (CallGraphNode *CN : Nodes)
13409467b48Spatrick CN->print(OS);
13509467b48Spatrick }
13609467b48Spatrick
13709467b48Spatrick #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const13809467b48Spatrick LLVM_DUMP_METHOD void CallGraph::dump() const { print(dbgs()); }
13909467b48Spatrick #endif
14009467b48Spatrick
ReplaceExternalCallEdge(CallGraphNode * Old,CallGraphNode * New)141097a140dSpatrick void CallGraph::ReplaceExternalCallEdge(CallGraphNode *Old,
142097a140dSpatrick CallGraphNode *New) {
143097a140dSpatrick for (auto &CR : ExternalCallingNode->CalledFunctions)
144097a140dSpatrick if (CR.second == Old) {
145097a140dSpatrick CR.second->DropRef();
146097a140dSpatrick CR.second = New;
147097a140dSpatrick CR.second->AddRef();
148097a140dSpatrick }
149097a140dSpatrick }
150097a140dSpatrick
15109467b48Spatrick // removeFunctionFromModule - Unlink the function from this module, returning
15209467b48Spatrick // it. Because this removes the function from the module, the call graph node
15309467b48Spatrick // is destroyed. This is only valid if the function does not call any other
15409467b48Spatrick // functions (ie, there are no edges in it's CGN). The easiest way to do this
15509467b48Spatrick // is to dropAllReferences before calling this.
15609467b48Spatrick //
removeFunctionFromModule(CallGraphNode * CGN)15709467b48Spatrick Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
15809467b48Spatrick assert(CGN->empty() && "Cannot remove function from call "
15909467b48Spatrick "graph if it references other functions!");
16009467b48Spatrick Function *F = CGN->getFunction(); // Get the function for the call graph node
16109467b48Spatrick FunctionMap.erase(F); // Remove the call graph node from the map
16209467b48Spatrick
16309467b48Spatrick M.getFunctionList().remove(F);
16409467b48Spatrick return F;
16509467b48Spatrick }
16609467b48Spatrick
16709467b48Spatrick // getOrInsertFunction - This method is identical to calling operator[], but
16809467b48Spatrick // it will insert a new CallGraphNode for the specified function if one does
16909467b48Spatrick // not already exist.
getOrInsertFunction(const Function * F)17009467b48Spatrick CallGraphNode *CallGraph::getOrInsertFunction(const Function *F) {
17109467b48Spatrick auto &CGN = FunctionMap[F];
17209467b48Spatrick if (CGN)
17309467b48Spatrick return CGN.get();
17409467b48Spatrick
17509467b48Spatrick assert((!F || F->getParent() == &M) && "Function not in current module!");
176097a140dSpatrick CGN = std::make_unique<CallGraphNode>(this, const_cast<Function *>(F));
17709467b48Spatrick return CGN.get();
17809467b48Spatrick }
17909467b48Spatrick
18009467b48Spatrick //===----------------------------------------------------------------------===//
18109467b48Spatrick // Implementations of the CallGraphNode class methods.
18209467b48Spatrick //
18309467b48Spatrick
print(raw_ostream & OS) const18409467b48Spatrick void CallGraphNode::print(raw_ostream &OS) const {
18509467b48Spatrick if (Function *F = getFunction())
18609467b48Spatrick OS << "Call graph node for function: '" << F->getName() << "'";
18709467b48Spatrick else
18809467b48Spatrick OS << "Call graph node <<null function>>";
18909467b48Spatrick
19009467b48Spatrick OS << "<<" << this << ">> #uses=" << getNumReferences() << '\n';
19109467b48Spatrick
19209467b48Spatrick for (const auto &I : *this) {
19309467b48Spatrick OS << " CS<" << I.first << "> calls ";
19409467b48Spatrick if (Function *FI = I.second->getFunction())
19509467b48Spatrick OS << "function '" << FI->getName() <<"'\n";
19609467b48Spatrick else
19709467b48Spatrick OS << "external node\n";
19809467b48Spatrick }
19909467b48Spatrick OS << '\n';
20009467b48Spatrick }
20109467b48Spatrick
20209467b48Spatrick #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const20309467b48Spatrick LLVM_DUMP_METHOD void CallGraphNode::dump() const { print(dbgs()); }
20409467b48Spatrick #endif
20509467b48Spatrick
20609467b48Spatrick /// removeCallEdgeFor - This method removes the edge in the node for the
20709467b48Spatrick /// specified call site. Note that this method takes linear time, so it
20809467b48Spatrick /// should be used sparingly.
removeCallEdgeFor(CallBase & Call)20909467b48Spatrick void CallGraphNode::removeCallEdgeFor(CallBase &Call) {
21009467b48Spatrick for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
21109467b48Spatrick assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
212097a140dSpatrick if (I->first && *I->first == &Call) {
21309467b48Spatrick I->second->DropRef();
21409467b48Spatrick *I = CalledFunctions.back();
21509467b48Spatrick CalledFunctions.pop_back();
216097a140dSpatrick
217097a140dSpatrick // Remove all references to callback functions if there are any.
218097a140dSpatrick forEachCallbackFunction(Call, [=](Function *CB) {
219097a140dSpatrick removeOneAbstractEdgeTo(CG->getOrInsertFunction(CB));
220097a140dSpatrick });
22109467b48Spatrick return;
22209467b48Spatrick }
22309467b48Spatrick }
22409467b48Spatrick }
22509467b48Spatrick
22609467b48Spatrick // removeAnyCallEdgeTo - This method removes any call edges from this node to
22709467b48Spatrick // the specified callee function. This takes more time to execute than
22809467b48Spatrick // removeCallEdgeTo, so it should not be used unless necessary.
removeAnyCallEdgeTo(CallGraphNode * Callee)22909467b48Spatrick void CallGraphNode::removeAnyCallEdgeTo(CallGraphNode *Callee) {
23009467b48Spatrick for (unsigned i = 0, e = CalledFunctions.size(); i != e; ++i)
23109467b48Spatrick if (CalledFunctions[i].second == Callee) {
23209467b48Spatrick Callee->DropRef();
23309467b48Spatrick CalledFunctions[i] = CalledFunctions.back();
23409467b48Spatrick CalledFunctions.pop_back();
23509467b48Spatrick --i; --e;
23609467b48Spatrick }
23709467b48Spatrick }
23809467b48Spatrick
23909467b48Spatrick /// removeOneAbstractEdgeTo - Remove one edge associated with a null callsite
24009467b48Spatrick /// from this node to the specified callee function.
removeOneAbstractEdgeTo(CallGraphNode * Callee)24109467b48Spatrick void CallGraphNode::removeOneAbstractEdgeTo(CallGraphNode *Callee) {
24209467b48Spatrick for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
24309467b48Spatrick assert(I != CalledFunctions.end() && "Cannot find callee to remove!");
24409467b48Spatrick CallRecord &CR = *I;
245097a140dSpatrick if (CR.second == Callee && !CR.first) {
24609467b48Spatrick Callee->DropRef();
24709467b48Spatrick *I = CalledFunctions.back();
24809467b48Spatrick CalledFunctions.pop_back();
24909467b48Spatrick return;
25009467b48Spatrick }
25109467b48Spatrick }
25209467b48Spatrick }
25309467b48Spatrick
25409467b48Spatrick /// replaceCallEdge - This method replaces the edge in the node for the
25509467b48Spatrick /// specified call site with a new one. Note that this method takes linear
25609467b48Spatrick /// time, so it should be used sparingly.
replaceCallEdge(CallBase & Call,CallBase & NewCall,CallGraphNode * NewNode)25709467b48Spatrick void CallGraphNode::replaceCallEdge(CallBase &Call, CallBase &NewCall,
25809467b48Spatrick CallGraphNode *NewNode) {
25909467b48Spatrick for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
26009467b48Spatrick assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
261097a140dSpatrick if (I->first && *I->first == &Call) {
26209467b48Spatrick I->second->DropRef();
26309467b48Spatrick I->first = &NewCall;
26409467b48Spatrick I->second = NewNode;
26509467b48Spatrick NewNode->AddRef();
266097a140dSpatrick
26773471bf0Spatrick // Refresh callback references. Do not resize CalledFunctions if the
26873471bf0Spatrick // number of callbacks is the same for new and old call sites.
26973471bf0Spatrick SmallVector<CallGraphNode *, 4u> OldCBs;
27073471bf0Spatrick SmallVector<CallGraphNode *, 4u> NewCBs;
27173471bf0Spatrick forEachCallbackFunction(Call, [this, &OldCBs](Function *CB) {
27273471bf0Spatrick OldCBs.push_back(CG->getOrInsertFunction(CB));
273097a140dSpatrick });
27473471bf0Spatrick forEachCallbackFunction(NewCall, [this, &NewCBs](Function *CB) {
27573471bf0Spatrick NewCBs.push_back(CG->getOrInsertFunction(CB));
276097a140dSpatrick });
27773471bf0Spatrick if (OldCBs.size() == NewCBs.size()) {
27873471bf0Spatrick for (unsigned N = 0; N < OldCBs.size(); ++N) {
27973471bf0Spatrick CallGraphNode *OldNode = OldCBs[N];
28073471bf0Spatrick CallGraphNode *NewNode = NewCBs[N];
28173471bf0Spatrick for (auto J = CalledFunctions.begin();; ++J) {
28273471bf0Spatrick assert(J != CalledFunctions.end() &&
28373471bf0Spatrick "Cannot find callsite to update!");
28473471bf0Spatrick if (!J->first && J->second == OldNode) {
28573471bf0Spatrick J->second = NewNode;
28673471bf0Spatrick OldNode->DropRef();
28773471bf0Spatrick NewNode->AddRef();
28873471bf0Spatrick break;
28973471bf0Spatrick }
29073471bf0Spatrick }
29173471bf0Spatrick }
29273471bf0Spatrick } else {
29373471bf0Spatrick for (auto *CGN : OldCBs)
29473471bf0Spatrick removeOneAbstractEdgeTo(CGN);
29573471bf0Spatrick for (auto *CGN : NewCBs)
29673471bf0Spatrick addCalledFunction(nullptr, CGN);
29773471bf0Spatrick }
29809467b48Spatrick return;
29909467b48Spatrick }
30009467b48Spatrick }
30109467b48Spatrick }
30209467b48Spatrick
30309467b48Spatrick // Provide an explicit template instantiation for the static ID.
30409467b48Spatrick AnalysisKey CallGraphAnalysis::Key;
30509467b48Spatrick
run(Module & M,ModuleAnalysisManager & AM)30609467b48Spatrick PreservedAnalyses CallGraphPrinterPass::run(Module &M,
30709467b48Spatrick ModuleAnalysisManager &AM) {
30809467b48Spatrick AM.getResult<CallGraphAnalysis>(M).print(OS);
30909467b48Spatrick return PreservedAnalyses::all();
31009467b48Spatrick }
31109467b48Spatrick
run(Module & M,ModuleAnalysisManager & AM)312*d415bd75Srobert PreservedAnalyses CallGraphSCCsPrinterPass::run(Module &M,
313*d415bd75Srobert ModuleAnalysisManager &AM) {
314*d415bd75Srobert auto &CG = AM.getResult<CallGraphAnalysis>(M);
315*d415bd75Srobert unsigned sccNum = 0;
316*d415bd75Srobert OS << "SCCs for the program in PostOrder:";
317*d415bd75Srobert for (scc_iterator<CallGraph *> SCCI = scc_begin(&CG); !SCCI.isAtEnd();
318*d415bd75Srobert ++SCCI) {
319*d415bd75Srobert const std::vector<CallGraphNode *> &nextSCC = *SCCI;
320*d415bd75Srobert OS << "\nSCC #" << ++sccNum << ": ";
321*d415bd75Srobert bool First = true;
322*d415bd75Srobert for (std::vector<CallGraphNode *>::const_iterator I = nextSCC.begin(),
323*d415bd75Srobert E = nextSCC.end();
324*d415bd75Srobert I != E; ++I) {
325*d415bd75Srobert if (First)
326*d415bd75Srobert First = false;
327*d415bd75Srobert else
328*d415bd75Srobert OS << ", ";
329*d415bd75Srobert OS << ((*I)->getFunction() ? (*I)->getFunction()->getName()
330*d415bd75Srobert : "external node");
331*d415bd75Srobert }
332*d415bd75Srobert
333*d415bd75Srobert if (nextSCC.size() == 1 && SCCI.hasCycle())
334*d415bd75Srobert OS << " (Has self-loop).";
335*d415bd75Srobert }
336*d415bd75Srobert OS << "\n";
337*d415bd75Srobert return PreservedAnalyses::all();
338*d415bd75Srobert }
339*d415bd75Srobert
34009467b48Spatrick //===----------------------------------------------------------------------===//
34109467b48Spatrick // Out-of-line definitions of CallGraphAnalysis class members.
34209467b48Spatrick //
34309467b48Spatrick
34409467b48Spatrick //===----------------------------------------------------------------------===//
34509467b48Spatrick // Implementations of the CallGraphWrapperPass class methods.
34609467b48Spatrick //
34709467b48Spatrick
CallGraphWrapperPass()34809467b48Spatrick CallGraphWrapperPass::CallGraphWrapperPass() : ModulePass(ID) {
34909467b48Spatrick initializeCallGraphWrapperPassPass(*PassRegistry::getPassRegistry());
35009467b48Spatrick }
35109467b48Spatrick
35209467b48Spatrick CallGraphWrapperPass::~CallGraphWrapperPass() = default;
35309467b48Spatrick
getAnalysisUsage(AnalysisUsage & AU) const35409467b48Spatrick void CallGraphWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
35509467b48Spatrick AU.setPreservesAll();
35609467b48Spatrick }
35709467b48Spatrick
runOnModule(Module & M)35809467b48Spatrick bool CallGraphWrapperPass::runOnModule(Module &M) {
35909467b48Spatrick // All the real work is done in the constructor for the CallGraph.
36009467b48Spatrick G.reset(new CallGraph(M));
36109467b48Spatrick return false;
36209467b48Spatrick }
36309467b48Spatrick
36409467b48Spatrick INITIALIZE_PASS(CallGraphWrapperPass, "basiccg", "CallGraph Construction",
36509467b48Spatrick false, true)
36609467b48Spatrick
36709467b48Spatrick char CallGraphWrapperPass::ID = 0;
36809467b48Spatrick
releaseMemory()36909467b48Spatrick void CallGraphWrapperPass::releaseMemory() { G.reset(); }
37009467b48Spatrick
print(raw_ostream & OS,const Module *) const37109467b48Spatrick void CallGraphWrapperPass::print(raw_ostream &OS, const Module *) const {
37209467b48Spatrick if (!G) {
37309467b48Spatrick OS << "No call graph has been built!\n";
37409467b48Spatrick return;
37509467b48Spatrick }
37609467b48Spatrick
37709467b48Spatrick // Just delegate.
37809467b48Spatrick G->print(OS);
37909467b48Spatrick }
38009467b48Spatrick
38109467b48Spatrick #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
38209467b48Spatrick LLVM_DUMP_METHOD
dump() const38309467b48Spatrick void CallGraphWrapperPass::dump() const { print(dbgs(), nullptr); }
38409467b48Spatrick #endif
38509467b48Spatrick
38609467b48Spatrick namespace {
38709467b48Spatrick
38809467b48Spatrick struct CallGraphPrinterLegacyPass : public ModulePass {
38909467b48Spatrick static char ID; // Pass ID, replacement for typeid
39009467b48Spatrick
CallGraphPrinterLegacyPass__anoneb90e9e80611::CallGraphPrinterLegacyPass39109467b48Spatrick CallGraphPrinterLegacyPass() : ModulePass(ID) {
39209467b48Spatrick initializeCallGraphPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
39309467b48Spatrick }
39409467b48Spatrick
getAnalysisUsage__anoneb90e9e80611::CallGraphPrinterLegacyPass39509467b48Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override {
39609467b48Spatrick AU.setPreservesAll();
39709467b48Spatrick AU.addRequiredTransitive<CallGraphWrapperPass>();
39809467b48Spatrick }
39909467b48Spatrick
runOnModule__anoneb90e9e80611::CallGraphPrinterLegacyPass40009467b48Spatrick bool runOnModule(Module &M) override {
40109467b48Spatrick getAnalysis<CallGraphWrapperPass>().print(errs(), &M);
40209467b48Spatrick return false;
40309467b48Spatrick }
40409467b48Spatrick };
40509467b48Spatrick
40609467b48Spatrick } // end anonymous namespace
40709467b48Spatrick
40809467b48Spatrick char CallGraphPrinterLegacyPass::ID = 0;
40909467b48Spatrick
41009467b48Spatrick INITIALIZE_PASS_BEGIN(CallGraphPrinterLegacyPass, "print-callgraph",
41109467b48Spatrick "Print a call graph", true, true)
41209467b48Spatrick INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
41309467b48Spatrick INITIALIZE_PASS_END(CallGraphPrinterLegacyPass, "print-callgraph",
41409467b48Spatrick "Print a call graph", true, true)
415