Add viewCFG() and viewCFGOnly() APIs.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14679 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h
index 2d36777..3a27fd7 100644
--- a/include/llvm/CodeGen/MachineFunction.h
+++ b/include/llvm/CodeGen/MachineFunction.h
@@ -135,6 +135,21 @@
///
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 @@
}
};
+//===--------------------------------------------------------------------===//
+// 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
diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp
index 520f1da..63785a3 100644
--- a/lib/CodeGen/MachineFunction.cpp
+++ b/lib/CodeGen/MachineFunction.cpp
@@ -26,7 +26,10 @@
#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 @@
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 @@
void MachineFunctionInfo::popAllTempValues() {
resetTmpAreaSize(); // clear tmp area to reuse
}
-