#include <thread>
#include <vector>
+#include "llvm/ADT/StringMap.h"
+
using namespace mlir::runtime;
//===----------------------------------------------------------------------===//
} // namespace
// Returns the default per-process instance of an async runtime.
-static AsyncRuntime *getDefaultAsyncRuntimeInstance() {
+static std::unique_ptr<AsyncRuntime> &getDefaultAsyncRuntimeInstance() {
static auto runtime = std::make_unique<AsyncRuntime>();
- return runtime.get();
+ return runtime;
+}
+
+static void resetDefaultAsyncRuntime() {
+ return getDefaultAsyncRuntimeInstance().reset();
+}
+
+static AsyncRuntime *getDefaultAsyncRuntime() {
+ return getDefaultAsyncRuntimeInstance().get();
}
// Async token provides a mechanism to signal asynchronous operation completion.
// Creates a new `async.token` in not-ready state.
extern "C" AsyncToken *mlirAsyncRuntimeCreateToken() {
- AsyncToken *token = new AsyncToken(getDefaultAsyncRuntimeInstance());
+ AsyncToken *token = new AsyncToken(getDefaultAsyncRuntime());
return token;
}
// Creates a new `async.value` in not-ready state.
extern "C" AsyncValue *mlirAsyncRuntimeCreateValue(int32_t size) {
- AsyncValue *value = new AsyncValue(getDefaultAsyncRuntimeInstance(), size);
+ AsyncValue *value = new AsyncValue(getDefaultAsyncRuntime(), size);
return value;
}
// Create a new `async.group` in empty state.
extern "C" AsyncGroup *mlirAsyncRuntimeCreateGroup() {
- AsyncGroup *group = new AsyncGroup(getDefaultAsyncRuntimeInstance());
+ AsyncGroup *group = new AsyncGroup(getDefaultAsyncRuntime());
return group;
}
std::cout << "Current thread id: " << thisId << std::endl;
}
+//===----------------------------------------------------------------------===//
+// MLIR Runner (JitRunner) dynamic library integration.
+//===----------------------------------------------------------------------===//
+
+// Export symbols for the MLIR runner integration. All other symbols are hidden.
+#ifndef _WIN32
+#define API __attribute__((visibility("default")))
+#else
+#define API
+#endif // _WIN32
+
+extern "C" API void __mlir_runner_init(llvm::StringMap<void *> &exportSymbols) {
+ auto exportSymbol = [&](llvm::StringRef name, auto ptr) {
+ assert(exportSymbols.count(name) == 0 && "symbol already exists");
+ exportSymbols[name] = reinterpret_cast<void *>(ptr);
+ };
+
+ exportSymbol("mlirAsyncRuntimeAddRef",
+ &mlir::runtime::mlirAsyncRuntimeAddRef);
+ exportSymbol("mlirAsyncRuntimeDropRef",
+ &mlir::runtime::mlirAsyncRuntimeDropRef);
+ exportSymbol("mlirAsyncRuntimeExecute",
+ &mlir::runtime::mlirAsyncRuntimeExecute);
+ exportSymbol("mlirAsyncRuntimeGetValueStorage",
+ &mlir::runtime::mlirAsyncRuntimeGetValueStorage);
+ exportSymbol("mlirAsyncRuntimeCreateToken",
+ &mlir::runtime::mlirAsyncRuntimeCreateToken);
+ exportSymbol("mlirAsyncRuntimeCreateValue",
+ &mlir::runtime::mlirAsyncRuntimeCreateValue);
+ exportSymbol("mlirAsyncRuntimeEmplaceToken",
+ &mlir::runtime::mlirAsyncRuntimeEmplaceToken);
+ exportSymbol("mlirAsyncRuntimeEmplaceValue",
+ &mlir::runtime::mlirAsyncRuntimeEmplaceValue);
+ exportSymbol("mlirAsyncRuntimeAwaitToken",
+ &mlir::runtime::mlirAsyncRuntimeAwaitToken);
+ exportSymbol("mlirAsyncRuntimeAwaitValue",
+ &mlir::runtime::mlirAsyncRuntimeAwaitValue);
+ exportSymbol("mlirAsyncRuntimeAwaitTokenAndExecute",
+ &mlir::runtime::mlirAsyncRuntimeAwaitTokenAndExecute);
+ exportSymbol("mlirAsyncRuntimeAwaitValueAndExecute",
+ &mlir::runtime::mlirAsyncRuntimeAwaitValueAndExecute);
+ exportSymbol("mlirAsyncRuntimeCreateGroup",
+ &mlir::runtime::mlirAsyncRuntimeCreateGroup);
+ exportSymbol("mlirAsyncRuntimeAddTokenToGroup",
+ &mlir::runtime::mlirAsyncRuntimeAddTokenToGroup);
+ exportSymbol("mlirAsyncRuntimeAwaitAllInGroup",
+ &mlir::runtime::mlirAsyncRuntimeAwaitAllInGroup);
+ exportSymbol("mlirAsyncRuntimeAwaitAllInGroupAndExecute",
+ &mlir::runtime::mlirAsyncRuntimeAwaitAllInGroupAndExecute);
+ exportSymbol("mlirAsyncRuntimePrintCurrentThreadId",
+ &mlir::runtime::mlirAsyncRuntimePrintCurrentThreadId);
+}
+
+extern "C" API void __mlir_runner_destroy() { resetDefaultAsyncRuntime(); }
+
#endif // MLIR_ASYNCRUNTIME_DEFINE_FUNCTIONS
if (auto clOptLevel = getCommandLineOptLevel(options))
jitCodeGenOptLevel =
static_cast<llvm::CodeGenOpt::Level>(clOptLevel.getValue());
+
+ // If shared library implements custom mlir-runner library init and destroy
+ // functions, we'll use them to register the library with the execution
+ // engine. Otherwise we'll pass library directly to the execution engine.
SmallVector<StringRef, 4> libs(options.clSharedLibs.begin(),
options.clSharedLibs.end());
+
+ // Libraries that we'll pass to the ExecutionEngine for loading.
+ SmallVector<StringRef, 4> executionEngineLibs;
+
+ using MlirRunnerInitFn = void (*)(llvm::StringMap<void *> &);
+ using MlirRunnerDestroyFn = void (*)();
+
+ llvm::StringMap<void *> exportSymbols;
+ SmallVector<MlirRunnerDestroyFn> destroyFns;
+
+ // Handle libraries that do support mlir-runner init/destroy callbacks.
+ for (auto libPath : libs) {
+ auto lib = llvm::sys::DynamicLibrary::getPermanentLibrary(libPath.data());
+ void *initSym = lib.getAddressOfSymbol("__mlir_runner_init");
+ void *destroySim = lib.getAddressOfSymbol("__mlir_runner_destroy");
+
+ // Library does not support mlir runner, load it with ExecutionEngine.
+ if (!initSym || !destroySim) {
+ executionEngineLibs.push_back(libPath);
+ continue;
+ }
+
+ auto initFn = reinterpret_cast<MlirRunnerInitFn>(initSym);
+ initFn(exportSymbols);
+
+ auto destroyFn = reinterpret_cast<MlirRunnerDestroyFn>(destroySim);
+ destroyFns.push_back(destroyFn);
+ }
+
+ // Build a runtime symbol map from the config and exported symbols.
+ auto runtimeSymbolMap = [&](llvm::orc::MangleAndInterner interner) {
+ auto symbolMap = config.runtimeSymbolMap ? config.runtimeSymbolMap(interner)
+ : llvm::orc::SymbolMap();
+ for (auto &exportSymbol : exportSymbols)
+ symbolMap[interner(exportSymbol.getKey())] =
+ llvm::JITEvaluatedSymbol::fromPointer(exportSymbol.getValue());
+ return symbolMap;
+ };
+
auto expectedEngine = mlir::ExecutionEngine::create(
module, config.llvmModuleBuilder, config.transformer, jitCodeGenOptLevel,
- libs);
+ executionEngineLibs);
if (!expectedEngine)
return expectedEngine.takeError();
auto engine = std::move(*expectedEngine);
- if (config.runtimeSymbolMap)
- engine->registerSymbols(config.runtimeSymbolMap);
+ engine->registerSymbols(runtimeSymbolMap);
auto expectedFPtr = engine->lookup(entryPoint);
if (!expectedFPtr)
void (*fptr)(void **) = *expectedFPtr;
(*fptr)(args);
+ // Run all dynamic library destroy callbacks to prepare for the shutdown.
+ llvm::for_each(destroyFns, [](MlirRunnerDestroyFn destroy) { destroy(); });
+
return Error::success();
}