[llvm] [offload] Add Windows offload support (PR #187006)
Weronika Lewandowska via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 01:14:03 PDT 2026
https://github.com/wlemkows updated https://github.com/llvm/llvm-project/pull/187006
>From 85c606a3d112ba8a0d416348144980c9e00f6f83 Mon Sep 17 00:00:00 2001
From: Weronika Lewandowska <weronika.lewandowska at intel.com>
Date: Mon, 11 May 2026 11:06:30 +0200
Subject: [PATCH] [Offload] Add Windows offload support
---
offload/CMakeLists.txt | 64 +++++++++++++++----
offload/include/omptarget.h | 2 +-
offload/liboffload/CMakeLists.txt | 16 ++++-
offload/liboffload/src/OffloadImpl.cpp | 2 +-
.../common/include/ErrorReporting.h | 4 ++
.../common/include/GlobalHandler.h | 3 +-
.../common/src/GlobalHandler.cpp | 13 ++++
.../common/src/RecordReplay.cpp | 6 +-
.../plugins-nextgen/common/src/Utils/ELF.cpp | 9 ++-
.../level_zero/include/L0Device.h | 5 +-
offload/tools/CMakeLists.txt | 6 +-
11 files changed, 107 insertions(+), 23 deletions(-)
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index e8a25ece89a11..fc23f6454f007 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -8,9 +8,16 @@ set(LLVM_SUBPROJECT_TITLE "liboffload")
set(OFFLOAD_MIN_CUDA_VERSION 11.8.0)
set(OFFLOAD_MIN_CUDA_VERSION_CODE 11080)
+# libomptarget is not supported on Windows.
+set(BUILD_LIBOMPTARGET ON)
+if(MSVC)
+ set(BUILD_LIBOMPTARGET OFF)
+ message(STATUS "libomptarget is not supported on Windows, skipping.")
+endif()
+
# Check that the library can actually be built.
-if(APPLE OR WIN32 OR WASM)
- message(WARNING "libomptarget cannot be built on Windows and MacOS X!")
+if(APPLE OR WASM)
+ message(WARNING "libomptarget cannot be built on MacOS X and WASM!")
return()
elseif("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^(amdgcn|nvptx|spirv)" OR
"${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^(amdgcn|nvptx|spirv)")
@@ -43,6 +50,11 @@ endif()
set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
+if(WIN32)
+ # These are needed for RtlGetLastNtStatus and delay-load helpers
+ add_link_options(/DEFAULTLIB:ntdll.lib /DEFAULTLIB:delayimp.lib)
+endif()
+
option(OFFLOAD_INCLUDE_TESTS "Generate and build offload tests." ${LLVM_INCLUDE_TESTS})
# Add path for custom modules
@@ -123,12 +135,29 @@ if(DEFINED LIBOMPTARGET_BUILD_CUDA_PLUGIN OR
message(WARNING "Option removed, use 'LIBOMPTARGET_PLUGINS_TO_BUILD' instead")
endif()
-set(LIBOMPTARGET_ALL_PLUGIN_TARGETS amdgpu cuda)
-set(LIBOMPTARGET_PLUGINS_TO_BUILD "all" CACHE STRING
- "Semicolon-separated list of plugins to use: cuda, amdgpu, level_zero, or \"all\".")
+if(WIN32)
+ set(LIBOMPTARGET_ALL_PLUGIN_TARGETS "")
+
+ set(LIBOMPTARGET_PLUGINS_TO_BUILD "" CACHE STRING
+ "Semicolon-separated list of plugins to use: level_zero or \"all\".")
+ if(LIBOMPTARGET_PLUGINS_TO_BUILD STREQUAL "all")
+ set(LIBOMPTARGET_PLUGINS_TO_BUILD ${LIBOMPTARGET_ALL_PLUGIN_TARGETS})
+ endif()
+
+ # Validate that only supported plugins are requested on Windows.
+ foreach(plugin IN LISTS LIBOMPTARGET_PLUGINS_TO_BUILD)
+ if(NOT (plugin STREQUAL "level_zero" OR plugin STREQUAL "host"))
+ message(FATAL_ERROR "Plugin '${plugin}' is not supported on Windows.")
+ endif()
+ endforeach()
+else()
+ set(LIBOMPTARGET_ALL_PLUGIN_TARGETS amdgpu cuda)
+ set(LIBOMPTARGET_PLUGINS_TO_BUILD "all" CACHE STRING
+ "Semicolon-separated list of plugins to use: cuda, amdgpu or \"all\".")
-if(LIBOMPTARGET_PLUGINS_TO_BUILD STREQUAL "all")
- set(LIBOMPTARGET_PLUGINS_TO_BUILD ${LIBOMPTARGET_ALL_PLUGIN_TARGETS})
+ if(LIBOMPTARGET_PLUGINS_TO_BUILD STREQUAL "all")
+ set(LIBOMPTARGET_PLUGINS_TO_BUILD ${LIBOMPTARGET_ALL_PLUGIN_TARGETS})
+ endif()
endif()
list(APPEND LIBOMPTARGET_PLUGINS_TO_BUILD "host")
@@ -166,7 +195,7 @@ foreach(plugin IN LISTS LIBOMPTARGET_PLUGINS_TO_BUILD)
set(LIBOMPTARGET_ENUM_PLUGIN_TARGETS
"${LIBOMPTARGET_ENUM_PLUGIN_TARGETS}PLUGIN_TARGET(${plugin})\n")
endforeach()
-string(STRIP ${LIBOMPTARGET_ENUM_PLUGIN_TARGETS} LIBOMPTARGET_ENUM_PLUGIN_TARGETS)
+string(STRIP "${LIBOMPTARGET_ENUM_PLUGIN_TARGETS}" LIBOMPTARGET_ENUM_PLUGIN_TARGETS)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/include/Shared/Targets.def.in
${CMAKE_CURRENT_BINARY_DIR}/include/Shared/Targets.def
@@ -214,10 +243,20 @@ if(LIBOMPTARGET_ENABLE_DEBUG)
endif()
# No exceptions and no RTTI, except if requested.
-set(offload_compile_flags -fno-exceptions)
+if(MSVC)
+ set(offload_compile_flags /EHs-c-)
+else()
+ set(offload_compile_flags -fno-exceptions)
+endif()
+
if(NOT LLVM_ENABLE_RTTI)
- set(offload_compile_flags ${offload_compile_flags} -fno-rtti)
+ if(MSVC)
+ list(APPEND offload_compile_flags /GR-)
+ else()
+ list(APPEND offload_compile_flags -fno-rtti)
+ endif()
endif()
+
if(OFFLOAD_HAVE_WERROR_CTOR)
list(APPEND offload_compile_flags -Werror=global-constructors)
endif()
@@ -297,8 +336,9 @@ add_subdirectory(plugins-nextgen)
add_subdirectory(tools)
add_subdirectory(docs)
-# Build target agnostic offloading library.
-add_subdirectory(libomptarget)
+if(BUILD_LIBOMPTARGET)
+ add_subdirectory(libomptarget)
+endif()
add_subdirectory(liboffload)
diff --git a/offload/include/omptarget.h b/offload/include/omptarget.h
index e5d9852ad48a6..db9590844b2fd 100644
--- a/offload/include/omptarget.h
+++ b/offload/include/omptarget.h
@@ -46,7 +46,7 @@ enum __tgt_target_return_t : int {
};
/// Data attributes for each data reference used in an OpenMP target region.
-enum tgt_map_type {
+enum tgt_map_type : uint64_t {
// No flags
OMP_TGT_MAPTYPE_NONE = 0x000,
// copy data from host to device
diff --git a/offload/liboffload/CMakeLists.txt b/offload/liboffload/CMakeLists.txt
index aeb34d45258ff..0f5a0109f4b8d 100644
--- a/offload/liboffload/CMakeLists.txt
+++ b/offload/liboffload/CMakeLists.txt
@@ -13,6 +13,8 @@ else()
endif()
target_link_libraries(LLVMOffload PRIVATE ${llvm_libs})
+target_link_libraries(LLVMOffload PRIVATE PluginCommon)
+
foreach(plugin IN LISTS LIBOMPTARGET_PLUGINS_TO_BUILD)
target_link_libraries(LLVMOffload PRIVATE omptarget.rtl.${plugin})
endforeach()
@@ -26,6 +28,7 @@ target_include_directories(LLVMOffload PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../include
+ PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../plugins-nextgen/common/include
${CMAKE_CURRENT_BINARY_DIR}/../plugins-nextgen/common/include
)
@@ -47,7 +50,18 @@ if(UNIX AND NOT APPLE)
SOVERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}"
VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}")
endif()
-install(TARGETS LLVMOffload LIBRARY COMPONENT offload DESTINATION "${OFFLOAD_INSTALL_LIBDIR}")
+install(TARGETS LLVMOffload
+ COMPONENT offload
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ LIBRARY DESTINATION "${OFFLOAD_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${OFFLOAD_INSTALL_LIBDIR}")
+
+if(MSVC)
+ install(FILES "$<TARGET_PDB_FILE:LLVMOffload>"
+ CONFIGURATIONS Debug RelWithDebInfo
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ OPTIONAL)
+endif()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/API/OffloadAPI.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/offload COMPONENT offload)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/API/OffloadPrint.hpp DESTINATION ${CMAKE_INSTALL_PREFIX}/include/offload COMPONENT offload)
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index 63294886e520e..20f3dffa081b3 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -259,7 +259,7 @@ template <typename HandleT> Error olDestroy(HandleT Handle) {
return Error::success();
}
-constexpr ol_platform_backend_t pluginNameToBackend(StringRef Name) {
+ol_platform_backend_t pluginNameToBackend(StringRef Name) {
if (Name == "amdgpu") {
return OL_PLATFORM_BACKEND_AMDGPU;
} else if (Name == "cuda") {
diff --git a/offload/plugins-nextgen/common/include/ErrorReporting.h b/offload/plugins-nextgen/common/include/ErrorReporting.h
index ff7d9b4f39d2b..e6f65549bc354 100644
--- a/offload/plugins-nextgen/common/include/ErrorReporting.h
+++ b/offload/plugins-nextgen/common/include/ErrorReporting.h
@@ -72,9 +72,11 @@ class ErrorReporter {
llvm_unreachable("Unknown target alloc kind");
}
+#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#pragma clang diagnostic ignored "-Wformat-security"
+#endif
/// Print \p Format, instantiated with \p Args to stderr.
/// TODO: Allow redirection into a file stream.
template <typename... ArgsTy>
@@ -109,7 +111,9 @@ class ErrorReporter {
print(BoldRed, Format, Args...);
print("\n");
}
+#ifdef __clang__
#pragma clang diagnostic pop
+#endif
static void reportError(const char *Str) { reportError("%s", Str); }
static void print(const char *Str) { print("%s", Str); }
diff --git a/offload/plugins-nextgen/common/include/GlobalHandler.h b/offload/plugins-nextgen/common/include/GlobalHandler.h
index fc8d6fe384754..5c1786afb9e89 100644
--- a/offload/plugins-nextgen/common/include/GlobalHandler.h
+++ b/offload/plugins-nextgen/common/include/GlobalHandler.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/Compiler.h"
#include "Shared/Debug.h"
#include "Shared/Utils.h"
@@ -72,7 +73,7 @@ struct __llvm_profile_gpu_sections {
};
extern "C" {
-extern int __attribute__((weak)) __llvm_write_custom_profile(
+extern int LLVM_ATTRIBUTE_WEAK __llvm_write_custom_profile(
const char *Target, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const char *CountersBegin,
const char *CountersEnd, const char *NamesBegin, const char *NamesEnd,
diff --git a/offload/plugins-nextgen/common/src/GlobalHandler.cpp b/offload/plugins-nextgen/common/src/GlobalHandler.cpp
index 9216834b1e15e..796ac2b33829a 100644
--- a/offload/plugins-nextgen/common/src/GlobalHandler.cpp
+++ b/offload/plugins-nextgen/common/src/GlobalHandler.cpp
@@ -30,6 +30,19 @@ using namespace plugin;
using namespace error;
using namespace llvm::offload::debug;
+// Windows/MSVC doesn't support weak symbols properly, so provide a stub
+// implementation that will be used if compiler-rt is not linked.
+#ifdef _WIN32
+extern "C" int __llvm_write_custom_profile(
+ const char *Target, const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const char *CountersBegin,
+ const char *CountersEnd, const char *NamesBegin, const char *NamesEnd,
+ const uint64_t *VersionOverride) {
+ // Return error code indicating profiling is not available
+ return -1;
+}
+#endif
+
Expected<std::unique_ptr<ObjectFile>>
GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
diff --git a/offload/plugins-nextgen/common/src/RecordReplay.cpp b/offload/plugins-nextgen/common/src/RecordReplay.cpp
index 1d4acbc5bbd4c..e89b516983e41 100644
--- a/offload/plugins-nextgen/common/src/RecordReplay.cpp
+++ b/offload/plugins-nextgen/common/src/RecordReplay.cpp
@@ -69,9 +69,9 @@ Error RecordReplayTy::init(uint64_t MemSize, void *VAddr) {
INFO(OMP_INFOTYPE_PLUGIN_KERNEL, Device.getDeviceId(),
"%s initialized with starting address %p, "
- "memory size %lu bytes, and output directory in %s\n",
+ "memory size %" PRIu64 " bytes, and output directory in %s\n",
Status == StatusTy::Recording ? "Record" : "Replay", StartAddr,
- TotalSize, OutputDirectory.c_str());
+ TotalSize, OutputDirectory.string().c_str());
return Plugin::success();
}
@@ -308,7 +308,7 @@ NativeRecordReplayTy::getFilenameImpl(const InstanceTy &Instance,
Filepath /= std::to_string(Instance.KernelHash) + "_" +
std::to_string(Instance.LaunchConfigHash);
Filepath.replace_extension(getExtension(FileType).data());
- SmallString<128> Filename(Filepath.c_str());
+ SmallString<128> Filename(Filepath.string());
return Filename;
}
diff --git a/offload/plugins-nextgen/common/src/Utils/ELF.cpp b/offload/plugins-nextgen/common/src/Utils/ELF.cpp
index 9762a5d738db8..6ddf8f1a3d270 100644
--- a/offload/plugins-nextgen/common/src/Utils/ELF.cpp
+++ b/offload/plugins-nextgen/common/src/Utils/ELF.cpp
@@ -50,7 +50,14 @@ uint16_t utils::elf::getTargetMachine() {
#elif defined(__loongarch__)
return EM_LOONGARCH;
#else
-#warning "Unknown ELF compilation target architecture"
+// #warning directive is available starting in C23 and C++23.
+#define UNKNOWN_ARCH_MSG "Unknown ELF compilation target architecture"
+#ifdef _MSC_VER
+#pragma message(UNKNOWN_ARCH_MSG)
+#else
+#warning UNKNOWN_ARCH_MSG
+#endif
+#undef UNKNOWN_ARCH_MSG
return EM_NONE;
#endif
}
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index 275182faebfd6..8a30a1d7020f1 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -22,6 +22,7 @@
#include "L0Program.h"
#include "L0Queue.h"
#include "PluginInterface.h"
+#include <limits>
namespace llvm::omp::target::plugin {
@@ -104,8 +105,8 @@ class L0DeviceTy final : public GenericDeviceTy {
std::string zeId;
/// Command queue group ordinals for each device.
- static constexpr uint32_t MaxOrdinal =
- std::numeric_limits<decltype(MaxOrdinal)>::max();
+ static constexpr uint32_t MaxOrdinal = std::numeric_limits<uint32_t>::max();
+
std::pair<uint32_t, uint32_t> ComputeOrdinal{MaxOrdinal, 0};
/// Command queue index for each device.
diff --git a/offload/tools/CMakeLists.txt b/offload/tools/CMakeLists.txt
index 7010ba93a4322..7c35cd4c80b93 100644
--- a/offload/tools/CMakeLists.txt
+++ b/offload/tools/CMakeLists.txt
@@ -11,4 +11,8 @@ macro(add_offload_tool_symlink name)
endmacro()
add_subdirectory(deviceinfo)
-add_subdirectory(kernelreplay)
+
+# kernelreplay requires libomptarget which is not available on Windows
+if(BUILD_LIBOMPTARGET)
+ add_subdirectory(kernelreplay)
+endif()
More information about the llvm-commits
mailing list