LLVM 17.0.0git
CFGPrinter.cpp
Go to the documentation of this file.
1//===- CFGPrinter.cpp - DOT printer for the control flow 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 a `-dot-cfg` analysis pass, which emits the
10// `<prefix>.<fnname>.dot` file for each function in the program, with a graph
11// of the CFG for that function. The default value for `<prefix>` is `cfg` but
12// can be customized as needed.
13//
14// The other main feature of this file is that it implements the
15// Function::viewCFG method, which is useful for debugging passes which operate
16// on the CFG.
17//
18//===----------------------------------------------------------------------===//
19
23#include "llvm/Pass.h"
27
28using namespace llvm;
29
31 CFGFuncName("cfg-func-name", cl::Hidden,
32 cl::desc("The name of a function (or its substring)"
33 " whose CFG is viewed/printed."));
34
36 "cfg-dot-filename-prefix", cl::Hidden,
37 cl::desc("The prefix used for the CFG dot file names."));
38
39static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
40 cl::init(false));
41
42static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
43 cl::init(false));
44
46 "cfg-hide-cold-paths", cl::init(0.0),
47 cl::desc("Hide blocks with relative frequency below the given value"));
48
49static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(true),
51 cl::desc("Show heat colors in CFG"));
52
53static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
55 cl::desc("Use raw weights for labels. "
56 "Use percentages as default."));
57
58static cl::opt<bool>
59 ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
60 cl::desc("Show edges labeled with weights"));
61
63 BranchProbabilityInfo *BPI, uint64_t MaxFreq,
64 bool CFGOnly = false) {
65 std::string Filename =
66 (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
67 errs() << "Writing '" << Filename << "'...";
68
69 std::error_code EC;
70 raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
71
72 DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
76
77 if (!EC)
78 WriteGraph(File, &CFGInfo, CFGOnly);
79 else
80 errs() << " error opening file for writing!";
81 errs() << "\n";
82}
83
84static void viewCFG(Function &F, const BlockFrequencyInfo *BFI,
85 const BranchProbabilityInfo *BPI, uint64_t MaxFreq,
86 bool CFGOnly = false) {
87 DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
91
92 ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);
93}
94
95namespace {
96struct CFGViewerLegacyPass : public FunctionPass {
97 static char ID; // Pass identifcation, replacement for typeid
98 CFGViewerLegacyPass() : FunctionPass(ID) {
100 }
101
102 bool runOnFunction(Function &F) override {
103 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
104 return false;
105 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
106 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
107 viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
108 return false;
109 }
110
111 void print(raw_ostream &OS, const Module * = nullptr) const override {}
112
113 void getAnalysisUsage(AnalysisUsage &AU) const override {
117 AU.setPreservesAll();
118 }
119};
120} // namespace
121
122char CFGViewerLegacyPass::ID = 0;
123INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false,
124 true)
125
127 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
128 return PreservedAnalyses::all();
129 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
130 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
131 viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
132 return PreservedAnalyses::all();
133}
134
135namespace {
136struct CFGOnlyViewerLegacyPass : public FunctionPass {
137 static char ID; // Pass identifcation, replacement for typeid
138 CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
140 }
141
142 bool runOnFunction(Function &F) override {
143 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
144 return false;
145 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
146 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
147 viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
148 return false;
149 }
150
151 void print(raw_ostream &OS, const Module * = nullptr) const override {}
152
153 void getAnalysisUsage(AnalysisUsage &AU) const override {
157 AU.setPreservesAll();
158 }
159};
160} // namespace
161
162char CFGOnlyViewerLegacyPass::ID = 0;
163INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
164 "View CFG of function (with no function bodies)", false, true)
165
168 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
169 return PreservedAnalyses::all();
170 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
171 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
172 viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
173 return PreservedAnalyses::all();
174}
175
176namespace {
177struct CFGPrinterLegacyPass : public FunctionPass {
178 static char ID; // Pass identification, replacement for typeid
179 CFGPrinterLegacyPass() : FunctionPass(ID) {
181 }
182
183 bool runOnFunction(Function &F) override {
184 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
185 return false;
186 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
187 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
188 writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
189 return false;
190 }
191
192 void print(raw_ostream &OS, const Module * = nullptr) const override {}
193
194 void getAnalysisUsage(AnalysisUsage &AU) const override {
198 AU.setPreservesAll();
199 }
200};
201} // namespace
202
203char CFGPrinterLegacyPass::ID = 0;
204INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg",
205 "Print CFG of function to 'dot' file", false, true)
206
209 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
210 return PreservedAnalyses::all();
211 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
212 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
213 writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
214 return PreservedAnalyses::all();
215}
216
217namespace {
218struct CFGOnlyPrinterLegacyPass : public FunctionPass {
219 static char ID; // Pass identification, replacement for typeid
220 CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
222 }
223
224 bool runOnFunction(Function &F) override {
225 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
226 return false;
227 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
228 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
229 writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
230 return false;
231 }
232 void print(raw_ostream &OS, const Module * = nullptr) const override {}
233
234 void getAnalysisUsage(AnalysisUsage &AU) const override {
238 AU.setPreservesAll();
239 }
240};
241} // namespace
242
243char CFGOnlyPrinterLegacyPass::ID = 0;
244INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
245 "Print CFG of function to 'dot' file (with no function bodies)",
246 false, true)
247
250 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
251 return PreservedAnalyses::all();
252 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
253 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
254 writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
255 return PreservedAnalyses::all();
256}
257
258/// viewCFG - This function is meant for use from the debugger. You can just
259/// say 'call F->viewCFG()' and a ghostview window should pop up from the
260/// program, displaying the CFG of the current function. This depends on there
261/// being a 'dot' and 'gv' program in your path.
262///
263void Function::viewCFG() const { viewCFG(false, nullptr, nullptr); }
264
265void Function::viewCFG(bool ViewCFGOnly, const BlockFrequencyInfo *BFI,
266 const BranchProbabilityInfo *BPI) const {
267 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
268 return;
269 DOTFuncInfo CFGInfo(this, BFI, BPI, BFI ? getMaxFreq(*this, BFI) : 0);
270 ViewGraph(&CFGInfo, "cfg" + getName(), ViewCFGOnly);
271}
272
273/// viewCFGOnly - This function is meant for use from the debugger. It works
274/// just like viewCFG, but it does not include the contents of basic blocks
275/// into the nodes, just the label. If you are only interested in the CFG
276/// this can make the graph smaller.
277///
278void Function::viewCFGOnly() const { viewCFGOnly(nullptr, nullptr); }
279
281 const BranchProbabilityInfo *BPI) const {
282 viewCFG(true, BFI, BPI);
283}
284
286 return new CFGPrinterLegacyPass();
287}
288
290 return new CFGOnlyPrinterLegacyPass();
291}
292
293/// Find all blocks on the paths which terminate with a deoptimize or
294/// unreachable (i.e. all blocks which are post-dominated by a deoptimize
295/// or unreachable). These paths are hidden if the corresponding cl::opts
296/// are enabled.
298 const Function *F) {
299 auto evaluateBB = [&](const BasicBlock *Node) {
300 if (succ_empty(Node)) {
301 const Instruction *TI = Node->getTerminator();
302 isOnDeoptOrUnreachablePath[Node] =
303 (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
304 (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
305 return;
306 }
307 isOnDeoptOrUnreachablePath[Node] =
308 llvm::all_of(successors(Node), [this](const BasicBlock *BB) {
309 return isOnDeoptOrUnreachablePath[BB];
310 });
311 };
312 /// The post order traversal iteration is done to know the status of
313 /// isOnDeoptOrUnreachablePath for all the successors on the current BB.
314 llvm::for_each(post_order(&F->getEntryBlock()), evaluateBB);
315}
316
318 const DOTFuncInfo *CFGInfo) {
319 if (HideColdPaths.getNumOccurrences() > 0)
320 if (auto *BFI = CFGInfo->getBFI()) {
321 uint64_t NodeFreq = BFI->getBlockFreq(Node).getFrequency();
322 uint64_t EntryFreq = BFI->getEntryFreq();
323 // Hide blocks with relative frequency below HideColdPaths threshold.
324 if ((double)NodeFreq / EntryFreq < HideColdPaths)
325 return true;
326 }
328 if (!isOnDeoptOrUnreachablePath.contains(Node))
329 computeDeoptOrUnreachablePaths(Node->getParent());
330 return isOnDeoptOrUnreachablePath[Node];
331 }
332 return false;
333}
static cl::opt< bool > UseRawEdgeWeight("cfg-raw-weights", cl::init(false), cl::Hidden, cl::desc("Use raw weights for labels. " "Use percentages as default."))
static cl::opt< bool > HideUnreachablePaths("cfg-hide-unreachable-paths", cl::init(false))
static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI, BranchProbabilityInfo *BPI, uint64_t MaxFreq, bool CFGOnly=false)
Definition: CFGPrinter.cpp:62
static cl::opt< bool > ShowHeatColors("cfg-heat-colors", cl::init(true), cl::Hidden, cl::desc("Show heat colors in CFG"))
static cl::opt< std::string > CFGDotFilenamePrefix("cfg-dot-filename-prefix", cl::Hidden, cl::desc("The prefix used for the CFG dot file names."))
static void viewCFG(Function &F, const BlockFrequencyInfo *BFI, const BranchProbabilityInfo *BPI, uint64_t MaxFreq, bool CFGOnly=false)
Definition: CFGPrinter.cpp:84
static cl::opt< double > HideColdPaths("cfg-hide-cold-paths", cl::init(0.0), cl::desc("Hide blocks with relative frequency below the given value"))
static cl::opt< bool > HideDeoptimizePaths("cfg-hide-deoptimize-paths", cl::init(false))
static cl::opt< std::string > CFGFuncName("cfg-func-name", cl::Hidden, cl::desc("The name of a function (or its substring)" " whose CFG is viewed/printed."))
static cl::opt< bool > ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden, cl::desc("Show edges labeled with weights"))
#define F(x, y, z)
Definition: MD5.cpp:55
static cl::opt< bool > CFGOnly("dot-mcfg-only", cl::init(false), cl::Hidden, cl::desc("Print only the CFG without blocks body"))
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
raw_pwrite_stream & OS
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:470
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
Analysis pass which computes BlockFrequencyInfo.
Legacy analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Analysis pass which computes BranchProbabilityInfo.
Legacy analysis pass which computes BranchProbabilityInfo.
Analysis providing branch probability information.
void setRawEdgeWeights(bool RawWeights)
Definition: CFGPrinter.h:96
void setEdgeWeights(bool EdgeWeights)
Definition: CFGPrinter.h:100
const BlockFrequencyInfo * getBFI() const
Definition: CFGPrinter.h:80
void setHeatColors(bool ShowHeat)
Definition: CFGPrinter.h:92
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
void viewCFG() const
viewCFG - This function is meant for use from the debugger.
Definition: CFGPrinter.cpp:263
void viewCFGOnly() const
viewCFGOnly - This function is meant for use from the debugger.
Definition: CFGPrinter.cpp:278
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:130
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: PassManager.h:152
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:454
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
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:445
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
Definition: FileSystem.h:761
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1812
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1819
bool succ_empty(const Instruction *I)
Definition: CFG.h:255
auto successors(const MachineBasicBlock *BB)
iterator_range< po_iterator< T > > post_order(const T &G)
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:359
FunctionPass * createCFGPrinterLegacyPassPass()
Definition: CFGPrinter.cpp:285
void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry &)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void initializeCFGViewerLegacyPassPass(PassRegistry &)
void initializeCFGPrinterLegacyPassPass(PassRegistry &)
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
FunctionPass * createCFGOnlyPrinterLegacyPassPass()
Definition: CFGPrinter.cpp:289
void initializeCFGOnlyViewerLegacyPassPass(PassRegistry &)
uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI)
Definition: HeatUtils.cpp:53
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
static bool isNodeHidden(const void *, const GraphType &)
isNodeHidden - If the function returns true, the given node is not displayed in the graph.