Add viewCFG() and viewCFGOnly() APIs.
authorAlkis Evlogimenos <alkis@evlogimenos.com>
Thu, 8 Jul 2004 00:47:58 +0000 (00:47 +0000)
committerAlkis Evlogimenos <alkis@evlogimenos.com>
Thu, 8 Jul 2004 00:47:58 +0000 (00:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14679 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/MachineFunction.h
lib/CodeGen/MachineFunction.cpp

index 2d36777d7a7aafe5df32a72eafefe822da4689c3..3a27fd7cdebeab193f95a2a655e2c829e2cedafb 100644 (file)
@@ -135,6 +135,21 @@ public:
   ///
   void print(std::ostream &OS) const;
 
+  /// viewCFG - This function is meant for use from the debugger.  You can just
+  /// say 'call F->viewCFG()' and a ghostview window should pop up from the
+  /// program, displaying the CFG of the current function with the code for each
+  /// basic block inside.  This depends on there being a 'dot' and 'gv' program
+  /// in your path.
+  ///
+  void viewCFG() const;
+  
+  /// viewCFGOnly - This function is meant for use from the debugger.  It works
+  /// just like viewCFG, but it does not include the contents of basic blocks
+  /// into the nodes, just the label.  If you are only interested in the CFG
+  /// this can make the graph smaller.
+  ///
+  void viewCFGOnly() const;
+
   /// dump - Print the current MachineFunction to cerr, useful for debugger use.
   ///
   void dump() const;
@@ -206,6 +221,57 @@ public:
   }
 };
 
+//===--------------------------------------------------------------------===//
+// GraphTraits specializations for function basic block graphs (CFGs)
+//===--------------------------------------------------------------------===//
+
+// Provide specializations of GraphTraits to be able to treat a
+// machine function as a graph of machine basic blocks... these are
+// the same as the machine basic block iterators, except that the root
+// node is implicitly the first node of the function.
+//
+template <> struct GraphTraits<MachineFunction*> :
+  public GraphTraits<MachineBasicBlock*> {
+  static NodeType *getEntryNode(MachineFunction *F) {
+    return &F->front();
+  }
+
+  // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+  typedef MachineFunction::iterator nodes_iterator;
+  static nodes_iterator nodes_begin(MachineFunction *F) { return F->begin(); }
+  static nodes_iterator nodes_end  (MachineFunction *F) { return F->end(); }
+};
+template <> struct GraphTraits<const MachineFunction*> :
+  public GraphTraits<const MachineBasicBlock*> {
+  static NodeType *getEntryNode(const MachineFunction *F) {
+    return &F->front();
+  }
+
+  // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+  typedef MachineFunction::const_iterator nodes_iterator;
+  static nodes_iterator nodes_begin(const MachineFunction *F) { return F->begin(); }
+  static nodes_iterator nodes_end  (const MachineFunction *F) { return F->end(); }
+};
+
+
+// Provide specializations of GraphTraits to be able to treat a function as a 
+// graph of basic blocks... and to walk it in inverse order.  Inverse order for
+// a function is considered to be when traversing the predecessor edges of a BB
+// instead of the successor edges.
+//
+template <> struct GraphTraits<Inverse<MachineFunction*> > :
+  public GraphTraits<Inverse<MachineBasicBlock*> > {
+  static NodeType *getEntryNode(Inverse<MachineFunction*> G) {
+    return &G.Graph->front();
+  }
+};
+template <> struct GraphTraits<Inverse<const MachineFunction*> > :
+  public GraphTraits<Inverse<const MachineBasicBlock*> > {
+  static NodeType *getEntryNode(Inverse<const MachineFunction *> G) {
+    return &G.Graph->front();
+  }
+};
+
 } // End llvm namespace
 
 #endif
index 520f1da960963641264e1aec1f004b2455f054b2..63785a301b97018d1bc136e3bf1db242dc3ed457 100644 (file)
 #include "llvm/iOther.h"
 #include "llvm/Type.h"
 #include "Support/LeakDetector.h"
+#include "Support/GraphWriter.h"
+#include <fstream>
 #include <iostream>
+#include <sstream>
 
 using namespace llvm;
 
@@ -140,6 +143,80 @@ void MachineFunction::print(std::ostream &OS) const {
   OS << "\n# End machine code for " << Fn->getName () << "().\n\n";
 }
 
+/// CFGOnly flag - This is used to control whether or not the CFG graph printer
+/// prints out the contents of basic blocks or not.  This is acceptable because
+/// this code is only really used for debugging purposes.
+///
+static bool CFGOnly = false;
+
+namespace llvm {
+template<>
+struct DOTGraphTraits<const MachineFunction*> : public DefaultDOTGraphTraits {
+  static std::string getGraphName(const MachineFunction *F) {
+    return "CFG for '" + F->getFunction()->getName() + "' function";
+  }
+
+  static std::string getNodeLabel(const MachineBasicBlock *Node,
+                                  const MachineFunction *Graph) {
+    if (CFGOnly && Node->getBasicBlock() &&
+        !Node->getBasicBlock()->getName().empty())
+      return Node->getBasicBlock()->getName() + ":";
+
+    std::ostringstream Out;
+    if (CFGOnly) {
+      Out << Node->getNumber() << ':';
+      return Out.str();
+    }
+
+    Node->print(Out);
+
+    std::string OutStr = Out.str();
+    if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
+
+    // Process string output to make it nicer...
+    for (unsigned i = 0; i != OutStr.length(); ++i)
+      if (OutStr[i] == '\n') {                            // Left justify
+        OutStr[i] = '\\';
+        OutStr.insert(OutStr.begin()+i+1, 'l');
+      }
+    return OutStr;
+  }
+};
+}
+
+void MachineFunction::viewCFG() const
+{
+  std::string Filename = "/tmp/cfg." + getFunction()->getName() + ".dot";
+  std::cerr << "Writing '" << Filename << "'... ";
+  std::ofstream F(Filename.c_str());
+  
+  if (!F) {
+    std::cerr << "  error opening file for writing!\n";
+    return;
+  }
+
+  WriteGraph(F, this);
+  F.close();
+  std::cerr << "\n";
+
+  std::cerr << "Running 'dot' program... " << std::flush;
+  if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename
+              + " > /tmp/cfg.tempgraph.ps").c_str())) {
+    std::cerr << "Error running dot: 'dot' not in path?\n";
+  } else {
+    std::cerr << "\n";
+    system("gv /tmp/cfg.tempgraph.ps");
+  }
+  system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str());
+}
+
+void MachineFunction::viewCFGOnly() const
+{
+  CFGOnly = true;
+  viewCFG();
+  CFGOnly = false;
+}
+
 // The next two methods are used to construct and to retrieve
 // the MachineCodeForFunction object for the given function.
 // construct() -- Allocates and initializes for a given function and target
@@ -405,4 +482,3 @@ MachineFunctionInfo::pushTempValue(unsigned size)
 void MachineFunctionInfo::popAllTempValues() {
   resetTmpAreaSize();            // clear tmp area to reuse
 }
-