Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp
35233 views
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
20
#include "llvm/Analysis/CFGPrinter.h"
21
#include "llvm/ADT/PostOrderIterator.h"
22
#include "llvm/Support/CommandLine.h"
23
#include "llvm/Support/FileSystem.h"
24
#include "llvm/Support/GraphWriter.h"
25
26
using namespace llvm;
27
28
static cl::opt<std::string>
29
CFGFuncName("cfg-func-name", cl::Hidden,
30
cl::desc("The name of a function (or its substring)"
31
" whose CFG is viewed/printed."));
32
33
static cl::opt<std::string> CFGDotFilenamePrefix(
34
"cfg-dot-filename-prefix", cl::Hidden,
35
cl::desc("The prefix used for the CFG dot file names."));
36
37
static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
38
cl::init(false));
39
40
static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
41
cl::init(false));
42
43
static cl::opt<double> HideColdPaths(
44
"cfg-hide-cold-paths", cl::init(0.0),
45
cl::desc("Hide blocks with relative frequency below the given value"));
46
47
static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(true),
48
cl::Hidden,
49
cl::desc("Show heat colors in CFG"));
50
51
static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
52
cl::Hidden,
53
cl::desc("Use raw weights for labels. "
54
"Use percentages as default."));
55
56
static cl::opt<bool>
57
ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
58
cl::desc("Show edges labeled with weights"));
59
60
static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
61
BranchProbabilityInfo *BPI, uint64_t MaxFreq,
62
bool CFGOnly = false) {
63
std::string Filename =
64
(CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
65
errs() << "Writing '" << Filename << "'...";
66
67
std::error_code EC;
68
raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
69
70
DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
71
CFGInfo.setHeatColors(ShowHeatColors);
72
CFGInfo.setEdgeWeights(ShowEdgeWeight);
73
CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
74
75
if (!EC)
76
WriteGraph(File, &CFGInfo, CFGOnly);
77
else
78
errs() << " error opening file for writing!";
79
errs() << "\n";
80
}
81
82
static void viewCFG(Function &F, const BlockFrequencyInfo *BFI,
83
const BranchProbabilityInfo *BPI, uint64_t MaxFreq,
84
bool CFGOnly = false) {
85
DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
86
CFGInfo.setHeatColors(ShowHeatColors);
87
CFGInfo.setEdgeWeights(ShowEdgeWeight);
88
CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
89
90
ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);
91
}
92
93
PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {
94
if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
95
return PreservedAnalyses::all();
96
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
97
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
98
viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
99
return PreservedAnalyses::all();
100
}
101
102
PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
103
FunctionAnalysisManager &AM) {
104
if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
105
return PreservedAnalyses::all();
106
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
107
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
108
viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
109
return PreservedAnalyses::all();
110
}
111
112
PreservedAnalyses CFGPrinterPass::run(Function &F,
113
FunctionAnalysisManager &AM) {
114
if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
115
return PreservedAnalyses::all();
116
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
117
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
118
writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
119
return PreservedAnalyses::all();
120
}
121
122
PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
123
FunctionAnalysisManager &AM) {
124
if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
125
return PreservedAnalyses::all();
126
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
127
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
128
writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
129
return PreservedAnalyses::all();
130
}
131
132
/// viewCFG - This function is meant for use from the debugger. You can just
133
/// say 'call F->viewCFG()' and a ghostview window should pop up from the
134
/// program, displaying the CFG of the current function. This depends on there
135
/// being a 'dot' and 'gv' program in your path.
136
///
137
void Function::viewCFG() const { viewCFG(false, nullptr, nullptr); }
138
139
void Function::viewCFG(bool ViewCFGOnly, const BlockFrequencyInfo *BFI,
140
const BranchProbabilityInfo *BPI) const {
141
if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
142
return;
143
DOTFuncInfo CFGInfo(this, BFI, BPI, BFI ? getMaxFreq(*this, BFI) : 0);
144
ViewGraph(&CFGInfo, "cfg" + getName(), ViewCFGOnly);
145
}
146
147
/// viewCFGOnly - This function is meant for use from the debugger. It works
148
/// just like viewCFG, but it does not include the contents of basic blocks
149
/// into the nodes, just the label. If you are only interested in the CFG
150
/// this can make the graph smaller.
151
///
152
void Function::viewCFGOnly() const { viewCFGOnly(nullptr, nullptr); }
153
154
void Function::viewCFGOnly(const BlockFrequencyInfo *BFI,
155
const BranchProbabilityInfo *BPI) const {
156
viewCFG(true, BFI, BPI);
157
}
158
159
/// Find all blocks on the paths which terminate with a deoptimize or
160
/// unreachable (i.e. all blocks which are post-dominated by a deoptimize
161
/// or unreachable). These paths are hidden if the corresponding cl::opts
162
/// are enabled.
163
void DOTGraphTraits<DOTFuncInfo *>::computeDeoptOrUnreachablePaths(
164
const Function *F) {
165
auto evaluateBB = [&](const BasicBlock *Node) {
166
if (succ_empty(Node)) {
167
const Instruction *TI = Node->getTerminator();
168
isOnDeoptOrUnreachablePath[Node] =
169
(HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
170
(HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
171
return;
172
}
173
isOnDeoptOrUnreachablePath[Node] =
174
llvm::all_of(successors(Node), [this](const BasicBlock *BB) {
175
return isOnDeoptOrUnreachablePath[BB];
176
});
177
};
178
/// The post order traversal iteration is done to know the status of
179
/// isOnDeoptOrUnreachablePath for all the successors on the current BB.
180
llvm::for_each(post_order(&F->getEntryBlock()), evaluateBB);
181
}
182
183
bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node,
184
const DOTFuncInfo *CFGInfo) {
185
if (HideColdPaths.getNumOccurrences() > 0)
186
if (auto *BFI = CFGInfo->getBFI()) {
187
BlockFrequency NodeFreq = BFI->getBlockFreq(Node);
188
BlockFrequency EntryFreq = BFI->getEntryFreq();
189
// Hide blocks with relative frequency below HideColdPaths threshold.
190
if ((double)NodeFreq.getFrequency() / EntryFreq.getFrequency() <
191
HideColdPaths)
192
return true;
193
}
194
if (HideUnreachablePaths || HideDeoptimizePaths) {
195
if (!isOnDeoptOrUnreachablePath.contains(Node))
196
computeDeoptOrUnreachablePaths(Node->getParent());
197
return isOnDeoptOrUnreachablePath[Node];
198
}
199
return false;
200
}
201
202