[clang] [llvm] [llvm][offload] Change Intel's SPIRV wrapper from ELF to OffloadBinary (PR #185413)
Alex Duran via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 9 06:08:39 PDT 2026
https://github.com/adurang created https://github.com/llvm/llvm-project/pull/185413
None
>From 0cbafd367321c547ad673c66fabcacbca629e039 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Mon, 9 Mar 2026 06:05:50 -0700
Subject: [PATCH] [llvm][offload] Change Intel's SPIRV containerizetion from
ELF to OffloadBinary
---
.../clang-linker-wrapper-spirv-elf.cpp | 22 ----
.../llvm/Frontend/Offloading/Utility.h | 27 ++++-
llvm/lib/Frontend/Offloading/Utility.cpp | 114 ++++++------------
3 files changed, 59 insertions(+), 104 deletions(-)
delete mode 100644 clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp
diff --git a/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp b/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp
deleted file mode 100644
index 8a7d36d36b025..0000000000000
--- a/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Verify the ELF packaging of OpenMP SPIR-V device images.
-// REQUIRES: system-linux
-// REQUIRES: spirv-tools
-// REQUIRES: spirv-registered-target
-// RUN: mkdir -p %t_tmp
-// RUN: cd %t_tmp
-// RUN: %clangxx -fopenmp -fopenmp-targets=spirv64-intel -nogpulib -c -o %t_clang-linker-wrapper-spirv-elf.o %s
-// RUN: not clang-linker-wrapper -o a.out %t_clang-linker-wrapper-spirv-elf.o --save-temps --linker-path=ld
-// RUN: llvm-offload-binary --image=triple=spirv64-intel,kind=openmp,file=%t.elf %t_tmp/a.out.openmp.image.wrapper.o
-// RUN: llvm-readelf -h %t.elf | FileCheck -check-prefix=CHECK-MACHINE %s
-// RUN: llvm-readelf -t %t.elf | FileCheck -check-prefix=CHECK-SECTION %s
-// RUN: llvm-readelf -n %t.elf | FileCheck -check-prefix=CHECK-NOTES %s
-
-// CHECK-MACHINE: Machine: Intel Graphics Technology
-
-// CHECK-SECTION: .note.inteloneompoffload
-// CHECK-SECTION: __openmp_offload_spirv_0
-
-// CHECK-NOTES-COUNT-3: INTELONEOMPOFFLOAD
-int main(int argc, char** argv) {
- return 0;
-}
diff --git a/llvm/include/llvm/Frontend/Offloading/Utility.h b/llvm/include/llvm/Frontend/Offloading/Utility.h
index 23e6702beb476..0c2e5e7c860e3 100644
--- a/llvm/include/llvm/Frontend/Offloading/Utility.h
+++ b/llvm/include/llvm/Frontend/Offloading/Utility.h
@@ -158,10 +158,29 @@ LLVM_ABI Error getAMDGPUMetaDataFromImage(
} // namespace amdgpu
namespace intel {
-/// Containerizes an offloading binary into the ELF binary format expected by
-/// the Intel runtime offload plugin.
-LLVM_ABI Error
-containerizeOpenMPSPIRVImage(std::unique_ptr<MemoryBuffer> &Binary);
+/// Containerizes an SPIR-V image into inner OffloadBinary format.
+/// Creates a nested OffloadBinary structure where the inner binary contains
+/// the raw SPIR-V and associated metadata (version, format, triple, etc.).
+/// This inner OffloadBinary is then embedded in an outer OffloadBinary.
+///
+/// \param Binary The SPIR-V binary to containerize
+/// \param CompileOpts Optional compilation options
+/// \param LinkOpts Optional linking options
+LLVM_ABI Error containerizeSPIRVImage(std::unique_ptr<MemoryBuffer> &Binary,
+ object::OffloadKind Kind,
+ StringRef CompileOpts = "",
+ StringRef LinkOpts = "");
+
+/// Containerizes OpenMP SPIR-V image into inner OffloadBinary format.
+/// \param Binary The SPIR-V binary to containerize
+/// \param CompileOpts Optional compilation options
+/// \param LinkOpts Optional linking options
+inline LLVM_ABI Error containerizeOpenMPSPIRVImage(
+ std::unique_ptr<MemoryBuffer> &Binary, StringRef CompileOpts = "",
+ StringRef LinkOpts = "") {
+ return containerizeSPIRVImage(Binary, object::OffloadKind::OFK_OpenMP,
+ CompileOpts, LinkOpts);
+}
} // namespace intel
} // namespace offloading
} // namespace llvm
diff --git a/llvm/lib/Frontend/Offloading/Utility.cpp b/llvm/lib/Frontend/Offloading/Utility.cpp
index 5000488a52f37..d5571a15baf1c 100644
--- a/llvm/lib/Frontend/Offloading/Utility.cpp
+++ b/llvm/lib/Frontend/Offloading/Utility.cpp
@@ -15,6 +15,7 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Value.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/OffloadBinary.h"
#include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/MemoryBufferRef.h"
@@ -377,84 +378,41 @@ Error llvm::offloading::amdgpu::getAMDGPUMetaDataFromImage(
}
return Error::success();
}
-Error offloading::intel::containerizeOpenMPSPIRVImage(
- std::unique_ptr<MemoryBuffer> &Img) {
- constexpr char INTEL_ONEOMP_OFFLOAD_VERSION[] = "1.0";
- constexpr int NT_INTEL_ONEOMP_OFFLOAD_VERSION = 1;
- constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT = 2;
- constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX = 3;
-
- // Start creating notes for the ELF container.
- std::vector<ELFYAML::NoteEntry> Notes;
- std::string Version = toHex(INTEL_ONEOMP_OFFLOAD_VERSION);
- Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
- yaml::BinaryRef(Version),
- NT_INTEL_ONEOMP_OFFLOAD_VERSION});
-
- // The AuxInfo string will hold auxiliary information for the image.
- // ELFYAML::NoteEntry structures will hold references to the
- // string, so we have to make sure the string is valid.
- std::string AuxInfo;
-
- // TODO: Pass compile/link opts
- StringRef CompileOpts = "";
- StringRef LinkOpts = "";
-
- unsigned ImageFmt = 1; // SPIR-V format
-
- AuxInfo = toHex((Twine(0) + Twine('\0') + Twine(ImageFmt) + Twine('\0') +
- CompileOpts + Twine('\0') + LinkOpts)
- .str());
- Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
- yaml::BinaryRef(AuxInfo),
- NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX});
-
- std::string ImgCount = toHex(Twine(1).str()); // always one image per ELF
- Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
- yaml::BinaryRef(ImgCount),
- NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT});
-
- std::string YamlFile;
- llvm::raw_string_ostream YamlFileStream(YamlFile);
-
- // Write the YAML template file.
-
- // We use 64-bit little-endian ELF currently.
- ELFYAML::FileHeader Header{};
- Header.Class = ELF::ELFCLASS64;
- Header.Data = ELF::ELFDATA2LSB;
- Header.Type = ELF::ET_DYN;
- Header.Machine = ELF::EM_INTELGT;
-
- // Create a section with notes.
- ELFYAML::NoteSection Section{};
- Section.Type = ELF::SHT_NOTE;
- Section.AddressAlign = 0;
- Section.Name = ".note.inteloneompoffload";
- Section.Notes.emplace(std::move(Notes));
-
- ELFYAML::Object Object{};
- Object.Header = Header;
- Object.Chunks.push_back(
- std::make_unique<ELFYAML::NoteSection>(std::move(Section)));
-
- // Create the section that will hold the image
- ELFYAML::RawContentSection ImageSection{};
- ImageSection.Type = ELF::SHT_PROGBITS;
- ImageSection.AddressAlign = 0;
- std::string Name = "__openmp_offload_spirv_0";
- ImageSection.Name = Name;
- ImageSection.Content =
- llvm::yaml::BinaryRef(arrayRefFromStringRef(Img->getBuffer()));
- Object.Chunks.push_back(
- std::make_unique<ELFYAML::RawContentSection>(std::move(ImageSection)));
- Error Err = Error::success();
- llvm::yaml::yaml2elf(
- Object, YamlFileStream,
- [&Err](const Twine &Msg) { Err = createStringError(Msg); }, UINT64_MAX);
- if (Err)
- return Err;
+Error offloading::intel::containerizeSPIRVImage(
+ std::unique_ptr<MemoryBuffer> &Img, object::OffloadKind Kind,
+ StringRef CompileOpts, StringRef LinkOpts) {
+ using namespace object;
+
+ // Create inner OffloadBinary containing the raw SPIR-V
+ OffloadBinary::OffloadingImage InnerImage;
+ InnerImage.TheImageKind = ImageKind::IMG_SPIRV;
+ InnerImage.TheOffloadKind = Kind;
+ InnerImage.Flags = 0;
+
+ // Add metadata about the SPIR-V image as string key-value pairs.
+ MapVector<StringRef, StringRef> StringData;
+ StringData["version"] = "1.0";
+ StringData["format"] = "spirv";
+ StringData["triple"] = "spirv64-intel";
+
+ // Store compile/link options if provided
+ if (!CompileOpts.empty())
+ StringData["compile-opts"] = CompileOpts;
+ if (!LinkOpts.empty())
+ StringData["link-opts"] = LinkOpts;
+
+ InnerImage.StringData = StringData;
+
+ // Wrap the raw SPIR-V binary
+ InnerImage.Image = std::move(Img);
+
+ // Serialize inner OffloadBinary
+ SmallVector<OffloadBinary::OffloadingImage> Images;
+ Images.push_back(std::move(InnerImage));
+ SmallString<0> InnerBinaryData = OffloadBinary::write(Images);
+
+ // Replace the buffer with the inner OffloadBinary
+ Img = MemoryBuffer::getMemBufferCopy(InnerBinaryData);
- Img = MemoryBuffer::getMemBufferCopy(YamlFile);
return Error::success();
}
More information about the cfe-commits
mailing list