| 1 | //===- ExecutionEngine.cpp - C API for MLIR JIT ---------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "mlir-c/ExecutionEngine.h" |
| 10 | #include "mlir/CAPI/ExecutionEngine.h" |
| 11 | #include "mlir/CAPI/IR.h" |
| 12 | #include "mlir/CAPI/Support.h" |
| 13 | #include "mlir/ExecutionEngine/OptUtils.h" |
| 14 | #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" |
| 15 | #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" |
| 16 | #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" |
| 17 | #include "llvm/ExecutionEngine/Orc/Mangling.h" |
| 18 | #include "llvm/Support/TargetSelect.h" |
| 19 | |
| 20 | using namespace mlir; |
| 21 | |
| 22 | extern "C" MlirExecutionEngine |
| 23 | mlirExecutionEngineCreate(MlirModule op, int optLevel, int numPaths, |
| 24 | const MlirStringRef *sharedLibPaths, |
| 25 | bool enableObjectDump) { |
| 26 | static bool initOnce = [] { |
| 27 | llvm::InitializeNativeTarget(); |
| 28 | llvm::InitializeNativeTargetAsmParser(); // needed for inline_asm |
| 29 | llvm::InitializeNativeTargetAsmPrinter(); |
| 30 | return true; |
| 31 | }(); |
| 32 | (void)initOnce; |
| 33 | |
| 34 | auto &ctx = *unwrap(op)->getContext(); |
| 35 | mlir::registerBuiltinDialectTranslation(ctx); |
| 36 | mlir::registerLLVMDialectTranslation(ctx); |
| 37 | mlir::registerOpenMPDialectTranslation(ctx); |
| 38 | |
| 39 | auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost(); |
| 40 | if (!tmBuilderOrError) { |
| 41 | llvm::errs() << "Failed to create a JITTargetMachineBuilder for the host\n" ; |
| 42 | return MlirExecutionEngine{.ptr: nullptr}; |
| 43 | } |
| 44 | auto tmOrError = tmBuilderOrError->createTargetMachine(); |
| 45 | if (!tmOrError) { |
| 46 | llvm::errs() << "Failed to create a TargetMachine for the host\n" ; |
| 47 | return MlirExecutionEngine{.ptr: nullptr}; |
| 48 | } |
| 49 | |
| 50 | SmallVector<StringRef> libPaths; |
| 51 | for (unsigned i = 0; i < static_cast<unsigned>(numPaths); ++i) |
| 52 | libPaths.push_back(Elt: sharedLibPaths[i].data); |
| 53 | |
| 54 | // Create a transformer to run all LLVM optimization passes at the |
| 55 | // specified optimization level. |
| 56 | auto transformer = mlir::makeOptimizingTransformer( |
| 57 | optLevel, /*sizeLevel=*/0, /*targetMachine=*/tmOrError->get()); |
| 58 | ExecutionEngineOptions jitOptions; |
| 59 | jitOptions.transformer = transformer; |
| 60 | jitOptions.jitCodeGenOptLevel = static_cast<llvm::CodeGenOptLevel>(optLevel); |
| 61 | jitOptions.sharedLibPaths = libPaths; |
| 62 | jitOptions.enableObjectDump = enableObjectDump; |
| 63 | auto jitOrError = ExecutionEngine::create(op: unwrap(op), options: jitOptions); |
| 64 | if (!jitOrError) { |
| 65 | consumeError(jitOrError.takeError()); |
| 66 | return MlirExecutionEngine{.ptr: nullptr}; |
| 67 | } |
| 68 | return wrap(jitOrError->release()); |
| 69 | } |
| 70 | |
| 71 | extern "C" void mlirExecutionEngineDestroy(MlirExecutionEngine jit) { |
| 72 | delete (unwrap(c: jit)); |
| 73 | } |
| 74 | |
| 75 | extern "C" MlirLogicalResult |
| 76 | mlirExecutionEngineInvokePacked(MlirExecutionEngine jit, MlirStringRef name, |
| 77 | void **arguments) { |
| 78 | const std::string ifaceName = ("_mlir_ciface_" + unwrap(ref: name)).str(); |
| 79 | llvm::Error error = unwrap(c: jit)->invokePacked( |
| 80 | name: ifaceName, args: MutableArrayRef<void *>{arguments, (size_t)0}); |
| 81 | if (error) |
| 82 | return wrap(res: failure()); |
| 83 | return wrap(res: success()); |
| 84 | } |
| 85 | |
| 86 | extern "C" void *mlirExecutionEngineLookupPacked(MlirExecutionEngine jit, |
| 87 | MlirStringRef name) { |
| 88 | auto optionalFPtr = |
| 89 | llvm::expectedToOptional(E: unwrap(c: jit)->lookupPacked(name: unwrap(ref: name))); |
| 90 | if (!optionalFPtr) |
| 91 | return nullptr; |
| 92 | return reinterpret_cast<void *>(*optionalFPtr); |
| 93 | } |
| 94 | |
| 95 | extern "C" void *mlirExecutionEngineLookup(MlirExecutionEngine jit, |
| 96 | MlirStringRef name) { |
| 97 | auto optionalFPtr = |
| 98 | llvm::expectedToOptional(E: unwrap(c: jit)->lookup(name: unwrap(ref: name))); |
| 99 | if (!optionalFPtr) |
| 100 | return nullptr; |
| 101 | return *optionalFPtr; |
| 102 | } |
| 103 | |
| 104 | extern "C" void mlirExecutionEngineRegisterSymbol(MlirExecutionEngine jit, |
| 105 | MlirStringRef name, |
| 106 | void *sym) { |
| 107 | unwrap(c: jit)->registerSymbols(symbolMap: [&](llvm::orc::MangleAndInterner interner) { |
| 108 | llvm::orc::SymbolMap symbolMap; |
| 109 | symbolMap[interner(unwrap(ref: name))] = |
| 110 | { llvm::orc::ExecutorAddr::fromPtr(Ptr: sym), |
| 111 | llvm::JITSymbolFlags::Exported }; |
| 112 | return symbolMap; |
| 113 | }); |
| 114 | } |
| 115 | |
| 116 | extern "C" void mlirExecutionEngineDumpToObjectFile(MlirExecutionEngine jit, |
| 117 | MlirStringRef name) { |
| 118 | unwrap(c: jit)->dumpToObjectFile(filename: unwrap(ref: name)); |
| 119 | } |
| 120 | |