LLVM API Documentation

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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 <sstream>
00028 #include <fstream>
00029 using namespace llvm;
00030 
00031 /// CFGOnly flag - This is used to control whether or not the CFG graph printer
00032 /// prints out the contents of basic blocks or not.  This is acceptable because
00033 /// this code is only really used for debugging purposes.
00034 ///
00035 static bool CFGOnly = false;
00036 
00037 namespace llvm {
00038 template<>
00039 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
00040   static std::string getGraphName(const Function *F) {
00041     return "CFG for '" + F->getName() + "' function";
00042   }
00043 
00044   static std::string getNodeLabel(const BasicBlock *Node,
00045                                   const Function *Graph) {
00046     if (CFGOnly && !Node->getName().empty())
00047       return Node->getName() + ":";
00048 
00049     std::ostringstream Out;
00050     if (CFGOnly) {
00051       WriteAsOperand(Out, Node, false, true);
00052       return Out.str();
00053     }
00054 
00055     if (Node->getName().empty()) {
00056       WriteAsOperand(Out, Node, false, true);
00057       Out << ":";
00058     }
00059 
00060     Out << *Node;
00061     std::string OutStr = Out.str();
00062     if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
00063 
00064     // Process string output to make it nicer...
00065     for (unsigned i = 0; i != OutStr.length(); ++i)
00066       if (OutStr[i] == '\n') {                            // Left justify
00067         OutStr[i] = '\\';
00068         OutStr.insert(OutStr.begin()+i+1, 'l');
00069       } else if (OutStr[i] == ';') {                      // Delete comments!
00070         unsigned Idx = OutStr.find('\n', i+1);            // Find end of line
00071         OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
00072         --i;
00073       }
00074 
00075     return OutStr;
00076   }
00077 
00078   static std::string getEdgeSourceLabel(const BasicBlock *Node,
00079                                         succ_const_iterator I) {
00080     // Label source of conditional branches with "T" or "F"
00081     if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
00082       if (BI->isConditional())
00083         return (I == succ_begin(Node)) ? "T" : "F";
00084     return "";
00085   }
00086 };
00087 }
00088 
00089 namespace {
00090   struct CFGPrinter : public FunctionPass {
00091     virtual bool runOnFunction(Function &F) {
00092       std::string Filename = "cfg." + F.getName() + ".dot";
00093       std::cerr << "Writing '" << Filename << "'...";
00094       std::ofstream File(Filename.c_str());
00095       
00096       if (File.good())
00097         WriteGraph(File, (const Function*)&F);
00098       else
00099         std::cerr << "  error opening file for writing!";
00100       std::cerr << "\n";
00101       return false;
00102     }
00103 
00104     void print(std::ostream &OS) const {}
00105     
00106     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00107       AU.setPreservesAll();
00108     }
00109   };
00110 
00111   RegisterAnalysis<CFGPrinter> P1("print-cfg",
00112                                   "Print CFG of function to 'dot' file");
00113 
00114   struct CFGOnlyPrinter : public CFGPrinter {
00115     virtual bool runOnFunction(Function &F) {
00116       bool OldCFGOnly = CFGOnly;
00117       CFGOnly = true;
00118       CFGPrinter::runOnFunction(F);
00119       CFGOnly = OldCFGOnly;
00120       return false;
00121     }
00122     void print(std::ostream &OS) const {}
00123     
00124     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00125       AU.setPreservesAll();
00126     }
00127   };
00128 
00129   RegisterAnalysis<CFGOnlyPrinter>
00130   P2("print-cfg-only",
00131      "Print CFG of function to 'dot' file (with no function bodies)");
00132 }
00133 
00134 /// viewCFG - This function is meant for use from the debugger.  You can just
00135 /// say 'call F->viewCFG()' and a ghostview window should pop up from the
00136 /// program, displaying the CFG of the current function.  This depends on there
00137 /// being a 'dot' and 'gv' program in your path.
00138 ///
00139 void Function::viewCFG() const {
00140   std::string Filename = "/tmp/cfg." + getName() + ".dot";
00141   std::cerr << "Writing '" << Filename << "'... ";
00142   std::ofstream F(Filename.c_str());
00143   
00144   if (!F.good()) {
00145     std::cerr << "  error opening file for writing!\n";
00146     return;
00147   }
00148 
00149   WriteGraph(F, this);
00150   F.close();
00151   std::cerr << "\n";
00152 
00153   std::cerr << "Running 'dot' program... " << std::flush;
00154   if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename
00155               + " > /tmp/cfg.tempgraph.ps").c_str())) {
00156     std::cerr << "Error running dot: 'dot' not in path?\n";
00157   } else {
00158     std::cerr << "\n";
00159     system("gv /tmp/cfg.tempgraph.ps");
00160   }
00161   system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str());
00162 }
00163 
00164 /// viewCFGOnly - This function is meant for use from the debugger.  It works
00165 /// just like viewCFG, but it does not include the contents of basic blocks
00166 /// into the nodes, just the label.  If you are only interested in the CFG t
00167 /// his can make the graph smaller.
00168 ///
00169 void Function::viewCFGOnly() const {
00170   CFGOnly = true;
00171   viewCFG();
00172   CFGOnly = false;
00173 }
00174 
00175 FunctionPass *llvm::createCFGPrinterPass () {
00176   return new CFGPrinter();
00177 }
00178 
00179 FunctionPass *llvm::createCFGOnlyPrinterPass () {
00180   return new CFGOnlyPrinter();
00181 }
00182