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