[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