From f23312294372f0b5d8da0182fce782711079a8d4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 16 Oct 2014 12:22:54 +0100 Subject: [PATCH] Added dumping of CFG to a .dot file [Delivers #80816506] --- evmcc/Compiler.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++ evmcc/Compiler.h | 4 ++++ evmcc/evmcc.cpp | 18 ++++++++++++++-- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77db366cf..a7e8ba483 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -929,6 +929,58 @@ void Compiler::linkBasicBlocks() } } +void Compiler::dumpBasicBlockGraph(std::ostream& out) +{ + out << "digraph BB {\n" + << " node [shape=record];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + // std::map blocksByName; + std::vector blocks; + for (auto& pair : this->basicBlocks) + { + blocks.push_back(&pair.second); + } + blocks.push_back(m_jumpTableBlock.get()); + blocks.push_back(m_badJumpBlock.get()); + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + // blocksByName.insert(std::pair(blockName, bb)); + + int numOfPhiNodes = 0; + auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI(); + for (auto instrIter = bb->llvm()->begin(); &*instrIter != firstNonPhiPtr; ++instrIter, ++numOfPhiNodes); + + auto endStackSize = bb->getStack().size(); + + out << " \"" << blockName << "\" [shape=record, label=\"" + << std::to_string(numOfPhiNodes) << "|" + << blockName << "|" + << std::to_string(endStackSize) + << "\"];\n"; + } + + out << " entry -> \"Instr.0\";\n"; + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::succ_end(bb->llvm()); + for (llvm::succ_iterator it = llvm::succ_begin(bb->llvm()); it != end; ++it) + { + std::string succName = it->getName(); + out << " \"" << blockName << "\" -> \"" << succName << "\";\n"; + } + } + + out << "}\n"; +} + } } } diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 1a0e61ca1..bda154689 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -24,6 +24,9 @@ public: std::unique_ptr compile(const bytes& bytecode); + void dumpBasicBlockGraph(std::ostream& out); + + private: void createBasicBlocks(const bytes& bytecode); @@ -32,6 +35,7 @@ private: void linkBasicBlocks(); + llvm::IRBuilder<> m_builder; /** diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index d8bf9438b..22ba1db50 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -22,6 +23,7 @@ void show_usage() std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; } + int main(int argc, char** argv) { @@ -30,7 +32,8 @@ int main(int argc, char** argv) bool opt_show_bytes = false; bool opt_compile = false; bool opt_interpret = false; - bool opt_unknown = false; + bool opt_dump_graph = false; + bool opt_unknown = false; for (int i = 1; i < argc; i++) { @@ -43,6 +46,8 @@ int main(int argc, char** argv) opt_dissassemble = true; else if (option == "-i") opt_interpret = true; + else if (option == "-g") + opt_dump_graph = true; else if (option[0] != '-' && input_file.empty()) input_file = option; else @@ -89,9 +94,18 @@ int main(int argc, char** argv) if (opt_compile) { - auto module = eth::jit::Compiler().compile(bytecode); + auto compiler = eth::jit::Compiler(); + auto module = compiler.compile(bytecode); llvm::raw_os_ostream out(std::cout); module->print(out, nullptr); + + if (opt_dump_graph) + { + std::ofstream ofs("blocks.dot"); + compiler.dumpBasicBlockGraph(ofs); + ofs.close(); + std::cout << "Basic blocks graph written to block.dot\n"; + } } if (opt_interpret)