[llvm] hosttask (PR #204173)

Ɓukasz Plewa via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 17 06:26:52 PDT 2026


https://github.com/lplewa updated https://github.com/llvm/llvm-project/pull/204173

>From 63367fa45fb0e210d4ccf974b281b8c3558f2632 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Plewa?= <lukasz.plewa at intel.com>
Date: Tue, 16 Jun 2026 14:57:56 +0200
Subject: [PATCH] [offload][l0] Implement olLaunchHost function for level zero
 plugin

---
 .../level_zero/include/L0CmdListManager.h     | 26 ++++++++++++++++++-
 .../level_zero/include/L0Context.h            |  6 +++++
 .../level_zero/include/L0Device.h             |  7 ++---
 .../level_zero/include/L0Queue.h              |  9 +++++++
 .../level_zero/src/L0Context.cpp              |  6 +++++
 .../level_zero/src/L0Device.cpp               |  9 +++++++
 .../level_zero/src/L0Queue.cpp                | 23 ++++++++++++++++
 .../unittests/OffloadAPI/memory/olMemFill.cpp |  6 -----
 .../OffloadAPI/queue/olLaunchHostFunction.cpp | 10 ++-----
 9 files changed, 82 insertions(+), 20 deletions(-)

diff --git a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
index f17c1149d88cb..1eed147f00456 100644
--- a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
+++ b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
@@ -13,6 +13,7 @@
 #ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CMDLISTMANAGER_H
 #define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CMDLISTMANAGER_H
 
+#include "L0Context.h"
 #include "L0Defs.h"
 #include "L0Trace.h"
 #include <mutex>
@@ -24,11 +25,14 @@ namespace llvm::omp::target::plugin {
 class L0CmdListManagerTy {
   /// Underlying immediate command list.
   ze_command_list_handle_t CmdList;
+  /// Owning context (provides driver-loaded extension function pointers).
+  L0ContextTy &Context;
   /// Mutex to protect L0 operations that are not thread safe.
   std::mutex Mtx;
 
 public:
-  L0CmdListManagerTy(ze_command_list_handle_t CmdList) : CmdList(CmdList) {}
+  L0CmdListManagerTy(ze_command_list_handle_t CmdList, L0ContextTy &Context)
+      : CmdList(CmdList), Context(Context) {}
 
   ze_command_list_handle_t getCmdList() const { return CmdList; }
 
@@ -152,6 +156,26 @@ class L0CmdListManagerTy {
                       NumWaitEvents, WaitEvents);
     return Plugin::success();
   }
+
+  /// Append a host function callback. Requires the
+  /// zeCommandListAppendHostFunction extension to be available on the driver;
+  /// otherwise returns UNSUPPORTED.
+  Error appendHostFunction(void (*Callback)(void *), void *UserData,
+                           ze_event_handle_t SignalEvent = nullptr,
+                           uint32_t NumWaitEvents = 0,
+                           ze_event_handle_t *WaitEvents = nullptr) {
+    auto zeCommandListAppendHost = Context.zeCommandListAppendHostFunction;
+    if (!zeCommandListAppendHost)
+      return Plugin::error(ErrorCode::UNSUPPORTED,
+                           "zeCommandListAppendHostFunction extension is not "
+                           "available on this driver");
+    std::lock_guard<std::mutex> Lock(Mtx);
+    CALL_ZE_RET_ERROR(zeCommandListAppendHost, CmdList,
+                      reinterpret_cast<void *>(Callback), UserData,
+                      /*pReserved*/ nullptr, SignalEvent, NumWaitEvents,
+                      WaitEvents);
+    return Plugin::success();
+  }
 };
 
 } // namespace llvm::omp::target::plugin
