mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
(1) Handling evmcc options with boost::program_options. (2) Writing out .ll and .bc files
This commit is contained in:
parent
cb870520b2
commit
ae9f57f687
2 changed files with 112 additions and 65 deletions
|
|
@ -8,6 +8,7 @@ set(EXECUTABLE evmcc)
|
||||||
|
|
||||||
add_executable(${EXECUTABLE} ${SRC_LIST})
|
add_executable(${EXECUTABLE} ${SRC_LIST})
|
||||||
|
|
||||||
|
target_link_libraries(${EXECUTABLE} boost_program_options)
|
||||||
target_link_libraries(${EXECUTABLE} devcore)
|
target_link_libraries(${EXECUTABLE} devcore)
|
||||||
target_link_libraries(${EXECUTABLE} ethcore)
|
target_link_libraries(${EXECUTABLE} ethcore)
|
||||||
target_link_libraries(${EXECUTABLE} ethereum)
|
target_link_libraries(${EXECUTABLE} ethereum)
|
||||||
|
|
@ -40,8 +41,8 @@ message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||||
include_directories(${LLVM_INCLUDE_DIRS})
|
include_directories(${LLVM_INCLUDE_DIRS})
|
||||||
add_definitions(${LLVM_DEFINITIONS})
|
add_definitions(${LLVM_DEFINITIONS})
|
||||||
|
|
||||||
# llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
|
llvm_map_components_to_libnames(llvm_libs bitwriter)
|
||||||
# target_link_libraries(evmcc ${llvm_libs})
|
target_link_libraries(evmcc ${llvm_libs})
|
||||||
|
|
||||||
# end of LLVM specific commands
|
# end of LLVM specific commands
|
||||||
|
|
||||||
|
|
|
||||||
172
evmcc/evmcc.cpp
172
evmcc/evmcc.cpp
|
|
@ -7,6 +7,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <llvm/Bitcode/ReaderWriter.h>
|
||||||
|
#include <llvm/Support/raw_os_ostream.h>
|
||||||
|
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
#include <libdevcore/CommonIO.h>
|
#include <libdevcore/CommonIO.h>
|
||||||
|
|
@ -15,67 +19,76 @@
|
||||||
#include <libevmjit/ExecutionEngine.h>
|
#include <libevmjit/ExecutionEngine.h>
|
||||||
|
|
||||||
|
|
||||||
void show_usage()
|
void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap)
|
||||||
{
|
{
|
||||||
// FIXME: Use arg[0] as program name?
|
namespace opt = boost::program_options;
|
||||||
std::cerr << "usage: evmcc (-b|-c|-d)+ <inputfile.bc>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
opt::options_description explicitOpts("Allowed options");
|
||||||
|
explicitOpts.add_options()
|
||||||
|
("help,h", "show usage information")
|
||||||
|
("compile,c", "compile the code to LLVM IR")
|
||||||
|
("interpret,i", "compile the code to LLVM IR and execute")
|
||||||
|
("gas,g", opt::value<size_t>(), "set initial gas for execution")
|
||||||
|
("disassemble,d", "dissassemble the code")
|
||||||
|
("dump-cfg", "dump control flow graph to graphviz file")
|
||||||
|
("optimize-stack,os", "optimize stack use between basic blocks")
|
||||||
|
("output-ll", opt::value<std::string>(), "dump generated LLVM IR to file")
|
||||||
|
("output-bc", opt::value<std::string>(), "dump generated LLVM bitcode to file")
|
||||||
|
("verbose,V", "enable verbose output");
|
||||||
|
|
||||||
|
opt::options_description implicitOpts("Input files");
|
||||||
|
implicitOpts.add_options()
|
||||||
|
("input-file", opt::value<std::string>(), "input file");
|
||||||
|
|
||||||
|
opt::options_description allOpts("");
|
||||||
|
allOpts.add(explicitOpts).add(implicitOpts);
|
||||||
|
|
||||||
|
opt::positional_options_description inputOpts;
|
||||||
|
inputOpts.add("input-file", 1);
|
||||||
|
|
||||||
|
const char* errorMsg = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts);
|
||||||
|
opt::store(parser.run(), _varMap);
|
||||||
|
opt::notify(_varMap);
|
||||||
|
}
|
||||||
|
catch (boost::program_options::error& err)
|
||||||
|
{
|
||||||
|
errorMsg = err.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errorMsg && _varMap.count("input-file") == 0)
|
||||||
|
errorMsg = "missing input file name";
|
||||||
|
|
||||||
|
if (_varMap.count("disassemble") == 0
|
||||||
|
&& _varMap.count("compile") == 0
|
||||||
|
&& _varMap.count("interpret") == 0)
|
||||||
|
{
|
||||||
|
errorMsg = "at least one of -c, -i, -d is required";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMsg || _varMap.count("help"))
|
||||||
|
{
|
||||||
|
if (errorMsg)
|
||||||
|
std::cerr << "Error: " << errorMsg << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Usage: " << _argv[0] << " <options> input-file " << std::endl
|
||||||
|
<< explicitOpts << std::endl;
|
||||||
|
std::exit(errorMsg ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
std::string input_file;
|
boost::program_options::variables_map options;
|
||||||
bool opt_dissassemble = false;
|
parseProgramOptions(argc, argv, options);
|
||||||
bool opt_show_bytes = false;
|
|
||||||
bool opt_compile = false;
|
|
||||||
bool opt_interpret = false;
|
|
||||||
bool opt_dump_graph = false;
|
|
||||||
bool opt_unknown = false;
|
|
||||||
bool opt_verbose = false;
|
|
||||||
size_t initialGas = 10000;
|
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
auto inputFile = options["input-file"].as<std::string>();
|
||||||
{
|
std::ifstream ifs(inputFile);
|
||||||
std::string option = argv[i];
|
|
||||||
if (option == "-b")
|
|
||||||
opt_show_bytes = true;
|
|
||||||
else if (option == "-c")
|
|
||||||
opt_compile = true;
|
|
||||||
else if (option == "-d")
|
|
||||||
opt_dissassemble = true;
|
|
||||||
else if (option == "-i")
|
|
||||||
opt_interpret = true;
|
|
||||||
else if (option == "--dump-cfg")
|
|
||||||
opt_dump_graph = true;
|
|
||||||
else if (option == "-g" && i + 1 < argc)
|
|
||||||
{
|
|
||||||
std::string gasValue = argv[++i];
|
|
||||||
initialGas = boost::lexical_cast<size_t>(gasValue);
|
|
||||||
std::cerr << "Initial gas set to " << initialGas << "\n";
|
|
||||||
}
|
|
||||||
else if (option == "-v")
|
|
||||||
opt_verbose = true;
|
|
||||||
else if (option[0] != '-' && input_file.empty())
|
|
||||||
input_file = option;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
opt_unknown = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_unknown ||
|
|
||||||
input_file.empty() ||
|
|
||||||
(!opt_show_bytes && !opt_compile && !opt_dissassemble && !opt_interpret))
|
|
||||||
{
|
|
||||||
show_usage();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream ifs(input_file);
|
|
||||||
if (!ifs.is_open())
|
if (!ifs.is_open())
|
||||||
{
|
{
|
||||||
std::cerr << "cannot open file " << input_file << std::endl;
|
std::cerr << "cannot open input file " << inputFile << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,37 +101,70 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
bytes bytecode = fromHex(src);
|
bytes bytecode = fromHex(src);
|
||||||
|
|
||||||
if (opt_show_bytes)
|
if (options.count("disassemble"))
|
||||||
std::cout << memDump(bytecode) << std::endl;
|
|
||||||
|
|
||||||
if (opt_dissassemble)
|
|
||||||
{
|
{
|
||||||
std::string assembly = eth::disassemble(bytecode);
|
std::string assembly = eth::disassemble(bytecode);
|
||||||
std::cout << assembly << std::endl;
|
std::cout << assembly << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_compile || opt_interpret)
|
if (options.count("compile") || options.count("interpret"))
|
||||||
{
|
{
|
||||||
|
size_t initialGas = 10000;
|
||||||
|
|
||||||
|
if (options.count("gas"))
|
||||||
|
initialGas = options["gas"].as<size_t>();
|
||||||
|
|
||||||
auto compilationStartTime = std::chrono::high_resolution_clock::now();
|
auto compilationStartTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
eth::jit::Compiler::Options options;
|
eth::jit::Compiler::Options compilerOptions;
|
||||||
options.dumpCFG = opt_dump_graph;
|
compilerOptions.dumpCFG = options.count("dump-cfg") > 0;
|
||||||
|
compilerOptions.optimizeStack = options.count("optimize-stack") > 0;
|
||||||
|
|
||||||
auto compiler = eth::jit::Compiler(options);
|
auto compiler = eth::jit::Compiler(compilerOptions);
|
||||||
auto module = compiler.compile({bytecode.data(), bytecode.size()});
|
auto module = compiler.compile({bytecode.data(), bytecode.size()});
|
||||||
|
|
||||||
auto compilationEndTime = std::chrono::high_resolution_clock::now();
|
auto compilationEndTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
module->dump();
|
module->dump();
|
||||||
|
|
||||||
if (opt_verbose)
|
if (options.count("output-ll"))
|
||||||
|
{
|
||||||
|
auto outputFile = options["output-ll"].as<std::string>();
|
||||||
|
std::ofstream ofs(outputFile);
|
||||||
|
if (!ofs.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "cannot open output file " << outputFile << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
llvm::raw_os_ostream ros(ofs);
|
||||||
|
module->print(ros, nullptr);
|
||||||
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.count("output-bc"))
|
||||||
|
{
|
||||||
|
auto outputFile = options["output-bc"].as<std::string>();
|
||||||
|
std::ofstream ofs(outputFile);
|
||||||
|
if (!ofs.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "cannot open output file " << outputFile << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
llvm::raw_os_ostream ros(ofs);
|
||||||
|
llvm::WriteBitcodeToFile(module.get(), ros);
|
||||||
|
ros.flush();
|
||||||
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (options.count("verbose"))
|
||||||
{
|
{
|
||||||
std::cerr << "*** Compilation time: "
|
std::cerr << "*** Compilation time: "
|
||||||
<< std::chrono::duration_cast<std::chrono::microseconds>(compilationEndTime - compilationStartTime).count()
|
<< std::chrono::duration_cast<std::chrono::microseconds>(compilationEndTime - compilationStartTime).count()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_interpret)
|
if (options.count("interpret"))
|
||||||
{
|
{
|
||||||
auto engine = eth::jit::ExecutionEngine();
|
auto engine = eth::jit::ExecutionEngine();
|
||||||
u256 gas = initialGas;
|
u256 gas = initialGas;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue