#include "llvm_jit.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace clang; using namespace std; namespace JIT { struct Block::Impl { Impl(LLVMEngine &engine_) : engine(engine_) { } LLVMEngine &engine; Func block = nullptr; size_t block_size = 0; bool compile(const std::string &source); }; Block::Block(LLVMEngine &engine) { impl = std::unique_ptr(new Impl(engine)); } Block::~Block() { } struct LLVMHolder { LLVMHolder() { llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmParser(); } ~LLVMHolder() { llvm::llvm_shutdown(); } }; struct LLVMEngine::Impl { Impl(const std::unordered_map &symbol_table_) : symbol_table(symbol_table_) { static LLVMHolder llvm_holder; execution_session = llvm::make_unique(); execution_session->setErrorReporter([](llvm::Error error) { if (error) llvm::errs() << "Error: " << error << "\n"; }); llvm::orc::LegacyRTDyldObjectLinkingLayer::Resources resources; resources.MemMgr = llvm::make_unique(); resources.Resolver = llvm::orc::createLegacyLookupResolver( *execution_session, [this](const std::string &name) -> llvm::JITSymbol { return findSymbol(name); }, [](llvm::Error) {}); object_layer = llvm::make_unique( *execution_session, [=](llvm::orc::VModuleKey) { return resources; }); auto host = llvm::orc::JITTargetMachineBuilder::detectHost(); target_machine = llvm::cantFail(host->createTargetMachine()); target_machine->setOptLevel(llvm::CodeGenOpt::Level::Default); data_layout = llvm::make_unique(std::move(*host->getDefaultDataLayoutForTarget())); compile_layer = llvm::make_unique< llvm::orc::LegacyIRCompileLayer>( *object_layer, llvm::orc::SimpleCompiler(*target_machine)); } std::unique_ptr compile_c(const std::string &source) { llvm::SmallVector args; args.push_back("__block.c"); args.push_back("-std=c99"); args.push_back("-O2"); std::string string_buffer; llvm::raw_string_ostream ss(string_buffer); IntrusiveRefCntPtr diag_opts = new DiagnosticOptions(); TextDiagnosticPrinter *diag_client = new TextDiagnosticPrinter(ss, &*diag_opts); IntrusiveRefCntPtr diag_id(new DiagnosticIDs()); DiagnosticsEngine diags(diag_id, &*diag_opts, diag_client); auto CI = llvm::make_unique(); auto *invocation = CI.get(); CompilerInvocation::CreateFromArgs(*CI, args.data(), args.data() + args.size(), diags); auto clang = llvm::make_unique(); clang->setInvocation(std::move(CI)); clang->createDiagnostics(); auto act = llvm::make_unique(); StringRef code_data(source); auto buffer = llvm::MemoryBuffer::getMemBufferCopy(code_data); invocation->getPreprocessorOpts().clearRemappedFiles(); invocation->getPreprocessorOpts().addRemappedFile("__block.c", buffer.release()); if (!clang->ExecuteAction(*act)) { llvm::errs() << "ExecuteAction failed.\n"; return {}; } return act; } Func compile(const std::string &source) { auto act = compile_c(source); if (!act) return nullptr; auto K = execution_session->allocateVModule(); auto error = compile_layer->addModule(K, act->takeModule()); if (error) return nullptr; auto entry_point = compile_layer->findSymbolIn(K, "block_entry", true); auto block = reinterpret_cast(llvm::cantFail(entry_point.getAddress())); return block; } llvm::JITSymbol findSymbol(const std::string &name) { auto itr = symbol_table.find(name); if (itr != symbol_table.end()) return llvm::JITSymbol(itr->second, llvm::JITSymbolFlags::None); else return llvm::JITSymbol(nullptr); } const std::unordered_map &symbol_table; llvm::LLVMContext context; std::unique_ptr execution_session; std::unique_ptr object_layer; std::unique_ptr< llvm::orc::LegacyIRCompileLayer> compile_layer; std::unique_ptr target_machine; std::unique_ptr mangler; std::unique_ptr data_layout; }; LLVMEngine::LLVMEngine(const std::unordered_map &symbol_table) { impl.reset(new Impl(symbol_table)); } LLVMEngine::~LLVMEngine() { } bool Block::compile(uint64_t, const std::string &source) { bool ret = impl->compile(source); if (ret) { block = impl->block; block_size = impl->block_size; } return ret; } bool Block::Impl::compile(const std::string &source) { block = engine.impl->compile(source); return block != nullptr; } } // namespace JIT