MLIR 24.0.0git
ExecutionEngine.h
Go to the documentation of this file.
1//===- ExecutionEngine.h - MLIR Execution engine and utils -----*- C++ -*--===//
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// This file provides a JIT-backed execution engine for MLIR modules.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_EXECUTIONENGINE_EXECUTIONENGINE_H_
14#define MLIR_EXECUTIONENGINE_EXECUTIONENGINE_H_
15
16#include "mlir/Support/LLVM.h"
17#include "llvm/ExecutionEngine/ObjectCache.h"
18#include "llvm/ExecutionEngine/Orc/LLJIT.h"
19#include "llvm/ExecutionEngine/SectionMemoryManager.h"
20#include "llvm/IR/LLVMContext.h"
21#include "llvm/Support/Error.h"
22
23#include <functional>
24#include <memory>
25#include <optional>
26
27namespace llvm {
28template <typename T>
30class Module;
31class ExecutionEngine;
32class JITEventListener;
33class MemoryBuffer;
34} // namespace llvm
35
36namespace mlir {
37
38class Operation;
39
40/// A simple object cache following Lang's LLJITWithObjectCache example.
41class SimpleObjectCache : public llvm::ObjectCache {
42public:
43 void notifyObjectCompiled(const llvm::Module *m,
44 llvm::MemoryBufferRef objBuffer) override;
45 std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module *m) override;
46
47 /// Dump cached object to output file `filename`.
48 void dumpToObjectFile(StringRef filename);
49
50 /// Returns `true` if cache hasn't been populated yet.
51 bool isEmpty();
52
53private:
54 llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> cachedObjects;
55};
56
58 /// Library options for the LLVMContext and the default TargetMachine.
59 const llvm::cl::LibraryOptionsContext *libraryOptions = nullptr;
60
61 /// If `llvmModuleBuilder` is provided, it will be used to create an LLVM
62 /// module from the given MLIR IR. Otherwise, a default
63 /// `translateModuleToLLVMIR` function will be used to translate to LLVM IR.
65 llvm::LLVMContext &)>
67
68 /// If `transformer` is provided, it will be called on the LLVM module during
69 /// JIT-compilation and can be used, e.g., for reporting or optimization.
70 llvm::function_ref<llvm::Error(llvm::Module *)> transformer = {};
71
72 /// `jitCodeGenOptLevel`, when provided, is used as the optimization level for
73 /// target code generation.
74 std::optional<llvm::CodeGenOptLevel> jitCodeGenOptLevel;
75
76 /// If `sharedLibPaths` are provided, the underlying JIT-compilation will
77 /// open and link the shared libraries for symbol resolution. Libraries that
78 /// are designed to be used with the `ExecutionEngine` may implement a
79 /// loading and unloading protocol: if they implement the two functions with
80 /// the names defined in `kLibraryInitFnName` and `kLibraryDestroyFnName`,
81 /// these functions will be called upon loading the library and upon
82 /// destruction of the `ExecutionEngine`. In the init function, the library
83 /// may provide a list of symbols that it wants to make available to code
84 /// run by the `ExecutionEngine`. If the two functions are not defined, only
85 /// symbols with public visibility are available to the executed code.
87
88 /// Specifies an existing `sectionMemoryMapper` to be associated with the
89 /// compiled code. If none is provided, a default memory mapper that directly
90 /// calls into the operating system is used.
91 llvm::SectionMemoryManager::MemoryMapper *sectionMemoryMapper = nullptr;
92
93 /// If `enableObjectCache` is set, the JIT compiler will create one to store
94 /// the object generated for the given module. The contents of the cache can
95 /// be dumped to a file via the `dumpToObjectFile` method.
96 bool enableObjectDump = false;
97
98 /// If enable `enableGDBNotificationListener` is set, the JIT compiler will
99 /// notify the llvm's global GDB notification listener.
101
102 /// If `enablePerfNotificationListener` is set, the JIT compiler will notify
103 /// the llvm's global Perf notification listener.
105};
106
107/// JIT-backed execution engine for MLIR. Assumes the IR can be converted to
108/// LLVM IR. For each function, creates a wrapper function with the fixed
109/// interface
110///
111/// void _mlir_funcName(void **)
112///
113/// where the only argument is interpreted as a list of pointers to the actual
114/// arguments of the function, followed by a pointer to the result. This allows
115/// the engine to provide the caller with a generic function pointer that can
116/// be used to invoke the JIT-compiled function.
118public:
119 /// Name of init functions of shared libraries. If a library provides a
120 /// function with this name and the one of the destroy function, this function
121 /// is called upon loading the library.
122 static constexpr const char *const kLibraryInitFnName =
123 "__mlir_execution_engine_init";
124
125 /// Name of destroy functions of shared libraries. If a library provides a
126 /// function with this name and the one of the init function, this function is
127 /// called upon destructing the `ExecutionEngine`.
128 static constexpr const char *const kLibraryDestroyFnName =
129 "__mlir_execution_engine_destroy";
130
131 /// Function type for init functions of shared libraries. The library may
132 /// provide a list of symbols that it wants to make available to code run by
133 /// the `ExecutionEngine`. If the two functions are not defined, only symbols
134 /// with public visibility are available to the executed code.
135 using LibraryInitFn = void (*)(llvm::StringMap<void *> &);
136
137 /// Function type for destroy functions of shared libraries.
138 using LibraryDestroyFn = void (*)();
139
140 ExecutionEngine(bool enableObjectDump, bool enableGDBNotificationListener,
141 bool enablePerfNotificationListener);
142
144
145 /// Creates an execution engine for the given MLIR IR. If TargetMachine is
146 /// not provided, default TM is created (i.e. ignoring any command line flags
147 /// that could affect the set-up).
150 std::unique_ptr<llvm::TargetMachine> tm = nullptr);
151
152 /// Looks up a packed-argument function wrapping the function with the given
153 /// name and returns a pointer to it. Propagates errors in case of failure.
154 llvm::Expected<void (*)(void **)> lookupPacked(StringRef name) const;
155
156 /// Looks up the original function with the given name and returns a
157 /// pointer to it. This is not necesarily a packed function. Propagates
158 /// errors in case of failure.
159 llvm::Expected<void *> lookup(StringRef name) const;
160
161 /// Invokes the function with the given name passing it the list of opaque
162 /// pointers to the actual arguments.
163 llvm::Error invokePacked(StringRef name, MutableArrayRef<void *> args = {});
164
165 /// Trait that defines how a given type is passed to the JIT code. This
166 /// defaults to passing the address but can be specialized.
167 template <typename T>
168 struct Argument {
169 static void pack(SmallVectorImpl<void *> &args, T &val) {
170 args.push_back(&val);
171 }
172 };
173
174 /// Tag to wrap an output parameter when invoking a jitted function.
175 template <typename T>
176 struct Result {
179 };
180
181 /// Helper function to wrap an output operand when using
182 /// ExecutionEngine::invoke.
183 template <typename T>
184 static Result<T> result(T &t) {
185 return Result<T>(t);
186 }
187
188 // Specialization for output parameter: their address is forwarded directly to
189 // the native code.
190 template <typename T>
191 struct Argument<Result<T>> {
193 args.push_back(&result.value);
194 }
195 };
196
197 /// Invokes the function with the given name passing it the list of arguments
198 /// by value. Function result can be obtain through output parameter using the
199 /// `Result` wrapper defined above. For example:
200 ///
201 /// func @foo(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface }
202 ///
203 /// can be invoked:
204 ///
205 /// int32_t result = 0;
206 /// llvm::Error error = jit->invoke("foo", 42,
207 /// result(result));
208 template <typename... Args>
209 llvm::Error invoke(StringRef funcName, Args... args) {
210 const std::string adapterName =
211 std::string("_mlir_ciface_") + funcName.str();
213 // Pack every arguments in an array of pointers. Delegate the packing to a
214 // trait so that it can be overridden per argument type.
215 (Argument<Args>::pack(argsArray, args), ...);
216 return invokePacked(adapterName, argsArray);
217 }
218
219 /// Set the target triple and the data layout for the input module based on
220 /// the input TargetMachine. This is implicitly done when creating the
221 /// engine.
222 static void setupTargetTripleAndDataLayout(llvm::Module *llvmModule,
223 llvm::TargetMachine *tm);
224
225 /// Dump object code to output file `filename`.
226 void dumpToObjectFile(StringRef filename);
227
228 /// Register symbols with this ExecutionEngine.
229 void registerSymbols(
230 llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
231 symbolMap);
232
233 /// Initialize the ExecutionEngine. Global constructors specified by
234 /// `llvm.mlir.global_ctors` will be run. One common scenario is that kernel
235 /// binary compiled from `gpu.module` gets loaded during initialization. Make
236 /// sure all symbols are resolvable before initialization by calling
237 /// `registerSymbols` or including shared libraries.
238 void initialize();
239
240private:
241 /// Ordering of llvmContext and jit is important for destruction purposes: the
242 /// jit must be destroyed before the context.
243 llvm::LLVMContext llvmContext;
244
245 /// Underlying LLJIT.
246 std::unique_ptr<llvm::orc::LLJIT> jit;
247
248 /// Underlying cache.
249 std::unique_ptr<SimpleObjectCache> cache;
250
251 /// Names of functions that may be looked up.
252 std::vector<std::string> functionNames;
253
254 /// GDB notification listener.
255 llvm::JITEventListener *gdbListener;
256
257 /// Perf notification listener.
258 llvm::JITEventListener *perfListener;
259
260 /// Destroy functions in the libraries loaded by the ExecutionEngine that are
261 /// called when this ExecutionEngine is destructed.
263
264 bool isInitialized = false;
265};
266
267} // namespace mlir
268
269#endif // MLIR_EXECUTIONENGINE_EXECUTIONENGINE_H_
static llvm::ManagedStatic< PassManagerOptions > options
JIT-backed execution engine for MLIR.
llvm::Error invoke(StringRef funcName, Args... args)
Invokes the function with the given name passing it the list of arguments by value.
llvm::Expected< void(*)(void **)> lookupPacked(StringRef name) const
Looks up a packed-argument function wrapping the function with the given name and returns a pointer t...
void(*)(llvm::StringMap< void * > &) LibraryInitFn
Function type for init functions of shared libraries.
void(*)() LibraryDestroyFn
Function type for destroy functions of shared libraries.
void registerSymbols(llvm::function_ref< llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)> symbolMap)
Register symbols with this ExecutionEngine.
llvm::Expected< void * > lookup(StringRef name) const
Looks up the original function with the given name and returns a pointer to it.
static llvm::Expected< std::unique_ptr< ExecutionEngine > > create(Operation *op, const ExecutionEngineOptions &options={}, std::unique_ptr< llvm::TargetMachine > tm=nullptr)
Creates an execution engine for the given MLIR IR.
void dumpToObjectFile(StringRef filename)
Dump object code to output file filename.
static Result< T > result(T &t)
Helper function to wrap an output operand when using ExecutionEngine::invoke.
static constexpr const char *const kLibraryInitFnName
Name of init functions of shared libraries.
static constexpr const char *const kLibraryDestroyFnName
Name of destroy functions of shared libraries.
llvm::Error invokePacked(StringRef name, MutableArrayRef< void * > args={})
Invokes the function with the given name passing it the list of opaque pointers to the actual argumen...
ExecutionEngine(bool enableObjectDump, bool enableGDBNotificationListener, bool enablePerfNotificationListener)
static void setupTargetTripleAndDataLayout(llvm::Module *llvmModule, llvm::TargetMachine *tm)
Set the target triple and the data layout for the input module based on the input TargetMachine.
void initialize()
Initialize the ExecutionEngine.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
A simple object cache following Lang's LLJITWithObjectCache example.
bool isEmpty()
Returns true if cache hasn't been populated yet.
void notifyObjectCompiled(const llvm::Module *m, llvm::MemoryBufferRef objBuffer) override
void dumpToObjectFile(StringRef filename)
Dump cached object to output file filename.
std::unique_ptr< llvm::MemoryBuffer > getObject(const llvm::Module *m) override
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:227
Include the generated interface declarations.
llvm::function_ref< std::unique_ptr< llvm::Module >(Operation *, llvm::LLVMContext &)> llvmModuleBuilder
If llvmModuleBuilder is provided, it will be used to create an LLVM module from the given MLIR IR.
std::optional< llvm::CodeGenOptLevel > jitCodeGenOptLevel
jitCodeGenOptLevel, when provided, is used as the optimization level for target code generation.
ArrayRef< StringRef > sharedLibPaths
If sharedLibPaths are provided, the underlying JIT-compilation will open and link the shared librarie...
bool enableObjectDump
If enableObjectCache is set, the JIT compiler will create one to store the object generated for the g...
bool enablePerfNotificationListener
If enablePerfNotificationListener is set, the JIT compiler will notify the llvm's global Perf notific...
const llvm::cl::LibraryOptionsContext * libraryOptions
Library options for the LLVMContext and the default TargetMachine.
llvm::function_ref< llvm::Error(llvm::Module *)> transformer
If transformer is provided, it will be called on the LLVM module during JIT-compilation and can be us...
llvm::SectionMemoryManager::MemoryMapper * sectionMemoryMapper
Specifies an existing sectionMemoryMapper to be associated with the compiled code.
bool enableGDBNotificationListener
If enable enableGDBNotificationListener is set, the JIT compiler will notify the llvm's global GDB no...
static void pack(SmallVectorImpl< void * > &args, Result< T > &result)
Trait that defines how a given type is passed to the JIT code.
static void pack(SmallVectorImpl< void * > &args, T &val)
Tag to wrap an output parameter when invoking a jitted function.