#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h" #include "llvm/ExecutionEngine/Orc/Speculation.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ThreadPool.h" #include #include using namespace llvm; using namespace llvm::orc; static cl::list InputFiles(cl::Positional, cl::OneOrMore, cl::desc("input files")); static cl::list InputArgv("args", cl::Positional, cl::desc("..."), cl::ZeroOrMore, cl::PositionalEatsArgs); static cl::opt NumThreads("num-threads", cl::Optional, cl::desc("Number of compile threads"), cl::init(4)); ExitOnError ExitOnErr; // Add Layers class SpeculativeJIT { public: static Expected> Create() { auto JTMB = orc::JITTargetMachineBuilder::detectHost(); if (!JTMB) return JTMB.takeError(); auto DL = JTMB->getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); auto ES = llvm::make_unique(); auto LCTMgr = createLocalLazyCallThroughManager( JTMB->getTargetTriple(), *ES, pointerToJITTargetAddress(explodeOnLazyCompileFailure)); if (!LCTMgr) return LCTMgr.takeError(); auto ISMBuilder = createLocalIndirectStubsManagerBuilder(JTMB->getTargetTriple()); if (!ISMBuilder) return make_error("No indirect stubs manager for target", inconvertibleErrorCode()); auto ProcessSymbolsSearchGenerator = DynamicLibrarySearchGenerator::GetForCurrentProcess( DL->getGlobalPrefix()); if (!ProcessSymbolsSearchGenerator) return ProcessSymbolsSearchGenerator.takeError(); std::unique_ptr SJ(new SpeculativeJIT( std::move(ES), std::move(*DL), std::move(*JTMB), std::move(*LCTMgr), std::move(ISMBuilder), std::move(*ProcessSymbolsSearchGenerator))); return std::move(SJ); } ExecutionSession &getES() { return *ES; } Error addModule(JITDylib &JD, ThreadSafeModule TSM) { return CODLayer.add(JD, std::move(TSM)); } Expected lookup(StringRef UnmangledName) { return ES->lookup({&ES->getMainJITDylib()}, Mangle(UnmangledName)); } ~SpeculativeJIT() { CompileThreads.wait(); } private: using IndirectStubsManagerBuilderFunction = std::function()>; static void explodeOnLazyCompileFailure() { errs() << "Lazy compilation failed, Symbol Implmentation not found!\n"; exit(1); } SpeculativeJIT(std::unique_ptr ES, DataLayout DL, orc::JITTargetMachineBuilder JTMB, std::unique_ptr LCTMgr, IndirectStubsManagerBuilderFunction ISMBuilder, DynamicLibrarySearchGenerator ProcessSymbolsGenerator) : ES(std::move(ES)), DL(std::move(DL)), LCTMgr(std::move(LCTMgr)), CompileLayer(*this->ES, ObjLayer, ConcurrentIRCompiler(std::move(JTMB))), S(Imps, *this->ES), SpeculateLayer(*this->ES, CompileLayer, S, BlockFreqQuery()), CODLayer(*this->ES, SpeculateLayer, *this->LCTMgr, std::move(ISMBuilder)) { this->ES->getMainJITDylib().setGenerator( std::move(ProcessSymbolsGenerator)); this->CODLayer.setImplMap(&Imps); this->ES->setDispatchMaterialization( [this](JITDylib &JD, std::unique_ptr MU) { // FIXME: Switch to move capture once we have c 14. auto SharedMU = std::shared_ptr(std::move(MU)); auto Work = [SharedMU, &JD]() { SharedMU->doMaterialize(JD); }; CompileThreads.async(std::move(Work)); }); JITEvaluatedSymbol SpeculatorSymbol(JITTargetAddress(&S), JITSymbolFlags::Exported); ExitOnErr(this->ES->getMainJITDylib().define( absoluteSymbols({{Mangle("__orc_speculator"), SpeculatorSymbol}}))); LocalCXXRuntimeOverrides CXXRuntimeoverrides; ExitOnErr(CXXRuntimeoverrides.enable(this->ES->getMainJITDylib(), Mangle)); } static std::unique_ptr createMemMgr() { return llvm::make_unique(); } std::unique_ptr ES; DataLayout DL; MangleAndInterner Mangle{*ES, DL}; ThreadPool CompileThreads{NumThreads}; Triple TT; std::unique_ptr LCTMgr; IRCompileLayer CompileLayer; ImplSymbolMap Imps; Speculator S; RTDyldObjectLinkingLayer ObjLayer{*ES, createMemMgr}; IRSpeculationLayer SpeculateLayer; CompileOnDemandLayer CODLayer; }; int main(int argc, char *argv[]) { // Initialize LLVM. InitLLVM X(argc, argv); InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); cl::ParseCommandLineOptions(argc, argv, "SpeculativeJIT"); ExitOnErr.setBanner(std::string(argv[0]) + ": "); if (NumThreads < 1) { errs() << "Speculative compilation requires one or more dedicated compile " "threads\n"; return 1; } // Create a JIT instance. auto SJ = ExitOnErr(SpeculativeJIT::Create()); // Load the IR inputs. for (const auto &InputFile : InputFiles) { SMDiagnostic Err; auto Ctx = llvm::make_unique(); auto M = parseIRFile(InputFile, Err, *Ctx); if (!M) { Err.print(argv[0], errs()); return 1; } ExitOnErr(SJ->addModule(SJ->getES().getMainJITDylib(), ThreadSafeModule(std::move(M), std::move(Ctx)))); } // Build an argv array for the JIT'd main. std::vector ArgV; ArgV.push_back(argv[0]); for (const auto &InputArg : InputArgv) ArgV.push_back(InputArg.data()); ArgV.push_back(nullptr); // Look up the JIT'd main, cast it to a function pointer, then call it. auto MainSym = ExitOnErr(SJ->lookup("main")); int (*Main)(int, const char *[]) = (int (*)(int, const char *[]))MainSym.getAddress(); Main(ArgV.size() - 1, ArgV.data()); return 0; }