From cb68dc4b2de256176e5ed224767241b033e2ede9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Aug 2013 00:59:07 -0700 Subject: gras: work on using clang api - but commented out The last thing missing is that the API use case doesnt automatically have default C++ include paths. --- lib/jit_factory.cpp | 212 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 146 insertions(+), 66 deletions(-) (limited to 'lib/jit_factory.cpp') 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 +#include +#include +#include #include +#include +#include +#include +#include -#ifdef CLANG_EXECUTABLE +//defined in module loader +std::string get_gras_runtime_include_path(void); +#ifdef HAVE_CLANG +#include +#include +#include +#include +#include +#include +#include +#endif //HAVE_CLANG + +#ifdef HAVE_LLVM #include #include #include @@ -12,36 +31,69 @@ #include #include #include +#include +#include #include +#endif //HAVE_LLVM -#include -#include -#include -#include -#include -#include -#include -#include +/*********************************************************************** + * 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 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; +} +#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 &flags) +#ifdef CLANG_EXECUTABLE +static llvm::Module *call_clang_exe(const std::string &source_file, const std::vector &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 cmd; cmd.push_back(BOOST_STRINGIZE(CLANG_EXECUTABLE)); @@ -63,9 +115,6 @@ static std::string call_clang(const std::string &source, const std::vector(bitcode_fstream)), std::istreambuf_iterator()); + const std::string bitcode((std::istreambuf_iterator(bitcode_fstream)), std::istreambuf_iterator()); + + //create a memory buffer from the bitcode + boost::shared_ptr 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 &flags) { - ExecutionEngineMonitor(void) - { - boost::mutex::scoped_lock l(mutex); - } + //begin command setup + std::vector 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 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 DiagID(new clang::DiagnosticIDs()); + clang::DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient); + + // Create the compiler invocation + clang::LangOptions LangOpts; + llvm::OwningPtr 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 > 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 &flags) +#ifdef HAVE_LLVM +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); + //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 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 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 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 &) { throw std::runtime_error("GRAS compiler not built with Clang support!"); } -#endif //CLANG_EXECUTABLE +#endif //HAVE_LLVM -- cgit