blob: 9530f5695abcc5a8be50bdfd9bc1a75f1c29a887 [file] [log] [blame]
Chris Lattner002362c2003-10-22 16:03:49 +00001//===- 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
Chris Lattner002362c2003-10-22 16:03:49 +000020#include "llvm/Function.h"
21#include "llvm/iTerminators.h"
Misha Brukmanbf94a1e2004-04-29 04:04:47 +000022#include "llvm/Pass.h"
Brian Gaekec6e2d8a2004-04-26 16:27:08 +000023#include "llvm/Analysis/CFGPrinter.h"
Misha Brukmanbf94a1e2004-04-29 04:04:47 +000024#include "llvm/Assembly/Writer.h"
Chris Lattner002362c2003-10-22 16:03:49 +000025#include "llvm/Support/CFG.h"
Misha Brukmanbf94a1e2004-04-29 04:04:47 +000026#include "Support/GraphWriter.h"
Chris Lattner002362c2003-10-22 16:03:49 +000027#include <sstream>
28#include <fstream>
Chris Lattner1ca2a582003-12-11 21:48:18 +000029using namespace llvm;
Brian Gaeked0fde302003-11-11 22:41:34 +000030
Chris Lattner002362c2003-10-22 16:03:49 +000031/// CFGOnly flag - This is used to control whether or not the CFG graph printer
32/// prints out the contents of basic blocks or not. This is acceptable because
33/// this code is only really used for debugging purposes.
34///
35static bool CFGOnly = false;
36
Chris Lattner1ca2a582003-12-11 21:48:18 +000037namespace llvm {
Chris Lattner002362c2003-10-22 16:03:49 +000038template<>
39struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
40 static std::string getGraphName(const Function *F) {
41 return "CFG for '" + F->getName() + "' function";
42 }
43
44 static std::string getNodeLabel(const BasicBlock *Node,
45 const Function *Graph) {
Chris Lattnerd073ea02003-10-22 16:30:58 +000046 if (CFGOnly && !Node->getName().empty())
47 return Node->getName() + ":";
Chris Lattner002362c2003-10-22 16:03:49 +000048
49 std::ostringstream Out;
Chris Lattnera75b3ef2003-10-22 16:22:42 +000050 if (CFGOnly) {
51 WriteAsOperand(Out, Node, false, true);
52 return Out.str();
53 }
54
Chris Lattnerd073ea02003-10-22 16:30:58 +000055 if (Node->getName().empty()) {
56 WriteAsOperand(Out, Node, false, true);
57 Out << ":";
58 }
59
Chris Lattner002362c2003-10-22 16:03:49 +000060 Out << *Node;
61 std::string OutStr = Out.str();
62 if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
63
64 // Process string output to make it nicer...
65 for (unsigned i = 0; i != OutStr.length(); ++i)
66 if (OutStr[i] == '\n') { // Left justify
67 OutStr[i] = '\\';
68 OutStr.insert(OutStr.begin()+i+1, 'l');
69 } else if (OutStr[i] == ';') { // Delete comments!
70 unsigned Idx = OutStr.find('\n', i+1); // Find end of line
71 OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
72 --i;
73 }
74
75 return OutStr;
76 }
77
78 static std::string getNodeAttributes(const BasicBlock *N) {
79 return "fontname=Courier";
80 }
81
82 static std::string getEdgeSourceLabel(const BasicBlock *Node,
83 succ_const_iterator I) {
84 // Label source of conditional branches with "T" or "F"
85 if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
86 if (BI->isConditional())
87 return (I == succ_begin(Node)) ? "T" : "F";
88 return "";
89 }
90};
Chris Lattner1ca2a582003-12-11 21:48:18 +000091}
Chris Lattner002362c2003-10-22 16:03:49 +000092
93namespace {
94 struct CFGPrinter : public FunctionPass {
95 virtual bool runOnFunction(Function &F) {
96 std::string Filename = "cfg." + F.getName() + ".dot";
97 std::cerr << "Writing '" << Filename << "'...";
98 std::ofstream File(Filename.c_str());
99
100 if (File.good())
101 WriteGraph(File, (const Function*)&F);
102 else
103 std::cerr << " error opening file for writing!";
104 std::cerr << "\n";
105 return false;
106 }
107
108 void print(std::ostream &OS) const {}
109
110 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
111 AU.setPreservesAll();
112 }
113 };
114
115 RegisterAnalysis<CFGPrinter> P1("print-cfg",
116 "Print CFG of function to 'dot' file");
Chris Lattner1ca2a582003-12-11 21:48:18 +0000117
118 struct CFGOnlyPrinter : public CFGPrinter {
119 virtual bool runOnFunction(Function &F) {
120 bool OldCFGOnly = CFGOnly;
121 CFGOnly = true;
122 CFGPrinter::runOnFunction(F);
123 CFGOnly = OldCFGOnly;
124 return false;
125 }
126 void print(std::ostream &OS) const {}
127
128 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
129 AU.setPreservesAll();
130 }
131 };
132
133 RegisterAnalysis<CFGOnlyPrinter>
134 P2("print-cfg-only",
135 "Print CFG of function to 'dot' file (with no function bodies)");
136}
Chris Lattner002362c2003-10-22 16:03:49 +0000137
Chris Lattner002362c2003-10-22 16:03:49 +0000138/// viewCFG - This function is meant for use from the debugger. You can just
139/// say 'call F->viewCFG()' and a ghostview window should pop up from the
140/// program, displaying the CFG of the current function. This depends on there
141/// being a 'dot' and 'gv' program in your path.
142///
143void Function::viewCFG() const {
144 std::string Filename = "/tmp/cfg." + getName() + ".dot";
145 std::cerr << "Writing '" << Filename << "'... ";
146 std::ofstream F(Filename.c_str());
147
148 if (!F.good()) {
149 std::cerr << " error opening file for writing!\n";
150 return;
151 }
152
153 WriteGraph(F, this);
154 F.close();
155 std::cerr << "\n";
156
157 std::cerr << "Running 'dot' program... " << std::flush;
158 if (system(("dot -Tps " + Filename + " > /tmp/cfg.tempgraph.ps").c_str())) {
159 std::cerr << "Error running dot: 'dot' not in path?\n";
160 } else {
161 std::cerr << "\n";
162 system("gv /tmp/cfg.tempgraph.ps");
163 }
164 system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str());
165}
166
167/// viewCFGOnly - This function is meant for use from the debugger. It works
168/// just like viewCFG, but it does not include the contents of basic blocks
169/// into the nodes, just the label. If you are only interested in the CFG t
170/// his can make the graph smaller.
171///
172void Function::viewCFGOnly() const {
173 CFGOnly = true;
174 viewCFG();
175 CFGOnly = false;
176}
Brian Gaekec6e2d8a2004-04-26 16:27:08 +0000177
178FunctionPass *llvm::createCFGPrinterPass () {
179 return new CFGPrinter();
180}
181
182FunctionPass *llvm::createCFGOnlyPrinterPass () {
183 return new CFGOnlyPrinter();
184}
185