diff options
author | Josh Blum | 2013-08-01 01:12:24 -0700 |
---|---|---|
committer | Josh Blum | 2013-08-01 01:12:24 -0700 |
commit | a23bf59c46dae7aa25c4763c6122d0822c88abc7 (patch) | |
tree | af37ea0c6b2872071938390c857e4efcb4975d86 /lib | |
parent | 1897808616c91d277e24335a337bec92592fb87a (diff) | |
download | sandhi-a23bf59c46dae7aa25c4763c6122d0822c88abc7.tar.gz sandhi-a23bf59c46dae7aa25c4763c6122d0822c88abc7.tar.bz2 sandhi-a23bf59c46dae7aa25c4763c6122d0822c88abc7.zip |
gras: jit factory api + unit tests
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 30 | ||||
-rw-r--r-- | lib/factory.cpp | 4 | ||||
-rw-r--r-- | lib/jit_factory.cpp | 158 |
3 files changed, 190 insertions, 2 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ab94525..2d61b91 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -57,6 +57,7 @@ list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/element.cpp ${CMAKE_CURRENT_SOURCE_DIR}/element_uid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/factory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/jit_factory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sbuffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/circular_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/buffer_queue_circ.cpp @@ -104,6 +105,35 @@ else() endif() ######################################################################## +# Setup factory compiler +######################################################################## +find_program(LLVM_CONFIG_EXECUTABLE llvm-config DOC "llvm-config executable") +if(LLVM_CONFIG_EXECUTABLE) + find_package(LLVM) +endif() +if(LLVM_FOUND) + find_program(CLANG_EXECUTABLE clang DOC "clang executable") + set(CLANG_FOUND ${CLANG_EXECUTABLE}) +else() + message(WARNING "LLVM library not found - optional for factory compiler") +endif() +if(NOT CLANG_FOUND) + message(WARNING "Clang executable not found - optional for factory compiler") +endif() + +if(CLANG_FOUND) + add_definitions(${LLVM_CFLAGS}) + link_directories(${LLVM_LIBRARY_DIRS}) + include_directories(${LLVM_INCLUDE_DIRS}) + list(APPEND GRAS_LIBRARIES ${LLVM_MODULE_LIBS}) + list(APPEND GRAS_LIBRARIES ${LLVM_LDFLAGS}) + SET_SOURCE_FILES_PROPERTIES( + ${CMAKE_CURRENT_SOURCE_DIR}/jit_factory.cpp + PROPERTIES COMPILE_DEFINITIONS "CLANG_EXECUTABLE=${CLANG_EXECUTABLE}" + ) +endif() + +######################################################################## # Build library ######################################################################## add_library(gras SHARED ${GRAS_SOURCES}) diff --git a/lib/factory.cpp b/lib/factory.cpp index 7115197..d168dba 100644 --- a/lib/factory.cpp +++ b/lib/factory.cpp @@ -36,7 +36,7 @@ static FactoryRegistryType &get_factory_registry(void) static boost::mutex mutex; -void Factory::_register_factory(const std::string &path, void *entry) +void gras::_register_factory(const std::string &path, void *entry) { boost::mutex::scoped_lock l(mutex); if (get_factory_registry().count(path) != 0) @@ -46,7 +46,7 @@ void Factory::_register_factory(const std::string &path, void *entry) get_factory_registry()[path].reset(reinterpret_cast<FactoryRegistryEntry *>(entry)); } -Element *Factory::_handle_make(const std::string &path, const PMCC &args) +Element *gras::_handle_make(const std::string &path, const PMCC &args) { boost::mutex::scoped_lock l(mutex); if (get_factory_registry().count(path) == 0) 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 <gras/factory.hpp> +#include <stdexcept> + +#ifdef CLANG_EXECUTABLE + +#include <llvm/LLVMContext.h> +#include <llvm/Support/TargetSelect.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/ExecutionEngine/ExecutionEngine.h> +#include <llvm/Support/MemoryBuffer.h> +#include <llvm/ExecutionEngine/JIT.h> +#include <llvm/Support/system_error.h> +#include <llvm/Module.h> + +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/thread/mutex.hpp> +#include <stdexcept> +#include <iostream> +#include <cstdio> +#include <fstream> +#include <map> + +/*********************************************************************** + * Helper function to call a clang compliation + **********************************************************************/ +static std::string call_clang(const std::string &source, const std::vector<std::string> &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<std::string> 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<char>(bitcode_fstream)), std::istreambuf_iterator<char>()); +} + +/*********************************************************************** + * 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<llvm::ExecutionEngine> 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<boost::shared_ptr<llvm::ExecutionEngine> > 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<std::string> &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<llvm::MemoryBuffer> 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<llvm::ExecutionEngine> 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<std::string> &) +{ + throw std::runtime_error("GRAS compiler not built with Clang support!"); +} + +#endif //CLANG_EXECUTABLE |