Skip to content
This repository was archived by the owner on Oct 11, 2025. It is now read-only.

Commit 7b8f380

Browse files
[MLIR] Split ExecutionEngine Initialization out of ctor into an explicit method call (#153373)
This PR introduces a mechanism to defer JIT engine initialization, enabling registration of required symbols before global constructor execution. ## Problem Modules containing `gpu.module` generate global constructors (e.g., kernel load/unload) that execute *during* engine creation. This can force premature symbol resolution, causing failures when: - Symbols are registered via `mlirExecutionEngineRegisterSymbol` *after* creation - Global constructors exist (even if not directly using unresolved symbols, e.g., an external function declaration) - GPU modules introduce mandatory binary loading logic ## Usage ```c // Create engine without initialization MlirExecutionEngine jit = mlirExecutionEngineCreate(...); // Register required symbols mlirExecutionEngineRegisterSymbol(jit, ...); // Explicitly initialize (runs global constructors) mlirExecutionEngineInitialize(jit); ``` --------- Co-authored-by: Mehdi Amini <[email protected]>
1 parent 03d7f47 commit 7b8f380

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

mlir/include/mlir-c/ExecutionEngine.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ MLIR_CAPI_EXPORTED MlirExecutionEngine mlirExecutionEngineCreate(
4646
MlirModule op, int optLevel, int numPaths,
4747
const MlirStringRef *sharedLibPaths, bool enableObjectDump);
4848

49+
/// Initialize the ExecutionEngine. Global constructors specified by
50+
/// `llvm.mlir.global_ctors` will be run. One common scenario is that kernel
51+
/// binary compiled from `gpu.module` gets loaded during initialization. Make
52+
/// sure all symbols are resolvable before initialization by calling
53+
/// `mlirExecutionEngineRegisterSymbol` or including shared libraries.
54+
MLIR_CAPI_EXPORTED void mlirExecutionEngineInitialize(MlirExecutionEngine jit);
55+
4956
/// Destroy an ExecutionEngine instance.
5057
MLIR_CAPI_EXPORTED void mlirExecutionEngineDestroy(MlirExecutionEngine jit);
5158

mlir/lib/Bindings/Python/ExecutionEngineModule.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "mlir-c/ExecutionEngine.h"
10-
#include "mlir/Bindings/Python/NanobindAdaptors.h"
1110
#include "mlir/Bindings/Python/Nanobind.h"
11+
#include "mlir/Bindings/Python/NanobindAdaptors.h"
1212

1313
namespace nb = nanobind;
1414
using namespace mlir;
@@ -124,6 +124,17 @@ NB_MODULE(_mlirExecutionEngine, m) {
124124
},
125125
nb::arg("name"), nb::arg("callback"),
126126
"Register `callback` as the runtime symbol `name`.")
127+
.def(
128+
"initialize",
129+
[](PyExecutionEngine &executionEngine) {
130+
mlirExecutionEngineInitialize(executionEngine.get());
131+
},
132+
"Initialize the ExecutionEngine. Global constructors specified by "
133+
"`llvm.mlir.global_ctors` will be run. One common scenario is that "
134+
"kernel binary compiled from `gpu.module` gets loaded during "
135+
"initialization. Make sure all symbols are resolvable before "
136+
"initialization by calling `raw_register_runtime` or including "
137+
"shared libraries.")
127138
.def(
128139
"dump_to_object_file",
129140
[](PyExecutionEngine &executionEngine, const std::string &fileName) {

mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ mlirExecutionEngineCreate(MlirModule op, int optLevel, int numPaths,
6868
return wrap(jitOrError->release());
6969
}
7070

71+
extern "C" void mlirExecutionEngineInitialize(MlirExecutionEngine jit) {
72+
unwrap(jit)->initialize();
73+
}
74+
7175
extern "C" void mlirExecutionEngineDestroy(MlirExecutionEngine jit) {
7276
delete (unwrap(jit));
7377
}
@@ -106,9 +110,8 @@ extern "C" void mlirExecutionEngineRegisterSymbol(MlirExecutionEngine jit,
106110
void *sym) {
107111
unwrap(jit)->registerSymbols([&](llvm::orc::MangleAndInterner interner) {
108112
llvm::orc::SymbolMap symbolMap;
109-
symbolMap[interner(unwrap(name))] =
110-
{ llvm::orc::ExecutorAddr::fromPtr(sym),
111-
llvm::JITSymbolFlags::Exported };
113+
symbolMap[interner(unwrap(name))] = {llvm::orc::ExecutorAddr::fromPtr(sym),
114+
llvm::JITSymbolFlags::Exported};
112115
return symbolMap;
113116
});
114117
}

0 commit comments

Comments
 (0)