[llvm] [offload] Add `dlwrap::loaded` function to check for optional symbols (PR #210737)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 06:26:55 PDT 2026


https://github.com/blazej-smorawski updated https://github.com/llvm/llvm-project/pull/210737

>From b56f231c699b16a59a35035b020a5dbcdd257b30 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Fri, 3 Jul 2026 13:48:27 +0200
Subject: [PATCH 1/9] [offload] Add `dlwrap::loaded` function to check for
 optional symbols

---
 offload/plugins-nextgen/common/include/DLWrap.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 95ce86e123cd3..116cd4afe37a6 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -135,6 +135,8 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
   static_assert(Requested == Required, "Arity Error");
 }
 
+template <auto Fn> bool loaded();
+
 } // namespace dlwrap
 
 #define DLWRAP_INSTANTIATE(SYM_DEF, SYM_USE, ARITY)                            \
@@ -167,6 +169,9 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
       return reinterpret_cast<T::FunctionType>(P);                             \
     }                                                                          \
   };                                                                           \
+  template <> bool loaded<&(::SYMBOL)>() {                                     \
+    return SYMBOL##_Trait::get() != nullptr;                                   \
+  }                                                                            \
   }
 
 #define DLWRAP_IMPL(SYMBOL, ARITY)                                             \

>From 69f70b7216f6e233c43b5247af631771944bcd10 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Wed, 22 Jul 2026 12:53:47 +0200
Subject: [PATCH 2/9] [offload] Add helpers to enable optional symbols from
 external APIs

---
 .../common/include/APIHelpers.h               | 41 +++++++++++++++++++
 .../plugins-nextgen/common/include/DLWrap.h   | 12 +++++-
 .../level_zero/include/L0CmdListManager.h     | 10 +++++
 .../level_zero/include/L0Compat.h             | 28 +++++++++++++
 4 files changed, 89 insertions(+), 2 deletions(-)
 create mode 100644 offload/plugins-nextgen/common/include/APIHelpers.h
 create mode 100644 offload/plugins-nextgen/level_zero/include/L0Compat.h

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
new file mode 100644
index 0000000000000..7c0e283ab5805
--- /dev/null
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -0,0 +1,41 @@
+//===-- Shared/APIHelpers.h - helpers for external APIs --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The header contains helper functions to make interactions with external APIs
+// such as CUDA or level zero easier
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_APIHELPERS_H
+#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_APIHELPERS_H
+
+#include "DLWrap.h"
+
+// Macro to mark external symbol as weak, so linker will be okay
+// if the symbol is missing. For direct linking (dlwrap::IsDlOpened<&name> ==
+// false), we need to check if linker could find the symbol. For symbols loaded
+// using dlsym we use dlwrap::loaded<name>().
+#define API_HELPER_OPTIONAL(return_type, name, ...)                            \
+  extern "C" return_type name(__VA_ARGS__) __attribute__((weak));              \
+  template <> inline bool api_helper::canCall<name>() {                    \
+    if constexpr (dlwrap::IsDlOpened<&name>)                                   \
+      return dlwrap::loaded<name>();                                           \
+    return name != nullptr;                                                    \
+  }
+
+namespace api_helper {
+
+// Default template specialization for extra safety
+template <auto Fn>
+bool canCall() {
+  static_assert(false, "api_helper::canCall() should only be called on symbols decorated with API_HELPER_OPTIONAL!");
+}
+
+} // namespace api_helper
+
+#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_APIHELPERS_H
\ No newline at end of file
diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 116cd4afe37a6..863d8006f246a 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -78,7 +78,7 @@
   static size_t size();                                                        \
   static const char *symbol(size_t); /* get symbol name in [0, size()) */      \
   static void **                                                               \
-      pointer(size_t); /* get pointer to function pointer in [0, size()) */    \
+  pointer(size_t); /* get pointer to function pointer in [0, size()) */        \
   }
 
 // DLWRAP_FINALIZE() implements the functions from DLWRAP_INITIALIZE
@@ -107,7 +107,9 @@ template <size_t S> struct count {
   static constexpr size_t N = count<S - 1>::N;
 };
 
