1 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines a '-dot-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/Compiler.h" 27 #include "llvm/Support/GraphWriter.h" 28 #include "llvm/Config/config.h" 29 #include <iosfwd> 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); 55 return Out.str(); 56 } 57 58 if (Node->getName().empty()) { 59 WriteAsOperand(Out, Node, false); 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 VISIBILITY_HIDDEN CFGViewer : public FunctionPass { 94 static char ID; // Pass identifcation, replacement for typeid 95 CFGViewer() : FunctionPass(&ID) {} 96 97 virtual bool runOnFunction(Function &F) { 98 F.viewCFG(); 99 return false; 100 } 101 102 void print(std::ostream &OS, const Module* = 0) const {} 103 104 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 105 AU.setPreservesAll(); 106 } 107 }; 108 } 109 110 char CFGViewer::ID = 0; 111 static RegisterPass<CFGViewer> 112 V0("view-cfg", "View CFG of function", false, true); 113 114 namespace { 115 struct VISIBILITY_HIDDEN CFGOnlyViewer : public FunctionPass { 116 static char ID; // Pass identifcation, replacement for typeid 117 CFGOnlyViewer() : FunctionPass(&ID) {} 118 119 virtual bool runOnFunction(Function &F) { 120 CFGOnly = true; 121 F.viewCFG(); 122 CFGOnly = false; 123 return false; 124 } 125 126 void print(std::ostream &OS, const Module* = 0) const {} 127 128 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 129 AU.setPreservesAll(); 130 } 131 }; 132 } 133 134 char CFGOnlyViewer::ID = 0; 135 static RegisterPass<CFGOnlyViewer> 136 V1("view-cfg-only", 137 "View CFG of function (with no function bodies)", false, true); 138 139 namespace { 140 struct VISIBILITY_HIDDEN CFGPrinter : public FunctionPass { 141 static char ID; // Pass identification, replacement for typeid 142 CFGPrinter() : FunctionPass(&ID) {} 143 explicit CFGPrinter(void *pid) : FunctionPass(pid) {} 144 145 virtual bool runOnFunction(Function &F) { 146 std::string Filename = "cfg." + F.getName() + ".dot"; 147 cerr << "Writing '" << Filename << "'..."; 148 std::ofstream File(Filename.c_str()); 149 150 if (File.good()) 151 WriteGraph(File, (const Function*)&F); 152 else 153 cerr << " error opening file for writing!"; 154 cerr << "\n"; 155 return false; 156 } 157 158 void print(std::ostream &OS, const Module* = 0) const {} 159 160 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 161 AU.setPreservesAll(); 162 } 163 }; 164 } 165 166 char CFGPrinter::ID = 0; 167 static RegisterPass<CFGPrinter> 168 P1("dot-cfg", "Print CFG of function to 'dot' file", false, true); 169 170 namespace { 171 struct VISIBILITY_HIDDEN CFGOnlyPrinter : public CFGPrinter { 172 static char ID; // Pass identification, replacement for typeid 173 CFGOnlyPrinter() : CFGPrinter(&ID) {} 174 virtual bool runOnFunction(Function &F) { 175 bool OldCFGOnly = CFGOnly; 176 CFGOnly = true; 177 CFGPrinter::runOnFunction(F); 178 CFGOnly = OldCFGOnly; 179 return false; 180 } 181 void print(std::ostream &OS, const Module* = 0) const {} 182 183 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 184 AU.setPreservesAll(); 185 } 186 }; 187 } 188 189 char CFGOnlyPrinter::ID = 0; 190 static RegisterPass<CFGOnlyPrinter> 191 P2("dot-cfg-only", 192 "Print CFG of function to 'dot' file (with no function bodies)", false, true); 193 194 /// viewCFG - This function is meant for use from the debugger. You can just 195 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 196 /// program, displaying the CFG of the current function. This depends on there 197 /// being a 'dot' and 'gv' program in your path. 198 /// 199 void Function::viewCFG() const { 200 ViewGraph(this, "cfg" + getName()); 201 } 202 203 /// viewCFGOnly - This function is meant for use from the debugger. It works 204 /// just like viewCFG, but it does not include the contents of basic blocks 205 /// into the nodes, just the label. If you are only interested in the CFG t 206 /// his can make the graph smaller. 207 /// 208 void Function::viewCFGOnly() const { 209 CFGOnly = true; 210 viewCFG(); 211 CFGOnly = false; 212 } 213 214 FunctionPass *llvm::createCFGPrinterPass () { 215 return new CFGPrinter(); 216 } 217 218 FunctionPass *llvm::createCFGOnlyPrinterPass () { 219 return new CFGOnlyPrinter(); 220 } 221 222