From a23bf59c46dae7aa25c4763c6122d0822c88abc7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Aug 2013 01:12:24 -0700 Subject: gras: jit factory api + unit tests --- lib/jit_factory.cpp | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 lib/jit_factory.cpp (limited to 'lib/jit_factory.cpp') diff --git a/lib/jit_factory.cpp b/lib/jit_factory.cpp new file mode 100644 index 0000000..cdcfc03 --- /dev/null +++ b/lib/jit_factory.cpp @@ -0,0 +1,158 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#include +#include + +#ifdef CLANG_EXECUTABLE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/*********************************************************************** + * Helper function to call a clang compliation + **********************************************************************/ +static std::string call_clang(const std::string &source, const std::vector &flags) +{ + //make up bitcode file path + char bitcode_file[L_tmpnam]; + std::tmpnam(bitcode_file); + + //write source to tmp file + char source_file[L_tmpnam]; + std::tmpnam(source_file); + std::ofstream source_fstream(source_file); + source_fstream << source; + source_fstream.close(); + + //begin command setup + std::vector cmd; + cmd.push_back(BOOST_STRINGIZE(CLANG_EXECUTABLE)); + cmd.push_back("-emit-llvm"); + + //inject source + cmd.push_back("-c"); + cmd.push_back("-x"); + cmd.push_back("c++"); + cmd.push_back(source_file); + + //inject output + cmd.push_back("-o"); + cmd.push_back(bitcode_file); + + //inject args... + BOOST_FOREACH(const std::string &flag, flags) + { + cmd.push_back(flag.c_str()); + } + + //format command string + std::string command; + BOOST_FOREACH(const std::string &c, cmd) + { + command += c + " "; + } + std::cout << " " << command << std::endl; + const int ret = system(command.c_str()); + if (ret != 0) + { + throw std::runtime_error("GRAS compiler: error system exec clang"); + } + + //readback bitcode for result + std::ifstream bitcode_fstream(bitcode_file); + return std::string((std::istreambuf_iterator(bitcode_fstream)), std::istreambuf_iterator()); +} + +/*********************************************************************** + * Storage for execution engines + **********************************************************************/ +struct ExecutionEngineMonitor +{ + ExecutionEngineMonitor(void) + { + boost::mutex::scoped_lock l(mutex); + } + + ~ExecutionEngineMonitor(void) + { + boost::mutex::scoped_lock l(mutex); + for (size_t i = 0; i < ees.size(); i++) + { + ees[i]->runStaticConstructorsDestructors(true); + ees[i].reset(); + } + ees.clear(); + } + + void add(boost::shared_ptr ee) + { + boost::mutex::scoped_lock l(mutex); + ee->runStaticConstructorsDestructors(false); + ees.push_back(ee); + } + + llvm::LLVMContext &get_context(void) + { + return context; + } + + boost::mutex mutex; + llvm::LLVMContext context; + std::vector > ees; +}; + +static ExecutionEngineMonitor &get_eemon(void) +{ + static ExecutionEngineMonitor eemon; + return eemon; +} + +/*********************************************************************** + * factory compile implementation + **********************************************************************/ +void gras::jit_factory(const std::string &source, const std::vector &flags) +{ + std::cout << "GRAS compiler: compile source into bitcode..." << std::endl; + const std::string bitcode = call_clang(source, flags); + + llvm::InitializeNativeTarget(); + llvm::llvm_start_multithreaded(); + std::string error; + + //create a memory buffer from the bitcode + boost::shared_ptr buffer(llvm::MemoryBuffer::getMemBuffer(bitcode)); + + //parse the bitcode into a module + llvm::Module *module = llvm::ParseBitcodeFile(buffer.get(), get_eemon().get_context(), &error); + if (not error.empty()) throw std::runtime_error("GRAS compiler: ParseBitcodeFile " + error); + + //create execution engine + boost::shared_ptr ee(llvm::ExecutionEngine::create(module, false, &error)); + if (not error.empty()) throw std::runtime_error("GRAS compiler: ExecutionEngine " + error); + std::cout << "GRAS compiler: execute static constructors..." << std::endl; + get_eemon().add(ee); +} + +#else //CLANG_EXECUTABLE + +void Factory::compile(const std::string &, const std::vector &) +{ + throw std::runtime_error("GRAS compiler not built with Clang support!"); +} + +#endif //CLANG_EXECUTABLE -- cgit