mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
Add viewCFG() and viewCFGOnly() APIs.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14679 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
cf617ddd98
commit
71bf404e9b
@ -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
|
||||
|
@ -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 @@ 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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user