[Mlir-commits] [mlir] [MLIR][ROCm] Export runtime wrappers on Windows (PR #213046)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Aug 3 03:00:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-execution-engine
Author: ppetrovi-amd
<details>
<summary>Changes</summary>
## Summary
Export the ROCm runtime wrapper entry points when building
`mlir_rocm_runtime` as a Windows DLL.
Use `__attribute__((visibility("default")))` on other platforms.
## Motivation
`extern "C"` prevents C++ name mangling, but it does not add symbols to a
Windows DLL export table. Consequently, `mlir-runner` can load
`mlir_rocm_runtime.dll`, but ORC cannot resolve its `mgpu*` entry points.
CUDA, SYCL, Vulkan, and SPIR-V runtime wrappers already use explicit Windows
export annotations. This applies the same approach to the ROCm runtime.
## Testing
Built with TheRock ROCm using clang-cl/lld-link on Windows.
Before this change:
- `llvm-readobj --coff-exports mlir_rocm_runtime.dll` reported no exports.
- `mlir-runner` failed with:
`Symbols not found: [ mgpuSetDefaultDevice ]`
After this change:
- `mlir_rocm_runtime` builds successfully.
- Its COFF export table contains all 26 `mgpu*` entry points.
- A minimal `mlir-runner --shared-libs=mlir_rocm_runtime.dll` JIT test
resolves and calls `mgpuSetDefaultDevice` successfully.
No automated test is added because validating the PE export table requires a Windows ROCm environment. The change was validated manually with COFF export inspection and a mlir-runner JIT test.
## AI assistance
I used Cursor to help research existing MLIR precedents and prepare this
change. I reviewed and validated the final patch.
---
Full diff: https://github.com/llvm/llvm-project/pull/213046.diff
1 Files Affected:
- (modified) mlir/lib/ExecutionEngine/RocmRuntimeWrappers.cpp (+51-37)
``````````diff
diff --git a/mlir/lib/ExecutionEngine/RocmRuntimeWrappers.cpp b/mlir/lib/ExecutionEngine/RocmRuntimeWrappers.cpp
index 42018b3722a8a..c90e1c6dfc219 100644
--- a/mlir/lib/ExecutionEngine/RocmRuntimeWrappers.cpp
+++ b/mlir/lib/ExecutionEngine/RocmRuntimeWrappers.cpp
@@ -20,6 +20,12 @@
#include "hip/hip_runtime.h"
+#ifdef _WIN32
+#define MLIR_ROCM_WRAPPERS_EXPORT __declspec(dllexport)
+#else
+#define MLIR_ROCM_WRAPPERS_EXPORT __attribute__((visibility("default")))
+#endif // _WIN32
+
#define HIP_REPORT_IF_ERROR(expr) \
[](hipError_t result) { \
if (!result) \
@@ -32,24 +38,25 @@
thread_local static int32_t defaultDevice = 0;
-extern "C" hipModule_t mgpuModuleLoad(void *data, size_t /*gpuBlobSize*/) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT hipModule_t
+mgpuModuleLoad(void *data, size_t /*gpuBlobSize*/) {
hipModule_t module = nullptr;
HIP_REPORT_IF_ERROR(hipModuleLoadData(&module, data));
return module;
}
-extern "C" hipModule_t mgpuModuleLoadJIT(void *data, int optLevel,
- size_t /*assmeblySize*/) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT hipModule_t
+mgpuModuleLoadJIT(void *data, int optLevel, size_t /*assmeblySize*/) {
assert(false && "This function is not available in HIP.");
return nullptr;
}
-extern "C" void mgpuModuleUnload(hipModule_t module) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuModuleUnload(hipModule_t module) {
HIP_REPORT_IF_ERROR(hipModuleUnload(module));
}
-extern "C" hipFunction_t mgpuModuleGetFunction(hipModule_t module,
- const char *name) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT hipFunction_t
+mgpuModuleGetFunction(hipModule_t module, const char *name) {
hipFunction_t function = nullptr;
HIP_REPORT_IF_ERROR(hipModuleGetFunction(&function, module, name));
return function;
@@ -58,12 +65,11 @@ extern "C" hipFunction_t mgpuModuleGetFunction(hipModule_t module,
// The wrapper uses intptr_t instead of ROCM's unsigned int to match
// the type of MLIR's index type. This avoids the need for casts in the
// generated MLIR code.
-extern "C" void mgpuLaunchKernel(hipFunction_t function, intptr_t gridX,
- intptr_t gridY, intptr_t gridZ,
- intptr_t blockX, intptr_t blockY,
- intptr_t blockZ, int32_t smem,
- hipStream_t stream, void **params,
- void **extra, size_t /*paramsCount*/) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuLaunchKernel(hipFunction_t function, intptr_t gridX, intptr_t gridY,
+ intptr_t gridZ, intptr_t blockX, intptr_t blockY,
+ intptr_t blockZ, int32_t smem, hipStream_t stream,
+ void **params, void **extra, size_t /*paramsCount*/) {
HIP_REPORT_IF_ERROR(hipModuleLaunchKernel(function, gridX, gridY, gridZ,
blockX, blockY, blockZ, smem,
stream, params, extra));
@@ -72,7 +78,7 @@ extern "C" void mgpuLaunchKernel(hipFunction_t function, intptr_t gridX,
// Cooperative launch entry point. The cluster dimensions are accepted to
// match the CUDA wrapper signature, but HIP does not support thread block
// clusters; passing nonzero cluster dimensions is a usage error.
-extern "C" void mgpuLaunchKernelCooperative(
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuLaunchKernelCooperative(
hipFunction_t function, intptr_t gridX, intptr_t gridY, intptr_t gridZ,
intptr_t clusterX, intptr_t clusterY, intptr_t clusterZ, intptr_t blockX,
intptr_t blockY, intptr_t blockZ, int32_t smem, hipStream_t stream,
@@ -89,67 +95,74 @@ extern "C" void mgpuLaunchKernelCooperative(
blockY, blockZ, smem, stream, params));
}
-extern "C" hipStream_t mgpuStreamCreate() {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT hipStream_t mgpuStreamCreate() {
hipStream_t stream = nullptr;
HIP_REPORT_IF_ERROR(hipStreamCreate(&stream));
return stream;
}
-extern "C" void mgpuStreamDestroy(hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuStreamDestroy(hipStream_t stream) {
HIP_REPORT_IF_ERROR(hipStreamDestroy(stream));
}
-extern "C" void mgpuStreamSynchronize(hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuStreamSynchronize(hipStream_t stream) {
return HIP_REPORT_IF_ERROR(hipStreamSynchronize(stream));
}
-extern "C" void mgpuStreamWaitEvent(hipStream_t stream, hipEvent_t event) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuStreamWaitEvent(hipStream_t stream, hipEvent_t event) {
HIP_REPORT_IF_ERROR(hipStreamWaitEvent(stream, event, /*flags=*/0));
}
-extern "C" hipEvent_t mgpuEventCreate() {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT hipEvent_t mgpuEventCreate() {
hipEvent_t event = nullptr;
HIP_REPORT_IF_ERROR(hipEventCreateWithFlags(&event, hipEventDisableTiming));
return event;
}
-extern "C" void mgpuEventDestroy(hipEvent_t event) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuEventDestroy(hipEvent_t event) {
HIP_REPORT_IF_ERROR(hipEventDestroy(event));
}
-extern "C" void mgpuEventSynchronize(hipEvent_t event) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuEventSynchronize(hipEvent_t event) {
HIP_REPORT_IF_ERROR(hipEventSynchronize(event));
}
-extern "C" void mgpuEventRecord(hipEvent_t event, hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuEventRecord(hipEvent_t event,
+ hipStream_t stream) {
HIP_REPORT_IF_ERROR(hipEventRecord(event, stream));
}
-extern "C" void *mgpuMemAlloc(uint64_t sizeBytes, hipStream_t /*stream*/,
- bool /*isHostShared*/) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void *mgpuMemAlloc(uint64_t sizeBytes,
+ hipStream_t /*stream*/,
+ bool /*isHostShared*/) {
void *ptr;
HIP_REPORT_IF_ERROR(hipMalloc(&ptr, sizeBytes));
return ptr;
}
-extern "C" void mgpuMemFree(void *ptr, hipStream_t /*stream*/) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuMemFree(void *ptr,
+ hipStream_t /*stream*/) {
HIP_REPORT_IF_ERROR(hipFree(ptr));
}
-extern "C" void mgpuMemcpy(void *dst, void *src, size_t sizeBytes,
- hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuMemcpy(void *dst, void *src, size_t sizeBytes, hipStream_t stream) {
HIP_REPORT_IF_ERROR(
hipMemcpyAsync(dst, src, sizeBytes, hipMemcpyDefault, stream));
}
-extern "C" void mgpuMemset32(void *dst, int value, size_t count,
- hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuMemset32(void *dst, int value, size_t count, hipStream_t stream) {
HIP_REPORT_IF_ERROR(hipMemsetD32Async(reinterpret_cast<hipDeviceptr_t>(dst),
value, count, stream));
}
-extern "C" void mgpuMemset16(void *dst, int short value, size_t count,
- hipStream_t stream) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuMemset16(void *dst, int short value, size_t count, hipStream_t stream) {
HIP_REPORT_IF_ERROR(hipMemsetD16Async(reinterpret_cast<hipDeviceptr_t>(dst),
value, count, stream));
}
@@ -158,13 +171,14 @@ extern "C" void mgpuMemset16(void *dst, int short value, size_t count,
// Allows to register byte array with the ROCM runtime. Helpful until we have
// transfer functions implemented.
-extern "C" void mgpuMemHostRegister(void *ptr, uint64_t sizeBytes) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
+mgpuMemHostRegister(void *ptr, uint64_t sizeBytes) {
HIP_REPORT_IF_ERROR(hipHostRegister(ptr, sizeBytes, /*flags=*/0));
}
// Allows to register a MemRef with the ROCm runtime. Helpful until we have
// transfer functions implemented.
-extern "C" void
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
mgpuMemHostRegisterMemRef(int64_t rank, StridedMemRefType<char, 1> *descriptor,
int64_t elementSizeBytes) {
int64_t *sizes = descriptor->sizes;
@@ -183,13 +197,13 @@ mgpuMemHostRegisterMemRef(int64_t rank, StridedMemRefType<char, 1> *descriptor,
// Allows to unregister byte array with the ROCM runtime. Helpful until we have
// transfer functions implemented.
-extern "C" void mgpuMemHostUnregister(void *ptr) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuMemHostUnregister(void *ptr) {
HIP_REPORT_IF_ERROR(hipHostUnregister(ptr));
}
// Allows to unregister a MemRef with the ROCm runtime. Helpful until we have
// transfer functions implemented.
-extern "C" void
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void
mgpuMemHostUnregisterMemRef(int64_t rank,
StridedMemRefType<char, 1> *descriptor,
int64_t elementSizeBytes) {
@@ -204,7 +218,7 @@ void mgpuMemGetDevicePointer(T *hostPtr, T **devicePtr) {
hipHostGetDevicePointer((void **)devicePtr, hostPtr, /*flags=*/0));
}
-extern "C" StridedMemRefType<float, 1>
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT StridedMemRefType<float, 1>
mgpuMemGetDeviceMemRef1dFloat(float *allocated, float *aligned, int64_t offset,
int64_t size, int64_t stride) {
float *devicePtr = nullptr;
@@ -212,7 +226,7 @@ mgpuMemGetDeviceMemRef1dFloat(float *allocated, float *aligned, int64_t offset,
return {devicePtr, devicePtr, offset, {size}, {stride}};
}
-extern "C" StridedMemRefType<int32_t, 1>
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT StridedMemRefType<int32_t, 1>
mgpuMemGetDeviceMemRef1dInt32(int32_t *allocated, int32_t *aligned,
int64_t offset, int64_t size, int64_t stride) {
int32_t *devicePtr = nullptr;
@@ -220,7 +234,7 @@ mgpuMemGetDeviceMemRef1dInt32(int32_t *allocated, int32_t *aligned,
return {devicePtr, devicePtr, offset, {size}, {stride}};
}
-extern "C" void mgpuSetDefaultDevice(int32_t device) {
+extern "C" MLIR_ROCM_WRAPPERS_EXPORT void mgpuSetDefaultDevice(int32_t device) {
defaultDevice = device;
HIP_REPORT_IF_ERROR(hipSetDevice(device));
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/213046
More information about the Mlir-commits
mailing list