[llvm] [offload] add support for SPIR-V kernel images (PR #166545)

Ɓukasz Plewa via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 5 04:14:49 PST 2025


https://github.com/lplewa created https://github.com/llvm/llvm-project/pull/166545

The olProgramCreate entry point currently doesn't define the format of the program binary. The PluginInterface implementation currently only accepts ELF images, which won't work for backends that don't support ELF, like Level Zero. This patch adds support for loading and handling kernels in SPIR-V format.

>From 0c30dafc3bff56c2a158a009f70cfc17f8078a0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Plewa?= <lukasz.plewa at intel.com>
Date: Mon, 3 Nov 2025 17:25:14 +0100
Subject: [PATCH] [offload] add support for SPIR-V kernel images

The olProgramCreate entry point currently doesn't define the format of
the program binary. The PluginInterface implementation currently only
accepts ELF images, which won't work for backends that don't support
ELF, like Level Zero. This patch adds support for loading and handling
kernels in SPIR-V format.
---
 .../common/src/PluginInterface.cpp            | 62 ++++++++++++-------
 1 file changed, 38 insertions(+), 24 deletions(-)

diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index d7e5a21600abf..3870f8fd6b477 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -403,19 +403,30 @@ Error GenericKernelTy::init(GenericDeviceTy &GenericDevice,
   ImagePtr = &Image;
 
   // Retrieve kernel environment object for the kernel.
-  std::string EnvironmentName = std::string(Name) + "_kernel_environment";
-  GenericGlobalHandlerTy &GHandler = GenericDevice.Plugin.getGlobalHandler();
-  if (GHandler.isSymbolInImage(GenericDevice, Image, EnvironmentName)) {
-    GlobalTy KernelEnv(EnvironmentName, sizeof(KernelEnvironment),
-                       &KernelEnvironment);
-    if (auto Err =
-            GHandler.readGlobalFromImage(GenericDevice, *ImagePtr, KernelEnv))
-      return Err;
-  } else {
+  switch (identify_magic(Image.getMemoryBuffer().getBuffer())) {
+  case file_magic::elf_executable: {
+    std::string EnvironmentName = std::string(Name) + "_kernel_environment";
+    GenericGlobalHandlerTy &GHandler = GenericDevice.Plugin.getGlobalHandler();
+    if (GHandler.isSymbolInImage(GenericDevice, Image, EnvironmentName)) {
+      GlobalTy KernelEnv(EnvironmentName, sizeof(KernelEnvironment),
+                         &KernelEnvironment);
+      if (auto Err =
+              GHandler.readGlobalFromImage(GenericDevice, *ImagePtr, KernelEnv))
+        return Err;
+    } else {
+      KernelEnvironment = KernelEnvironmentTy{};
+      DP("Failed to read kernel environment for '%s' Using default Bare (0) "
+         "execution mode\n",
+         getName());
+    }
+    break;
+  }
+  case file_magic::spirv_object:
     KernelEnvironment = KernelEnvironmentTy{};
-    DP("Failed to read kernel environment for '%s' Using default Bare (0) "
-       "execution mode\n",
-       getName());
+    break;
+  default:
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Unsupported image format for kernel '%s'", getName());
   }
 
   // Max = Config.Max > 0 ? min(Config.Max, Device.Max) : Device.Max;
@@ -808,20 +819,23 @@ Error GenericDeviceTy::unloadBinary(DeviceImageTy *Image) {
     DeviceMemoryPoolTracking.combine(ImageDeviceMemoryPoolTracking);
   }
 
-  GenericGlobalHandlerTy &Handler = Plugin.getGlobalHandler();
-  auto ProfOrErr = Handler.readProfilingGlobals(*this, *Image);
-  if (!ProfOrErr)
-    return ProfOrErr.takeError();
+  if (utils::elf::isELF(Image->getMemoryBuffer().getBuffer())) {
 
-  if (!ProfOrErr->empty()) {
-    // Dump out profdata
-    if ((OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::PGODump)) ==
-        uint32_t(DeviceDebugKind::PGODump))
-      ProfOrErr->dump();
+    GenericGlobalHandlerTy &Handler = Plugin.getGlobalHandler();
+    auto ProfOrErr = Handler.readProfilingGlobals(*this, *Image);
+    if (!ProfOrErr)
+      return ProfOrErr.takeError();
 
-    // Write data to profiling file
-    if (auto Err = ProfOrErr->write())
-      return Err;
+    if (!ProfOrErr->empty()) {
+      // Dump out profdata
+      if ((OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::PGODump)) ==
+          uint32_t(DeviceDebugKind::PGODump))
+        ProfOrErr->dump();
+
+      // Write data to profiling file
+      if (auto Err = ProfOrErr->write())
+        return Err;
+    }
   }
 
   return unloadBinaryImpl(Image);



More information about the llvm-commits mailing list