For PR798:
[oota-llvm.git] / lib / Analysis / CFGPrinter.cpp
1 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a '-print-cfg' analysis pass, which emits the
11 // cfg.<fnname>.dot file for each function in the program, with a graph of the
12 // CFG for that function.
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/Function.h"
21 #include "llvm/Instructions.h"
22 #include "llvm/Pass.h"
23 #include "llvm/Analysis/CFGPrinter.h"
24 #include "llvm/Assembly/Writer.h"
25 #include "llvm/Support/CFG.h"
26 #include "llvm/Support/GraphWriter.h"
27 #include "llvm/System/Path.h"
28 #include "llvm/System/Program.h"
29 #include "llvm/Config/config.h"
30 #include <sstream>
31 #include <fstream>
32 using namespace llvm;
33
34 /// CFGOnly flag - This is used to control whether or not the CFG graph printer
35 /// prints out the contents of basic blocks or not.  This is acceptable because
36 /// this code is only really used for debugging purposes.
37 ///
38 static bool CFGOnly = false;
39
40 namespace llvm {
41 template<>
42 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
43   static std::string getGraphName(const Function *F) {
44     return "CFG for '" + F->getName() + "' function";
45   }
46
47   static std::string getNodeLabel(const BasicBlock *Node,
48                                   const Function *Graph) {
49     if (CFGOnly && !Node->getName().empty())
50       return Node->getName() + ":";
51
52     std::ostringstream Out;
53     if (CFGOnly) {
54       WriteAsOperand(Out, Node, false, true);
55       return Out.str();
56     }
57
58     if (Node->getName().empty()) {
59       WriteAsOperand(Out, Node, false, true);
60       Out << ":";
61     }
62
63     Out << *Node;
64     std::string OutStr = Out.str();
65     if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
66
67     // Process string output to make it nicer...
68     for (unsigned i = 0; i != OutStr.length(); ++i)
69       if (OutStr[i] == '\n') {                            // Left justify
70         OutStr[i] = '\\';
71         OutStr.insert(OutStr.begin()+i+1, 'l');
72       } else if (OutStr[i] == ';') {                      // Delete comments!
73         unsigned Idx = OutStr.find('\n', i+1);            // Find end of line
74         OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
75         --i;
76       }
77
78     return OutStr;
79   }
80
81   static std::string getEdgeSourceLabel(const BasicBlock *Node,
82                                         succ_const_iterator I) {
83     // Label source of conditional branches with "T" or "F"
84     if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
85       if (BI->isConditional())
86         return (I == succ_begin(Node)) ? "T" : "F";
87     return "";
88   }
89 };
90 }
91
92 namespace {
93   struct CFGPrinter : public FunctionPass {
94     virtual bool runOnFunction(Function &F) {
95       std::string Filename = "cfg." + F.getName() + ".dot";
96       std::cerr << "Writing '" << Filename << "'...";
97       std::ofstream File(Filename.c_str());
98
99       if (File.good())
100         WriteGraph(File, (const Function*)&F);
101       else
102         std::cerr << "  error opening file for writing!";
103       std::cerr << "\n";
104       return false;
105     }
106
107     void print(std::ostream &OS, const Module* = 0) const {}
108
109     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
110       AU.setPreservesAll();
111     }
112   };
113
114   RegisterAnalysis<CFGPrinter> P1("print-cfg",
115                                   "Print CFG of function to 'dot' file");
116
117   struct CFGOnlyPrinter : public CFGPrinter {
118     virtual bool runOnFunction(Function &F) {
119       bool OldCFGOnly = CFGOnly;
120       CFGOnly = true;
121       CFGPrinter::runOnFunction(F);
122       CFGOnly = OldCFGOnly;
123       return false;
124     }
125     void print(std::ostream &OS, const Module* = 0) const {}
126
127     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
128       AU.setPreservesAll();
129     }
130   };
131
132   RegisterAnalysis<CFGOnlyPrinter>
133   P2("print-cfg-only",
134      "Print CFG of function to 'dot' file (with no function bodies)");
135 }
136
137 /// viewCFG - This function is meant for use from the debugger.  You can just
138 /// say 'call F->viewCFG()' and a ghostview window should pop up from the
139 /// program, displaying the CFG of the current function.  This depends on there
140 /// being a 'dot' and 'gv' program in your path.
141 ///
142 void Function::viewCFG() const {
143 #ifndef NDEBUG
144   char pathsuff[9];
145
146   sprintf(pathsuff, "%06u", unsigned(rand()));
147
148   sys::Path TempDir = sys::Path::GetTemporaryDirectory();
149   sys::Path Filename = TempDir;
150
151   Filename.appendComponent("cfg" + getName() + "." + pathsuff + ".dot");
152   std::cerr << "Writing '" << Filename << "'... ";
153   std::ofstream F(Filename.c_str());
154
155   if (!F.good()) {
156     std::cerr << "  error opening file for writing!\n";
157     return;
158   }
159
160   WriteGraph(F, this);
161   F.close();
162   std::cerr << "\n";
163
164 #if HAVE_GRAPHVIZ
165   sys::Path Graphviz(LLVM_PATH_GRAPHVIZ);
166   std::vector<const char*> args;
167   args.push_back(Graphviz.c_str());
168   args.push_back(Filename.c_str());
169   args.push_back(0);
170   
171   std::cerr << "Running 'Graphviz' program... " << std::flush;
172   if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) {
173     std::cerr << "Error viewing graph: 'Graphviz' not in path?\n";
174   } else {
175     Filename.eraseFromDisk();
176     return;
177   }
178 #elif (HAVE_GV && HAVE_DOT)
179   sys::Path PSFilename = TempDir;
180   PSFilename.appendComponent(std::string("cfg.tempgraph") + "." + pathsuff + ".ps");
181
182   sys::Path dot(LLVM_PATH_DOT);
183   std::vector<const char*> args;
184   args.push_back(dot.c_str());
185   args.push_back("-Tps");
186   args.push_back("-Nfontname=Courier");
187   args.push_back("-Gsize=7.5,10");
188   args.push_back(Filename.c_str());
189   args.push_back("-o");
190   args.push_back(PSFilename.c_str());
191   args.push_back(0);
192   
193   std::cerr << "Running 'dot' program... " << std::flush;
194   if (sys::Program::ExecuteAndWait(dot, &args[0])) {
195     std::cerr << "Error viewing graph: 'dot' not in path?\n";
196   } else {
197     std::cerr << "\n";
198
199     sys::Path gv(LLVM_PATH_GV);
200     args.clear();
201     args.push_back(gv.c_str());
202     args.push_back(PSFilename.c_str());
203     args.push_back(0);
204     
205     sys::Program::ExecuteAndWait(gv, &args[0]);
206   }
207   Filename.eraseFromDisk();
208   PSFilename.eraseFromDisk();
209   return;
210 #elif HAVE_DOTTY
211   sys::Path dotty(LLVM_PATH_DOTTY);
212   std::vector<const char*> args;
213   args.push_back(dotty.c_str());
214   args.push_back(Filename.c_str());
215   args.push_back(0);
216   
217   std::cerr << "Running 'dotty' program... " << std::flush;
218   if (sys::Program::ExecuteAndWait(dotty, &args[0])) {
219     std::cerr << "Error viewing graph: 'dotty' not in path?\n";
220   } else {
221 #ifndef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns
222     Filename.eraseFromDisk();
223 #endif
224     return;
225   }
226 #endif
227
228 #endif  // NDEBUG
229   std::cerr << "Function::viewCFG is only available in debug builds on "
230             << "systems with Graphviz or gv or dotty!\n";
231
232 #ifndef NDEBUG
233   Filename.eraseFromDisk();
234   TempDir.eraseFromDisk(true);
235 #endif
236 }
237
238 /// viewCFGOnly - This function is meant for use from the debugger.  It works
239 /// just like viewCFG, but it does not include the contents of basic blocks
240 /// into the nodes, just the label.  If you are only interested in the CFG t
241 /// his can make the graph smaller.
242 ///
243 void Function::viewCFGOnly() const {
244   CFGOnly = true;
245   viewCFG();
246   CFGOnly = false;
247 }
248
249 FunctionPass *llvm::createCFGPrinterPass () {
250   return new CFGPrinter();
251 }
252
253 FunctionPass *llvm::createCFGOnlyPrinterPass () {
254   return new CFGOnlyPrinter();
255 }
256