xref: /llvm-project/mlir/lib/ExecutionEngine/ExecutionEngine.cpp (revision 884221eddb9d395830704fac79fd04008e02e368)
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