LLVM 20.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 "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/SmallSet.h"
23#include "llvm/IR/Module.h"
28
29using namespace llvm;
30
31namespace llvm {
32template <class GraphType> struct GraphTraits;
33} // namespace llvm
34
35// This option shows static (relative) call counts.
36// FIXME:
37// Need to show real counts when profile data is available
38static cl::opt<bool> ShowHeatColors("callgraph-heat-colors", cl::init(false),
40 cl::desc("Show heat colors in call-graph"));
41
42static cl::opt<bool>
43 ShowEdgeWeight("callgraph-show-weights", cl::init(false), cl::Hidden,
44 cl::desc("Show edges labeled with weights"));
45
46static cl::opt<bool>
47 CallMultiGraph("callgraph-multigraph", cl::init(false), cl::Hidden,
48 cl::desc("Show call-multigraph (do not remove parallel edges)"));
49
51 "callgraph-dot-filename-prefix", cl::Hidden,
52 cl::desc("The prefix used for the CallGraph dot file names."));
53
54namespace llvm {
55
57private:
58 Module *M;
59 CallGraph *CG;
61 uint64_t MaxFreq;
62
63public:
65
68 : M(M), CG(CG), LookupBFI(LookupBFI) {
69 MaxFreq = 0;
70
71 for (Function &F : M->getFunctionList()) {
72 uint64_t localSumFreq = 0;
74 for (User *U : F.users())
75 if (isa<CallInst>(U))
76 Callers.insert(cast<Instruction>(U)->getFunction());
77 for (Function *Caller : Callers)
78 localSumFreq += getNumOfCalls(*Caller, F);
79 if (localSumFreq >= MaxFreq)
80 MaxFreq = localSumFreq;
81 Freq[&F] = localSumFreq;
82 }
83 if (!CallMultiGraph)
84 removeParallelEdges();
85 }
86
87 Module *getModule() const { return M; }
88
89 CallGraph *getCallGraph() const { return CG; }
90
91 uint64_t getFreq(const Function *F) { return Freq[F]; }
92
93 uint64_t getMaxFreq() { return MaxFreq; }
94
95private:
96 void removeParallelEdges() {
97 for (auto &I : (*CG)) {
98 CallGraphNode *Node = I.second.get();
99
100 bool FoundParallelEdge = true;
101 while (FoundParallelEdge) {
103 FoundParallelEdge = false;
104 for (auto CI = Node->begin(), CE = Node->end(); CI != CE; CI++) {
105 if (!(Visited.insert(CI->second->getFunction())).second) {
106 FoundParallelEdge = true;
107 Node->removeCallEdge(CI);
108 break;
109 }
110 }
111 }
112 }
113 }
114};
115
116template <>
120 // Start at the external node!
121 return CGInfo->getCallGraph()->getExternalCallingNode();
122 }
123
124 typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
126 static const CallGraphNode *CGGetValuePtr(const PairTy &P) {
127 return P.second.get();
128 }
129
130 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
131 typedef mapped_iterator<CallGraph::const_iterator, decltype(&CGGetValuePtr)>
133
135 return nodes_iterator(CGInfo->getCallGraph()->begin(), &CGGetValuePtr);
136 }
138 return nodes_iterator(CGInfo->getCallGraph()->end(), &CGGetValuePtr);
139 }
140};
141
142template <>
144
146
147 static std::string getGraphName(CallGraphDOTInfo *CGInfo) {
148 return "Call graph: " +
149 std::string(CGInfo->getModule()->getModuleIdentifier());
150 }
151
152 static bool isNodeHidden(const CallGraphNode *Node,
153 const CallGraphDOTInfo *CGInfo) {
154 if (CallMultiGraph || Node->getFunction())
155 return false;
156 return true;
157 }
158
159 std::string getNodeLabel(const CallGraphNode *Node,
160 CallGraphDOTInfo *CGInfo) {
161 if (Node == CGInfo->getCallGraph()->getExternalCallingNode())
162 return "external caller";
163 if (Node == CGInfo->getCallGraph()->getCallsExternalNode())
164 return "external callee";
165
166 if (Function *Func = Node->getFunction())
167 return std::string(Func->getName());
168 return "external node";
169 }
171 return P.second;
172 }
173
174 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
176 decltype(&CGGetValuePtr)>
178
180 CallGraphDOTInfo *CGInfo) {
181 if (!ShowEdgeWeight)
182 return "";
183
184 Function *Caller = Node->getFunction();
185 if (Caller == nullptr || Caller->isDeclaration())
186 return "";
187
188 Function *Callee = (*I)->getFunction();
189 if (Callee == nullptr)
190 return "";
191
192 uint64_t Counter = getNumOfCalls(*Caller, *Callee);
193 double Width =
194 1 + 2 * (double(Counter) / CGInfo->getMaxFreq());
195 std::string Attrs = "label=\"" + std::to_string(Counter) +
196 "\" penwidth=" + std::to_string(Width);
197 return Attrs;
198 }
199
200 std::string getNodeAttributes(const CallGraphNode *Node,
201 CallGraphDOTInfo *CGInfo) {
202 Function *F = Node->getFunction();
203 if (F == nullptr)
204 return "";
205 std::string attrs;
206 if (ShowHeatColors) {
207 uint64_t freq = CGInfo->getFreq(F);
208 std::string color = getHeatColor(freq, CGInfo->getMaxFreq());
209 std::string edgeColor = (freq <= (CGInfo->getMaxFreq() / 2))
210 ? getHeatColor(0)
211 : getHeatColor(1);
212 attrs = "color=\"" + edgeColor + "ff\", style=filled, fillcolor=\"" +
213 color + "80\"";
214 }
215 return attrs;
216 }
217};
218
219} // namespace llvm
220
221namespace {
222void doCallGraphDOTPrinting(
223 Module &M, function_ref<BlockFrequencyInfo *(Function &)> LookupBFI) {
224 std::string Filename;
225 if (!CallGraphDotFilenamePrefix.empty())
226 Filename = (CallGraphDotFilenamePrefix + ".callgraph.dot");
227 else
228 Filename = (std::string(M.getModuleIdentifier()) + ".callgraph.dot");
229 errs() << "Writing '" << Filename << "'...";
230
231 std::error_code EC;
232 raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
233
234 CallGraph CG(M);
235 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
236
237 if (!EC)
238 WriteGraph(File, &CFGInfo);
239 else
240 errs() << " error opening file for writing!";
241 errs() << "\n";
242}
243
244void viewCallGraph(Module &M,
245 function_ref<BlockFrequencyInfo *(Function &)> LookupBFI) {
246 CallGraph CG(M);
247 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
248
249 std::string Title =
251 ViewGraph(&CFGInfo, "callgraph", true, Title);
252}
253} // namespace
254
255namespace llvm {
260
261 auto LookupBFI = [&FAM](Function &F) {
263 };
264
265 doCallGraphDOTPrinting(M, LookupBFI);
266
267 return PreservedAnalyses::all();
268}
269
272
275
276 auto LookupBFI = [&FAM](Function &F) {
278 };
279
280 viewCallGraph(M, LookupBFI);
281
282 return PreservedAnalyses::all();
283}
284} // namespace llvm
285
286namespace {
287// Viewer
288class CallGraphViewer : public ModulePass {
289public:
290 static char ID;
291 CallGraphViewer() : ModulePass(ID) {}
292
293 void getAnalysisUsage(AnalysisUsage &AU) const override;
294 bool runOnModule(Module &M) override;
295};
296
297void CallGraphViewer::getAnalysisUsage(AnalysisUsage &AU) const {
298 ModulePass::getAnalysisUsage(AU);
300 AU.setPreservesAll();
301}
302
303bool CallGraphViewer::runOnModule(Module &M) {
304 auto LookupBFI = [this](Function &F) {
305 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
306 };
307
308 viewCallGraph(M, LookupBFI);
309
310 return false;
311}
312
313// DOT Printer
314
315class CallGraphDOTPrinter : public ModulePass {
316public:
317 static char ID;
318 CallGraphDOTPrinter() : ModulePass(ID) {}
319
320 void getAnalysisUsage(AnalysisUsage &AU) const override;
321 bool runOnModule(Module &M) override;
322};
323
324void CallGraphDOTPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
325 ModulePass::getAnalysisUsage(AU);
327 AU.setPreservesAll();
328}
329
330bool CallGraphDOTPrinter::runOnModule(Module &M) {
331 auto LookupBFI = [this](Function &F) {
332 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
333 };
334
335 doCallGraphDOTPrinting(M, LookupBFI);
336
337 return false;
338}
339
340} // end anonymous namespace
341
342char CallGraphViewer::ID = 0;
343INITIALIZE_PASS(CallGraphViewer, "view-callgraph", "View call graph", false,
344 false)
345
346char CallGraphDOTPrinter::ID = 0;
347INITIALIZE_PASS(CallGraphDOTPrinter, "dot-callgraph",
348 "Print call graph to 'dot' file", false, false)
349
350// Create methods available outside of this file, to use them
351// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by
352// the link time optimization.
353
354ModulePass *llvm::createCallGraphViewerPass() { return new CallGraphViewer(); }
355
357 return new CallGraphDOTPrinter();
358}
block freq
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
static cl::opt< bool > ShowHeatColors("callgraph-heat-colors", cl::init(false), cl::Hidden, cl::desc("Show heat colors in call-graph"))
static cl::opt< bool > ShowEdgeWeight("callgraph-show-weights", cl::init(false), cl::Hidden, cl::desc("Show edges labeled with weights"))
static cl::opt< bool > CallMultiGraph("callgraph-multigraph", cl::init(false), cl::Hidden, cl::desc("Show call-multigraph (do not remove parallel edges)"))
static cl::opt< std::string > CallGraphDotFilenamePrefix("callgraph-dot-filename-prefix", cl::Hidden, cl::desc("The prefix used for the CallGraph dot file names."))
This file defines the DenseMap class.
static Function * getFunction(Constant *C)
Definition: Evaluator.cpp:236
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Module.h This file contains the declarations for the Module class.
#define P(N)
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
dot regions Print regions of function to dot file(with no function bodies)"
static bool isSimple(Instruction *I)
This file defines the SmallSet class.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:405
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.
Legacy analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
CallGraph * getCallGraph() const
Definition: CallPrinter.cpp:89
std::function< BlockFrequencyInfo *(Function &)> LookupBFI
Definition: CallPrinter.cpp:64
Module * getModule() const
Definition: CallPrinter.cpp:87
uint64_t getFreq(const Function *F)
Definition: CallPrinter.cpp:91
CallGraphDOTInfo(Module *M, CallGraph *CG, function_ref< BlockFrequencyInfo *(Function &)> LookupBFI)
Definition: CallPrinter.cpp:66
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A node in the call graph for a module.
Definition: CallGraph.h:165
std::vector< CallRecord >::const_iterator const_iterator
Definition: CallGraph.h:193
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:177
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
The basic data container for the call graph of a Module of IR.
Definition: CallGraph.h:71
iterator end()
Definition: CallGraph.h:106
iterator begin()
Definition: CallGraph.h:105
FunctionMapTy::const_iterator const_iterator
Definition: CallGraph.h:97
CallGraphNode * getCallsExternalNode() const
Definition: CallGraph.h:128
CallGraphNode * getExternalCallingNode() const
Returns the CallGraphNode which is used to represent undetermined calls into the callgraph.
Definition: CallGraph.h:126
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
Definition: PassManager.h:563
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition: Module.h:265
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:117
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:179
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:460
TargetPassConfig.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
Definition: FileSystem.h:758
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ModulePass * createCallGraphDOTPrinterPass()
uint64_t getNumOfCalls(Function &callerFunction, Function &calledFunction)
Definition: HeatUtils.cpp:41
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:359
ModulePass * createCallGraphViewerPass()
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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.
Definition: GraphWriter.h:427
std::string getHeatColor(uint64_t freq, uint64_t maxFreq)
Definition: HeatUtils.cpp:63
std::string getNodeAttributes(const CallGraphNode *Node, CallGraphDOTInfo *CGInfo)
static std::string getGraphName(CallGraphDOTInfo *CGInfo)
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)
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
DefaultDOTGraphTraits - This class provides the default implementations of all of the DOTGraphTraits ...
static std::string getGraphName(const GraphType &)
getGraphName - Return the label for the graph as a whole.
static NodeRef getEntryNode(CallGraphDOTInfo *CGInfo)
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)