[Offload][L0] Add support for OffloadBinary format in L0 plugin (#185404)

- Accept OffloadBinaries as valid images by plugins that support them in
the PluginInterface.
- Add support in L0 plugin to extract SPIRV images and their associated
metadata from an OffloadBinary image.

Depends on:
- #185663

Follow-up PRs:
- #185413 (Changes SPIRV wrapper generation to use OffloadBinary)
- #185425 (Adjusts llvm-objdump)
- #184774 (Adjusts llvm-offload-binary)
This commit is contained in:
Alex Duran 2026-03-11 11:42:36 +01:00 committed by GitHub
parent 1ae518aa76
commit 3ff332ad0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 108 additions and 1 deletions

View File

@ -18,6 +18,8 @@
#include "L0Plugin.h"
#include "L0Trace.h"
#include "llvm/Object/OffloadBinary.h"
namespace llvm::omp::target::plugin {
using namespace llvm::omp::target;
@ -161,6 +163,42 @@ Expected<bool> LevelZeroPluginTy::isELFCompatible(uint32_t DeviceId,
return isValidOneOmpImage(Image, MajorVer, MinorVer);
}
// We only need to check for formats other than ELF here.
Expected<bool> LevelZeroPluginTy::isImageCompatible(StringRef Image) const {
switch (identify_magic(Image)) {
case file_magic::spirv_object:
// Handle SPIRV objects directly
return true;
case file_magic::offload_binary: {
// Handle OffloadBinary format
MemoryBufferRef Buffer(Image, "offload_binary");
auto BinariesOrErr = OffloadBinary::create(Buffer);
if (!BinariesOrErr)
return BinariesOrErr.takeError();
auto &Binaries = *BinariesOrErr;
if (Binaries.size() != 1)
return false;
const OffloadBinary *InnerBinary = Binaries[0].get();
ImageKind ImageKind = InnerBinary->getImageKind();
llvm::Triple Triple(InnerBinary->getTriple());
if (Triple.getArch() != getTripleArch())
return false;
if (ImageKind != llvm::object::IMG_SPIRV &&
ImageKind != llvm::object::IMG_Object)
return false;
return true;
}
default:
// Unknown format
return false;
}
}
Error LevelZeroPluginTy::syncBarrierImpl(omp_interop_val_t *Interop) {
if (!Interop) {
return Plugin::error(ErrorCode::INVALID_ARGUMENT,

View File

@ -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";
// 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 CompileOpts = InnerBinary->getString("compile-opts");
llvm::StringRef LinkOpts = InnerBinary->getString("link-opts");
ODBG(OLDT_Module) << "Inner OffloadBinary metadata: version=" << Version
<< ", kind=" << ImageKind;
// 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;
}
// 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";
ModuleFormat = ZE_MODULE_FORMAT_IL_SPIRV;
} else if (ImageKind == llvm::object::IMG_Object) {
// Native binary format
ODBG(OLDT_Module) << "Loading native binary module";
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";
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";
// Iterate over the images and pick the first one that fits.
uint64_t ImageCount = 0;