diff --git a/offload/plugins-nextgen/level_zero/include/L0Context.h b/offload/plugins-nextgen/level_zero/include/L0Context.h
index 3ea68d8dd07a1..1bb5b76c61a84 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Context.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Context.h
@@ -141,6 +141,12 @@ class L0ContextTy {
   ze_result_t(ZE_APICALL *zexKernelGetArgumentSize)(
       ze_kernel_handle_t hKernel, uint32_t argIndex,
       uint32_t *pArgSize) = nullptr;
+
+  /// Level Zero extension function pointer for host function callbacks.
+  ze_result_t(ZE_APICALL *zeCommandListAppendHostFunction)(
+      ze_command_list_handle_t hCommandList, void *pfnHostFunction,
+      void *pUserData, void *pReserved, ze_event_handle_t hSignalEvent,
+      uint32_t numWaitEvents, ze_event_handle_t *phWaitEvents) = nullptr;
 };
 
 } // namespace llvm::omp::target::plugin
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index 275182faebfd6..b70cfeeb8fd4f 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -361,7 +361,7 @@ class L0DeviceTy final : public GenericDeviceTy {
     auto CmdListOrErr = createImmCmdList(InOrder);
     if (!CmdListOrErr)
       return CmdListOrErr.takeError();
-    return new L0CmdListManagerTy(*CmdListOrErr);
+    return new L0CmdListManagerTy(*CmdListOrErr, l0Context);
   }
 
   Error releaseCmdListManager(L0CmdListManagerTy *CmndListMngr) {
@@ -522,10 +522,7 @@ class L0DeviceTy final : public GenericDeviceTy {
   hasPendingWorkImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) override;
 
   Error enqueueHostCallImpl(void (*Callback)(void *), void *UserData,
-                            AsyncInfoWrapperTy &AsyncInfo) override {
-    return Plugin::error(ErrorCode::UNIMPLEMENTED,
-                         "enqueueHostCallImpl not implemented yet");
-  }
+                            AsyncInfoWrapperTy &AsyncInfo) override;
 
   Expected<bool> isEventCompleteImpl(void *EventPtr,
                                      AsyncInfoWrapperTy &) override;
diff --git a/offload/plugins-nextgen/level_zero/include/L0Queue.h b/offload/plugins-nextgen/level_zero/include/L0Queue.h
index ee5b9491ca2ec..60558650b75b3 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Queue.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Queue.h
@@ -82,6 +82,10 @@ class L0QueueTy {
     return launchKernelImpl(Kernel, KEnv);
   }
 
