diff options
-rw-r--r-- | cmake/Modules/FindClang.cmake | 1 | ||||
m--------- | grextras | 0 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 28 | ||||
-rw-r--r-- | lib/jit_factory.cpp | 212 |
4 files changed, 165 insertions, 76 deletions
diff --git a/cmake/Modules/FindClang.cmake b/cmake/Modules/FindClang.cmake index cbce0af..1b8be4a 100644 --- a/cmake/Modules/FindClang.cmake +++ b/cmake/Modules/FindClang.cmake @@ -18,6 +18,7 @@ ENDMACRO(FIND_AND_ADD_CLANG_LIB) # Clang shared library provides just the limited C interface, so it # can not be used. We look for the static libraries. +FIND_AND_ADD_CLANG_LIB(clangSerialization) FIND_AND_ADD_CLANG_LIB(clangFrontend) FIND_AND_ADD_CLANG_LIB(clangDriver) FIND_AND_ADD_CLANG_LIB(clangCodeGen) diff --git a/grextras b/grextras -Subproject 3aa900e4908d82d222806a3a7d17faf94505d86 +Subproject 02e23f149fda731a5049f6df40a7a6eaff882f1 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2d61b91..f8aaebc 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -107,26 +107,34 @@ endif() ######################################################################## # Setup factory compiler ######################################################################## + +#step 1) call into the LLVM find package 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) +#step 2) setup LLVM if found and find Clang +if(LLVM_FOUND) + add_definitions(-DHAVE_LLVM) 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}) + find_package(Clang) +endif() + +#step 3) setup Clang if found +if(CLANG_FOUND) + add_definitions(-DHAVE_CLANG) + include_directories(${CLANG_INCLUDE_DIRS}) + list(APPEND GRAS_LIBRARIES ${CLANG_LIBS}) +endif() + +#step 4) find clang executable as backup (found llvm but not clang dev) +find_program(CLANG_EXECUTABLE clang DOC "clang executable") +if(CLANG_EXECUTABLE) SET_SOURCE_FILES_PROPERTIES( ${CMAKE_CURRENT_SOURCE_DIR}/jit_factory.cpp PROPERTIES COMPILE_DEFINITIONS "CLANG_EXECUTABLE=${CLANG_EXECUTABLE}" diff --git a/lib/jit_factory.cpp b/lib/jit_factory.cpp index 882ee05..e7362cc 100644 --- a/lib/jit_factory.cpp +++ b/lib/jit_factory.cpp @@ -1,10 +1,29 @@ // Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. #include <gras/factory.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/thread/mutex.hpp> #include <stdexcept> +#include <iostream> +#include <cstdio> +#include <fstream> +#include <map> -#ifdef CLANG_EXECUTABLE +//defined in module loader +std::string get_gras_runtime_include_path(void); +#ifdef HAVE_CLANG +#include <clang/CodeGen/CodeGenAction.h> +#include <clang/Frontend/CompilerInstance.h> +#include <clang/Frontend/CompilerInvocation.h> +#include <clang/Frontend/TextDiagnosticPrinter.h> +#include <clang/Driver/Compilation.h> +#include <clang/Driver/Driver.h> +#include <clang/Driver/ArgList.h> +#endif //HAVE_CLANG + +#ifdef HAVE_LLVM #include <llvm/LLVMContext.h> #include <llvm/Support/TargetSelect.h> #include <llvm/Bitcode/ReaderWriter.h> @@ -12,36 +31,69 @@ #include <llvm/Support/MemoryBuffer.h> #include <llvm/ExecutionEngine/JIT.h> #include <llvm/Support/system_error.h> +#include <llvm/Support/Host.h> +#include <llvm/Support/Program.h> #include <llvm/Module.h> +#endif //HAVE_LLVM -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/thread/mutex.hpp> -#include <stdexcept> -#include <iostream> -#include <cstdio> -#include <fstream> -#include <map> +/*********************************************************************** + * Storage for execution engines + **********************************************************************/ +#ifdef HAVE_LLVM +struct ExecutionEngineMonitor +{ + ExecutionEngineMonitor(void) + { + boost::mutex::scoped_lock l(mutex); + } -//defined in module loader -std::string get_gras_runtime_include_path(void); + ~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; +} +#endif //HAVE_LLVM /*********************************************************************** - * Helper function to call a clang compliation + * Helper function to call a clang compliation -- execs clang **********************************************************************/ -static std::string call_clang(const std::string &source, const std::vector<std::string> &flags) +#ifdef CLANG_EXECUTABLE +static llvm::Module *call_clang_exe(const std::string &source_file, const std::vector<std::string> &flags) { + std::cout << "GRAS compiler: compile source into bitcode..." << std::endl; + //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)); @@ -63,9 +115,6 @@ static std::string call_clang(const std::string &source, const std::vector<std:: cmd.push_back(flag.c_str()); } - //root include path - cmd.push_back("-I"+get_gras_runtime_include_path()); - //format command string std::string command; BOOST_FOREACH(const std::string &c, cmd) @@ -81,84 +130,115 @@ static std::string call_clang(const std::string &source, const std::vector<std:: //readback bitcode for result std::ifstream bitcode_fstream(bitcode_file); - return std::string((std::istreambuf_iterator<char>(bitcode_fstream)), std::istreambuf_iterator<char>()); + const std::string bitcode((std::istreambuf_iterator<char>(bitcode_fstream)), std::istreambuf_iterator<char>()); + + //create a memory buffer from the bitcode + boost::shared_ptr<llvm::MemoryBuffer> buffer(llvm::MemoryBuffer::getMemBuffer(bitcode)); + + //parse the bitcode into a module + std::string error; + llvm::Module *module = llvm::ParseBitcodeFile(buffer.get(), get_eemon().get_context(), &error); + if (not error.empty()) throw std::runtime_error("GRAS compiler: ParseBitcodeFile " + error); + return module; } +#endif //CLANG_EXECUTABLE /*********************************************************************** - * Storage for execution engines + * Helper function to call a clang compliation -- uses clang API **********************************************************************/ -struct ExecutionEngineMonitor +/* +#ifdef HAVE_CLANG +static llvm::Module *call_clang_api(const std::string &source_file, const std::vector<std::string> &flags) { - ExecutionEngineMonitor(void) - { - boost::mutex::scoped_lock l(mutex); - } + //begin command setup + std::vector<const char *> args; - ~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(); - } + //inject source + args.push_back("-c"); + args.push_back("-x"); + args.push_back("c++"); + args.push_back(source_file.c_str()); - void add(boost::shared_ptr<llvm::ExecutionEngine> ee) + //inject args... + BOOST_FOREACH(const std::string &flag, flags) { - boost::mutex::scoped_lock l(mutex); - ee->runStaticConstructorsDestructors(false); - ees.push_back(ee); + args.push_back(flag.c_str()); } - llvm::LLVMContext &get_context(void) + //http://fdiv.net/2012/08/15/compiling-code-clang-api + + // The compiler invocation needs a DiagnosticsEngine so it can report problems + clang::DiagnosticOptions *DiagOpts = new clang::DiagnosticOptions(); + clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts); + llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs()); + clang::DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient); + + // Create the compiler invocation + clang::LangOptions LangOpts; + llvm::OwningPtr<clang::CompilerInvocation> CI(new clang::CompilerInvocation()); + //CI->setLangDefaults(LangOpts, clang::IK_CXX, clang::LangStandard::lang_gnucxx98); + clang::CompilerInvocation::CreateFromArgs(*CI, &args[0], &args[0] + args.size(), Diags); + + // Print the argument list + std::cout << "clang "; + BOOST_FOREACH(const char *arg, args) { - return context; + std::cout << arg << " "; } + std::cout << std::endl; - boost::mutex mutex; - llvm::LLVMContext context; - std::vector<boost::shared_ptr<llvm::ExecutionEngine> > ees; -}; + // Create the compiler instance + clang::CompilerInstance Clang; + Clang.setInvocation(CI.take()); -static ExecutionEngineMonitor &get_eemon(void) -{ - static ExecutionEngineMonitor eemon; - return eemon; + // Get ready to report problems + Clang.createDiagnostics(args.size(), &args[0]); + if (not Clang.hasDiagnostics()) throw std::runtime_error("ClangBlock::createDiagnostics"); + + // Create an action and make the compiler instance carry it out + clang::CodeGenAction *Act = new clang::EmitLLVMOnlyAction(); + if (not Clang.ExecuteAction(*Act)) throw std::runtime_error("ClangBlock::EmitLLVMOnlyAction"); + + return Act->takeModule(); } +#endif //HAVE_CLANG +*/ /*********************************************************************** * factory compile implementation **********************************************************************/ -void gras::jit_factory(const std::string &source, const std::vector<std::string> &flags) +#ifdef HAVE_LLVM +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); + //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(); 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); + //use clang to compile source into bitcode + std::cout << "GRAS compiler: compile source into bitcode..." << std::endl; + std::vector<std::string> flags = flags_; + flags.push_back("-I"+get_gras_runtime_include_path()); //add root include path + llvm::Module *module = call_clang_exe(source_file, flags); //create execution engine + std::string error; 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 +#else //HAVE_LLVM 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 +#endif //HAVE_LLVM |