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