+  Error hostCall(void (*Callback)(void *), void *UserData) {
+    return hostCallImpl(Callback, UserData);
+  }
+
   Error dataFence() { return dataFenceImpl(); }
 
   Error appendSignalEvent(L0EventTy *Event) {
@@ -126,6 +130,7 @@ class L0QueueTy {
   }
   virtual Error launchKernelImpl(ze_kernel_handle_t Kernel,
                                  L0LaunchEnvTy &KEnv) = 0;
+  virtual Error hostCallImpl(void (*Callback)(void *), void *UserData) = 0;
 
   virtual Error memoryFillImpl(void *Ptr, const void *Pattern,
                                size_t PatternSize, size_t Size) {
@@ -186,6 +191,7 @@ class L0AsyncQueueTy : public L0QueueTy {
   Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size) override;
   Error launchKernelImpl(ze_kernel_handle_t Kernel,
                          L0LaunchEnvTy &KEnv) override;
+  Error hostCallImpl(void (*Callback)(void *), void *UserData) override;
   Error memoryFillImpl(void *Ptr, const void *Pattern, size_t PatternSize,
                        size_t Size) override;
   Error dataFenceImpl() override;
@@ -204,6 +210,7 @@ class L0AsyncOrderedQueueTy : public L0AsyncQueueTy {
   Error synchronizeImpl() override;
   std::tuple<size_t, ze_event_handle_t *> getMemCopyEvents() override;
   std::tuple<size_t, ze_event_handle_t *> getLaunchKernelEvents() override;
+  Error hostCallImpl(void (*Callback)(void *), void *UserData) override;
   Error dataFenceImpl() override { return Plugin::success(); }
 };
 
@@ -222,6 +229,7 @@ class L0InorderQueueTy : public L0QueueTy {
   Error memoryCopyImpl(void *Dst, const void *Src, size_t Size) override;
   Error launchKernelImpl(ze_kernel_handle_t Kernel,
                          L0LaunchEnvTy &KEnv) override;
+  Error hostCallImpl(void (*Callback)(void *), void *UserData) override;
   Error dataFenceImpl() override { return Plugin::success(); }
 };
 
@@ -240,6 +248,7 @@ class L0SyncQueueTy : public L0InorderQueueTy {
   Error memoryCopyImpl(void *Dst, const void *Src, size_t Size) override;
   Error launchKernelImpl(ze_kernel_handle_t Kernel,
                          L0LaunchEnvTy &KEnv) override;
+  Error hostCallImpl(void (*Callback)(void *), void *UserData) override;
 };
 
 /// Simple cache for queue objects.
diff --git a/offload/plugins-nextgen/level_zero/src/L0Context.cpp b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
index 4fe0aa34ecbaf..c1556dc5b37f7 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Context.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
@@ -57,6 +57,12 @@ Error L0ContextTy::init() {
   if (RC != ZE_RESULT_SUCCESS)
     zexKernelGetArgumentSize = nullptr;
 
+  CALL_ZE(RC, zeDriverGetExtensionFunctionAddress, zeDriver,
+          "zeCommandListAppendHostFunction",
+          (void **)&zeCommandListAppendHostFunction);
+  if (RC != ZE_RESULT_SUCCESS)
+    zeCommandListAppendHostFunction = nullptr;
+
   return Plugin::success();
 }
 
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index fd664f33b81e9..ac57c74ff15f0 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -387,6 +387,15 @@ Error L0DeviceTy::dataRetrieveImpl(void *HstPtr, const void *TgtPtr,
   return Plugin::success();
 }
 
+Error L0DeviceTy::enqueueHostCallImpl(void (*Callback)(void *), void *UserData,
+                                      AsyncInfoWrapperTy &AsyncInfoWrapper) {
+  __tgt_async_info *AsyncInfo = AsyncInfoWrapper;
+  auto QueueOrErr = getOrCreateQueue(AsyncInfo);
+  if (!QueueOrErr)
+    return QueueOrErr.takeError();
+  return (*QueueOrErr)->hostCall(Callback, UserData);
+}
+
 Error L0DeviceTy::dataExchangeImpl(const void *SrcPtr, GenericDeviceTy &DstDev,
                                    void *DstPtr, int64_t Size,
                                    AsyncInfoWrapperTy &AsyncInfoWrapper) {
diff --git a/offload/plugins-nextgen/level_zero/src/L0Queue.cpp b/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
index 1edafcd04be57..81cef7be2df48 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
@@ -247,6 +247,12 @@ Error L0AsyncQueueTy::launchKernelImpl(ze_kernel_handle_t Kernel,
   return Plugin::success();
 }
 
+Error L0AsyncQueueTy::hostCallImpl(void (*Callback)(void *), void *UserData) {
+  return Plugin::error(ErrorCode::UNIMPLEMENTED,
+                       "Host function callbacks are not yet implemented for "
+                       "out-of-order async queues");
+}
+
 Error L0AsyncQueueTy::memoryFillImpl(void *Ptr, const void *Pattern,
                                      size_t PatternSize, size_t Size) {
   auto EventOrErr = Device.getEvent();
@@ -306,6 +312,13 @@ L0AsyncOrderedQueueTy::getLaunchKernelEvents() {
                             : std::make_tuple(1, &WaitEvents.back());
 }
 
+Error L0AsyncOrderedQueueTy::hostCallImpl(void (*Callback)(void *),
+                                          void *UserData) {
+  return Plugin::error(ErrorCode::UNIMPLEMENTED,
+                       "Host function callbacks are not yet implemented for "
+                       "ordered async queues");
+}
+
 // L0InorderQueueTy implementation.
 Error L0InorderQueueTy::synchronizeImpl() { return CmdList->hostSynchronize(); }
 
@@ -323,6 +336,10 @@ Error L0InorderQueueTy::launchKernelImpl(ze_kernel_handle_t Kernel,
   return dispatchLaunchKernel(Kernel, KEnv);
 }
 
+Error L0InorderQueueTy::hostCallImpl(void (*Callback)(void *), void *UserData) {
+  return CmdList->appendHostFunction(Callback, UserData);
+}
+
 // L0SyncQueueTy implementation.
 Error L0SyncQueueTy::memoryCopyImpl(void *Dst, const void *Src, size_t Size) {
   if (auto Err = L0InorderQueueTy::memoryCopyImpl(Dst, Src, Size))
@@ -337,6 +354,12 @@ Error L0SyncQueueTy::launchKernelImpl(ze_kernel_handle_t Kernel,
   return CmdList->hostSynchronize();
 }
 
+Error L0SyncQueueTy::hostCallImpl(void (*Callback)(void *), void *UserData) {
+  if (auto Err = L0InorderQueueTy::hostCallImpl(Callback, UserData))
+    return Err;
+  return CmdList->hostSynchronize();
+}
+
 // L0QueueCache implementation.
 Expected<L0QueueTy *> L0QueueCacheTy::getQueue() {
   {
diff --git a/offload/unittests/OffloadAPI/memory/olMemFill.cpp b/offload/unittests/OffloadAPI/memory/olMemFill.cpp
index f314879a94394..b094c6298e16d 100644
--- a/offload/unittests/OffloadAPI/memory/olMemFill.cpp
+++ b/offload/unittests/OffloadAPI/memory/olMemFill.cpp
@@ -16,11 +16,6 @@ struct olMemFillTest : OffloadQueueTest {
   template <typename PatternTy, PatternTy PatternVal, size_t Size,
             bool Block = false>
   void test_body() {
-    if constexpr (Block) {
-      // Only tests relying on olLaunchHostFunction are failing.
-      SKIP_KNOWN_FAILURE(LevelZero{"unsupported feature"});
-    }
-
     ManuallyTriggeredTask Manual;
 
     // Block/enqueue tests ensure that the test has been enqueued to a queue
@@ -103,7 +98,6 @@ TEST_P(olMemFillTest, SuccessLarge) {
 }
 
 TEST_P(olMemFillTest, SuccessLargeEnqueue) {
-  SKIP_KNOWN_FAILURE(LevelZero{"unsupported feature"});
   constexpr size_t Size = 1024;
   void *Alloc;
   ManuallyTriggeredTask Manual;
diff --git a/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp b/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
index 387fb308da6d4..f3f28f82e9d30 100644
--- a/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
+++ b/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
@@ -12,18 +12,12 @@
 #include <thread>
 
 struct olLaunchHostFunctionTest : OffloadQueueTest {
-  void SetUp() override {
-    RETURN_ON_FATAL_FAILURE(OffloadQueueTest::SetUp());
-    SKIP_KNOWN_FAILURE(LevelZero{"unsupported feature"});
-  }
+  void SetUp() override { RETURN_ON_FATAL_FAILURE(OffloadQueueTest::SetUp()); }
 };
 OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olLaunchHostFunctionTest);
 
 struct olLaunchHostFunctionKernelTest : OffloadKernelTest {
-  void SetUp() override {
-    RETURN_ON_FATAL_FAILURE(OffloadKernelTest::SetUp());
-    SKIP_KNOWN_FAILURE(LevelZero{"unsupported feature"});
-  }
+  void SetUp() override { RETURN_ON_FATAL_FAILURE(OffloadKernelTest::SetUp()); }
 };
 OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olLaunchHostFunctionKernelTest);
 



More information about the llvm-commits mailing list