summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJosh Blum2013-08-01 01:12:24 -0700
committerJosh Blum2013-08-01 01:12:24 -0700
commita23bf59c46dae7aa25c4763c6122d0822c88abc7 (patch)
treeaf37ea0c6b2872071938390c857e4efcb4975d86 /lib
parent1897808616c91d277e24335a337bec92592fb87a (diff)
downloadsandhi-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.txt30
-rw-r--r--lib/factory.cpp4
-rw-r--r--lib/jit_factory.cpp158
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