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   ViewGraph(this, "cfg" + getName());
00142 }
00143 
00144 /// viewCFGOnly - This function is meant for use from the debugger.  It works
00145 /// just like viewCFG, but it does not include the contents of basic blocks
00146 /// into the nodes, just the label.  If you are only interested in the CFG t
00147 /// his can make the graph smaller.
00148 ///
00149 void Function::viewCFGOnly() const {
00150   CFGOnly = true;
00151   viewCFG();
00152   CFGOnly = false;
00153 }
00154 
00155 FunctionPass *llvm::createCFGPrinterPass () {
00156   return new CFGPrinter();
00157 }
00158 
00159 FunctionPass *llvm::createCFGOnlyPrinterPass () {
00160   return new CFGOnlyPrinter();
00161 }
00162