-template <> struct count<0> { static constexpr size_t N = 0; };
+template <> struct count<0> {
+  static constexpr size_t N = 0;
+};
 
 // Get a constexpr size_t ID, starts at zero
 #define DLWRAP_ID() (dlwrap::type::count<__LINE__>::N)
@@ -135,8 +137,13 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
   static_assert(Requested == Required, "Arity Error");
 }
 
+// Template to check if a symbol was loaded successfully
 template <auto Fn> bool loaded();
 
+// Template to check if a symbol is provided by dlwrap
+// By default all symbols resolve to false
+template <auto Fn> constexpr bool IsDlOpened = false;
+
 } // namespace dlwrap
 
 #define DLWRAP_INSTANTIATE(SYM_DEF, SYM_USE, ARITY)                            \
@@ -160,6 +167,7 @@ template <auto Fn> bool loaded();
   DLWRAP_INC();                                                                \
   DLWRAP_SYMBOL(SYMBOL, DLWRAP_ID() - 1);                                      \
   namespace dlwrap {                                                           \
+  template <> inline constexpr bool IsDlOpened<&::SYMBOL> = true;              \
   struct SYMBOL##_Trait : public dlwrap::trait<decltype(&SYMBOL)> {            \
     using T = dlwrap::trait<decltype(&SYMBOL)>;                                \
     static T::FunctionType get() {                                             \
diff --git a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
index 94ddef231ff11..1f86006b30a0b 100644
--- a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
+++ b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
@@ -13,9 +13,11 @@
 #ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CMDLISTMANAGER_H
 #define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CMDLISTMANAGER_H
 
+#include "L0Compat.h"
 #include "L0Context.h"
 #include "L0Defs.h"
 #include "L0Trace.h"
+#include "PluginInterface.h"
 #include <mutex>
 
 namespace llvm::omp::target::plugin {
@@ -126,10 +128,18 @@ class L0CmdListManagerTy {
       const ze_group_size_t *GroupSizes, void **ArgPtrs,
       ze_event_handle_t SignalEvent = nullptr, uint32_t NumWaitEvents = 0,
       ze_event_handle_t *WaitEvents = nullptr, bool IsCooperative = false) {
+
+    if (!api_helper::canCall<zeCommandListAppendLaunchKernelWithArguments>())
+      return Plugin::error(
+          ErrorCode::UNSUPPORTED,
+          "zeCommandListAppendLaunchKernelWithArguments is not "
+          "available on this driver");
+
     ze_command_list_append_launch_kernel_param_cooperative_desc_t CoopDesc = {
         ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_PARAM_COOPERATIVE_DESC, nullptr,
         static_cast<ze_bool_t>(IsCooperative)};
     std::lock_guard<std::mutex> Lock(Mtx);
+
     CALL_ZE_RET_ERROR(zeCommandListAppendLaunchKernelWithArguments, CmdList,
                       Kernel, *GroupCounts, *GroupSizes, ArgPtrs,
                       IsCooperative ? &CoopDesc : nullptr, SignalEvent,
diff --git a/offload/plugins-nextgen/level_zero/include/L0Compat.h b/offload/plugins-nextgen/level_zero/include/L0Compat.h
new file mode 100644
index 0000000000000..2062c9624ad20
--- /dev/null
+++ b/offload/plugins-nextgen/level_zero/include/L0Compat.h
@@ -0,0 +1,28 @@
+//===--- Level Zero Target RTL Implementation -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Level Zero compatibility layer enabling us to compile using new APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0COMPAT_H
+#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0COMPAT_H
+
+#include "APIHelpers.h"
+
+#include <level_zero/ze_api.h>
+
+API_HELPER_OPTIONAL(ze_result_t, zeCommandListAppendLaunchKernelWithArguments,
+                    ze_command_list_handle_t hCommandList,
+                    ze_kernel_handle_t hKernel,
+                    const ze_group_count_t groupCounts,
+                    const ze_group_size_t groupSizes, void **pArguments,
+                    const void *pNext, ze_event_handle_t hSignalEvent,
+                    uint32_t numWaitEvents, ze_event_handle_t *phWaitEvents);
+
+#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0COMPAT_H

>From a84b4d7104618abd075eac95520de690c5a1088f Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Wed, 22 Jul 2026 14:43:45 +0200
Subject: [PATCH 3/9] [offload] Make `canCall` work on older compilers

---
 offload/plugins-nextgen/common/include/APIHelpers.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 7c0e283ab5805..2bf331507ec8d 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -33,7 +33,7 @@ namespace api_helper {
 // Default template specialization for extra safety
 template <auto Fn>
 bool canCall() {
-  static_assert(false, "api_helper::canCall() should only be called on symbols decorated with API_HELPER_OPTIONAL!");
+  static_assert(sizeof(decltype(Fn)*) == 0, "api_helper::canCall() should only be called on symbols decorated with API_HELPER_OPTIONAL!");
 }
 
 } // namespace api_helper

>From 434a91e2088fc810bbe39f979c944bae076562d2 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Wed, 22 Jul 2026 14:50:00 +0200
Subject: [PATCH 4/9] [offload] Fix format

---
 offload/plugins-nextgen/common/include/APIHelpers.h | 9 +++++----
 offload/plugins-nextgen/common/include/DLWrap.h     | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 2bf331507ec8d..88a430bdb4839 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -22,7 +22,7 @@
 // using dlsym we use dlwrap::loaded<name>().
 #define API_HELPER_OPTIONAL(return_type, name, ...)                            \
   extern "C" return_type name(__VA_ARGS__) __attribute__((weak));              \
-  template <> inline bool api_helper::canCall<name>() {                    \
+  template <> inline bool api_helper::canCall<name>() {                        \
     if constexpr (dlwrap::IsDlOpened<&name>)                                   \
       return dlwrap::loaded<name>();                                           \
     return name != nullptr;                                                    \
@@ -31,9 +31,10 @@
 namespace api_helper {
 
 // Default template specialization for extra safety
-template <auto Fn>
-bool canCall() {
-  static_assert(sizeof(decltype(Fn)*) == 0, "api_helper::canCall() should only be called on symbols decorated with API_HELPER_OPTIONAL!");
+template <auto Fn> bool canCall() {
+  static_assert(sizeof(decltype(Fn) *) == 0,
+                "api_helper::canCall() should only be called on symbols "
+                "decorated with API_HELPER_OPTIONAL!");
 }
 
 } // namespace api_helper
diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 863d8006f246a..160731a176d6d 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -78,7 +78,7 @@
   static size_t size();                                                        \
   static const char *symbol(size_t); /* get symbol name in [0, size()) */      \
   static void **                                                               \
-  pointer(size_t); /* get pointer to function pointer in [0, size()) */        \
+      pointer(size_t); /* get pointer to function pointer in [0, size()) */    \
   }
 
 // DLWRAP_FINALIZE() implements the functions from DLWRAP_INITIALIZE

>From a0667a9133959aa50c004b1f230722441cb5185f Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Thu, 23 Jul 2026 16:16:08 +0200
Subject: [PATCH 5/9] [offload] Fix incorrect constexpr in
 `API_HELPER_OPTIONAL`

---
 offload/plugins-nextgen/common/include/APIHelpers.h | 11 +++++++----
 offload/plugins-nextgen/common/include/DLWrap.h     | 12 +++++-------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 88a430bdb4839..85bdfb8f640e1 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -20,12 +20,15 @@
 // if the symbol is missing. For direct linking (dlwrap::IsDlOpened<&name> ==
 // false), we need to check if linker could find the symbol. For symbols loaded
 // using dlsym we use dlwrap::loaded<name>().
-#define API_HELPER_OPTIONAL(return_type, name, ...)                            \
+#define API_HELPER_OPTIONAL(return_type, name, ...)                           \
   extern "C" return_type name(__VA_ARGS__) __attribute__((weak));              \
   template <> inline bool api_helper::canCall<name>() {                        \
-    if constexpr (dlwrap::IsDlOpened<&name>)                                   \
-      return dlwrap::loaded<name>();                                           \
-    return name != nullptr;                                                    \
+    if (name == nullptr)                                                       \
+      /* Not loaded weak symbol */                                             \
+      return false;                                                          \
+    /* Symbols from dlwrap are never nullptr, but `loaded` might return false  \
+     */                                                                        \
+    return dlwrap::loaded<name>();                                             \
   }
 
 namespace api_helper {
diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 160731a176d6d..394891abded9d 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -137,12 +137,11 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
   static_assert(Requested == Required, "Arity Error");
 }
 
-// Template to check if a symbol was loaded successfully
-template <auto Fn> bool loaded();
-
-// Template to check if a symbol is provided by dlwrap
-// By default all symbols resolve to false
-template <auto Fn> constexpr bool IsDlOpened = false;
+// Template to check if a symbol was loaded successfully.
+// Returns true for symbols that were not wrapped by dlwrap.
+template <auto Fn> bool loaded() {
+  return true;
+}
 
 } // namespace dlwrap
 
@@ -167,7 +166,6 @@ template <auto Fn> constexpr bool IsDlOpened = false;
   DLWRAP_INC();                                                                \
   DLWRAP_SYMBOL(SYMBOL, DLWRAP_ID() - 1);                                      \
   namespace dlwrap {                                                           \
-  template <> inline constexpr bool IsDlOpened<&::SYMBOL> = true;              \
   struct SYMBOL##_Trait : public dlwrap::trait<decltype(&SYMBOL)> {            \
     using T = dlwrap::trait<decltype(&SYMBOL)>;                                \
     static T::FunctionType get() {                                             \

>From 07c151b7bf58cde95d5c66538f78dc67a2c62946 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Thu, 23 Jul 2026 16:22:08 +0200
Subject: [PATCH 6/9] [offload] Fix format

---
 offload/plugins-nextgen/common/include/APIHelpers.h | 4 ++--
 offload/plugins-nextgen/common/include/DLWrap.h     | 4 +---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 85bdfb8f640e1..182f11fc4bc3a 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -20,12 +20,12 @@
 // if the symbol is missing. For direct linking (dlwrap::IsDlOpened<&name> ==
 // false), we need to check if linker could find the symbol. For symbols loaded
 // using dlsym we use dlwrap::loaded<name>().
-#define API_HELPER_OPTIONAL(return_type, name, ...)                           \
+#define API_HELPER_OPTIONAL(return_type, name, ...)                            \
   extern "C" return_type name(__VA_ARGS__) __attribute__((weak));              \
   template <> inline bool api_helper::canCall<name>() {                        \
     if (name == nullptr)                                                       \
       /* Not loaded weak symbol */                                             \
-      return false;                                                          \
+      return false;                                                            \
     /* Symbols from dlwrap are never nullptr, but `loaded` might return false  \
      */                                                                        \
     return dlwrap::loaded<name>();                                             \
diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 394891abded9d..16f5a86911da3 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -139,9 +139,7 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
 
 // Template to check if a symbol was loaded successfully.
 // Returns true for symbols that were not wrapped by dlwrap.
-template <auto Fn> bool loaded() {
-  return true;
-}
+template <auto Fn> bool loaded() { return true; }
 
 } // namespace dlwrap
 

>From 6d10d147bc020b23d5d54f4dc031f1d1951198c1 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Fri, 24 Jul 2026 10:34:31 +0200
Subject: [PATCH 7/9] [offload] Disable direct linking on Windows

---
 offload/plugins-nextgen/amdgpu/CMakeLists.txt     | 8 +++++++-
 offload/plugins-nextgen/cuda/CMakeLists.txt       | 8 +++++++-
 offload/plugins-nextgen/level_zero/CMakeLists.txt | 8 +++++++-
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/offload/plugins-nextgen/amdgpu/CMakeLists.txt b/offload/plugins-nextgen/amdgpu/CMakeLists.txt
index af2db85f74c64..4f680087e3fcf 100644
--- a/offload/plugins-nextgen/amdgpu/CMakeLists.txt
+++ b/offload/plugins-nextgen/amdgpu/CMakeLists.txt
@@ -8,7 +8,13 @@ target_sources(omptarget.rtl.amdgpu PRIVATE src/rtl.cpp)
 target_include_directories(omptarget.rtl.amdgpu PRIVATE
                            ${CMAKE_CURRENT_SOURCE_DIR}/utils)
 
-if(hsa-runtime64_FOUND AND NOT "amdgpu" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+if (WIN32 AND NOT "amdgpu" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+  message(WARNING "Direct linking against libhsa is not supported on Windows; "
+                  "falling back to dlopen. Add 'amdgpu' to "
+                  "LIBOMPTARGET_DLOPEN_PLUGINS to silence this warning.")
+endif()
+
+if(hsa-runtime64_FOUND AND NOT "amdgpu" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS AND NOT WIN32)
   message(STATUS "Building AMDGPU plugin linked against libhsa")
   target_link_libraries(omptarget.rtl.amdgpu PRIVATE hsa-runtime64::hsa-runtime64)
 else()
diff --git a/offload/plugins-nextgen/cuda/CMakeLists.txt b/offload/plugins-nextgen/cuda/CMakeLists.txt
index b96e25e3dc517..b3e7b7eeaa10a 100644
--- a/offload/plugins-nextgen/cuda/CMakeLists.txt
+++ b/offload/plugins-nextgen/cuda/CMakeLists.txt
@@ -8,7 +8,13 @@ target_compile_definitions(omptarget.rtl.cuda PRIVATE OFFLOAD_MIN_CUDA_VERSION=$
 
 find_package(CUDAToolkit QUIET ${OFFLOAD_MIN_CUDA_VERSION})
 
-if(CUDAToolkit_FOUND AND NOT "cuda" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+if (WIN32 AND NOT "cuda" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+  message(WARNING "Direct linking against libcuda is not supported on Windows; "
+                  "falling back to dlopen. Add 'cuda' to "
+                  "LIBOMPTARGET_DLOPEN_PLUGINS to silence this warning.")
+endif()
+
+if(CUDAToolkit_FOUND AND NOT "cuda" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS AND NOT WIN32)
   message(STATUS "Building CUDA plugin linked against libcuda")
   target_link_libraries(omptarget.rtl.cuda PRIVATE CUDA::cuda_driver)
 else()
diff --git a/offload/plugins-nextgen/level_zero/CMakeLists.txt b/offload/plugins-nextgen/level_zero/CMakeLists.txt
index c40a375166f8b..15ca8d90ba714 100644
--- a/offload/plugins-nextgen/level_zero/CMakeLists.txt
+++ b/offload/plugins-nextgen/level_zero/CMakeLists.txt
@@ -34,7 +34,13 @@ target_include_directories(omptarget.rtl.level_zero PRIVATE
   ${LIBOMPTARGET_LLVM_INCLUDE_DIRS}
 )
 
-if (LIBOMPTARGET_DEP_LEVEL_ZERO_LIBRARY AND NOT "level_zero" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+if (WIN32 AND NOT "level_zero" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS)
+  message(WARNING "Direct linking against level_zero library is not supported on "
+                  "Windows; falling back to dlopen. Add 'level_zero' to "
+                  "LIBOMPTARGET_DLOPEN_PLUGINS to silence this warning.")
+endif()
+
+if (LIBOMPTARGET_DEP_LEVEL_ZERO_LIBRARY AND NOT "level_zero" IN_LIST LIBOMPTARGET_DLOPEN_PLUGINS AND NOT WIN32)
   message(STATUS "Building Level Zero NG plugin linked against level_zero library")
   target_include_directories(omptarget.rtl.level_zero PRIVATE
     ${LIBOMPTARGET_DEP_LEVEL_ZERO_INCLUDE_DIR}

>From 578ce61ef8f38542936b42cc2cdc6e52afe136f5 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Mon, 27 Jul 2026 16:29:52 +0200
Subject: [PATCH 8/9] [offload] fix missing endline

---
 offload/plugins-nextgen/common/include/APIHelpers.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 182f11fc4bc3a..6e52e34793ef4 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -42,4 +42,4 @@ template <auto Fn> bool canCall() {
 
 } // namespace api_helper
 
-#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_APIHELPERS_H
\ No newline at end of file
+#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_APIHELPERS_H

>From 4cee5d21e4200ccb4707003ffa88790e5235f009 Mon Sep 17 00:00:00 2001
From: blazej-smorawski <blazej.smorawski at intel.com>
Date: Wed, 29 Jul 2026 15:24:43 +0200
Subject: [PATCH 9/9] [offload] Rework `API_HELPER_OPTIONAL` so it no longer
 uses UB templates

---
 .../common/include/APIHelpers.h               | 22 +++++++++++++------
 .../plugins-nextgen/common/include/DLWrap.h   |  8 +------
 2 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/offload/plugins-nextgen/common/include/APIHelpers.h b/offload/plugins-nextgen/common/include/APIHelpers.h
index 6e52e34793ef4..ef59442f1604c 100644
--- a/offload/plugins-nextgen/common/include/APIHelpers.h
+++ b/offload/plugins-nextgen/common/include/APIHelpers.h
@@ -17,18 +17,26 @@
 #include "DLWrap.h"
 
 // Macro to mark external symbol as weak, so linker will be okay
-// if the symbol is missing. For direct linking (dlwrap::IsDlOpened<&name> ==
-// false), we need to check if linker could find the symbol. For symbols loaded
-// using dlsym we use dlwrap::loaded<name>().
+// if the symbol is missing. For direct linking only available on Linux, we need
+// to check if linker could find the symbol. For symbols loaded using dlsym we
+// call name##_loaded function. The name##_loaded function will be nullptr if
+// external library was linked directly.
 #define API_HELPER_OPTIONAL(return_type, name, ...)                            \
+  namespace dlwrap {                                                           \
+  bool name##_loaded() __attribute__((weak));                                  \
+  }                                                                            \
   extern "C" return_type name(__VA_ARGS__) __attribute__((weak));              \
   template <> inline bool api_helper::canCall<name>() {                        \
     if (name == nullptr)                                                       \
-      /* Not loaded weak symbol */                                             \
+      /* Not loaded weak symbol, only possible on Linux */                     \
       return false;                                                            \
-    /* Symbols from dlwrap are never nullptr, but `loaded` might return false  \
-     */                                                                        \
-    return dlwrap::loaded<name>();                                             \
+    /* If symbol wasn't dlwrapped, i.e name##_loaded == nullptr and is not     \
+     * nullptr, it means the symbol was linked directly, so we can call it */  \
+    if (dlwrap::name##_loaded == nullptr)                                      \
+      return true;                                                             \
+    /* Symbol is not nullptr and it was dlwrapped, all symbols on Windows go   \
+     * here*/                                                                  \
+    return dlwrap::name##_loaded();                                            \
   }
 
 namespace api_helper {
diff --git a/offload/plugins-nextgen/common/include/DLWrap.h b/offload/plugins-nextgen/common/include/DLWrap.h
index 16f5a86911da3..0a33e8ef97db7 100644
--- a/offload/plugins-nextgen/common/include/DLWrap.h
+++ b/offload/plugins-nextgen/common/include/DLWrap.h
@@ -137,10 +137,6 @@ template <size_t Requested, size_t Required> constexpr void verboseAssert() {
   static_assert(Requested == Required, "Arity Error");
 }
 
-// Template to check if a symbol was loaded successfully.
-// Returns true for symbols that were not wrapped by dlwrap.
-template <auto Fn> bool loaded() { return true; }
-
 } // namespace dlwrap
 
 #define DLWRAP_INSTANTIATE(SYM_DEF, SYM_USE, ARITY)                            \
@@ -173,9 +169,7 @@ template <auto Fn> bool loaded() { return true; }
       return reinterpret_cast<T::FunctionType>(P);                             \
     }                                                                          \
   };                                                                           \
-  template <> bool loaded<&(::SYMBOL)>() {                                     \
-    return SYMBOL##_Trait::get() != nullptr;                                   \
-  }                                                                            \
+  bool SYMBOL##_loaded() { return SYMBOL##_Trait::get() != nullptr; }          \
   }
 
 #define DLWRAP_IMPL(SYMBOL, ARITY)                                             \



More information about the llvm-commits mailing list