[llvm] [Offload][L0] Add support for OffloadBinary format in L0 plugin (PR #185404)
Alex Duran via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 9 06:10:14 PDT 2026
https://github.com/adurang updated https://github.com/llvm/llvm-project/pull/185404
>From 131c2f234b8a5db526157856f861e30038be5b39 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Mon, 9 Mar 2026 03:23:25 -0700
Subject: [PATCH 1/2] [Offload][L0] Add support for OffloadBinary format in L0
plugin
---
.../common/include/PluginInterface.h | 4 ++
.../common/src/PluginInterface.cpp | 38 ++++++++++
.../level_zero/src/L0Program.cpp | 71 ++++++++++++++++++-
3 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index 1c59ed1eda841..c2aba32376cac 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -1358,6 +1358,10 @@ struct GenericPluginTy {
/// target architecture.
Expected<bool> checkBitcodeImage(StringRef Image) const;
+ /// Return true if the \p Image has OffloadBinary magic bytes.
+ /// The actual compatibility and parsing will be handled by the runtime.
+ Expected<bool> checkOffloadBinaryImage(StringRef Image) const;
+
/// Indicate if an image is compatible with the plugin devices. Notice that
/// this function may be called before actually initializing the devices. So
/// we could not move this function into GenericDeviceTy.
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index f681213b38794..3214538f57657 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -28,6 +28,7 @@
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/Object/OffloadBinary.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/MathExtras.h"
@@ -1624,6 +1625,31 @@ Expected<bool> GenericPluginTy::checkBitcodeImage(StringRef Image) const {
return M.getTargetTriple().getArch() == getTripleArch();
}
+Expected<bool> GenericPluginTy::checkOffloadBinaryImage(StringRef Image) const {
+ // Check if the image has OffloadBinary magic bytes
+ if (identify_magic(Image) != file_magic::offload_binary)
+ return false;
+
+ // Parse the OffloadBinary to check triple compatibility
+ MemoryBufferRef Buffer(Image, "offload_binary");
+ auto BinariesOrErr = OffloadBinary::create(Buffer);
+ if (!BinariesOrErr)
+ return BinariesOrErr.takeError();
+
+ // Check if any of the binaries match this plugin's architecture
+ auto &Binaries = *BinariesOrErr;
+ Triple::ArchType PluginArch = getTripleArch();
+
+ for (const auto &Binary : Binaries) {
+ StringRef Triple = Binary->getTriple();
+ llvm::Triple T(Triple);
+ if (T.getArch() == PluginArch)
+ return true;
+ }
+
+ return false;
+}
+
int32_t GenericPluginTy::is_initialized() const { return Initialized; }
int32_t GenericPluginTy::isPluginCompatible(StringRef Image) {
@@ -1651,6 +1677,12 @@ int32_t GenericPluginTy::isPluginCompatible(StringRef Image) {
return HandleError(std::move(Err));
return *MatchOrErr;
}
+ case file_magic::offload_binary: {
+ auto MatchOrErr = checkOffloadBinaryImage(Image);
+ if (Error Err = MatchOrErr.takeError())
+ return HandleError(std::move(Err));
+ return *MatchOrErr;
+ }
default:
return false;
}
@@ -1688,6 +1720,12 @@ int32_t GenericPluginTy::isDeviceCompatible(int32_t DeviceId, StringRef Image) {
return HandleError(std::move(Err));
return *MatchOrErr;
}
+ case file_magic::offload_binary: {
+ auto MatchOrErr = checkOffloadBinaryImage(Image);
+ if (Error Err = MatchOrErr.takeError())
+ return HandleError(std::move(Err));
+ return *MatchOrErr;
+ }
default:
return false;
}
diff --git a/offload/plugins-nextgen/level_zero/src/L0Program.cpp b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
index 9c914f0eb7cab..ea272ff1cb279 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Program.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
@@ -215,8 +215,76 @@ bool isValidOneOmpImage(StringRef Image, uint64_t &MajorVer,
Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
auto &l0Device = getL0Device();
auto Image = getMemoryBuffer();
+
+ // Check if image is an inner OffloadBinary (nested format)
+ if (identify_magic(Image.getBuffer()) == file_magic::offload_binary) {
+ ODBG(OLDT_Module) << "Processing nested OffloadBinary image\n";
+
+ // Parse inner OffloadBinary
+ auto InnerBinariesOrErr = llvm::object::OffloadBinary::create(Image);
+ if (!InnerBinariesOrErr)
+ return Plugin::error(ErrorCode::UNKNOWN,
+ "Failed to parse inner OffloadBinary: %s",
+ llvm::toString(InnerBinariesOrErr.takeError()).c_str());
+
+ auto &InnerBinaries = *InnerBinariesOrErr;
+
+ // Should contain exactly one image
+ if (InnerBinaries.size() != 1)
+ return Plugin::error(ErrorCode::UNKNOWN,
+ "Expected single inner OffloadBinary entry, got %zu",
+ InnerBinaries.size());
+
+ const llvm::object::OffloadBinary *InnerBinary = InnerBinaries[0].get();
+ llvm::object::ImageKind ImageKind = InnerBinary->getImageKind();
+
+ // Extract image data from inner binary
+ llvm::StringRef ImageData = InnerBinary->getImage();
+ const uint8_t *ImgBegin = reinterpret_cast<const uint8_t *>(ImageData.data());
+
+ // Read metadata from inner binary
+ llvm::StringRef Version = InnerBinary->getString("version");
+ llvm::StringRef Format = InnerBinary->getString("format");
+ llvm::StringRef CompileOpts = InnerBinary->getString("compile-opts");
+ llvm::StringRef LinkOpts = InnerBinary->getString("link-opts");
+
+ ODBG(OLDT_Module) << "Inner OffloadBinary metadata: version=" << Version
+ << ", format=" << Format << ", kind=" << ImageKind << "\n";
+
+ // Build options string combining BuildOptions with compile/link opts
+ std::string Options(BuildOptions);
+ if (!CompileOpts.empty() || !LinkOpts.empty()) {
+ if (!CompileOpts.empty())
+ Options += " " + CompileOpts.str();
+ if (!LinkOpts.empty())
+ Options += " " + LinkOpts.str();
+ replaceDriverOptsWithBackendOpts(l0Device, Options);
+ ODBG(OLDT_Module) << "Using compile options: " << CompileOpts
+ << ", link options: " << LinkOpts << "\n";
+ }
+
+ // Determine module format based on image kind
+ ze_module_format_t ModuleFormat;
+ if (ImageKind == llvm::object::IMG_SPIRV) {
+ // SPIR-V intermediate language
+ ODBG(OLDT_Module) << "Loading SPIR-V module\n";
+ ModuleFormat = ZE_MODULE_FORMAT_IL_SPIRV;
+ } else if (ImageKind == llvm::object::IMG_Object) {
+ // Native binary format
+ ODBG(OLDT_Module) << "Loading native binary module\n";
+ ModuleFormat = ZE_MODULE_FORMAT_NATIVE;
+ } else {
+ return Plugin::error(ErrorCode::UNKNOWN,
+ "Unsupported image kind %d in inner OffloadBinary",
+ static_cast<int>(ImageKind));
+ }
+
+ // Load module into Level Zero
+ return addModule(ImageData.size(), ImgBegin, Options, ModuleFormat);
+ }
+
if (identify_magic(Image.getBuffer()) == file_magic::spirv_object) {
- // Handle legacy plain SPIR-V image.
+ ODBG(OLDT_Module) << "Processing raw SPIR-V image\n";
const uint8_t *ImgBegin =
reinterpret_cast<const uint8_t *>(Image.getBufferStart());
return addModule(Image.getBufferSize(), ImgBegin, BuildOptions,
@@ -228,6 +296,7 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
ODBG(OLDT_Module) << "Warning: image is not a valid oneAPI OpenMP image.";
return Plugin::error(ErrorCode::UNKNOWN, "Invalid oneAPI OpenMP image");
}
+ ODBG(OLDT_Module) << "Processing ELF-wrapped SPIR-V image\n";
// Iterate over the images and pick the first one that fits.
uint64_t ImageCount = 0;
>From b09b10cf18f60950b6bfa26d81703278f4845a5b Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Mon, 9 Mar 2026 06:09:57 -0700
Subject: [PATCH 2/2] format
---
.../level_zero/src/L0Program.cpp | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/offload/plugins-nextgen/level_zero/src/L0Program.cpp b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
index ea272ff1cb279..cf73d44129254 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Program.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Program.cpp
@@ -223,24 +223,25 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
// Parse inner OffloadBinary
auto InnerBinariesOrErr = llvm::object::OffloadBinary::create(Image);
if (!InnerBinariesOrErr)
- return Plugin::error(ErrorCode::UNKNOWN,
- "Failed to parse inner OffloadBinary: %s",
- llvm::toString(InnerBinariesOrErr.takeError()).c_str());
+ return Plugin::error(
+ ErrorCode::UNKNOWN, "Failed to parse inner OffloadBinary: %s",
+ llvm::toString(InnerBinariesOrErr.takeError()).c_str());
auto &InnerBinaries = *InnerBinariesOrErr;
// Should contain exactly one image
if (InnerBinaries.size() != 1)
return Plugin::error(ErrorCode::UNKNOWN,
- "Expected single inner OffloadBinary entry, got %zu",
- InnerBinaries.size());
+ "Expected single inner OffloadBinary entry, got %zu",
+ InnerBinaries.size());
const llvm::object::OffloadBinary *InnerBinary = InnerBinaries[0].get();
llvm::object::ImageKind ImageKind = InnerBinary->getImageKind();
// Extract image data from inner binary
llvm::StringRef ImageData = InnerBinary->getImage();
- const uint8_t *ImgBegin = reinterpret_cast<const uint8_t *>(ImageData.data());
+ const uint8_t *ImgBegin =
+ reinterpret_cast<const uint8_t *>(ImageData.data());
// Read metadata from inner binary
llvm::StringRef Version = InnerBinary->getString("version");
@@ -249,7 +250,8 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
llvm::StringRef LinkOpts = InnerBinary->getString("link-opts");
ODBG(OLDT_Module) << "Inner OffloadBinary metadata: version=" << Version
- << ", format=" << Format << ", kind=" << ImageKind << "\n";
+ << ", format=" << Format << ", kind=" << ImageKind
+ << "\n";
// Build options string combining BuildOptions with compile/link opts
std::string Options(BuildOptions);
@@ -275,8 +277,8 @@ Error L0ProgramBuilderTy::buildModules(const std::string_view BuildOptions) {
ModuleFormat = ZE_MODULE_FORMAT_NATIVE;
} else {
return Plugin::error(ErrorCode::UNKNOWN,
- "Unsupported image kind %d in inner OffloadBinary",
- static_cast<int>(ImageKind));
+ "Unsupported image kind %d in inner OffloadBinary",
+ static_cast<int>(ImageKind));
}
// Load module into Level Zero
More information about the llvm-commits
mailing list