diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 2d36777d7a7..3a27fd7cdeb 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -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 : + public GraphTraits { + 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 : + public GraphTraits { + 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 > : + public GraphTraits > { + static NodeType *getEntryNode(Inverse G) { + return &G.Graph->front(); + } +}; +template <> struct GraphTraits > : + public GraphTraits > { + static NodeType *getEntryNode(Inverse G) { + return &G.Graph->front(); + } +}; + } // End llvm namespace #endif diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 520f1da9609..63785a301b9 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 #include +#include 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 : 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 } -