1f22ef01cSRoman Divacky //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky // The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10*b5893f02SDimitry Andric // This file defines a `-dot-cfg` analysis pass, which emits the
11*b5893f02SDimitry Andric // `<prefix>.<fnname>.dot` file for each function in the program, with a graph
12*b5893f02SDimitry Andric // of the CFG for that function. The default value for `<prefix>` is `cfg` but
13*b5893f02SDimitry Andric // can be customized as needed.
14f22ef01cSRoman Divacky //
15f22ef01cSRoman Divacky // The other main feature of this file is that it implements the
16f22ef01cSRoman Divacky // Function::viewCFG method, which is useful for debugging passes which operate
17f22ef01cSRoman Divacky // on the CFG.
18f22ef01cSRoman Divacky //
19f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
20f22ef01cSRoman Divacky
21f22ef01cSRoman Divacky #include "llvm/Analysis/CFGPrinter.h"
22f22ef01cSRoman Divacky #include "llvm/Pass.h"
2391bc56edSDimitry Andric #include "llvm/Support/FileSystem.h"
24f22ef01cSRoman Divacky using namespace llvm;
25f22ef01cSRoman Divacky
264ba319b5SDimitry Andric static cl::opt<std::string> CFGFuncName(
274ba319b5SDimitry Andric "cfg-func-name", cl::Hidden,
284ba319b5SDimitry Andric cl::desc("The name of a function (or its substring)"
294ba319b5SDimitry Andric " whose CFG is viewed/printed."));
304ba319b5SDimitry Andric
31*b5893f02SDimitry Andric static cl::opt<std::string> CFGDotFilenamePrefix(
32*b5893f02SDimitry Andric "cfg-dot-filename-prefix", cl::Hidden,
33*b5893f02SDimitry Andric cl::desc("The prefix used for the CFG dot file names."));
34*b5893f02SDimitry Andric
35f22ef01cSRoman Divacky namespace {
36d88c1a5aSDimitry Andric struct CFGViewerLegacyPass : public FunctionPass {
37f22ef01cSRoman Divacky static char ID; // Pass identifcation, replacement for typeid
CFGViewerLegacyPass__anon52f097dc0111::CFGViewerLegacyPass38d88c1a5aSDimitry Andric CFGViewerLegacyPass() : FunctionPass(ID) {
39d88c1a5aSDimitry Andric initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
402754fe60SDimitry Andric }
41f22ef01cSRoman Divacky
runOnFunction__anon52f097dc0111::CFGViewerLegacyPass4291bc56edSDimitry Andric bool runOnFunction(Function &F) override {
43f22ef01cSRoman Divacky F.viewCFG();
44f22ef01cSRoman Divacky return false;
45f22ef01cSRoman Divacky }
46f22ef01cSRoman Divacky
print__anon52f097dc0111::CFGViewerLegacyPass4791bc56edSDimitry Andric void print(raw_ostream &OS, const Module* = nullptr) const override {}
48f22ef01cSRoman Divacky
getAnalysisUsage__anon52f097dc0111::CFGViewerLegacyPass4991bc56edSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
50f22ef01cSRoman Divacky AU.setPreservesAll();
51f22ef01cSRoman Divacky }
52f22ef01cSRoman Divacky };
533dac3a9bSDimitry Andric }
54f22ef01cSRoman Divacky
55d88c1a5aSDimitry Andric char CFGViewerLegacyPass::ID = 0;
56d88c1a5aSDimitry Andric INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
57d88c1a5aSDimitry Andric
run(Function & F,FunctionAnalysisManager & AM)58d88c1a5aSDimitry Andric PreservedAnalyses CFGViewerPass::run(Function &F,
59d88c1a5aSDimitry Andric FunctionAnalysisManager &AM) {
60d88c1a5aSDimitry Andric F.viewCFG();
61d88c1a5aSDimitry Andric return PreservedAnalyses::all();
62d88c1a5aSDimitry Andric }
63d88c1a5aSDimitry Andric
64f22ef01cSRoman Divacky
65f22ef01cSRoman Divacky namespace {
66d88c1a5aSDimitry Andric struct CFGOnlyViewerLegacyPass : public FunctionPass {
67f22ef01cSRoman Divacky static char ID; // Pass identifcation, replacement for typeid
CFGOnlyViewerLegacyPass__anon52f097dc0211::CFGOnlyViewerLegacyPass68d88c1a5aSDimitry Andric CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
69d88c1a5aSDimitry Andric initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
702754fe60SDimitry Andric }
71f22ef01cSRoman Divacky
runOnFunction__anon52f097dc0211::CFGOnlyViewerLegacyPass7291bc56edSDimitry Andric bool runOnFunction(Function &F) override {
73f22ef01cSRoman Divacky F.viewCFGOnly();
74f22ef01cSRoman Divacky return false;
75f22ef01cSRoman Divacky }
76f22ef01cSRoman Divacky
print__anon52f097dc0211::CFGOnlyViewerLegacyPass7791bc56edSDimitry Andric void print(raw_ostream &OS, const Module* = nullptr) const override {}
78f22ef01cSRoman Divacky
getAnalysisUsage__anon52f097dc0211::CFGOnlyViewerLegacyPass7991bc56edSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
80f22ef01cSRoman Divacky AU.setPreservesAll();
81f22ef01cSRoman Divacky }
82f22ef01cSRoman Divacky };
833dac3a9bSDimitry Andric }
84f22ef01cSRoman Divacky
85d88c1a5aSDimitry Andric char CFGOnlyViewerLegacyPass::ID = 0;
86d88c1a5aSDimitry Andric INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
872754fe60SDimitry Andric "View CFG of function (with no function bodies)", false, true)
88f22ef01cSRoman Divacky
run(Function & F,FunctionAnalysisManager & AM)89d88c1a5aSDimitry Andric PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
90d88c1a5aSDimitry Andric FunctionAnalysisManager &AM) {
91d88c1a5aSDimitry Andric F.viewCFGOnly();
92d88c1a5aSDimitry Andric return PreservedAnalyses::all();
932754fe60SDimitry Andric }
94f22ef01cSRoman Divacky
writeCFGToDotFile(Function & F,bool CFGOnly=false)95da09e106SDimitry Andric static void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
964ba319b5SDimitry Andric if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
974ba319b5SDimitry Andric return;
98*b5893f02SDimitry Andric std::string Filename =
99*b5893f02SDimitry Andric (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
100f22ef01cSRoman Divacky errs() << "Writing '" << Filename << "'...";
101f22ef01cSRoman Divacky
10239d628a0SDimitry Andric std::error_code EC;
10339d628a0SDimitry Andric raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
104f22ef01cSRoman Divacky
10539d628a0SDimitry Andric if (!EC)
106da09e106SDimitry Andric WriteGraph(File, (const Function*)&F, CFGOnly);
107f22ef01cSRoman Divacky else
108f22ef01cSRoman Divacky errs() << " error opening file for writing!";
109f22ef01cSRoman Divacky errs() << "\n";
110f22ef01cSRoman Divacky }
111f22ef01cSRoman Divacky
112f22ef01cSRoman Divacky namespace {
113d88c1a5aSDimitry Andric struct CFGPrinterLegacyPass : public FunctionPass {
114f22ef01cSRoman Divacky static char ID; // Pass identification, replacement for typeid
CFGPrinterLegacyPass__anon52f097dc0311::CFGPrinterLegacyPass115d88c1a5aSDimitry Andric CFGPrinterLegacyPass() : FunctionPass(ID) {
116d88c1a5aSDimitry Andric initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
1172754fe60SDimitry Andric }
1182754fe60SDimitry Andric
runOnFunction__anon52f097dc0311::CFGPrinterLegacyPass11991bc56edSDimitry Andric bool runOnFunction(Function &F) override {
120d88c1a5aSDimitry Andric writeCFGToDotFile(F);
121d88c1a5aSDimitry Andric return false;
122d88c1a5aSDimitry Andric }
123f22ef01cSRoman Divacky
print__anon52f097dc0311::CFGPrinterLegacyPass124d88c1a5aSDimitry Andric void print(raw_ostream &OS, const Module* = nullptr) const override {}
125f22ef01cSRoman Divacky
getAnalysisUsage__anon52f097dc0311::CFGPrinterLegacyPass126d88c1a5aSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
127d88c1a5aSDimitry Andric AU.setPreservesAll();
128d88c1a5aSDimitry Andric }
129d88c1a5aSDimitry Andric };
130d88c1a5aSDimitry Andric }
131d88c1a5aSDimitry Andric
132d88c1a5aSDimitry Andric char CFGPrinterLegacyPass::ID = 0;
133d88c1a5aSDimitry Andric INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
134d88c1a5aSDimitry Andric false, true)
135d88c1a5aSDimitry Andric
run(Function & F,FunctionAnalysisManager & AM)136d88c1a5aSDimitry Andric PreservedAnalyses CFGPrinterPass::run(Function &F,
137d88c1a5aSDimitry Andric FunctionAnalysisManager &AM) {
138d88c1a5aSDimitry Andric writeCFGToDotFile(F);
139d88c1a5aSDimitry Andric return PreservedAnalyses::all();
140d88c1a5aSDimitry Andric }
141d88c1a5aSDimitry Andric
142d88c1a5aSDimitry Andric namespace {
143d88c1a5aSDimitry Andric struct CFGOnlyPrinterLegacyPass : public FunctionPass {
144d88c1a5aSDimitry Andric static char ID; // Pass identification, replacement for typeid
CFGOnlyPrinterLegacyPass__anon52f097dc0411::CFGOnlyPrinterLegacyPass145d88c1a5aSDimitry Andric CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
146d88c1a5aSDimitry Andric initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
147d88c1a5aSDimitry Andric }
148d88c1a5aSDimitry Andric
runOnFunction__anon52f097dc0411::CFGOnlyPrinterLegacyPass149d88c1a5aSDimitry Andric bool runOnFunction(Function &F) override {
150da09e106SDimitry Andric writeCFGToDotFile(F, /*CFGOnly=*/true);
151f22ef01cSRoman Divacky return false;
152f22ef01cSRoman Divacky }
print__anon52f097dc0411::CFGOnlyPrinterLegacyPass15391bc56edSDimitry Andric void print(raw_ostream &OS, const Module* = nullptr) const override {}
154f22ef01cSRoman Divacky
getAnalysisUsage__anon52f097dc0411::CFGOnlyPrinterLegacyPass15591bc56edSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
156f22ef01cSRoman Divacky AU.setPreservesAll();
157f22ef01cSRoman Divacky }
158f22ef01cSRoman Divacky };
1593dac3a9bSDimitry Andric }
160f22ef01cSRoman Divacky
161d88c1a5aSDimitry Andric char CFGOnlyPrinterLegacyPass::ID = 0;
162d88c1a5aSDimitry Andric INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
163e580952dSDimitry Andric "Print CFG of function to 'dot' file (with no function bodies)",
1642754fe60SDimitry Andric false, true)
165f22ef01cSRoman Divacky
run(Function & F,FunctionAnalysisManager & AM)166d88c1a5aSDimitry Andric PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
167d88c1a5aSDimitry Andric FunctionAnalysisManager &AM) {
168da09e106SDimitry Andric writeCFGToDotFile(F, /*CFGOnly=*/true);
169d88c1a5aSDimitry Andric return PreservedAnalyses::all();
170d88c1a5aSDimitry Andric }
171d88c1a5aSDimitry Andric
172f22ef01cSRoman Divacky /// viewCFG - This function is meant for use from the debugger. You can just
173f22ef01cSRoman Divacky /// say 'call F->viewCFG()' and a ghostview window should pop up from the
174f22ef01cSRoman Divacky /// program, displaying the CFG of the current function. This depends on there
175f22ef01cSRoman Divacky /// being a 'dot' and 'gv' program in your path.
176f22ef01cSRoman Divacky ///
viewCFG() const177f22ef01cSRoman Divacky void Function::viewCFG() const {
1784ba319b5SDimitry Andric if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
1794ba319b5SDimitry Andric return;
180dff0c46cSDimitry Andric ViewGraph(this, "cfg" + getName());
181f22ef01cSRoman Divacky }
182f22ef01cSRoman Divacky
183f22ef01cSRoman Divacky /// viewCFGOnly - This function is meant for use from the debugger. It works
184f22ef01cSRoman Divacky /// just like viewCFG, but it does not include the contents of basic blocks
18591bc56edSDimitry Andric /// into the nodes, just the label. If you are only interested in the CFG
18691bc56edSDimitry Andric /// this can make the graph smaller.
187f22ef01cSRoman Divacky ///
viewCFGOnly() const188f22ef01cSRoman Divacky void Function::viewCFGOnly() const {
1894ba319b5SDimitry Andric if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
1904ba319b5SDimitry Andric return;
191dff0c46cSDimitry Andric ViewGraph(this, "cfg" + getName(), true);
192f22ef01cSRoman Divacky }
193f22ef01cSRoman Divacky
createCFGPrinterLegacyPassPass()194d88c1a5aSDimitry Andric FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
195d88c1a5aSDimitry Andric return new CFGPrinterLegacyPass();
196f22ef01cSRoman Divacky }
197f22ef01cSRoman Divacky
createCFGOnlyPrinterLegacyPassPass()198d88c1a5aSDimitry Andric FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
199d88c1a5aSDimitry Andric return new CFGOnlyPrinterLegacyPass();
200f22ef01cSRoman Divacky }
201f22ef01cSRoman Divacky
202