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"
289f2ce5b9SHaruki Imai #include "llvm/MC/SubtargetFeature.h"
2989b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
3053bb528bSMehdi Amini #include "llvm/Support/Debug.h"
315a440378SAlex Zinenko #include "llvm/Support/Error.h"
3290dbec26SMehdi Amini #include "llvm/Support/Host.h"
3306e81010SJacques Pienaar #include "llvm/Support/ToolOutputFile.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.
makeStringError(const Twine & message)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 
notifyObjectCompiled(const Module * m,MemoryBufferRef objBuffer)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 
getObject(const Module * m)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 
dumpToObjectFile(StringRef outputFilename)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 
dumpToObjectFile(StringRef filename)994562e389SRiver Riddle void ExecutionEngine::dumpToObjectFile(StringRef filename) {
100b24de9f6SEmilio Cota   if (cache == nullptr) {
101b24de9f6SEmilio Cota     llvm::errs() << "cannot dump ExecutionEngine object code to file: "
102b24de9f6SEmilio Cota                     "object cache is disabled\n";
103b24de9f6SEmilio Cota     return;
104b24de9f6SEmilio Cota   }
10506e81010SJacques Pienaar   cache->dumpToObjectFile(filename);
10606e81010SJacques Pienaar }
10706e81010SJacques Pienaar 
registerSymbols(llvm::function_ref<SymbolMap (MangleAndInterner)> symbolMap)1083a11ca7bSEugene Zhulenev void ExecutionEngine::registerSymbols(
1093a11ca7bSEugene Zhulenev     llvm::function_ref<SymbolMap(MangleAndInterner)> symbolMap) {
1103a11ca7bSEugene Zhulenev   auto &mainJitDylib = jit->getMainJITDylib();
1113a11ca7bSEugene Zhulenev   cantFail(mainJitDylib.define(
1123a11ca7bSEugene Zhulenev       absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner(
1133a11ca7bSEugene Zhulenev           mainJitDylib.getExecutionSession(), jit->getDataLayout())))));
1143a11ca7bSEugene Zhulenev }
1153a11ca7bSEugene Zhulenev 
1165a440378SAlex Zinenko // Setup LLVM target triple from the current machine.
setupTargetTriple(Module * llvmModule)117fe3594f7SNicolas Vasilache bool ExecutionEngine::setupTargetTriple(Module *llvmModule) {
1185a440378SAlex Zinenko   // Setup the machine properties from the current architecture.
1195a440378SAlex Zinenko   auto targetTriple = llvm::sys::getDefaultTargetTriple();
1205a440378SAlex Zinenko   std::string errorMessage;
12102b6fb21SMehdi Amini   const auto *target =
12202b6fb21SMehdi Amini       llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
1235a440378SAlex Zinenko   if (!target) {
124fe3594f7SNicolas Vasilache     errs() << "NO target: " << errorMessage << "\n";
1255a440378SAlex Zinenko     return true;
1265a440378SAlex Zinenko   }
1279f2ce5b9SHaruki Imai 
1289f2ce5b9SHaruki Imai   std::string cpu(llvm::sys::getHostCPUName());
1299f2ce5b9SHaruki Imai   llvm::SubtargetFeatures features;
1309f2ce5b9SHaruki Imai   llvm::StringMap<bool> hostFeatures;
1319f2ce5b9SHaruki Imai 
1329f2ce5b9SHaruki Imai   if (llvm::sys::getHostCPUFeatures(hostFeatures))
1339f2ce5b9SHaruki Imai     for (auto &f : hostFeatures)
1349f2ce5b9SHaruki Imai       features.AddFeature(f.first(), f.second);
1359f2ce5b9SHaruki Imai 
1369f2ce5b9SHaruki Imai   std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
1379f2ce5b9SHaruki Imai       targetTriple, cpu, features.getString(), {}, {}));
1381756d679SElla Ma   if (!machine) {
1391756d679SElla Ma     errs() << "Unable to create target machine\n";
1401756d679SElla Ma     return true;
1411756d679SElla Ma   }
1425a440378SAlex Zinenko   llvmModule->setDataLayout(machine->createDataLayout());
1435a440378SAlex Zinenko   llvmModule->setTargetTriple(targetTriple);
1445a440378SAlex Zinenko   return false;
1455a440378SAlex Zinenko }
1465a440378SAlex Zinenko 
makePackedFunctionName(StringRef name)1475a440378SAlex Zinenko static std::string makePackedFunctionName(StringRef name) {
1485a440378SAlex Zinenko   return "_mlir_" + name.str();
1495a440378SAlex Zinenko }
1505a440378SAlex Zinenko 
1515a440378SAlex Zinenko // For each function in the LLVM module, define an interface function that wraps
1525a440378SAlex Zinenko // all the arguments of the original function and all its results into an i8**
1535a440378SAlex Zinenko // pointer to provide a unified invocation interface.
packFunctionArguments(Module * module)154df186507SBenjamin Kramer static void packFunctionArguments(Module *module) {
1555a440378SAlex Zinenko   auto &ctx = module->getContext();
1565a440378SAlex Zinenko   llvm::IRBuilder<> builder(ctx);
1574562e389SRiver Riddle   DenseSet<llvm::Function *> interfaceFunctions;
1585a440378SAlex Zinenko   for (auto &func : module->getFunctionList()) {
1595a440378SAlex Zinenko     if (func.isDeclaration()) {
1605a440378SAlex Zinenko       continue;
1615a440378SAlex Zinenko     }
1625a440378SAlex Zinenko     if (interfaceFunctions.count(&func)) {
1635a440378SAlex Zinenko       continue;
1645a440378SAlex Zinenko     }
1655a440378SAlex Zinenko 
1665a440378SAlex Zinenko     // Given a function `foo(<...>)`, define the interface function
1675a440378SAlex Zinenko     // `mlir_foo(i8**)`.
16802b6fb21SMehdi Amini     auto *newType = llvm::FunctionType::get(
1695a440378SAlex Zinenko         builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(),
1705a440378SAlex Zinenko         /*isVarArg=*/false);
1715a440378SAlex Zinenko     auto newName = makePackedFunctionName(func.getName());
172c46b0feaSRiver Riddle     auto funcCst = module->getOrInsertFunction(newName, newType);
1734562e389SRiver Riddle     llvm::Function *interfaceFunc = cast<llvm::Function>(funcCst.getCallee());
1745a440378SAlex Zinenko     interfaceFunctions.insert(interfaceFunc);
1755a440378SAlex Zinenko 
1765a440378SAlex Zinenko     // Extract the arguments from the type-erased argument list and cast them to
1775a440378SAlex Zinenko     // the proper types.
17802b6fb21SMehdi Amini     auto *bb = llvm::BasicBlock::Create(ctx);
1795a440378SAlex Zinenko     bb->insertInto(interfaceFunc);
1805a440378SAlex Zinenko     builder.SetInsertPoint(bb);
1815a440378SAlex Zinenko     llvm::Value *argList = interfaceFunc->arg_begin();
1824562e389SRiver Riddle     SmallVector<llvm::Value *, 8> args;
1835a440378SAlex Zinenko     args.reserve(llvm::size(func.args()));
1845a440378SAlex Zinenko     for (auto &indexedArg : llvm::enumerate(func.args())) {
1855a440378SAlex Zinenko       llvm::Value *argIndex = llvm::Constant::getIntegerValue(
1864562e389SRiver Riddle           builder.getInt64Ty(), APInt(64, indexedArg.index()));
187f1f5a85aSNicolas Vasilache       llvm::Value *argPtrPtr =
188f1f5a85aSNicolas Vasilache           builder.CreateGEP(builder.getInt8PtrTy(), argList, argIndex);
189f1f5a85aSNicolas Vasilache       llvm::Value *argPtr =
190f1f5a85aSNicolas Vasilache           builder.CreateLoad(builder.getInt8PtrTy(), argPtrPtr);
191f3f0c6cdSNikita Popov       llvm::Type *argTy = indexedArg.value().getType();
192f3f0c6cdSNikita Popov       argPtr = builder.CreateBitCast(argPtr, argTy->getPointerTo());
193f3f0c6cdSNikita Popov       llvm::Value *arg = builder.CreateLoad(argTy, argPtr);
1945a440378SAlex Zinenko       args.push_back(arg);
1955a440378SAlex Zinenko     }
1965a440378SAlex Zinenko 
1975a440378SAlex Zinenko     // Call the implementation function with the extracted arguments.
1985a440378SAlex Zinenko     llvm::Value *result = builder.CreateCall(&func, args);
1995a440378SAlex Zinenko 
2005a440378SAlex Zinenko     // Assuming the result is one value, potentially of type `void`.
2015a440378SAlex Zinenko     if (!result->getType()->isVoidTy()) {
2025a440378SAlex Zinenko       llvm::Value *retIndex = llvm::Constant::getIntegerValue(
2034562e389SRiver Riddle           builder.getInt64Ty(), APInt(64, llvm::size(func.args())));
2042c68ecccSNikita Popov       llvm::Value *retPtrPtr =
205ffe94738SNikita Popov           builder.CreateGEP(builder.getInt8PtrTy(), argList, retIndex);
206f1f5a85aSNicolas Vasilache       llvm::Value *retPtr =
207f1f5a85aSNicolas Vasilache           builder.CreateLoad(builder.getInt8PtrTy(), retPtrPtr);
2085a440378SAlex Zinenko       retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo());
2095a440378SAlex Zinenko       builder.CreateStore(result, retPtr);
2105a440378SAlex Zinenko     }
2115a440378SAlex Zinenko 
2125a440378SAlex Zinenko     // The interface function returns void.
2135a440378SAlex Zinenko     builder.CreateRetVoid();
2145a440378SAlex Zinenko   }
2155a440378SAlex Zinenko }
2165a440378SAlex Zinenko 
ExecutionEngine(bool enableObjectCache,bool enableGDBNotificationListener,bool enablePerfNotificationListener)217d1186fcbSaartbik ExecutionEngine::ExecutionEngine(bool enableObjectCache,
2183c5dd586SEugene Zhulenev                                  bool enableGDBNotificationListener,
2193c5dd586SEugene Zhulenev                                  bool enablePerfNotificationListener)
220d1186fcbSaartbik     : cache(enableObjectCache ? new SimpleObjectCache() : nullptr),
221d1186fcbSaartbik       gdbListener(enableGDBNotificationListener
222d1186fcbSaartbik                       ? llvm::JITEventListener::createGDBRegistrationListener()
2233c5dd586SEugene Zhulenev                       : nullptr),
224f68ecdd4SNicolas Vasilache       perfListener(nullptr) {
225f68ecdd4SNicolas Vasilache   if (enablePerfNotificationListener) {
226f68ecdd4SNicolas Vasilache     if (auto *listener = llvm::JITEventListener::createPerfJITEventListener())
227f68ecdd4SNicolas Vasilache       perfListener = listener;
228f68ecdd4SNicolas Vasilache     else if (auto *listener =
229f68ecdd4SNicolas Vasilache                  llvm::JITEventListener::createIntelJITEventListener())
230f68ecdd4SNicolas Vasilache       perfListener = listener;
231f68ecdd4SNicolas Vasilache   }
232f68ecdd4SNicolas Vasilache }
23306e81010SJacques Pienaar 
234a7db3c61SEmilio Cota Expected<std::unique_ptr<ExecutionEngine>>
create(ModuleOp m,const ExecutionEngineOptions & options)235a7db3c61SEmilio Cota ExecutionEngine::create(ModuleOp m, const ExecutionEngineOptions &options) {
236d1186fcbSaartbik   auto engine = std::make_unique<ExecutionEngine>(
237a7db3c61SEmilio Cota       options.enableObjectCache, options.enableGDBNotificationListener,
238a7db3c61SEmilio Cota       options.enablePerfNotificationListener);
2395a440378SAlex Zinenko 
240fe3594f7SNicolas Vasilache   std::unique_ptr<llvm::LLVMContext> ctx(new llvm::LLVMContext);
241a7db3c61SEmilio Cota   auto llvmModule = options.llvmModuleBuilder
242a7db3c61SEmilio Cota                         ? options.llvmModuleBuilder(m, *ctx)
24389808ce7SGeorge Mitenkov                         : translateModuleToLLVMIR(m, *ctx);
2445a440378SAlex Zinenko   if (!llvmModule)
24502b6fb21SMehdi Amini     return makeStringError("could not convert to LLVM IR");
2465a440378SAlex Zinenko   // FIXME: the triple should be passed to the translation or dialect conversion
2475a440378SAlex Zinenko   // instead of this.  Currently, the LLVM module created above has no triple
2485a440378SAlex Zinenko   // associated with it.
2495a440378SAlex Zinenko   setupTargetTriple(llvmModule.get());
2505a440378SAlex Zinenko   packFunctionArguments(llvmModule.get());
2515a440378SAlex Zinenko 
252db1c197bSAlex Zinenko   auto dataLayout = llvmModule->getDataLayout();
253fe3594f7SNicolas Vasilache 
254fe3594f7SNicolas Vasilache   // Callback to create the object layer with symbol resolution to current
255fe3594f7SNicolas Vasilache   // process and dynamically linked libraries.
256fe3594f7SNicolas Vasilache   auto objectLinkingLayerCreator = [&](ExecutionSession &session,
25702b6fb21SMehdi Amini                                        const Triple &tt) {
258fe3594f7SNicolas Vasilache     auto objectLayer = std::make_unique<RTDyldObjectLinkingLayer>(
259011f6532SEmilio Cota         session, [sectionMemoryMapper = options.sectionMemoryMapper]() {
260011f6532SEmilio Cota           return std::make_unique<SectionMemoryManager>(sectionMemoryMapper);
261011f6532SEmilio Cota         });
2623c5dd586SEugene Zhulenev 
2633c5dd586SEugene Zhulenev     // Register JIT event listeners if they are enabled.
2643c5dd586SEugene Zhulenev     if (engine->gdbListener)
2653c5dd586SEugene Zhulenev       objectLayer->registerJITEventListener(*engine->gdbListener);
2663c5dd586SEugene Zhulenev     if (engine->perfListener)
2673c5dd586SEugene Zhulenev       objectLayer->registerJITEventListener(*engine->perfListener);
268fe3594f7SNicolas Vasilache 
2693c4cdd0bSKern Handa     // COFF format binaries (Windows) need special handling to deal with
2703c4cdd0bSKern Handa     // exported symbol visibility.
2713c4cdd0bSKern Handa     // cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp LLJIT::createObjectLinkingLayer
2723c4cdd0bSKern Handa     llvm::Triple targetTriple(llvm::Twine(llvmModule->getTargetTriple()));
2733c4cdd0bSKern Handa     if (targetTriple.isOSBinFormatCOFF()) {
2743c4cdd0bSKern Handa       objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true);
2753c4cdd0bSKern Handa       objectLayer->setAutoClaimResponsibilityForObjectSymbols(true);
2763c4cdd0bSKern Handa     }
2773c4cdd0bSKern Handa 
278fe3594f7SNicolas Vasilache     // Resolve symbols from shared libraries.
279a7db3c61SEmilio Cota     for (auto libPath : options.sharedLibPaths) {
280fe3594f7SNicolas Vasilache       auto mb = llvm::MemoryBuffer::getFile(libPath);
281fe3594f7SNicolas Vasilache       if (!mb) {
282670063ebSAden Grue         errs() << "Failed to create MemoryBuffer for: " << libPath
283670063ebSAden Grue                << "\nError: " << mb.getError().message() << "\n";
284fe3594f7SNicolas Vasilache         continue;
285fe3594f7SNicolas Vasilache       }
28602b6fb21SMehdi Amini       auto &jd = session.createBareJITDylib(std::string(libPath));
287fe3594f7SNicolas Vasilache       auto loaded = DynamicLibrarySearchGenerator::Load(
288fe3594f7SNicolas Vasilache           libPath.data(), dataLayout.getGlobalPrefix());
289fe3594f7SNicolas Vasilache       if (!loaded) {
290e38fe4a7SChristian Sigg         errs() << "Could not load " << libPath << ":\n  " << loaded.takeError()
291e38fe4a7SChristian Sigg                << "\n";
292fe3594f7SNicolas Vasilache         continue;
293fe3594f7SNicolas Vasilache       }
29402b6fb21SMehdi Amini       jd.addGenerator(std::move(*loaded));
29502b6fb21SMehdi Amini       cantFail(objectLayer->add(jd, std::move(mb.get())));
296fe3594f7SNicolas Vasilache     }
297fe3594f7SNicolas Vasilache 
298fe3594f7SNicolas Vasilache     return objectLayer;
299fe3594f7SNicolas Vasilache   };
300fe3594f7SNicolas Vasilache 
301fe3594f7SNicolas Vasilache   // Callback to inspect the cache and recompile on demand. This follows Lang's
302fe3594f7SNicolas Vasilache   // LLJITWithObjectCache example.
30302b6fb21SMehdi Amini   auto compileFunctionCreator = [&](JITTargetMachineBuilder jtmb)
3047984b474SAlex Zinenko       -> Expected<std::unique_ptr<IRCompileLayer::IRCompiler>> {
305a7db3c61SEmilio Cota     if (options.jitCodeGenOptLevel)
306*6d5fc1e3SKazu Hirata       jtmb.setCodeGenOptLevel(*options.jitCodeGenOptLevel);
30702b6fb21SMehdi Amini     auto tm = jtmb.createTargetMachine();
30802b6fb21SMehdi Amini     if (!tm)
30902b6fb21SMehdi Amini       return tm.takeError();
31002b6fb21SMehdi Amini     return std::make_unique<TMOwningSimpleCompiler>(std::move(*tm),
3117984b474SAlex Zinenko                                                     engine->cache.get());
312fe3594f7SNicolas Vasilache   };
313fe3594f7SNicolas Vasilache 
314fe3594f7SNicolas Vasilache   // Create the LLJIT by calling the LLJITBuilder with 2 callbacks.
315fe3594f7SNicolas Vasilache   auto jit =
316fe3594f7SNicolas Vasilache       cantFail(llvm::orc::LLJITBuilder()
317fe3594f7SNicolas Vasilache                    .setCompileFunctionCreator(compileFunctionCreator)
318fe3594f7SNicolas Vasilache                    .setObjectLinkingLayerCreator(objectLinkingLayerCreator)
319fe3594f7SNicolas Vasilache                    .create());
320fe3594f7SNicolas Vasilache 
321fe3594f7SNicolas Vasilache   // Add a ThreadSafemodule to the engine and return.
322db1c197bSAlex Zinenko   ThreadSafeModule tsm(std::move(llvmModule), std::move(ctx));
323a7db3c61SEmilio Cota   if (options.transformer)
324cf26e5faSNicolas Vasilache     cantFail(tsm.withModuleDo(
325a7db3c61SEmilio Cota         [&](llvm::Module &module) { return options.transformer(&module); }));
326fe3594f7SNicolas Vasilache   cantFail(jit->addIRModule(std::move(tsm)));
327fe3594f7SNicolas Vasilache   engine->jit = std::move(jit);
3285a440378SAlex Zinenko 
3296d60d869SRiver Riddle   // Resolve symbols that are statically linked in the current process.
3306d60d869SRiver Riddle   llvm::orc::JITDylib &mainJD = engine->jit->getMainJITDylib();
3316d60d869SRiver Riddle   mainJD.addGenerator(
3326d60d869SRiver Riddle       cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
3336d60d869SRiver Riddle           dataLayout.getGlobalPrefix())));
3346d60d869SRiver Riddle 
335e7111fd6SJacques Pienaar   return std::move(engine);
3365a440378SAlex Zinenko }
3375a440378SAlex Zinenko 
338106f3074STres Popp Expected<void (*)(void **)>
lookupPacked(StringRef name) const339106f3074STres Popp ExecutionEngine::lookupPacked(StringRef name) const {
340106f3074STres Popp   auto result = lookup(makePackedFunctionName(name));
341106f3074STres Popp   if (!result)
342106f3074STres Popp     return result.takeError();
343106f3074STres Popp   return reinterpret_cast<void (*)(void **)>(result.get());
344106f3074STres Popp }
345106f3074STres Popp 
lookup(StringRef name) const346106f3074STres Popp Expected<void *> ExecutionEngine::lookup(StringRef name) const {
347106f3074STres Popp   auto expectedSymbol = jit->lookup(name);
348d7fbfbb1SAlex Zinenko 
349d7fbfbb1SAlex Zinenko   // JIT lookup may return an Error referring to strings stored internally by
350d7fbfbb1SAlex Zinenko   // the JIT. If the Error outlives the ExecutionEngine, it would want have a
351d7fbfbb1SAlex Zinenko   // dangling reference, which is currently caught by an assertion inside JIT
352d7fbfbb1SAlex Zinenko   // thanks to hand-rolled reference counting. Rewrap the error message into a
353d7fbfbb1SAlex Zinenko   // string before returning. Alternatively, ORC JIT should consider copying
354d7fbfbb1SAlex Zinenko   // the string into the error message.
355d7fbfbb1SAlex Zinenko   if (!expectedSymbol) {
356d7fbfbb1SAlex Zinenko     std::string errorMessage;
357d7fbfbb1SAlex Zinenko     llvm::raw_string_ostream os(errorMessage);
358d7fbfbb1SAlex Zinenko     llvm::handleAllErrors(expectedSymbol.takeError(),
359d7fbfbb1SAlex Zinenko                           [&os](llvm::ErrorInfoBase &ei) { ei.log(os); });
36002b6fb21SMehdi Amini     return makeStringError(os.str());
361d7fbfbb1SAlex Zinenko   }
362d7fbfbb1SAlex Zinenko 
3638bb5b657SRiver Riddle   if (void *fptr = expectedSymbol->toPtr<void *>())
3645a440378SAlex Zinenko     return fptr;
3658bb5b657SRiver Riddle   return makeStringError("looked up function is null");
3665a440378SAlex Zinenko }
367629f5b7fSNicolas Vasilache 
invokePacked(StringRef name,MutableArrayRef<void * > args)368d6efb6fcSMehdi Amini Error ExecutionEngine::invokePacked(StringRef name,
369d6efb6fcSMehdi Amini                                     MutableArrayRef<void *> args) {
370106f3074STres Popp   auto expectedFPtr = lookupPacked(name);
371629f5b7fSNicolas Vasilache   if (!expectedFPtr)
372629f5b7fSNicolas Vasilache     return expectedFPtr.takeError();
373629f5b7fSNicolas Vasilache   auto fptr = *expectedFPtr;
374629f5b7fSNicolas Vasilache 
375629f5b7fSNicolas Vasilache   (*fptr)(args.data());
376629f5b7fSNicolas Vasilache 
377fe3594f7SNicolas Vasilache   return Error::success();
378629f5b7fSNicolas Vasilache }
379