LLVM 24.0.0git
CallPrinter.cpp
Go to the documentation of this file.
1//===- CallPrinter.cpp - DOT printer for call graph -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines '-dot-callgraph', which emit a callgraph.<fnname>.dot
10// containing the call graph of a module.
11//
12// There is also a pass available to directly call dotty ('-view-callgraph').
13//
14//===----------------------------------------------------------------------===//
15
17#include "AnalysisOptions.h"
18#include "llvm/ADT/DenseMap.h"
23#include "llvm/IR/Module.h"
27
28using namespace llvm;
29
30namespace llvm {
31template <class GraphType> struct GraphTraits;
32} // namespace llvm
33
34namespace llvm {
35
37private:
38 const AnalysisOptions &Opts;
39 Module *M;
40 CallGraph *CG;
42 uint64_t MaxFreq;
43
44public:
46
49 : Opts(getAnalysisOptions(*M)), M(M), CG(CG), LookupBFI(LookupBFI) {
50 MaxFreq = 0;
51
52 for (Function &F : M->getFunctionList()) {
53 uint64_t localSumFreq = 0;
54 SmallPtrSet<Function *, 16> Callers;
55 for (User *U : F.users())
56 if (isa<CallInst>(U))
57 Callers.insert(cast<Instruction>(U)->getFunction());
58 for (Function *Caller : Callers)
59 localSumFreq += getNumOfCalls(*Caller, F);
60 if (localSumFreq >= MaxFreq)
61 MaxFreq = localSumFreq;
62 Freq[&F] = localSumFreq;
63 }
64 if (!Opts.callgraph_multigraph)
65 removeParallelEdges();
66 }
67
68 const AnalysisOptions &getOpts() const { return Opts; }
69
70 Module *getModule() const { return M; }
71
72 CallGraph *getCallGraph() const { return CG; }
73
74 uint64_t getFreq(const Function *F) { return Freq[F]; }
75
76 uint64_t getMaxFreq() { return MaxFreq; }
77
78private:
79 void removeParallelEdges() {
80 for (auto &I : (*CG)) {
81 CallGraphNode *Node = I.second.get();
82
83 bool FoundParallelEdge = true;
84 while (FoundParallelEdge) {
86 FoundParallelEdge = false;
87 for (auto CI = Node->begin(), CE = Node->end(); CI != CE; CI++) {
88 if (!(Visited.insert(CI->second->getFunction())).second) {
89 FoundParallelEdge = true;
90 Node->removeCallEdge(CI);
91 break;
92 }
93 }
94 }
95 }
96 }
97};
98
99template <>
103 // Start at the external node!
104 return CGInfo->getCallGraph()->getExternalCallingNode();
105 }
106
107 typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
109 static const CallGraphNode *CGGetValuePtr(const PairTy &P) {
110 return P.second.get();
111 }
112
113 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
114 typedef mapped_iterator<CallGraph::const_iterator, decltype(&CGGetValuePtr)>
116
118 return nodes_iterator(CGInfo->getCallGraph()->begin(), &CGGetValuePtr);
119 }
121 return nodes_iterator(CGInfo->getCallGraph()->end(), &CGGetValuePtr);
122 }
123};
124
125template <>
127
129
130 static std::string getGraphName(CallGraphDOTInfo *CGInfo) {
131 return "Call graph: " +
132 std::string(CGInfo->getModule()->getModuleIdentifier());
133 }
134
135 static bool isNodeHidden(const CallGraphNode *Node,
136 const CallGraphDOTInfo *CGInfo) {
137 if (CGInfo->getOpts().callgraph_multigraph || Node->getFunction())
138 return false;
139 return true;
140 }
141
142 std::string getNodeLabel(const CallGraphNode *Node,
143 CallGraphDOTInfo *CGInfo) {
144 if (Node == CGInfo->getCallGraph()->getExternalCallingNode())
145 return "external caller";
146 if (Node == CGInfo->getCallGraph()->getCallsExternalNode())
147 return "external callee";
148
149 if (Function *Func = Node->getFunction())
150 return std::string(Func->getName());
151 return "external node";
152 }
154 return P.second;
155 }
156
157 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
159 decltype(&CGGetValuePtr)>
161
163 CallGraphDOTInfo *CGInfo) {
164 if (!CGInfo->getOpts().callgraph_show_weights)
165 return "";
166
167 Function *Caller = Node->getFunction();
168 if (Caller == nullptr || Caller->isDeclaration())
169 return "";
170
171 Function *Callee = (*I)->getFunction();
172 if (Callee == nullptr)
173 return "";
174
175 uint64_t Counter = getNumOfCalls(*Caller, *Callee);
176 double Width =
177 1 + 2 * (double(Counter) / CGInfo->getMaxFreq());
178 std::string Attrs = "label=\"" + std::to_string(Counter) +
179 "\" penwidth=" + std::to_string(Width);
180 return Attrs;
181 }
182
184 CallGraphDOTInfo *CGInfo) {
185 Function *F = Node->getFunction();
186 if (F == nullptr)
187 return "";
188 std::string attrs;
189 if (CGInfo->getOpts().callgraph_heat_colors) {
190 uint64_t freq = CGInfo->getFreq(F);
191 std::string color = getHeatColor(freq, CGInfo->getMaxFreq());
192 std::string edgeColor = (freq <= (CGInfo->getMaxFreq() / 2))
193 ? getHeatColor(0)
194 : getHeatColor(1);
195 attrs = "color=\"" + edgeColor + "ff\", style=filled, fillcolor=\"" +
196 color + "80\"";
197 }
198 return attrs;
199 }
200};
201
202} // namespace llvm
203
204namespace {
205void doCallGraphDOTPrinting(
206 Module &M, function_ref<BlockFrequencyInfo *(Function &)> LookupBFI) {
207 StringRef Prefix = getAnalysisOptions(M).callgraph_dot_filename_prefix;
208 std::string Filename;
209 if (!Prefix.empty())
210 Filename = (Prefix + ".callgraph.dot").str();
211 else
212 Filename = (std::string(M.getModuleIdentifier()) + ".callgraph.dot");
213 errs() << "Writing '" << Filename << "'...";
214
215 std::error_code EC;
216 raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
217
218 CallGraph CG(M);
219 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
220
221 if (!EC)
222 WriteGraph(File, &CFGInfo);
223 else
224 errs() << " error opening file for writing!";
225 errs() << "\n";
226}
227
228void viewCallGraph(Module &M,
229 function_ref<BlockFrequencyInfo *(Function &)> LookupBFI) {
230 CallGraph CG(M);
231 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
232
233 std::string Title =
235 ViewGraph(&CFGInfo, "callgraph", true, Title);
236}
237} // namespace
238
239namespace llvm {
244
245 auto LookupBFI = [&FAM](Function &F) {
246 return &FAM.getResult<BlockFrequencyAnalysis>(F);
247 };
248
249 doCallGraphDOTPrinting(M, LookupBFI);
250
251 return PreservedAnalyses::all();
252}
253
256
259
260 auto LookupBFI = [&FAM](Function &F) {
261 return &FAM.getResult<BlockFrequencyAnalysis>(F);
262 };
263
264 viewCallGraph(M, LookupBFI);
265
266 return PreservedAnalyses::all();
267}
268} // namespace llvm
269
270namespace {
271// Viewer
272class CallGraphViewer : public ModulePass {
273public:
274 static char ID;
275 CallGraphViewer() : ModulePass(ID) {}
276
277 void getAnalysisUsage(AnalysisUsage &AU) const override;
278 bool runOnModule(Module &M) override;
279};
280
281void CallGraphViewer::getAnalysisUsage(AnalysisUsage &AU) const {
282 ModulePass::getAnalysisUsage(AU);
283 AU.addRequired<BlockFrequencyInfoWrapperPass>();
284 AU.setPreservesAll();
285}
286
287bool CallGraphViewer::runOnModule(Module &M) {
288 auto LookupBFI = [this](Function &F) {
289 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
290 };
291
292 viewCallGraph(M, LookupBFI);
293
294 return false;
295}
296
297// DOT Printer
298
299class CallGraphDOTPrinter : public ModulePass {
300public:
301 static char ID;
302 CallGraphDOTPrinter() : ModulePass(ID) {}
303
304 void getAnalysisUsage(AnalysisUsage &AU) const override;
305 bool runOnModule(Module &M) override;
306};
307
308void CallGraphDOTPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
309 ModulePass::getAnalysisUsage(AU);
310 AU.addRequired<BlockFrequencyInfoWrapperPass>();
311 AU.setPreservesAll();
312}
313
314bool CallGraphDOTPrinter::runOnModule(Module &M) {
315 auto LookupBFI = [this](Function &F) {
316 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
317 };
318
319 doCallGraphDOTPrinting(M, LookupBFI);
320
321 return false;
322}
323
324} // end anonymous namespace
325
326char CallGraphViewer::ID = 0;
327INITIALIZE_PASS(CallGraphViewer, "view-callgraph", "View call graph", false,
328 false)
329
330char CallGraphDOTPrinter::ID = 0;
331INITIALIZE_PASS(CallGraphDOTPrinter, "dot-callgraph",
332 "Print call graph to 'dot' file", false, false)
333
334// Create methods available outside of this file, to use them
335// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by
336// the link time optimization.
337
338ModulePass *llvm::createCallGraphViewerPass() { return new CallGraphViewer(); }
339
341 return new CallGraphDOTPrinter();
342}
block freq
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file defines the DenseMap class.
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
static constexpr StringLiteral Filename
#define P(N)
FunctionAnalysisManager FAM
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
Analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
CallGraph * getCallGraph() const
std::function< BlockFrequencyInfo *(Function &)> LookupBFI
Module * getModule() const
const AnalysisOptions & getOpts() const
uint64_t getFreq(const Function *F)
CallGraphDOTInfo(Module *M, CallGraph *CG, function_ref< BlockFrequencyInfo *(Function &)> LookupBFI)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A node in the call graph for a module.
Definition CallGraph.h:162
std::vector< CallRecord >::const_iterator const_iterator
Definition CallGraph.h:190
std::pair< std::optional< WeakTrackingVH >, CallGraphNode * > CallRecord
A pair of the calling instruction (a call or invoke) and the call graph node being called.
Definition CallGraph.h:174
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
The basic data container for the call graph of a Module of IR.
Definition CallGraph.h:72
iterator end()
Definition CallGraph.h:107
iterator begin()
Definition CallGraph.h:106
FunctionMapTy::const_iterator const_iterator
Definition CallGraph.h:98
CallGraphNode * getCallsExternalNode() const
Definition CallGraph.h:129
CallGraphNode * getExternalCallingNode() const
Returns the CallGraphNode which is used to represent undetermined calls into the callgraph.
Definition CallGraph.h:127
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:253
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition Module.h:299
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
An efficient, type-erasing, non-owning reference to a callable.
TargetPassConfig.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
Definition FileSystem.h:793
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI ModulePass * createCallGraphDOTPrinterPass()
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
LLVM_ABI uint64_t getNumOfCalls(const Function &CallerFunction, const Function &CalledFunction)
Definition HeatUtils.cpp:40
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI std::string getHeatColor(uint64_t Freq, uint64_t MaxFreq)
Definition HeatUtils.cpp:59
void ViewGraph(const GraphType &G, const Twine &Name, bool ShortNames=false, const Twine &Title="", GraphProgram::Name Program=GraphProgram::DOT)
ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, then cleanup.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI ModulePass * createCallGraphViewerPass()
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
std::string getNodeAttributes(const CallGraphNode *Node, CallGraphDOTInfo *CGInfo)
static std::string getGraphName(CallGraphDOTInfo *CGInfo)
mapped_iterator< CallGraphNode::const_iterator, decltype(&CGGetValuePtr)> nodes_iterator
static const CallGraphNode * CGGetValuePtr(CallGraphNode::CallRecord P)
static bool isNodeHidden(const CallGraphNode *Node, const CallGraphDOTInfo *CGInfo)
std::string getEdgeAttributes(const CallGraphNode *Node, nodes_iterator I, CallGraphDOTInfo *CGInfo)
std::string getNodeLabel(const CallGraphNode *Node, CallGraphDOTInfo *CGInfo)
static std::string getGraphName(const GraphType &)
getGraphName - Return the label for the graph as a whole.
static NodeRef getEntryNode(CallGraphDOTInfo *CGInfo)
mapped_iterator< CallGraph::const_iterator, decltype(&CGGetValuePtr)> nodes_iterator
static const CallGraphNode * CGGetValuePtr(const PairTy &P)
static nodes_iterator nodes_begin(CallGraphDOTInfo *CGInfo)
std::pair< const Function *const, std::unique_ptr< CallGraphNode > > PairTy
static nodes_iterator nodes_end(CallGraphDOTInfo *CGInfo)
typename CallGraphDOTInfo *::UnknownGraphTypeError NodeRef
Definition GraphTraits.h:94