forked from OSchip/llvm-project
Add option to dump CFGs in (simple) graphviz format during all passes.
Summary: I noticed the BinaryFunction::viewGraph() method that hadn't been implemented and decided I could use a simple DOT dumper for CFGs while working on the indirect call optimization. I've implemented the bare minimum for the dumper. It's just nodes+BB labels with dges. We can add more detailed information as needed/desired. (cherry picked from FBD3509326)
This commit is contained in:
parent
6eb4e5b687
commit
260f6fbdb6
|
@ -24,6 +24,7 @@
|
|||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
|
@ -1316,6 +1317,76 @@ void BinaryFunction::modifyLayout(LayoutType Type, bool Split) {
|
|||
fixBranches();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 255
|
||||
#endif
|
||||
|
||||
std::string constructFilename(std::string Filename,
|
||||
std::string Annotation,
|
||||
std::string Suffix) {
|
||||
std::replace(Filename.begin(), Filename.end(), '/', '-');
|
||||
if (!Annotation.empty()) {
|
||||
Annotation.insert(0, "-");
|
||||
}
|
||||
if (Filename.size() + Annotation.size() + Suffix.size() > MAX_PATH) {
|
||||
assert(Suffix.size() + Annotation.size() <= MAX_PATH);
|
||||
dbgs() << "BOLT-WARNING: Filename \"" << Filename << Annotation << Suffix
|
||||
<< "\" exceeds the " << MAX_PATH << " size limit, truncating.\n";
|
||||
Filename.resize(MAX_PATH - (Suffix.size() + Annotation.size()));
|
||||
}
|
||||
Filename += Annotation;
|
||||
Filename += Suffix;
|
||||
return Filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BinaryFunction::dumpGraph(raw_ostream& OS) const {
|
||||
OS << "strict digraph \"" << getName() << "\" {\n";
|
||||
for (auto *BB : BasicBlocks) {
|
||||
for (auto *Succ : BB->successors()) {
|
||||
OS << "\"" << BB->getName() << "\" -> "
|
||||
<< "\"" << Succ->getName() << "\"\n";
|
||||
}
|
||||
}
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
void BinaryFunction::viewGraph() const {
|
||||
SmallString<MAX_PATH> Filename;
|
||||
if (auto EC = sys::fs::createTemporaryFile("bolt-cfg", "dot", Filename)) {
|
||||
dbgs() << "BOLT-WARNING: " << EC.message() << ", unable to create "
|
||||
<< " bolt-cfg-XXXXX.dot temporary file.\n";
|
||||
return;
|
||||
}
|
||||
dumpGraphToFile(Filename.str());
|
||||
if (DisplayGraph(Filename)) {
|
||||
dbgs() << "BOLT-WARNING: Can't display " << Filename
|
||||
<< " with graphviz.\n";
|
||||
}
|
||||
if (auto EC = sys::fs::remove(Filename)) {
|
||||
dbgs() << "BOLT-WARNING: " << EC.message() << ", failed to remove "
|
||||
<< Filename.str() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFunction::dumpGraphForPass(std::string Annotation) const {
|
||||
dumpGraphToFile(constructFilename(getName(), Annotation, ".dot"));
|
||||
}
|
||||
|
||||
void BinaryFunction::dumpGraphToFile(std::string Filename) const {
|
||||
std::error_code EC;
|
||||
raw_fd_ostream of(Filename, EC, sys::fs::F_None);
|
||||
if (EC) {
|
||||
dbgs() << "BOLT-WARNING: " << EC.message() << ", unable to open "
|
||||
<< Filename << " for output.\n";
|
||||
return;
|
||||
}
|
||||
dumpGraph(of);
|
||||
}
|
||||
|
||||
const BinaryBasicBlock *
|
||||
BinaryFunction::getOriginalLayoutSuccessor(const BinaryBasicBlock *BB) const {
|
||||
auto I = std::upper_bound(begin(), end(), *BB);
|
||||
|
|
|
@ -392,9 +392,20 @@ public:
|
|||
void modifyLayout(LayoutType Type, bool Split);
|
||||
|
||||
/// View CFG in graphviz program
|
||||
void viewGraph();
|
||||
void viewGraph() const;
|
||||
|
||||
/// Get basic block index assuming it belongs to this function.
|
||||
/// Dump CFG in graphviz format
|
||||
void dumpGraph(raw_ostream& OS) const;
|
||||
|
||||
/// Dump CFG in graphviz format to file.
|
||||
void dumpGraphToFile(std::string Filename) const;
|
||||
|
||||
/// Dump CFG in graphviz format to a file with a filename that is derived
|
||||
/// from the function name and Annotation strings. Useful for dumping the
|
||||
/// CFG after an optimization pass.
|
||||
void dumpGraphForPass(std::string Annotation = "") const;
|
||||
|
||||
/// Get basic block index assuming it belongs to this function.
|
||||
unsigned getIndex(const BinaryBasicBlock *BB) const {
|
||||
assert(BasicBlockIndices.find(BB) != BasicBlockIndices.end());
|
||||
return BasicBlockIndices.find(BB)->second;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
namespace opts {
|
||||
|
||||
extern llvm::cl::opt<bool> PrintAll;
|
||||
extern llvm::cl::opt<bool> DumpDotAll;
|
||||
extern llvm::cl::opt<bool> PrintReordered;
|
||||
extern llvm::cl::opt<bool> PrintEHRanges;
|
||||
extern llvm::cl::opt<bool> PrintUCE;
|
||||
|
@ -343,6 +344,9 @@ void EliminateUnreachableBlocks::runOnFunction(BinaryFunction& Function) {
|
|||
|
||||
if (opts::PrintAll || opts::PrintUCE)
|
||||
Function.print(errs(), "after unreachable code elimination", true);
|
||||
|
||||
if (opts::DumpDotAll)
|
||||
Function.dumpGraphForPass("unreachable-code");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,6 +383,8 @@ void ReorderBasicBlocks::runOnFunctions(
|
|||
Function.modifyLayout(opts::ReorderBlocks, ShouldSplit);
|
||||
if (opts::PrintAll || opts::PrintReordered)
|
||||
Function.print(errs(), "after reordering blocks", true);
|
||||
if (opts::DumpDotAll)
|
||||
Function.dumpGraphForPass("reordering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,6 +415,8 @@ void FixupFunctions::runOnFunctions(
|
|||
Function.updateEHRanges();
|
||||
if (opts::PrintAll || opts::PrintEHRanges)
|
||||
Function.print(errs(), "after updating EH ranges", true);
|
||||
if (opts::DumpDotAll)
|
||||
Function.dumpGraphForPass("update-EH-ranges");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,6 +527,9 @@ void SimplifyConditionalTailCalls::runOnFunctions(
|
|||
if (opts::PrintAll || opts::PrintReordered) {
|
||||
Function.print(errs(), "after tail call patching", true);
|
||||
}
|
||||
if (opts::DumpDotAll) {
|
||||
Function.dumpGraphForPass("tail-call-patching");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,11 @@ cl::opt<bool>
|
|||
PrintAll("print-all", cl::desc("print functions after each stage"),
|
||||
cl::Hidden);
|
||||
|
||||
cl::opt<bool>
|
||||
DumpDotAll("dump-dot-all",
|
||||
cl::desc("dump function CFGs to graphviz format after each stage"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintCFG("print-cfg", cl::desc("print functions after CFG construction"),
|
||||
cl::Hidden);
|
||||
|
@ -913,6 +918,9 @@ void RewriteInstance::disassembleFunctions() {
|
|||
if (opts::PrintAll || opts::PrintCFG)
|
||||
Function.print(errs(), "after building cfg", true);
|
||||
|
||||
if (opts::DumpDotAll)
|
||||
Function.dumpGraphForPass("build-cfg");
|
||||
|
||||
TotalScore += Function.getFunctionScore();
|
||||
|
||||
} // Iterate over all functions
|
||||
|
|
Loading…
Reference in New Issue