15a440378SAlex Zinenko //===- ExecutionEngine.cpp - MLIR Execution engine and utils --------------===// 25a440378SAlex Zinenko // 330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information. 556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65a440378SAlex Zinenko // 756222a06SMehdi Amini //===----------------------------------------------------------------------===// 85a440378SAlex Zinenko // 95a440378SAlex Zinenko // This file implements the execution engine for MLIR modules based on LLVM Orc 105a440378SAlex Zinenko // JIT engine. 115a440378SAlex Zinenko // 125a440378SAlex Zinenko //===----------------------------------------------------------------------===// 135a440378SAlex Zinenko #include "mlir/ExecutionEngine/ExecutionEngine.h" 1469040d5bSStephan Herhut #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 1565fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h" 1606e81010SJacques Pienaar #include "mlir/Support/FileUtilities.h" 17ce8f10d6SAlex Zinenko #include "mlir/Target/LLVMIR/Export.h" 185a440378SAlex Zinenko 19c3f0ed7bSRiver Riddle #include "llvm/ExecutionEngine/JITEventListener.h" 20fe3594f7SNicolas Vasilache #include "llvm/ExecutionEngine/ObjectCache.h" 215a440378SAlex Zinenko #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 225a440378SAlex Zinenko #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 235a440378SAlex Zinenko #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 248093f17aSAlex Zinenko #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" 255a440378SAlex Zinenko #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" 265a440378SAlex Zinenko #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 275a440378SAlex Zinenko #include "llvm/IR/IRBuilder.h" 2889b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h" 2953bb528bSMehdi Amini #include "llvm/Support/Debug.h" 305a440378SAlex Zinenko #include "llvm/Support/Error.h" 3106e81010SJacques Pienaar #include "llvm/Support/ToolOutputFile.h" 32d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h" 338de9f2b5SJob Noorman #include "llvm/TargetParser/SubtargetFeature.h" 345a440378SAlex Zinenko 3553bb528bSMehdi Amini #define DEBUG_TYPE "execution-engine" 3653bb528bSMehdi Amini 375a440378SAlex Zinenko using namespace mlir; 38fe3594f7SNicolas Vasilache using llvm::dbgs; 395a440378SAlex Zinenko using llvm::Error; 40fe3594f7SNicolas Vasilache using llvm::errs; 415a440378SAlex Zinenko using llvm::Expected; 42fe3594f7SNicolas Vasilache using llvm::LLVMContext; 43fe3594f7SNicolas Vasilache using llvm::MemoryBuffer; 44fe3594f7SNicolas Vasilache using llvm::MemoryBufferRef; 45fe3594f7SNicolas Vasilache using llvm::Module; 46fe3594f7SNicolas Vasilache using llvm::SectionMemoryManager; 47fe3594f7SNicolas Vasilache using llvm::StringError; 48fe3594f7SNicolas Vasilache using llvm::Triple; 49fe3594f7SNicolas Vasilache using llvm::orc::DynamicLibrarySearchGenerator; 50fe3594f7SNicolas Vasilache using llvm::orc::ExecutionSession; 51fe3594f7SNicolas Vasilache using llvm::orc::IRCompileLayer; 52fe3594f7SNicolas Vasilache using llvm::orc::JITTargetMachineBuilder; 533a11ca7bSEugene Zhulenev using llvm::orc::MangleAndInterner; 54fe3594f7SNicolas Vasilache using llvm::orc::RTDyldObjectLinkingLayer; 553a11ca7bSEugene Zhulenev using llvm::orc::SymbolMap; 56fe3594f7SNicolas Vasilache using llvm::orc::ThreadSafeModule; 57fe3594f7SNicolas Vasilache using llvm::orc::TMOwningSimpleCompiler; 586aa5cc8bSNicolas Vasilache 592666b973SRiver Riddle /// Wrap a string into an llvm::StringError. 6002b6fb21SMehdi Amini static Error makeStringError(const Twine &message) { 61fe3594f7SNicolas Vasilache return llvm::make_error<StringError>(message.str(), 625a440378SAlex Zinenko llvm::inconvertibleErrorCode()); 635a440378SAlex Zinenko } 645a440378SAlex Zinenko 6502b6fb21SMehdi Amini void SimpleObjectCache::notifyObjectCompiled(const Module *m, 6602b6fb21SMehdi Amini MemoryBufferRef objBuffer) { 6702b6fb21SMehdi Amini cachedObjects[m->getModuleIdentifier()] = MemoryBuffer::getMemBufferCopy( 6802b6fb21SMehdi Amini objBuffer.getBuffer(), objBuffer.getBufferIdentifier()); 69fe3594f7SNicolas Vasilache } 70fe3594f7SNicolas Vasilache 7102b6fb21SMehdi Amini std::unique_ptr<MemoryBuffer> SimpleObjectCache::getObject(const Module *m) { 7202b6fb21SMehdi Amini auto i = cachedObjects.find(m->getModuleIdentifier()); 7302b6fb21SMehdi Amini if (i == cachedObjects.end()) { 7402b6fb21SMehdi Amini LLVM_DEBUG(dbgs() << "No object for " << m->getModuleIdentifier() 7553bb528bSMehdi Amini << " in cache. Compiling.\n"); 76fe3594f7SNicolas Vasilache return nullptr; 77fe3594f7SNicolas Vasilache } 7802b6fb21SMehdi Amini LLVM_DEBUG(dbgs() << "Object for " << m->getModuleIdentifier() 7953bb528bSMehdi Amini << " loaded from cache.\n"); 8002b6fb21SMehdi Amini return MemoryBuffer::getMemBuffer(i->second->getMemBufferRef()); 81fe3594f7SNicolas Vasilache } 82fe3594f7SNicolas Vasilache 834562e389SRiver Riddle void SimpleObjectCache::dumpToObjectFile(StringRef outputFilename) { 8406e81010SJacques Pienaar // Set up the output file. 8506e81010SJacques Pienaar std::string errorMessage; 8606e81010SJacques Pienaar auto file = openOutputFile(outputFilename, &errorMessage); 8706e81010SJacques Pienaar if (!file) { 8806e81010SJacques Pienaar llvm::errs() << errorMessage << "\n"; 8906e81010SJacques Pienaar return; 9006e81010SJacques Pienaar } 9106e81010SJacques Pienaar 9206e81010SJacques Pienaar // Dump the object generated for a single module to the output file. 9306e81010SJacques Pienaar assert(cachedObjects.size() == 1 && "Expected only one object entry."); 9406e81010SJacques Pienaar auto &cachedObject = cachedObjects.begin()->second; 9506e81010SJacques Pienaar file->os() << cachedObject->getBuffer(); 9606e81010SJacques Pienaar file->keep(); 9706e81010SJacques Pienaar } 9806e81010SJacques Pienaar 99a4ef4445SMehdi Amini bool SimpleObjectCache::isEmpty() { return cachedObjects.empty(); } 10095c083f5SDenys Shabalin 1014562e389SRiver Riddle void ExecutionEngine::dumpToObjectFile(StringRef filename) { 102b24de9f6SEmilio Cota if (cache == nullptr) { 103b24de9f6SEmilio Cota llvm::errs() << "cannot dump ExecutionEngine object code to file: " 104b24de9f6SEmilio Cota "object cache is disabled\n"; 105b24de9f6SEmilio Cota return; 106b24de9f6SEmilio Cota } 10795c083f5SDenys Shabalin // Compilation is lazy and it doesn't populate object cache unless requested. 10895c083f5SDenys Shabalin // In case object dump is requested before cache is populated, we need to 10995c083f5SDenys Shabalin // force compilation manually. 11095c083f5SDenys Shabalin if (cache->isEmpty()) { 11195c083f5SDenys Shabalin for (std::string &functionName : functionNames) { 11295c083f5SDenys Shabalin auto result = lookupPacked(functionName); 11395c083f5SDenys Shabalin if (!result) { 11495c083f5SDenys Shabalin llvm::errs() << "Could not compile " << functionName << ":\n " 11595c083f5SDenys Shabalin << result.takeError() << "\n"; 11695c083f5SDenys Shabalin return; 11795c083f5SDenys Shabalin } 11895c083f5SDenys Shabalin } 11995c083f5SDenys Shabalin } 12006e81010SJacques Pienaar cache->dumpToObjectFile(filename); 12106e81010SJacques Pienaar } 12206e81010SJacques Pienaar 1233a11ca7bSEugene Zhulenev void ExecutionEngine::registerSymbols( 1243a11ca7bSEugene Zhulenev llvm::function_ref<SymbolMap(MangleAndInterner)> symbolMap) { 1253a11ca7bSEugene Zhulenev auto &mainJitDylib = jit->getMainJITDylib(); 1263a11ca7bSEugene Zhulenev cantFail(mainJitDylib.define( 1273a11ca7bSEugene Zhulenev absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner( 1283a11ca7bSEugene Zhulenev mainJitDylib.getExecutionSession(), jit->getDataLayout()))))); 1293a11ca7bSEugene Zhulenev } 1303a11ca7bSEugene Zhulenev 131fb0b035eSAndrzej Warzynski void ExecutionEngine::setupTargetTripleAndDataLayout(Module *llvmModule, 132fb0b035eSAndrzej Warzynski llvm::TargetMachine *tm) { 133fb0b035eSAndrzej Warzynski llvmModule->setDataLayout(tm->createDataLayout()); 134fb0b035eSAndrzej Warzynski llvmModule->setTargetTriple(tm->getTargetTriple().getTriple()); 1355a440378SAlex Zinenko } 1365a440378SAlex Zinenko 1375a440378SAlex Zinenko static std::string makePackedFunctionName(StringRef name) { 1385a440378SAlex Zinenko return "_mlir_" + name.str(); 1395a440378SAlex Zinenko } 1405a440378SAlex Zinenko 1415a440378SAlex Zinenko // For each function in the LLVM module, define an interface function that wraps 1425a440378SAlex Zinenko // all the arguments of the original function and all its results into an i8** 1435a440378SAlex Zinenko // pointer to provide a unified invocation interface. 144df186507SBenjamin Kramer static void packFunctionArguments(Module *module) { 1455a440378SAlex Zinenko auto &ctx = module->getContext(); 1465a440378SAlex Zinenko llvm::IRBuilder<> builder(ctx); 1474562e389SRiver Riddle DenseSet<llvm::Function *> interfaceFunctions; 1485a440378SAlex Zinenko for (auto &func : module->getFunctionList()) { 1495a440378SAlex Zinenko if (func.isDeclaration()) { 1505a440378SAlex Zinenko continue; 1515a440378SAlex Zinenko } 1525a440378SAlex Zinenko if (interfaceFunctions.count(&func)) { 1535a440378SAlex Zinenko continue; 1545a440378SAlex Zinenko } 1555a440378SAlex Zinenko 1565a440378SAlex Zinenko // Given a function `foo(<...>)`, define the interface function 1575a440378SAlex Zinenko // `mlir_foo(i8**)`. 15820488362SJOE1994 auto *newType = 15920488362SJOE1994 llvm::FunctionType::get(builder.getVoidTy(), builder.getPtrTy(), 1605a440378SAlex Zinenko /*isVarArg=*/false); 1615a440378SAlex Zinenko auto newName = makePackedFunctionName(func.getName()); 162c46b0feaSRiver Riddle auto funcCst = module->getOrInsertFunction(newName, newType); 1634562e389SRiver Riddle llvm::Function *interfaceFunc = cast<llvm::Function>(funcCst.getCallee()); 1645a440378SAlex Zinenko interfaceFunctions.insert(interfaceFunc); 1655a440378SAlex Zinenko 1665a440378SAlex Zinenko // Extract the arguments from the type-erased argument list and cast them to 1675a440378SAlex Zinenko // the proper types. 16802b6fb21SMehdi Amini auto *bb = llvm::BasicBlock::Create(ctx); 1695a440378SAlex Zinenko bb->insertInto(interfaceFunc); 1705a440378SAlex Zinenko builder.SetInsertPoint(bb); 1715a440378SAlex Zinenko llvm::Value *argList = interfaceFunc->arg_begin(); 1724562e389SRiver Riddle SmallVector<llvm::Value *, 8> args; 1735a440378SAlex Zinenko args.reserve(llvm::size(func.args())); 1748c258fdaSJakub Kuderski for (auto [index, arg] : llvm::enumerate(func.args())) { 1755a440378SAlex Zinenko llvm::Value *argIndex = llvm::Constant::getIntegerValue( 1768c258fdaSJakub Kuderski builder.getInt64Ty(), APInt(64, index)); 177f1f5a85aSNicolas Vasilache llvm::Value *argPtrPtr = 178a3ef8589SFangrui Song builder.CreateGEP(builder.getPtrTy(), argList, argIndex); 179a3ef8589SFangrui Song llvm::Value *argPtr = builder.CreateLoad(builder.getPtrTy(), argPtrPtr); 1808c258fdaSJakub Kuderski llvm::Type *argTy = arg.getType(); 1818c258fdaSJakub Kuderski llvm::Value *load = builder.CreateLoad(argTy, argPtr); 1828c258fdaSJakub Kuderski args.push_back(load); 1835a440378SAlex Zinenko } 1845a440378SAlex Zinenko 1855a440378SAlex Zinenko // Call the implementation function with the extracted arguments. 1865a440378SAlex Zinenko llvm::Value *result = builder.CreateCall(&func, args); 1875a440378SAlex Zinenko 1885a440378SAlex Zinenko // Assuming the result is one value, potentially of type `void`. 1895a440378SAlex Zinenko if (!result->getType()->isVoidTy()) { 1905a440378SAlex Zinenko llvm::Value *retIndex = llvm::Constant::getIntegerValue( 1914562e389SRiver Riddle builder.getInt64Ty(), APInt(64, llvm::size(func.args()))); 1922c68ecccSNikita Popov llvm::Value *retPtrPtr = 193a3ef8589SFangrui Song builder.CreateGEP(builder.getPtrTy(), argList, retIndex); 194a3ef8589SFangrui Song llvm::Value *retPtr = builder.CreateLoad(builder.getPtrTy(), retPtrPtr); 1955a440378SAlex Zinenko builder.CreateStore(result, retPtr); 1965a440378SAlex Zinenko } 1975a440378SAlex Zinenko 1985a440378SAlex Zinenko // The interface function returns void. 1995a440378SAlex Zinenko builder.CreateRetVoid(); 2005a440378SAlex Zinenko } 2015a440378SAlex Zinenko } 2025a440378SAlex Zinenko 20395c083f5SDenys Shabalin ExecutionEngine::ExecutionEngine(bool enableObjectDump, 2043c5dd586SEugene Zhulenev bool enableGDBNotificationListener, 2053c5dd586SEugene Zhulenev bool enablePerfNotificationListener) 20695c083f5SDenys Shabalin : cache(enableObjectDump ? new SimpleObjectCache() : nullptr), 20795c083f5SDenys Shabalin functionNames(), 208d1186fcbSaartbik gdbListener(enableGDBNotificationListener 209d1186fcbSaartbik ? llvm::JITEventListener::createGDBRegistrationListener() 2103c5dd586SEugene Zhulenev : nullptr), 211f68ecdd4SNicolas Vasilache perfListener(nullptr) { 212f68ecdd4SNicolas Vasilache if (enablePerfNotificationListener) { 213f68ecdd4SNicolas Vasilache if (auto *listener = llvm::JITEventListener::createPerfJITEventListener()) 214f68ecdd4SNicolas Vasilache perfListener = listener; 215f68ecdd4SNicolas Vasilache else if (auto *listener = 216f68ecdd4SNicolas Vasilache llvm::JITEventListener::createIntelJITEventListener()) 217f68ecdd4SNicolas Vasilache perfListener = listener; 218f68ecdd4SNicolas Vasilache } 219f68ecdd4SNicolas Vasilache } 22006e81010SJacques Pienaar 2210b3841ebSIngo Müller ExecutionEngine::~ExecutionEngine() { 22201dbc5daSFabian Mora // Execute the global destructors from the module being processed. 22301dbc5daSFabian Mora // TODO: Allow JIT deinitialize for AArch64. Currently there's a bug causing a 22401dbc5daSFabian Mora // crash for AArch64 see related issue #71963. 22501dbc5daSFabian Mora if (jit && !jit->getTargetTriple().isAArch64()) 22601dbc5daSFabian Mora llvm::consumeError(jit->deinitialize(jit->getMainJITDylib())); 2270b3841ebSIngo Müller // Run all dynamic library destroy callbacks to prepare for the shutdown. 2280b3841ebSIngo Müller for (LibraryDestroyFn destroy : destroyFns) 2290b3841ebSIngo Müller destroy(); 2300b3841ebSIngo Müller } 2310b3841ebSIngo Müller 232a7db3c61SEmilio Cota Expected<std::unique_ptr<ExecutionEngine>> 233fb0b035eSAndrzej Warzynski ExecutionEngine::create(Operation *m, const ExecutionEngineOptions &options, 234fb0b035eSAndrzej Warzynski std::unique_ptr<llvm::TargetMachine> tm) { 235d1186fcbSaartbik auto engine = std::make_unique<ExecutionEngine>( 23695c083f5SDenys Shabalin options.enableObjectDump, options.enableGDBNotificationListener, 237a7db3c61SEmilio Cota options.enablePerfNotificationListener); 2385a440378SAlex Zinenko 23995c083f5SDenys Shabalin // Remember all entry-points if object dumping is enabled. 24095c083f5SDenys Shabalin if (options.enableObjectDump) { 24195c083f5SDenys Shabalin for (auto funcOp : m->getRegion(0).getOps<LLVM::LLVMFuncOp>()) { 24295c083f5SDenys Shabalin StringRef funcName = funcOp.getSymName(); 24395c083f5SDenys Shabalin engine->functionNames.push_back(funcName.str()); 24495c083f5SDenys Shabalin } 24595c083f5SDenys Shabalin } 24695c083f5SDenys Shabalin 247fe3594f7SNicolas Vasilache std::unique_ptr<llvm::LLVMContext> ctx(new llvm::LLVMContext); 248a7db3c61SEmilio Cota auto llvmModule = options.llvmModuleBuilder 249a7db3c61SEmilio Cota ? options.llvmModuleBuilder(m, *ctx) 25089808ce7SGeorge Mitenkov : translateModuleToLLVMIR(m, *ctx); 2515a440378SAlex Zinenko if (!llvmModule) 25202b6fb21SMehdi Amini return makeStringError("could not convert to LLVM IR"); 253fb0b035eSAndrzej Warzynski 254fb0b035eSAndrzej Warzynski // If no valid TargetMachine was passed, create a default TM ignoring any 255fb0b035eSAndrzej Warzynski // input arguments from the user. 256fb0b035eSAndrzej Warzynski if (!tm) { 257fb0b035eSAndrzej Warzynski auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost(); 258fb0b035eSAndrzej Warzynski if (!tmBuilderOrError) 259fb0b035eSAndrzej Warzynski return tmBuilderOrError.takeError(); 260fb0b035eSAndrzej Warzynski 261fb0b035eSAndrzej Warzynski auto tmOrError = tmBuilderOrError->createTargetMachine(); 262fb0b035eSAndrzej Warzynski if (!tmOrError) 263fb0b035eSAndrzej Warzynski return tmOrError.takeError(); 264fb0b035eSAndrzej Warzynski tm = std::move(tmOrError.get()); 265fb0b035eSAndrzej Warzynski } 266fb0b035eSAndrzej Warzynski 267fb0b035eSAndrzej Warzynski // TODO: Currently, the LLVM module created above has no triple associated 268fb0b035eSAndrzej Warzynski // with it. Instead, the triple is extracted from the TargetMachine, which is 269fb0b035eSAndrzej Warzynski // either based on the host defaults or command line arguments when specified 270fb0b035eSAndrzej Warzynski // (set-up by callers of this method). It could also be passed to the 271fb0b035eSAndrzej Warzynski // translation or dialect conversion instead of this. 272fb0b035eSAndrzej Warzynski setupTargetTripleAndDataLayout(llvmModule.get(), tm.get()); 2735a440378SAlex Zinenko packFunctionArguments(llvmModule.get()); 2745a440378SAlex Zinenko 275db1c197bSAlex Zinenko auto dataLayout = llvmModule->getDataLayout(); 276fe3594f7SNicolas Vasilache 2770b3841ebSIngo Müller // Use absolute library path so that gdb can find the symbol table. 2780b3841ebSIngo Müller SmallVector<SmallString<256>, 4> sharedLibPaths; 2790b3841ebSIngo Müller transform( 2800b3841ebSIngo Müller options.sharedLibPaths, std::back_inserter(sharedLibPaths), 2810b3841ebSIngo Müller [](StringRef libPath) { 2820b3841ebSIngo Müller SmallString<256> absPath(libPath.begin(), libPath.end()); 2830b3841ebSIngo Müller cantFail(llvm::errorCodeToError(llvm::sys::fs::make_absolute(absPath))); 2840b3841ebSIngo Müller return absPath; 2850b3841ebSIngo Müller }); 2860b3841ebSIngo Müller 2870eb0fecbSIngo Müller // If shared library implements custom execution layer library init and 2880eb0fecbSIngo Müller // destroy functions, we'll use them to register the library. Otherwise, load 2890eb0fecbSIngo Müller // the library as JITDyLib below. 2900eb0fecbSIngo Müller llvm::StringMap<void *> exportSymbols; 2910eb0fecbSIngo Müller SmallVector<LibraryDestroyFn> destroyFns; 2920eb0fecbSIngo Müller SmallVector<StringRef> jitDyLibPaths; 2930eb0fecbSIngo Müller 2940eb0fecbSIngo Müller for (auto &libPath : sharedLibPaths) { 2950eb0fecbSIngo Müller auto lib = llvm::sys::DynamicLibrary::getPermanentLibrary( 2960eb0fecbSIngo Müller libPath.str().str().c_str()); 2970eb0fecbSIngo Müller void *initSym = lib.getAddressOfSymbol(kLibraryInitFnName); 2980eb0fecbSIngo Müller void *destroySim = lib.getAddressOfSymbol(kLibraryDestroyFnName); 2990eb0fecbSIngo Müller 3000eb0fecbSIngo Müller // Library does not provide call backs, rely on symbol visiblity. 3010eb0fecbSIngo Müller if (!initSym || !destroySim) { 3020eb0fecbSIngo Müller jitDyLibPaths.push_back(libPath); 3030eb0fecbSIngo Müller continue; 3040eb0fecbSIngo Müller } 3050eb0fecbSIngo Müller 3060eb0fecbSIngo Müller auto initFn = reinterpret_cast<LibraryInitFn>(initSym); 3070eb0fecbSIngo Müller initFn(exportSymbols); 3080eb0fecbSIngo Müller 3090eb0fecbSIngo Müller auto destroyFn = reinterpret_cast<LibraryDestroyFn>(destroySim); 3100eb0fecbSIngo Müller destroyFns.push_back(destroyFn); 3110eb0fecbSIngo Müller } 3120eb0fecbSIngo Müller engine->destroyFns = std::move(destroyFns); 3130eb0fecbSIngo Müller 314fe3594f7SNicolas Vasilache // Callback to create the object layer with symbol resolution to current 315fe3594f7SNicolas Vasilache // process and dynamically linked libraries. 316fe3594f7SNicolas Vasilache auto objectLinkingLayerCreator = [&](ExecutionSession &session, 31702b6fb21SMehdi Amini const Triple &tt) { 318fe3594f7SNicolas Vasilache auto objectLayer = std::make_unique<RTDyldObjectLinkingLayer>( 319011f6532SEmilio Cota session, [sectionMemoryMapper = options.sectionMemoryMapper]() { 320011f6532SEmilio Cota return std::make_unique<SectionMemoryManager>(sectionMemoryMapper); 321011f6532SEmilio Cota }); 3223c5dd586SEugene Zhulenev 3233c5dd586SEugene Zhulenev // Register JIT event listeners if they are enabled. 3243c5dd586SEugene Zhulenev if (engine->gdbListener) 3253c5dd586SEugene Zhulenev objectLayer->registerJITEventListener(*engine->gdbListener); 3263c5dd586SEugene Zhulenev if (engine->perfListener) 3273c5dd586SEugene Zhulenev objectLayer->registerJITEventListener(*engine->perfListener); 328fe3594f7SNicolas Vasilache 3293c4cdd0bSKern Handa // COFF format binaries (Windows) need special handling to deal with 3303c4cdd0bSKern Handa // exported symbol visibility. 3313c4cdd0bSKern Handa // cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp LLJIT::createObjectLinkingLayer 3323c4cdd0bSKern Handa llvm::Triple targetTriple(llvm::Twine(llvmModule->getTargetTriple())); 3333c4cdd0bSKern Handa if (targetTriple.isOSBinFormatCOFF()) { 3343c4cdd0bSKern Handa objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); 3353c4cdd0bSKern Handa objectLayer->setAutoClaimResponsibilityForObjectSymbols(true); 3363c4cdd0bSKern Handa } 3373c4cdd0bSKern Handa 338fe3594f7SNicolas Vasilache // Resolve symbols from shared libraries. 3390eb0fecbSIngo Müller for (auto &libPath : jitDyLibPaths) { 340fe3594f7SNicolas Vasilache auto mb = llvm::MemoryBuffer::getFile(libPath); 341fe3594f7SNicolas Vasilache if (!mb) { 342670063ebSAden Grue errs() << "Failed to create MemoryBuffer for: " << libPath 343670063ebSAden Grue << "\nError: " << mb.getError().message() << "\n"; 344fe3594f7SNicolas Vasilache continue; 345fe3594f7SNicolas Vasilache } 34602b6fb21SMehdi Amini auto &jd = session.createBareJITDylib(std::string(libPath)); 347fe3594f7SNicolas Vasilache auto loaded = DynamicLibrarySearchGenerator::Load( 3480eb0fecbSIngo Müller libPath.str().c_str(), dataLayout.getGlobalPrefix()); 349fe3594f7SNicolas Vasilache if (!loaded) { 350e38fe4a7SChristian Sigg errs() << "Could not load " << libPath << ":\n " << loaded.takeError() 351e38fe4a7SChristian Sigg << "\n"; 352fe3594f7SNicolas Vasilache continue; 353fe3594f7SNicolas Vasilache } 35402b6fb21SMehdi Amini jd.addGenerator(std::move(*loaded)); 35502b6fb21SMehdi Amini cantFail(objectLayer->add(jd, std::move(mb.get()))); 356fe3594f7SNicolas Vasilache } 357fe3594f7SNicolas Vasilache 358fe3594f7SNicolas Vasilache return objectLayer; 359fe3594f7SNicolas Vasilache }; 360fe3594f7SNicolas Vasilache 361fe3594f7SNicolas Vasilache // Callback to inspect the cache and recompile on demand. This follows Lang's 362fe3594f7SNicolas Vasilache // LLJITWithObjectCache example. 36302b6fb21SMehdi Amini auto compileFunctionCreator = [&](JITTargetMachineBuilder jtmb) 3647984b474SAlex Zinenko -> Expected<std::unique_ptr<IRCompileLayer::IRCompiler>> { 365a7db3c61SEmilio Cota if (options.jitCodeGenOptLevel) 3666d5fc1e3SKazu Hirata jtmb.setCodeGenOptLevel(*options.jitCodeGenOptLevel); 367fb0b035eSAndrzej Warzynski return std::make_unique<TMOwningSimpleCompiler>(std::move(tm), 3687984b474SAlex Zinenko engine->cache.get()); 369fe3594f7SNicolas Vasilache }; 370fe3594f7SNicolas Vasilache 371fe3594f7SNicolas Vasilache // Create the LLJIT by calling the LLJITBuilder with 2 callbacks. 372fe3594f7SNicolas Vasilache auto jit = 373fe3594f7SNicolas Vasilache cantFail(llvm::orc::LLJITBuilder() 374fe3594f7SNicolas Vasilache .setCompileFunctionCreator(compileFunctionCreator) 375fe3594f7SNicolas Vasilache .setObjectLinkingLayerCreator(objectLinkingLayerCreator) 376fb0b035eSAndrzej Warzynski .setDataLayout(dataLayout) 377fe3594f7SNicolas Vasilache .create()); 378fe3594f7SNicolas Vasilache 379fe3594f7SNicolas Vasilache // Add a ThreadSafemodule to the engine and return. 380db1c197bSAlex Zinenko ThreadSafeModule tsm(std::move(llvmModule), std::move(ctx)); 381a7db3c61SEmilio Cota if (options.transformer) 382cf26e5faSNicolas Vasilache cantFail(tsm.withModuleDo( 383a7db3c61SEmilio Cota [&](llvm::Module &module) { return options.transformer(&module); })); 384fe3594f7SNicolas Vasilache cantFail(jit->addIRModule(std::move(tsm))); 385fe3594f7SNicolas Vasilache engine->jit = std::move(jit); 3865a440378SAlex Zinenko 3876d60d869SRiver Riddle // Resolve symbols that are statically linked in the current process. 3886d60d869SRiver Riddle llvm::orc::JITDylib &mainJD = engine->jit->getMainJITDylib(); 3896d60d869SRiver Riddle mainJD.addGenerator( 3906d60d869SRiver Riddle cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( 3916d60d869SRiver Riddle dataLayout.getGlobalPrefix()))); 3926d60d869SRiver Riddle 3930b3841ebSIngo Müller // Build a runtime symbol map from the exported symbols and register them. 3940b3841ebSIngo Müller auto runtimeSymbolMap = [&](llvm::orc::MangleAndInterner interner) { 3950b3841ebSIngo Müller auto symbolMap = llvm::orc::SymbolMap(); 3960b3841ebSIngo Müller for (auto &exportSymbol : exportSymbols) 3970b3841ebSIngo Müller symbolMap[interner(exportSymbol.getKey())] = { 3980b3841ebSIngo Müller llvm::orc::ExecutorAddr::fromPtr(exportSymbol.getValue()), 3990b3841ebSIngo Müller llvm::JITSymbolFlags::Exported}; 4000b3841ebSIngo Müller return symbolMap; 4010b3841ebSIngo Müller }; 4020b3841ebSIngo Müller engine->registerSymbols(runtimeSymbolMap); 4030b3841ebSIngo Müller 40401dbc5daSFabian Mora // Execute the global constructors from the module being processed. 40501dbc5daSFabian Mora // TODO: Allow JIT initialize for AArch64. Currently there's a bug causing a 40601dbc5daSFabian Mora // crash for AArch64 see related issue #71963. 40701dbc5daSFabian Mora if (!engine->jit->getTargetTriple().isAArch64()) 40801dbc5daSFabian Mora cantFail(engine->jit->initialize(engine->jit->getMainJITDylib())); 40901dbc5daSFabian Mora 410e7111fd6SJacques Pienaar return std::move(engine); 4115a440378SAlex Zinenko } 4125a440378SAlex Zinenko 413106f3074STres Popp Expected<void (*)(void **)> 414106f3074STres Popp ExecutionEngine::lookupPacked(StringRef name) const { 415106f3074STres Popp auto result = lookup(makePackedFunctionName(name)); 416106f3074STres Popp if (!result) 417106f3074STres Popp return result.takeError(); 418106f3074STres Popp return reinterpret_cast<void (*)(void **)>(result.get()); 419106f3074STres Popp } 420106f3074STres Popp 421106f3074STres Popp Expected<void *> ExecutionEngine::lookup(StringRef name) const { 422106f3074STres Popp auto expectedSymbol = jit->lookup(name); 423d7fbfbb1SAlex Zinenko 424d7fbfbb1SAlex Zinenko // JIT lookup may return an Error referring to strings stored internally by 425d7fbfbb1SAlex Zinenko // the JIT. If the Error outlives the ExecutionEngine, it would want have a 426d7fbfbb1SAlex Zinenko // dangling reference, which is currently caught by an assertion inside JIT 427d7fbfbb1SAlex Zinenko // thanks to hand-rolled reference counting. Rewrap the error message into a 428d7fbfbb1SAlex Zinenko // string before returning. Alternatively, ORC JIT should consider copying 429d7fbfbb1SAlex Zinenko // the string into the error message. 430d7fbfbb1SAlex Zinenko if (!expectedSymbol) { 431d7fbfbb1SAlex Zinenko std::string errorMessage; 432d7fbfbb1SAlex Zinenko llvm::raw_string_ostream os(errorMessage); 433d7fbfbb1SAlex Zinenko llvm::handleAllErrors(expectedSymbol.takeError(), 434d7fbfbb1SAlex Zinenko [&os](llvm::ErrorInfoBase &ei) { ei.log(os); }); 435*884221edSJOE1994 return makeStringError(errorMessage); 436d7fbfbb1SAlex Zinenko } 437d7fbfbb1SAlex Zinenko 4388bb5b657SRiver Riddle if (void *fptr = expectedSymbol->toPtr<void *>()) 4395a440378SAlex Zinenko return fptr; 4408bb5b657SRiver Riddle return makeStringError("looked up function is null"); 4415a440378SAlex Zinenko } 442629f5b7fSNicolas Vasilache 443d6efb6fcSMehdi Amini Error ExecutionEngine::invokePacked(StringRef name, 444d6efb6fcSMehdi Amini MutableArrayRef<void *> args) { 445106f3074STres Popp auto expectedFPtr = lookupPacked(name); 446629f5b7fSNicolas Vasilache if (!expectedFPtr) 447629f5b7fSNicolas Vasilache return expectedFPtr.takeError(); 448629f5b7fSNicolas Vasilache auto fptr = *expectedFPtr; 449629f5b7fSNicolas Vasilache 450629f5b7fSNicolas Vasilache (*fptr)(args.data()); 451629f5b7fSNicolas Vasilache 452fe3594f7SNicolas Vasilache return Error::success(); 453629f5b7fSNicolas Vasilache } 454