LLVM API Documentation

CFGPrinter.cpp

Go to the documentation of this file.
00001 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by the LLVM research group and is distributed under
00006 // the University of Illinois Open Source License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines a '-print-cfg' analysis pass, which emits the
00011 // cfg.<fnname>.dot file for each function in the program, with a graph of the
00012 // CFG for that function.
00013 //
00014 // The other main feature of this file is that it implements the
00015 // Function::viewCFG method, which is useful for debugging passes which operate
00016 // on the CFG.
00017 //
00018 //===----------------------------------------------------------------------===//
00019 
00020 #include "llvm/Function.h"
00021 #include "llvm/Instructions.h"
00022 #include "llvm/Pass.h"
00023 #include "llvm/Analysis/CFGPrinter.h"
00024 #include "llvm/Assembly/Writer.h"
00025 #include "llvm/Support/CFG.h"
00026 #include "llvm/Support/GraphWriter.h"
00027 #include "llvm/Config/config.h"
00028 #include <sstream>
00029 #include <fstream>
00030 using namespace llvm;
00031 
00032 /// CFGOnly flag - This is used to control whether or not the CFG graph printer
00033 /// prints out the contents of basic blocks or not.  This is acceptable because
00034 /// this code is only really used for debugging purposes.
00035 ///
00036 static bool CFGOnly = false;
00037 
00038 namespace llvm {
00039 template<>
00040 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
00041   static std::string getGraphName(const Function *F) {
00042     return "CFG for '" + F->getName() + "' function";
00043   }
00044 
00045   static std::string getNodeLabel(const BasicBlock *Node,
00046                                   const Function *Graph) {
00047     if (CFGOnly && !Node->getName().empty())
00048       return Node->getName() + ":";
00049 
00050     std::ostringstream Out;
00051     if (CFGOnly) {
00052       WriteAsOperand(Out, Node, false, true);
00053       return Out.str();
00054     }
00055 
00056     if (Node->getName().empty()) {
00057       WriteAsOperand(Out, Node, false, true);
00058       Out << ":";
00059     }
00060 
00061     Out << *Node;
00062     std::string OutStr = Out.str();
00063     if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
00064 
00065     // Process string output to make it nicer...
00066     for (unsigned i = 0; i != OutStr.length(); ++i)
00067       if (OutStr[i] == '\n') {                            // Left justify
00068         OutStr[i] = '\\';
00069         OutStr.insert(OutStr.begin()+i+1, 'l');
00070       } else if (OutStr[i] == ';') {                      // Delete comments!
00071         unsigned Idx = OutStr.find('\n', i+1);            // Find end of line
00072         OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
00073         --i;
00074       }
00075 
00076     return OutStr;
00077   }
00078 
00079   static std::string getEdgeSourceLabel(const BasicBlock *Node,
00080                                         succ_const_iterator I) {
00081     // Label source of conditional branches with "T" or "F"
00082     if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
00083       if (BI->isConditional())
00084         return (I == succ_begin(Node)) ? "T" : "F";
00085     return "";
00086   }
00087 };
00088 }
00089 
00090 namespace {
00091   struct CFGPrinter : public FunctionPass {
00092     virtual bool runOnFunction(Function &F) {
00093       std::string Filename = "cfg." + F.getName() + ".dot";
00094       std::cerr << "Writing '" << Filename << "'...";
00095       std::ofstream File(Filename.c_str());
00096 
00097       if (File.good())
00098         WriteGraph(File, (const Function*)&F);
00099       else
00100         std::cerr << "  error opening file for writing!";
00101       std::cerr << "\n";
00102       return false;
00103     }
00104 
00105     void print(std::ostream &OS, const Module* = 0) const {}
00106 
00107     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00108       AU.setPreservesAll();
00109     }
00110   };
00111 
00112   RegisterAnalysis<CFGPrinter> P1("print-cfg",
00113                                   "Print CFG of function to 'dot' file");
00114 
00115   struct CFGOnlyPrinter : public CFGPrinter {
00116     virtual bool runOnFunction(Function &F) {
00117       bool OldCFGOnly = CFGOnly;
00118       CFGOnly = true;
00119       CFGPrinter::runOnFunction(F);
00120       CFGOnly = OldCFGOnly;
00121       return false;
00122     }
00123     void print(std::ostream &OS, const Module* = 0) const {}
00124 
00125     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00126       AU.setPreservesAll();
00127     }
00128   };
00129 
00130   RegisterAnalysis<CFGOnlyPrinter>
00131   P2("print-cfg-only",
00132      "Print CFG of function to 'dot' file (with no function bodies)");
00133 }
00134 
00135 /// viewCFG - This function is meant for use from the debugger.  You can just
00136 /// say 'call F->viewCFG()' and a ghostview window should pop up from the
00137 /// program, displaying the CFG of the current function.  This depends on there
00138 /// being a 'dot' and 'gv' program in your path.
00139 ///
00140 void Function::viewCFG() const {
00141 #ifndef NDEBUG
00142   std::string Filename = "/tmp/cfg." + getName() + ".dot";
00143   std::cerr << "Writing '" << Filename << "'... ";
00144   std::ofstream F(Filename.c_str());
00145 
00146   if (!F.good()) {
00147     std::cerr << "  error opening file for writing!\n";
00148     return;
00149   }
00150 
00151   WriteGraph(F, this);
00152   F.close();
00153   std::cerr << "\n";
00154 
00155 #ifdef HAVE_GRAPHVIZ
00156   std::cerr << "Running 'Graphviz' program... " << std::flush;
00157   if (system((LLVM_PATH_GRAPHVIZ " " + Filename).c_str())) {
00158     std::cerr << "Error viewing graph: 'Graphviz' not in path?\n";
00159   } else {
00160     system(("rm " + Filename).c_str());
00161     return;
00162   }
00163 #endif  // HAVE_GRAPHVIZ
00164   
00165 #ifdef HAVE_GV
00166   std::cerr << "Running 'dot' program... " << std::flush;
00167   if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename
00168               + " > /tmp/cfg.tempgraph.ps").c_str())) {
00169     std::cerr << "Error running dot: 'dot' not in path?\n";
00170   } else {
00171     std::cerr << "\n";
00172     system("gv /tmp/cfg.tempgraph.ps");
00173   }
00174   system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str());
00175   return;
00176 #endif  // HAVE_GV
00177 #endif  // NDEBUG
00178   std::cerr << "Function::viewCFG is only available in debug builds on "
00179             << "systems with Graphviz or gv!\n";
00180 
00181 #ifndef NDEBUG
00182   system(("rm " + Filename).c_str());
00183 #endif
00184 }
00185 
00186 /// viewCFGOnly - This function is meant for use from the debugger.  It works
00187 /// just like viewCFG, but it does not include the contents of basic blocks
00188 /// into the nodes, just the label.  If you are only interested in the CFG t
00189 /// his can make the graph smaller.
00190 ///
00191 void Function::viewCFGOnly() const {
00192   CFGOnly = true;
00193   viewCFG();
00194   CFGOnly = false;
00195 }
00196 
00197 FunctionPass *llvm::createCFGPrinterPass () {
00198   return new CFGPrinter();
00199 }
00200 
00201 FunctionPass *llvm::createCFGOnlyPrinterPass () {
00202   return new CFGOnlyPrinter();
00203 }
00204