[llvm] [OFFOLOAD][L0] Add support to dump embedded spirv files (PR #180715)

Alex Duran via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 10 23:54:08 PST 2026


https://github.com/adurang updated https://github.com/llvm/llvm-project/pull/180715

>From c2d0ae75977d961466a733d97692cc7a5fd3b876 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 10:56:13 +0100
Subject: [PATCH 01/10] [OFFLOAD] Add exclude debug filters

---
 offload/include/Shared/Debug.h | 36 +++++++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 0f98a445c73ea..3f5c44de7511c 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -271,6 +271,7 @@ struct DebugFilter {
 struct DebugSettings {
   bool Enabled = false;
   uint32_t DefaultLevel = 1;
+  llvm::SmallVector<StringRef> ExcludeFilters;
   llvm::SmallVector<DebugFilter> Filters;
 };
 
@@ -309,13 +310,12 @@ struct DebugSettings {
 
     Settings.Enabled = true;
 
-    if (EnvRef.starts_with_insensitive("all")) {
-      auto Spec = parseDebugFilter(EnvRef);
-      if (Spec.Type.equals_insensitive("all")) {
-        Settings.DefaultLevel = Spec.Level;
-        return;
-      }
-    }
+    // Messages with Type/Components added to the exclude list are not 
+    // not printed when debug is enabled unless they are explicitly 
+    // requested by the user.
+    // Eventuall this should be configured from the upper layers but 
+    // for now we can hardcode some excluded types here like:
+    // Settings.ExcludeFilters.push_back(Type); 
 
     if (!EnvRef.getAsInteger(10, Settings.DefaultLevel))
       return;
@@ -325,7 +325,18 @@ struct DebugSettings {
     for (auto &FilterSpec : llvm::split(EnvRef, ',')) {
       if (FilterSpec.empty())
         continue;
-      Settings.Filters.push_back(parseDebugFilter(FilterSpec));
+      DebugFilter Filter = parseDebugFilter(FilterSpec);
+
+      // Remove from ExcludeFilters if present
+      Settings.ExcludeFilters.erase(
+            std::remove_if(Settings.ExcludeFilters.begin(),
+                           Settings.ExcludeFilters.end(),
+                           [&](StringRef OutType) {
+                             return OutType.equals_insensitive(Filter.Type);
+                           }),
+            Settings.ExcludeFilters.end());
+
+      Settings.Filters.push_back(Filter);
     }
   });
 
@@ -340,6 +351,12 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
   if (!Settings.Enabled)
     return false;
 
+  for (const auto &Filter : Settings.ExcludeFilters) {
+    if (Filter.equals_insensitive(Type) ||
+        Filter.equals_insensitive(Component))
+      return false;
+  }
+
   if (Settings.Filters.empty()) {
     if (Level <= Settings.DefaultLevel) {
       Level = Settings.DefaultLevel;
@@ -351,7 +368,8 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
   for (const auto &DT : Settings.Filters) {
     if (DT.Level < Level)
       continue;
-    if (DT.Type.equals_insensitive(Type) ||
+    if (DT.Type.equals_insensitive("all") ||
+        DT.Type.equals_insensitive(Type) ||
         DT.Type.equals_insensitive(Component)) {
       Level = DT.Level;
       return true;

>From 1817317ab53f314951a40e3cd76153854873e1f6 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 11:03:15 +0100
Subject: [PATCH 02/10] rename other filter field

---
 offload/include/Shared/Debug.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 3f5c44de7511c..cb158b2db0709 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -272,7 +272,7 @@ struct DebugSettings {
   bool Enabled = false;
   uint32_t DefaultLevel = 1;
   llvm::SmallVector<StringRef> ExcludeFilters;
-  llvm::SmallVector<DebugFilter> Filters;
+  llvm::SmallVector<DebugFilter> IncludeFilters;
 };
 
 [[maybe_unused]] static DebugFilter parseDebugFilter(StringRef Filter) {
@@ -336,7 +336,7 @@ struct DebugSettings {
                            }),
             Settings.ExcludeFilters.end());
 
-      Settings.Filters.push_back(Filter);
+      Settings.IncludeFilters.push_back(Filter);
     }
   });
 
@@ -357,7 +357,7 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
       return false;
   }
 
-  if (Settings.Filters.empty()) {
+  if (Settings.IncludeFilters.empty()) {
     if (Level <= Settings.DefaultLevel) {
       Level = Settings.DefaultLevel;
       return true;
@@ -365,7 +365,7 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
     return false;
   }
 
-  for (const auto &DT : Settings.Filters) {
+  for (const auto &DT : Settings.IncludeFilters) {
     if (DT.Level < Level)
       continue;
     if (DT.Type.equals_insensitive("all") ||

>From 2b9a7d3783ad6c20733d57f17eff3c30fdb75328 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 11:07:59 +0100
Subject: [PATCH 03/10] add comments

---
 offload/include/Shared/Debug.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index cb158b2db0709..31b46129540d4 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -271,7 +271,11 @@ struct DebugFilter {
 struct DebugSettings {
   bool Enabled = false;
   uint32_t DefaultLevel = 1;
+  // Types/Components in this list are not printed when debug is enabled 
+  // unless they are explicitly requested by the user in IncludeFilters.
   llvm::SmallVector<StringRef> ExcludeFilters;
+  // Types/Components in this list are printed when debug is enabled if 
+  // the debug level is equal or higher than the specified level.
   llvm::SmallVector<DebugFilter> IncludeFilters;
 };
 
@@ -310,10 +314,10 @@ struct DebugSettings {
 
     Settings.Enabled = true;
 
-    // Messages with Type/Components added to the exclude list are not 
+    // Messages with Type/Components added to the exclude list are not
     // not printed when debug is enabled unless they are explicitly 
     // requested by the user.
-    // Eventuall this should be configured from the upper layers but 
+    // Eventuall this should be configured from the upper layers but
     // for now we can hardcode some excluded types here like:
     // Settings.ExcludeFilters.push_back(Type); 
 

>From 7b265bb5f54926aa0e3f459b294a0515f5cc6cbb Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 14:55:52 +0100
Subject: [PATCH 04/10] [OFFLOAD] Add support to dump device binary images

---
 offload/include/Shared/Debug.h                | 36 ++++++++-----
 offload/include/Utils/OsUtils.h               | 51 +++++++++++++++++++
 .../common/src/PluginInterface.cpp            | 26 ++++++++++
 3 files changed, 100 insertions(+), 13 deletions(-)
 create mode 100644 offload/include/Utils/OsUtils.h

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 31b46129540d4..89d49d5e23c05 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -159,6 +159,28 @@ inline uint32_t getInfoLevel() { return getInfoLevelInternal().load(); }
 
 namespace llvm::offload::debug {
 
+enum OffloadDebugLevel : uint32_t {
+  OLDL_Default = 1,
+  OLDL_Error = OLDL_Default,
+  OLDL_Detailed = 2,
+  OLDL_Verbose = 3,
+  OLDL_VeryVerbose = 4,
+};
+
+// Common debug types in offload.
+constexpr const char *OLDT_Init = "Init";
+constexpr const char *OLDT_Kernel = "Kernel";
+constexpr const char *OLDT_DataTransfer = "DataTransfer";
+constexpr const char *OLDT_Sync = "Sync";
+constexpr const char *OLDT_Deinit = "Deinit";
+constexpr const char *OLDT_Error = "Error";
+constexpr const char *OLDT_Device = "Device";
+constexpr const char *OLDT_Interface = "Interface";
+constexpr const char *OLDT_Alloc = "Alloc";
+constexpr const char *OLDT_Tool = "Tool";
+constexpr const char *OLDT_Module = "Module";
+constexpr const char *OLDT_BinaryDump = "BinaryDump";
+
 /// A raw_ostream that tracks `\n` and print the prefix after each
 /// newline. Based on raw_ldbg_ostream from Support/DebugLog.h
 class LLVM_ABI odbg_ostream final : public raw_ostream {
@@ -320,6 +342,7 @@ struct DebugSettings {
     // Eventuall this should be configured from the upper layers but
     // for now we can hardcode some excluded types here like:
     // Settings.ExcludeFilters.push_back(Type); 
+    Settings.ExcludeFilters.push_back(OLDT_BinaryDump);
 
     if (!EnvRef.getAsInteger(10, Settings.DefaultLevel))
       return;
@@ -565,19 +588,6 @@ inline bool isDebugEnabled() { return false; }
 
 #endif
 
-// Common debug types in offload.
-constexpr const char *OLDT_Init = "Init";
-constexpr const char *OLDT_Kernel = "Kernel";
-constexpr const char *OLDT_DataTransfer = "DataTransfer";
-constexpr const char *OLDT_Sync = "Sync";
-constexpr const char *OLDT_Deinit = "Deinit";
-constexpr const char *OLDT_Error = "Error";
-constexpr const char *OLDT_Device = "Device";
-constexpr const char *OLDT_Interface = "Interface";
-constexpr const char *OLDT_Alloc = "Alloc";
-constexpr const char *OLDT_Tool = "Tool";
-constexpr const char *OLDT_Module = "Module";
-
 } // namespace llvm::offload::debug
 
 namespace llvm::omp::target::debug {
diff --git a/offload/include/Utils/OsUtils.h b/offload/include/Utils/OsUtils.h
new file mode 100644
index 0000000000000..9da9ce69faa4d
--- /dev/null
+++ b/offload/include/Utils/OsUtils.h
@@ -0,0 +1,51 @@
+//===-- Utils/OsUtils.h - Target independent OpenMP target RTL -- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Useful utilites to interact with the OS environment in a platform independent
+// way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OMPTARGET_UTILS_OSUTILS_H
+#define OMPTARGET_UTILS_OSUTILS_H
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <limits.h>
+#include <unistd.h>
+#endif
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace utils {
+
+static inline std::string getExecName() {
+#if defined(_WIN32)
+  char Buffer[MAX_PATH];
+  GetModuleFileNameA(nullptr, Buffer, MAX_PATH);
+#else
+  char Buffer[PATH_MAX];
+  ssize_t Len = readlink("/proc/self/exe", Buffer, sizeof(Buffer) - 1);
+  if (Len == -1)
+    return "unknown";
+  Buffer[Len] = '\0';
+#endif
+  llvm::StringRef Path(Buffer);
+
+  if (!Path.empty())
+    return llvm::sys::path::filename(Path).str();
+
+  return "unknown";
+}
+
+} // namespace utils
+
+#endif // OMPTARGET_UTILS_OSUTILS_H
\ No newline at end of file
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index 807df0ffd7874..4a962fea9b45d 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -19,6 +19,7 @@
 #include "JIT.h"
 #include "Shared/Utils.h"
 #include "Utils/ELF.h"
+#include "Utils/OsUtils.h"
 #include "omptarget.h"
 
 #ifdef OMPT_SUPPORT
@@ -851,6 +852,24 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
                                                       StringRef InputTgtImage) {
   ODBG(OLDT_Init) << "Load data from image "
                   << static_cast<const void *>(InputTgtImage.bytes_begin());
+  auto DumpImage = [](StringRef Label, StringRef Image, llvm::raw_ostream &Os,
+                      int ImageId) {
+    std::string Filename = llvm::formatv(
+        "{0}_{1}_image{2}.bin", utils::getExecName(), Label.str(), ImageId);
+    std::error_code EC;
+    raw_fd_ostream FS(Filename, EC, llvm::sys::fs::OF_None);
+    if (EC) {
+      Os << "Error saving " << Label << " image : " << StringRef(EC.message());
+      return;
+    }
+    FS << Image;
+    FS.close();
+    Os << "Saved " << Label << " image to " << Filename;
+  };
+
+  ODBG_OS(OLDT_BinaryDump, OLDL_Verbose, [&](llvm::raw_ostream &Os) {
+    DumpImage("input", InputTgtImage, Os, LoadedImages.size());
+  });
 
   std::unique_ptr<MemoryBuffer> Buffer;
   if (identify_magic(InputTgtImage) == file_magic::bitcode) {
@@ -861,6 +880,9 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
                            "failure to jit IR image");
     }
     Buffer = std::move(*CompiledImageOrErr);
+    ODBG_OS(OLDT_BinaryDump, OLDL_Verbose, [&](llvm::raw_ostream &Os){
+      DumpImage("jitted", Buffer->getBuffer(), Os, LoadedImages.size());
+    });
   } else {
     Buffer = MemoryBuffer::getMemBufferCopy(InputTgtImage);
   }
@@ -871,6 +893,10 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
   if (!ImageOrErr)
     return ImageOrErr.takeError();
   DeviceImageTy *Image = *ImageOrErr;
+  ODBG_OS(OLDT_BinaryDump, [&](llvm::raw_ostream &Os) {
+    DumpImage("loaded", StringRef(static_cast<const char *>(Image->getStart()),
+                                  Image->getSize()), Os, LoadedImages.size());
+  });
 
   // Add the image to list.
   LoadedImages.push_back(Image);

>From 5a9a65d1eda35a32513556231751f9ee60a5054e Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 16:23:43 +0100
Subject: [PATCH 05/10] format

---
 offload/include/Shared/Debug.h | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 31b46129540d4..723761b2f65ed 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -271,10 +271,10 @@ struct DebugFilter {
 struct DebugSettings {
   bool Enabled = false;
   uint32_t DefaultLevel = 1;
-  // Types/Components in this list are not printed when debug is enabled 
+  // Types/Components in this list are not printed when debug is enabled
   // unless they are explicitly requested by the user in IncludeFilters.
   llvm::SmallVector<StringRef> ExcludeFilters;
-  // Types/Components in this list are printed when debug is enabled if 
+  // Types/Components in this list are printed when debug is enabled if
   // the debug level is equal or higher than the specified level.
   llvm::SmallVector<DebugFilter> IncludeFilters;
 };
@@ -315,11 +315,11 @@ struct DebugSettings {
     Settings.Enabled = true;
 
     // Messages with Type/Components added to the exclude list are not
-    // not printed when debug is enabled unless they are explicitly 
+    // not printed when debug is enabled unless they are explicitly
     // requested by the user.
     // Eventuall this should be configured from the upper layers but
     // for now we can hardcode some excluded types here like:
-    // Settings.ExcludeFilters.push_back(Type); 
+    // Settings.ExcludeFilters.push_back(Type);
 
     if (!EnvRef.getAsInteger(10, Settings.DefaultLevel))
       return;
@@ -333,12 +333,12 @@ struct DebugSettings {
 
       // Remove from ExcludeFilters if present
       Settings.ExcludeFilters.erase(
-            std::remove_if(Settings.ExcludeFilters.begin(),
-                           Settings.ExcludeFilters.end(),
-                           [&](StringRef OutType) {
-                             return OutType.equals_insensitive(Filter.Type);
-                           }),
-            Settings.ExcludeFilters.end());
+          std::remove_if(Settings.ExcludeFilters.begin(),
+                         Settings.ExcludeFilters.end(),
+                         [&](StringRef OutType) {
+                           return OutType.equals_insensitive(Filter.Type);
+                         }),
+          Settings.ExcludeFilters.end());
 
       Settings.IncludeFilters.push_back(Filter);
     }
@@ -356,8 +356,7 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
     return false;
 
   for (const auto &Filter : Settings.ExcludeFilters) {
-    if (Filter.equals_insensitive(Type) ||
-        Filter.equals_insensitive(Component))
+    if (Filter.equals_insensitive(Type) || Filter.equals_insensitive(Component))
       return false;
   }
 
@@ -372,8 +371,7 @@ shouldPrintDebug(const char *Component, const char *Type, uint32_t &Level) {
   for (const auto &DT : Settings.IncludeFilters) {
     if (DT.Level < Level)
       continue;
-    if (DT.Type.equals_insensitive("all") ||
-        DT.Type.equals_insensitive(Type) ||
+    if (DT.Type.equals_insensitive("all") || DT.Type.equals_insensitive(Type) ||
         DT.Type.equals_insensitive(Component)) {
       Level = DT.Level;
       return true;

>From 8efc3abbbc422ef394471d4e8cc76dfaca25895a Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 16:26:45 +0100
Subject: [PATCH 06/10] format

---
 offload/plugins-nextgen/common/src/PluginInterface.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index 4a962fea9b45d..1ed6aa49490f8 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -880,7 +880,7 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
                            "failure to jit IR image");
     }
     Buffer = std::move(*CompiledImageOrErr);
-    ODBG_OS(OLDT_BinaryDump, OLDL_Verbose, [&](llvm::raw_ostream &Os){
+    ODBG_OS(OLDT_BinaryDump, OLDL_Verbose, [&](llvm::raw_ostream &Os) {
       DumpImage("jitted", Buffer->getBuffer(), Os, LoadedImages.size());
     });
   } else {
@@ -894,8 +894,10 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
     return ImageOrErr.takeError();
   DeviceImageTy *Image = *ImageOrErr;
   ODBG_OS(OLDT_BinaryDump, [&](llvm::raw_ostream &Os) {
-    DumpImage("loaded", StringRef(static_cast<const char *>(Image->getStart()),
-                                  Image->getSize()), Os, LoadedImages.size());
+    DumpImage("loaded",
+              StringRef(static_cast<const char *>(Image->getStart()),
+                        Image->getSize()),
+              Os, LoadedImages.size());
   });
 
   // Add the image to list.

>From 69d8ff4dac74add6e1768cfbe1dc5b5539669fb8 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Mon, 9 Feb 2026 16:30:32 +0100
Subject: [PATCH 07/10] remove line

---
 offload/include/Shared/Debug.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 1d8dda9f1420c..1517574ade92e 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -343,7 +343,6 @@ struct DebugSettings {
     // for now we can hardcode some excluded types here like:
     // Settings.ExcludeFilters.push_back(Type);
     Settings.ExcludeFilters.push_back(OLDT_BinaryDump);
-    
 
     if (!EnvRef.getAsInteger(10, Settings.DefaultLevel))
       return;

>From 36c0666ddd4dd86c2c010405b8f53a08adf0867e Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 10 Feb 2026 09:59:40 +0100
Subject: [PATCH 08/10] moved getExecName out of header

---
 offload/include/Utils/OsUtils.h               | 51 -------------------
 offload/plugins-nextgen/common/CMakeLists.txt |  1 +
 .../common/include/Utils/OsUtils.h            | 24 +++++++++
 .../common/src/PluginInterface.cpp            |  3 +-
 4 files changed, 27 insertions(+), 52 deletions(-)
 delete mode 100644 offload/include/Utils/OsUtils.h
 create mode 100644 offload/plugins-nextgen/common/include/Utils/OsUtils.h

diff --git a/offload/include/Utils/OsUtils.h b/offload/include/Utils/OsUtils.h
deleted file mode 100644
index 9da9ce69faa4d..0000000000000
--- a/offload/include/Utils/OsUtils.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//===-- Utils/OsUtils.h - Target independent OpenMP target RTL -- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Useful utilites to interact with the OS environment in a platform independent
-// way.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef OMPTARGET_UTILS_OSUTILS_H
-#define OMPTARGET_UTILS_OSUTILS_H
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <limits.h>
-#include <unistd.h>
-#endif
-
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
-namespace utils {
-
-static inline std::string getExecName() {
-#if defined(_WIN32)
-  char Buffer[MAX_PATH];
-  GetModuleFileNameA(nullptr, Buffer, MAX_PATH);
-#else
-  char Buffer[PATH_MAX];
-  ssize_t Len = readlink("/proc/self/exe", Buffer, sizeof(Buffer) - 1);
-  if (Len == -1)
-    return "unknown";
-  Buffer[Len] = '\0';
-#endif
-  llvm::StringRef Path(Buffer);
-
-  if (!Path.empty())
-    return llvm::sys::path::filename(Path).str();
-
-  return "unknown";
-}
-
-} // namespace utils
-
-#endif // OMPTARGET_UTILS_OSUTILS_H
\ No newline at end of file
diff --git a/offload/plugins-nextgen/common/CMakeLists.txt b/offload/plugins-nextgen/common/CMakeLists.txt
index ea0910abf95d5..5ce9ebb0e730b 100644
--- a/offload/plugins-nextgen/common/CMakeLists.txt
+++ b/offload/plugins-nextgen/common/CMakeLists.txt
@@ -16,6 +16,7 @@ add_library(PluginCommon OBJECT
   src/RPC.cpp
   src/OffloadError.cpp
   src/Utils/ELF.cpp
+  src/Utils/OsUtils.cpp
 )
 add_dependencies(PluginCommon intrinsics_gen PluginErrcodes)
 
diff --git a/offload/plugins-nextgen/common/include/Utils/OsUtils.h b/offload/plugins-nextgen/common/include/Utils/OsUtils.h
new file mode 100644
index 0000000000000..105ea83db2f88
--- /dev/null
+++ b/offload/plugins-nextgen/common/include/Utils/OsUtils.h
@@ -0,0 +1,24 @@
+//===-- Utils/OsUtils.h - Common OS utilities ------------------- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Useful utilites to interact with the OS environment in a platform independent
+// way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OMPTARGET_UTILS_OSUTILS_H
+#define OMPTARGET_UTILS_OSUTILS_H
+
+namespace utils::os {
+
+/// Get the name of the current executable, without the path
+std::string getExecName();
+
+} // namespace utils::os
+
+#endif // OMPTARGET_UTILS_OSUTILS_H
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index 1ed6aa49490f8..035de903cf296 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -30,6 +30,7 @@
 #include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -855,7 +856,7 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
   auto DumpImage = [](StringRef Label, StringRef Image, llvm::raw_ostream &Os,
                       int ImageId) {
     std::string Filename = llvm::formatv(
-        "{0}_{1}_image{2}.bin", utils::getExecName(), Label.str(), ImageId);
+        "{0}_{1}_image{2}.bin", utils::os::getExecName(), Label.str(), ImageId);
     std::error_code EC;
     raw_fd_ostream FS(Filename, EC, llvm::sys::fs::OF_None);
     if (EC) {

>From 129640fdf682909feb4ed2f13fe1ba881fc9b96f Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 10 Feb 2026 11:24:42 +0100
Subject: [PATCH 09/10] [OFFLOAD][L0] Add support to dump embedded spirv files

---
 .../level_zero/include/L0Program.h            |  8 ++++++--
 .../level_zero/src/L0Device.cpp               |  2 +-
 .../level_zero/src/L0Program.cpp              | 19 ++++++++++++++++++-
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/offload/plugins-nextgen/level_zero/include/L0Program.h b/offload/plugins-nextgen/level_zero/include/L0Program.h
index 0796e316e6afb..34aad6e797fd7 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Program.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Program.h
@@ -45,6 +45,9 @@ class L0ProgramBuilderTy {
   /// Requires module link.
   bool RequiresModuleLink = false;
 
+  /// Id of the image being built.
+  int32_t ImageId;
+
   /// Build a single module with the given image, build option, and format.
   Error addModule(const size_t Size, const uint8_t *Image,
                   const std::string_view BuildOption,
@@ -53,8 +56,9 @@ class L0ProgramBuilderTy {
   Error linkModules();
 
 public:
-  L0ProgramBuilderTy(L0DeviceTy &Device, std::unique_ptr<MemoryBuffer> &&Image)
-      : Device(Device), Image(std::move(Image)) {}
+  L0ProgramBuilderTy(L0DeviceTy &Device, std::unique_ptr<MemoryBuffer> &&Image,
+                     int32_t ImageId)
+      : Device(Device), Image(std::move(Image)), ImageId(ImageId) {}
   ~L0ProgramBuilderTy() = default;
 
   L0DeviceTy &getL0Device() const { return Device; }
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index 4db3c4e47f544..f5eb1c4ef247c 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -255,7 +255,7 @@ L0DeviceTy::loadBinaryImpl(std::unique_ptr<MemoryBuffer> &&TgtImage,
   CompilationOptions += " ";
   CompilationOptions += Options.InternalCompilationOptions;
 
-  L0ProgramBuilderTy Builder(*this, std::move(TgtImage));
+  L0ProgramBuilderTy Builder(*this, std::move(TgtImage), ImageId);
   if (auto Err = Builder.buildModules(CompilationOptions))
     return std::move(Err);
 
diff --git a/offload/plugins-nextgen/level_zero/src/L0Program.cpp b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
index 4fd7af098fa1f..052e09eb88093 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Program.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
@@ -20,6 +20,9 @@
 #include <unistd.h>
 #endif // !_WIN32
 
+#include "Utils/OsUtils.h"
+#include "llvm/Support/FileSystem.h"
+
 #include "L0Plugin.h"
 #include "L0Program.h"
 
@@ -417,7 +420,21 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
       const unsigned char *ImgBegin =
           reinterpret_cast<const unsigned char *>(It->second.PartBegin[I]);
       size_t ImgSize = It->second.PartSize[I];
-
+      ODBG_OS(OLDT_BinaryDump, [&](llvm::raw_ostream &Os) {
+        std::string Filename = llvm::formatv(
+            "{0}_image{1}_module_{2}_{3}.{4}", utils::os::getExecName(),
+            ImageId++, Idx, I, (IsBinary ? "bin" : "spv"));
+        std::error_code EC;
+        raw_fd_ostream FS(Filename, EC, llvm::sys::fs::OF_None);
+        if (EC) {
+          Os << "Error saving " << Filename
+             << " image : " << StringRef(EC.message());
+          return;
+        }
+        FS << StringRef(reinterpret_cast<const char *>(ImgBegin), ImgSize);
+        FS.close();
+        Os << "Saved module " << Idx << "-" << I << " image to " << Filename;
+      });
       ODBG(OLDT_Module) << "Creating module from "
                         << (IsBinary ? "Binary" : "SPIR-V") << " image part #"
                         << Idx << "-" << I << ".";

>From 5ed14d0656de4482f388b5de6d1ad847a0c2d443 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Wed, 11 Feb 2026 08:53:50 +0100
Subject: [PATCH 10/10] fix

---
 offload/plugins-nextgen/level_zero/src/L0Program.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/offload/plugins-nextgen/level_zero/src/L0Program.cpp b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
index 052e09eb88093..dd873df074ae3 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Program.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
@@ -423,7 +423,7 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
       ODBG_OS(OLDT_BinaryDump, [&](llvm::raw_ostream &Os) {
         std::string Filename = llvm::formatv(
             "{0}_image{1}_module_{2}_{3}.{4}", utils::os::getExecName(),
-            ImageId++, Idx, I, (IsBinary ? "bin" : "spv"));
+            ImageId, Idx, I, (IsBinary ? "bin" : "spv"));
         std::error_code EC;
         raw_fd_ostream FS(Filename, EC, llvm::sys::fs::OF_None);
         if (EC) {



More information about the llvm-commits mailing list