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"
15*65fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h"
1606e81010SJacques Pienaar #include "mlir/Support/FileUtilities.h"
175a440378SAlex Zinenko #include "mlir/Target/LLVMIR.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/ExecutionEngine/SectionMemoryManager.h"
285a440378SAlex Zinenko #include "llvm/IR/IRBuilder.h"
299f2ce5b9SHaruki Imai #include "llvm/MC/SubtargetFeature.h"
3053bb528bSMehdi Amini #include "llvm/Support/Debug.h"
315a440378SAlex Zinenko #include "llvm/Support/Error.h"
3290dbec26SMehdi Amini #include "llvm/Support/Host.h"
335a440378SAlex Zinenko #include "llvm/Support/TargetRegistry.h"
3406e81010SJacques Pienaar #include "llvm/Support/ToolOutputFile.h"
355a440378SAlex Zinenko 
3653bb528bSMehdi Amini #define DEBUG_TYPE "execution-engine"
3753bb528bSMehdi Amini 
385a440378SAlex Zinenko using namespace mlir;
39fe3594f7SNicolas Vasilache using llvm::dbgs;
405a440378SAlex Zinenko using llvm::Error;
41fe3594f7SNicolas Vasilache using llvm::errs;
425a440378SAlex Zinenko using llvm::Expected;
43fe3594f7SNicolas Vasilache using llvm::LLVMContext;
44fe3594f7SNicolas Vasilache using llvm::MemoryBuffer;
45fe3594f7SNicolas Vasilache using llvm::MemoryBufferRef;
46fe3594f7SNicolas Vasilache using llvm::Module;
47fe3594f7SNicolas Vasilache using llvm::SectionMemoryManager;
48fe3594f7SNicolas Vasilache using llvm::StringError;
49fe3594f7SNicolas Vasilache using llvm::Triple;
50fe3594f7SNicolas Vasilache using llvm::orc::DynamicLibrarySearchGenerator;
51fe3594f7SNicolas Vasilache using llvm::orc::ExecutionSession;
52fe3594f7SNicolas Vasilache using llvm::orc::IRCompileLayer;
53fe3594f7SNicolas Vasilache using llvm::orc::JITTargetMachineBuilder;
543a11ca7bSEugene Zhulenev using llvm::orc::MangleAndInterner;
55fe3594f7SNicolas Vasilache using llvm::orc::RTDyldObjectLinkingLayer;
563a11ca7bSEugene Zhulenev using llvm::orc::SymbolMap;
57fe3594f7SNicolas Vasilache using llvm::orc::ThreadSafeModule;
58fe3594f7SNicolas Vasilache using llvm::orc::TMOwningSimpleCompiler;
596aa5cc8bSNicolas Vasilache 
602666b973SRiver Riddle /// Wrap a string into an llvm::StringError.
612666b973SRiver Riddle static Error make_string_error(const Twine &message) {
62fe3594f7SNicolas Vasilache   return llvm::make_error<StringError>(message.str(),
635a440378SAlex Zinenko                                        llvm::inconvertibleErrorCode());
645a440378SAlex Zinenko }
655a440378SAlex Zinenko 
66fe3594f7SNicolas Vasilache void SimpleObjectCache::notifyObjectCompiled(const Module *M,
67fe3594f7SNicolas Vasilache                                              MemoryBufferRef ObjBuffer) {
6806e81010SJacques Pienaar   cachedObjects[M->getModuleIdentifier()] = MemoryBuffer::getMemBufferCopy(
69fe3594f7SNicolas Vasilache       ObjBuffer.getBuffer(), ObjBuffer.getBufferIdentifier());
70fe3594f7SNicolas Vasilache }
71fe3594f7SNicolas Vasilache 
72fe3594f7SNicolas Vasilache std::unique_ptr<MemoryBuffer> SimpleObjectCache::getObject(const Module *M) {
7306e81010SJacques Pienaar   auto I = cachedObjects.find(M->getModuleIdentifier());
7406e81010SJacques Pienaar   if (I == cachedObjects.end()) {
7553bb528bSMehdi Amini     LLVM_DEBUG(dbgs() << "No object for " << M->getModuleIdentifier()
7653bb528bSMehdi Amini                       << " in cache. Compiling.\n");
77fe3594f7SNicolas Vasilache     return nullptr;
78fe3594f7SNicolas Vasilache   }
7953bb528bSMehdi Amini   LLVM_DEBUG(dbgs() << "Object for " << M->getModuleIdentifier()
8053bb528bSMehdi Amini                     << " loaded from cache.\n");
81fe3594f7SNicolas Vasilache   return MemoryBuffer::getMemBuffer(I->second->getMemBufferRef());
82fe3594f7SNicolas Vasilache }
83fe3594f7SNicolas Vasilache 
844562e389SRiver Riddle void SimpleObjectCache::dumpToObjectFile(StringRef outputFilename) {
8506e81010SJacques Pienaar   // Set up the output file.
8606e81010SJacques Pienaar   std::string errorMessage;
8706e81010SJacques Pienaar   auto file = openOutputFile(outputFilename, &errorMessage);
8806e81010SJacques Pienaar   if (!file) {
8906e81010SJacques Pienaar     llvm::errs() << errorMessage << "\n";
9006e81010SJacques Pienaar     return;
9106e81010SJacques Pienaar   }
9206e81010SJacques Pienaar 
9306e81010SJacques Pienaar   // Dump the object generated for a single module to the output file.
9406e81010SJacques Pienaar   assert(cachedObjects.size() == 1 && "Expected only one object entry.");
9506e81010SJacques Pienaar   auto &cachedObject = cachedObjects.begin()->second;
9606e81010SJacques Pienaar   file->os() << cachedObject->getBuffer();
9706e81010SJacques Pienaar   file->keep();
9806e81010SJacques Pienaar }
9906e81010SJacques Pienaar 
1004562e389SRiver Riddle void ExecutionEngine::dumpToObjectFile(StringRef filename) {
10106e81010SJacques Pienaar   cache->dumpToObjectFile(filename);
10206e81010SJacques Pienaar }
10306e81010SJacques Pienaar 
1043a11ca7bSEugene Zhulenev void ExecutionEngine::registerSymbols(
1053a11ca7bSEugene Zhulenev     llvm::function_ref<SymbolMap(MangleAndInterner)> symbolMap) {
1063a11ca7bSEugene Zhulenev   auto &mainJitDylib = jit->getMainJITDylib();
1073a11ca7bSEugene Zhulenev   cantFail(mainJitDylib.define(
1083a11ca7bSEugene Zhulenev       absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner(
1093a11ca7bSEugene Zhulenev           mainJitDylib.getExecutionSession(), jit->getDataLayout())))));
1103a11ca7bSEugene Zhulenev }
1113a11ca7bSEugene Zhulenev 
1125a440378SAlex Zinenko // Setup LLVM target triple from the current machine.
113fe3594f7SNicolas Vasilache bool ExecutionEngine::setupTargetTriple(Module *llvmModule) {
1145a440378SAlex Zinenko   // Setup the machine properties from the current architecture.
1155a440378SAlex Zinenko   auto targetTriple = llvm::sys::getDefaultTargetTriple();
1165a440378SAlex Zinenko   std::string errorMessage;
1175a440378SAlex Zinenko   auto target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
1185a440378SAlex Zinenko   if (!target) {
119fe3594f7SNicolas Vasilache     errs() << "NO target: " << errorMessage << "\n";
1205a440378SAlex Zinenko     return true;
1215a440378SAlex Zinenko   }
1229f2ce5b9SHaruki Imai 
1239f2ce5b9SHaruki Imai   std::string cpu(llvm::sys::getHostCPUName());
1249f2ce5b9SHaruki Imai   llvm::SubtargetFeatures features;
1259f2ce5b9SHaruki Imai   llvm::StringMap<bool> hostFeatures;
1269f2ce5b9SHaruki Imai 
1279f2ce5b9SHaruki Imai   if (llvm::sys::getHostCPUFeatures(hostFeatures))
1289f2ce5b9SHaruki Imai     for (auto &f : hostFeatures)
1299f2ce5b9SHaruki Imai       features.AddFeature(f.first(), f.second);
1309f2ce5b9SHaruki Imai 
1319f2ce5b9SHaruki Imai   std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
1329f2ce5b9SHaruki Imai       targetTriple, cpu, features.getString(), {}, {}));
1335a440378SAlex Zinenko   llvmModule->setDataLayout(machine->createDataLayout());
1345a440378SAlex Zinenko   llvmModule->setTargetTriple(targetTriple);
1355a440378SAlex Zinenko   return false;
1365a440378SAlex Zinenko }
1375a440378SAlex Zinenko 
1385a440378SAlex Zinenko static std::string makePackedFunctionName(StringRef name) {
1395a440378SAlex Zinenko   return "_mlir_" + name.str();
1405a440378SAlex Zinenko }
1415a440378SAlex Zinenko 
1425a440378SAlex Zinenko // For each function in the LLVM module, define an interface function that wraps
1435a440378SAlex Zinenko // all the arguments of the original function and all its results into an i8**
1445a440378SAlex Zinenko // pointer to provide a unified invocation interface.
145df186507SBenjamin Kramer static void packFunctionArguments(Module *module) {
1465a440378SAlex Zinenko   auto &ctx = module->getContext();
1475a440378SAlex Zinenko   llvm::IRBuilder<> builder(ctx);
1484562e389SRiver Riddle   DenseSet<llvm::Function *> interfaceFunctions;
1495a440378SAlex Zinenko   for (auto &func : module->getFunctionList()) {
1505a440378SAlex Zinenko     if (func.isDeclaration()) {
1515a440378SAlex Zinenko       continue;
1525a440378SAlex Zinenko     }
1535a440378SAlex Zinenko     if (interfaceFunctions.count(&func)) {
1545a440378SAlex Zinenko       continue;
1555a440378SAlex Zinenko     }
1565a440378SAlex Zinenko 
1575a440378SAlex Zinenko     // Given a function `foo(<...>)`, define the interface function
1585a440378SAlex Zinenko     // `mlir_foo(i8**)`.
1595a440378SAlex Zinenko     auto newType = llvm::FunctionType::get(
1605a440378SAlex Zinenko         builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(),
1615a440378SAlex Zinenko         /*isVarArg=*/false);
1625a440378SAlex Zinenko     auto newName = makePackedFunctionName(func.getName());
163c46b0feaSRiver Riddle     auto funcCst = module->getOrInsertFunction(newName, newType);
1644562e389SRiver Riddle     llvm::Function *interfaceFunc = cast<llvm::Function>(funcCst.getCallee());
1655a440378SAlex Zinenko     interfaceFunctions.insert(interfaceFunc);
1665a440378SAlex Zinenko 
1675a440378SAlex Zinenko     // Extract the arguments from the type-erased argument list and cast them to
1685a440378SAlex Zinenko     // the proper types.
1695a440378SAlex Zinenko     auto bb = llvm::BasicBlock::Create(ctx);
1705a440378SAlex Zinenko     bb->insertInto(interfaceFunc);
1715a440378SAlex Zinenko     builder.SetInsertPoint(bb);
1725a440378SAlex Zinenko     llvm::Value *argList = interfaceFunc->arg_begin();
1734562e389SRiver Riddle     SmallVector<llvm::Value *, 8> args;
1745a440378SAlex Zinenko     args.reserve(llvm::size(func.args()));
1755a440378SAlex Zinenko     for (auto &indexedArg : llvm::enumerate(func.args())) {
1765a440378SAlex Zinenko       llvm::Value *argIndex = llvm::Constant::getIntegerValue(
1774562e389SRiver Riddle           builder.getInt64Ty(), APInt(64, indexedArg.index()));
1785a440378SAlex Zinenko       llvm::Value *argPtrPtr = builder.CreateGEP(argList, argIndex);
1795a440378SAlex Zinenko       llvm::Value *argPtr = builder.CreateLoad(argPtrPtr);
1805a440378SAlex Zinenko       argPtr = builder.CreateBitCast(
1815a440378SAlex Zinenko           argPtr, indexedArg.value().getType()->getPointerTo());
1825a440378SAlex Zinenko       llvm::Value *arg = builder.CreateLoad(argPtr);
1835a440378SAlex Zinenko       args.push_back(arg);
1845a440378SAlex Zinenko     }
1855a440378SAlex Zinenko 
1865a440378SAlex Zinenko     // Call the implementation function with the extracted arguments.
1875a440378SAlex Zinenko     llvm::Value *result = builder.CreateCall(&func, args);
1885a440378SAlex Zinenko 
1895a440378SAlex Zinenko     // Assuming the result is one value, potentially of type `void`.
1905a440378SAlex Zinenko     if (!result->getType()->isVoidTy()) {
1915a440378SAlex Zinenko       llvm::Value *retIndex = llvm::Constant::getIntegerValue(
1924562e389SRiver Riddle           builder.getInt64Ty(), APInt(64, llvm::size(func.args())));
1935a440378SAlex Zinenko       llvm::Value *retPtrPtr = builder.CreateGEP(argList, retIndex);
1945a440378SAlex Zinenko       llvm::Value *retPtr = builder.CreateLoad(retPtrPtr);
1955a440378SAlex Zinenko       retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo());
1965a440378SAlex Zinenko       builder.CreateStore(result, retPtr);
1975a440378SAlex Zinenko     }
1985a440378SAlex Zinenko 
1995a440378SAlex Zinenko     // The interface function returns void.
2005a440378SAlex Zinenko     builder.CreateRetVoid();
2015a440378SAlex Zinenko   }
2025a440378SAlex Zinenko }
2035a440378SAlex Zinenko 
204d1186fcbSaartbik ExecutionEngine::ExecutionEngine(bool enableObjectCache,
2053c5dd586SEugene Zhulenev                                  bool enableGDBNotificationListener,
2063c5dd586SEugene Zhulenev                                  bool enablePerfNotificationListener)
207d1186fcbSaartbik     : cache(enableObjectCache ? new SimpleObjectCache() : nullptr),
208d1186fcbSaartbik       gdbListener(enableGDBNotificationListener
209d1186fcbSaartbik                       ? llvm::JITEventListener::createGDBRegistrationListener()
2103c5dd586SEugene Zhulenev                       : nullptr),
2113c5dd586SEugene Zhulenev       perfListener(enablePerfNotificationListener
2123c5dd586SEugene Zhulenev                        ? llvm::JITEventListener::createPerfJITEventListener()
213d1186fcbSaartbik                        : nullptr) {}
21406e81010SJacques Pienaar 
21506e81010SJacques Pienaar Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
21689808ce7SGeorge Mitenkov     ModuleOp m,
21789808ce7SGeorge Mitenkov     llvm::function_ref<std::unique_ptr<llvm::Module>(ModuleOp,
21889808ce7SGeorge Mitenkov                                                      llvm::LLVMContext &)>
21989808ce7SGeorge Mitenkov         llvmModuleBuilder,
22089808ce7SGeorge Mitenkov     llvm::function_ref<Error(llvm::Module *)> transformer,
221713ab0ddSUday Bondhugula     Optional<llvm::CodeGenOpt::Level> jitCodeGenOptLevel,
222d1186fcbSaartbik     ArrayRef<StringRef> sharedLibPaths, bool enableObjectCache,
2233c5dd586SEugene Zhulenev     bool enableGDBNotificationListener, bool enablePerfNotificationListener) {
224d1186fcbSaartbik   auto engine = std::make_unique<ExecutionEngine>(
2253c5dd586SEugene Zhulenev       enableObjectCache, enableGDBNotificationListener,
2263c5dd586SEugene Zhulenev       enablePerfNotificationListener);
2275a440378SAlex Zinenko 
228fe3594f7SNicolas Vasilache   std::unique_ptr<llvm::LLVMContext> ctx(new llvm::LLVMContext);
22989808ce7SGeorge Mitenkov   auto llvmModule = llvmModuleBuilder ? llvmModuleBuilder(m, *ctx)
23089808ce7SGeorge Mitenkov                                       : translateModuleToLLVMIR(m, *ctx);
2315a440378SAlex Zinenko   if (!llvmModule)
2325a440378SAlex Zinenko     return make_string_error("could not convert to LLVM IR");
2335a440378SAlex Zinenko   // FIXME: the triple should be passed to the translation or dialect conversion
2345a440378SAlex Zinenko   // instead of this.  Currently, the LLVM module created above has no triple
2355a440378SAlex Zinenko   // associated with it.
2365a440378SAlex Zinenko   setupTargetTriple(llvmModule.get());
2375a440378SAlex Zinenko   packFunctionArguments(llvmModule.get());
2385a440378SAlex Zinenko 
239db1c197bSAlex Zinenko   auto dataLayout = llvmModule->getDataLayout();
240fe3594f7SNicolas Vasilache 
241fe3594f7SNicolas Vasilache   // Callback to create the object layer with symbol resolution to current
242fe3594f7SNicolas Vasilache   // process and dynamically linked libraries.
243fe3594f7SNicolas Vasilache   auto objectLinkingLayerCreator = [&](ExecutionSession &session,
244fe3594f7SNicolas Vasilache                                        const Triple &TT) {
245fe3594f7SNicolas Vasilache     auto objectLayer = std::make_unique<RTDyldObjectLinkingLayer>(
246fe3594f7SNicolas Vasilache         session, []() { return std::make_unique<SectionMemoryManager>(); });
2473c5dd586SEugene Zhulenev 
2483c5dd586SEugene Zhulenev     // Register JIT event listeners if they are enabled.
2493c5dd586SEugene Zhulenev     if (engine->gdbListener)
2503c5dd586SEugene Zhulenev       objectLayer->registerJITEventListener(*engine->gdbListener);
2513c5dd586SEugene Zhulenev     if (engine->perfListener)
2523c5dd586SEugene Zhulenev       objectLayer->registerJITEventListener(*engine->perfListener);
253fe3594f7SNicolas Vasilache 
254fe3594f7SNicolas Vasilache     // Resolve symbols from shared libraries.
255fe3594f7SNicolas Vasilache     for (auto libPath : sharedLibPaths) {
256fe3594f7SNicolas Vasilache       auto mb = llvm::MemoryBuffer::getFile(libPath);
257fe3594f7SNicolas Vasilache       if (!mb) {
258670063ebSAden Grue         errs() << "Failed to create MemoryBuffer for: " << libPath
259670063ebSAden Grue                << "\nError: " << mb.getError().message() << "\n";
260fe3594f7SNicolas Vasilache         continue;
261fe3594f7SNicolas Vasilache       }
262a7504226SRiver Riddle       auto &JD = session.createBareJITDylib(std::string(libPath));
263fe3594f7SNicolas Vasilache       auto loaded = DynamicLibrarySearchGenerator::Load(
264fe3594f7SNicolas Vasilache           libPath.data(), dataLayout.getGlobalPrefix());
265fe3594f7SNicolas Vasilache       if (!loaded) {
266e38fe4a7SChristian Sigg         errs() << "Could not load " << libPath << ":\n  " << loaded.takeError()
267e38fe4a7SChristian Sigg                << "\n";
268fe3594f7SNicolas Vasilache         continue;
269fe3594f7SNicolas Vasilache       }
270fe3594f7SNicolas Vasilache       JD.addGenerator(std::move(*loaded));
271fe3594f7SNicolas Vasilache       cantFail(objectLayer->add(JD, std::move(mb.get())));
272fe3594f7SNicolas Vasilache     }
273fe3594f7SNicolas Vasilache 
274fe3594f7SNicolas Vasilache     return objectLayer;
275fe3594f7SNicolas Vasilache   };
276fe3594f7SNicolas Vasilache 
277fe3594f7SNicolas Vasilache   // Callback to inspect the cache and recompile on demand. This follows Lang's
278fe3594f7SNicolas Vasilache   // LLJITWithObjectCache example.
279fe3594f7SNicolas Vasilache   auto compileFunctionCreator = [&](JITTargetMachineBuilder JTMB)
2807984b474SAlex Zinenko       -> Expected<std::unique_ptr<IRCompileLayer::IRCompiler>> {
281713ab0ddSUday Bondhugula     if (jitCodeGenOptLevel)
282713ab0ddSUday Bondhugula       JTMB.setCodeGenOptLevel(jitCodeGenOptLevel.getValue());
283fe3594f7SNicolas Vasilache     auto TM = JTMB.createTargetMachine();
284fe3594f7SNicolas Vasilache     if (!TM)
285fe3594f7SNicolas Vasilache       return TM.takeError();
2867984b474SAlex Zinenko     return std::make_unique<TMOwningSimpleCompiler>(std::move(*TM),
2877984b474SAlex Zinenko                                                     engine->cache.get());
288fe3594f7SNicolas Vasilache   };
289fe3594f7SNicolas Vasilache 
290fe3594f7SNicolas Vasilache   // Create the LLJIT by calling the LLJITBuilder with 2 callbacks.
291fe3594f7SNicolas Vasilache   auto jit =
292fe3594f7SNicolas Vasilache       cantFail(llvm::orc::LLJITBuilder()
293fe3594f7SNicolas Vasilache                    .setCompileFunctionCreator(compileFunctionCreator)
294fe3594f7SNicolas Vasilache                    .setObjectLinkingLayerCreator(objectLinkingLayerCreator)
295fe3594f7SNicolas Vasilache                    .create());
296fe3594f7SNicolas Vasilache 
297fe3594f7SNicolas Vasilache   // Add a ThreadSafemodule to the engine and return.
298db1c197bSAlex Zinenko   ThreadSafeModule tsm(std::move(llvmModule), std::move(ctx));
299cf26e5faSNicolas Vasilache   if (transformer)
300cf26e5faSNicolas Vasilache     cantFail(tsm.withModuleDo(
301cf26e5faSNicolas Vasilache         [&](llvm::Module &module) { return transformer(&module); }));
302fe3594f7SNicolas Vasilache   cantFail(jit->addIRModule(std::move(tsm)));
303fe3594f7SNicolas Vasilache   engine->jit = std::move(jit);
3045a440378SAlex Zinenko 
3056d60d869SRiver Riddle   // Resolve symbols that are statically linked in the current process.
3066d60d869SRiver Riddle   llvm::orc::JITDylib &mainJD = engine->jit->getMainJITDylib();
3076d60d869SRiver Riddle   mainJD.addGenerator(
3086d60d869SRiver Riddle       cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
3096d60d869SRiver Riddle           dataLayout.getGlobalPrefix())));
3106d60d869SRiver Riddle 
311e7111fd6SJacques Pienaar   return std::move(engine);
3125a440378SAlex Zinenko }
3135a440378SAlex Zinenko 
3145a440378SAlex Zinenko Expected<void (*)(void **)> ExecutionEngine::lookup(StringRef name) const {
3155a440378SAlex Zinenko   auto expectedSymbol = jit->lookup(makePackedFunctionName(name));
316d7fbfbb1SAlex Zinenko 
317d7fbfbb1SAlex Zinenko   // JIT lookup may return an Error referring to strings stored internally by
318d7fbfbb1SAlex Zinenko   // the JIT. If the Error outlives the ExecutionEngine, it would want have a
319d7fbfbb1SAlex Zinenko   // dangling reference, which is currently caught by an assertion inside JIT
320d7fbfbb1SAlex Zinenko   // thanks to hand-rolled reference counting. Rewrap the error message into a
321d7fbfbb1SAlex Zinenko   // string before returning. Alternatively, ORC JIT should consider copying
322d7fbfbb1SAlex Zinenko   // the string into the error message.
323d7fbfbb1SAlex Zinenko   if (!expectedSymbol) {
324d7fbfbb1SAlex Zinenko     std::string errorMessage;
325d7fbfbb1SAlex Zinenko     llvm::raw_string_ostream os(errorMessage);
326d7fbfbb1SAlex Zinenko     llvm::handleAllErrors(expectedSymbol.takeError(),
327d7fbfbb1SAlex Zinenko                           [&os](llvm::ErrorInfoBase &ei) { ei.log(os); });
328d7fbfbb1SAlex Zinenko     return make_string_error(os.str());
329d7fbfbb1SAlex Zinenko   }
330d7fbfbb1SAlex Zinenko 
3315a440378SAlex Zinenko   auto rawFPtr = expectedSymbol->getAddress();
3325a440378SAlex Zinenko   auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
3335a440378SAlex Zinenko   if (!fptr)
3345a440378SAlex Zinenko     return make_string_error("looked up function is null");
3355a440378SAlex Zinenko   return fptr;
3365a440378SAlex Zinenko }
337629f5b7fSNicolas Vasilache 
338fe3594f7SNicolas Vasilache Error ExecutionEngine::invoke(StringRef name, MutableArrayRef<void *> args) {
339629f5b7fSNicolas Vasilache   auto expectedFPtr = lookup(name);
340629f5b7fSNicolas Vasilache   if (!expectedFPtr)
341629f5b7fSNicolas Vasilache     return expectedFPtr.takeError();
342629f5b7fSNicolas Vasilache   auto fptr = *expectedFPtr;
343629f5b7fSNicolas Vasilache 
344629f5b7fSNicolas Vasilache   (*fptr)(args.data());
345629f5b7fSNicolas Vasilache 
346fe3594f7SNicolas Vasilache   return Error::success();
347629f5b7fSNicolas Vasilache }
348