[clang] 9348026 - [llvm][offload] Change Intel's SPIRV wrapper from ELF to OffloadBinary (#185413)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 08:13:15 PDT 2026
Author: Alex Duran
Date: 2026-03-11T16:13:09+01:00
New Revision: 9348026ab434066babcce5ef7cf64281ed36bb83
URL: https://github.com/llvm/llvm-project/commit/9348026ab434066babcce5ef7cf64281ed36bb83
DIFF: https://github.com/llvm/llvm-project/commit/9348026ab434066babcce5ef7cf64281ed36bb83.diff
LOG: [llvm][offload] Change Intel's SPIRV wrapper from ELF to OffloadBinary (#185413)
Change SPIRV wrapping done in clang-linker-wrapper from custom ELF to
OffloadBinary.
Depends on:
- #185404 (Accept OffloadBinary in liboffload & L0 plugin)
Follow-up PRs:
- #185425 (Adjusts llvm-objdump)
- #184774 (Adjusts llvm-offload-binary)
---------
Co-authored-by: Yury Plyakhin <yury.plyakhin at intel.com>
Added:
Modified:
clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
llvm/include/llvm/Frontend/Offloading/Utility.h
llvm/lib/Frontend/Offloading/Utility.cpp
Removed:
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/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 54fad8a6ed5e7..9e24a9c26d897 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -652,7 +652,7 @@ Error containerizeRawImage(std::unique_ptr<MemoryBuffer> &Img, OffloadKind Kind,
llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
if (Kind == OFK_OpenMP && Triple.isSPIRV() &&
Triple.getVendor() == llvm::Triple::Intel)
- return offloading::intel::containerizeOpenMPSPIRVImage(Img);
+ return offloading::intel::containerizeOpenMPSPIRVImage(Img, Triple);
return Error::success();
}
diff --git a/llvm/include/llvm/Frontend/Offloading/Utility.h b/llvm/include/llvm/Frontend/Offloading/Utility.h
index 23e6702beb476..eb08e7ec661e4 100644
--- a/llvm/include/llvm/Frontend/Offloading/Utility.h
+++ b/llvm/include/llvm/Frontend/Offloading/Utility.h
@@ -157,11 +157,34 @@ LLVM_ABI Error getAMDGPUMetaDataFromImage(
uint16_t &ELFABIVersion);
} // namespace amdgpu
+/// Containerizes an image within an OffloadBinary image.
+/// Creates a nested OffloadBinary structure where the inner binary contains
+/// the raw image and associated metadata (version, format, triple, etc.).
+/// \param Binary The image to containerize.
+/// \param Triple The target triple to be associated with the image.
+/// \param ImageKind The format of the image, e.g. SPIR-V or CUBIN.
+/// \param OffloadKind The expected consuming runtime of the image, e.g. CUDA or
+/// OpenMP.
+/// \param ImageFlags Flags associated with the image, e.g. for AMDGPU the
+/// features.
+/// \param MetaData The key-value map of metadata to be associated with the
+/// image.
+LLVM_ABI Error containerizeImage(std::unique_ptr<MemoryBuffer> &Binary,
+ llvm::Triple Triple,
+ object::ImageKind ImageKind,
+ object::OffloadKind OffloadKind,
+ int32_t ImageFlags,
+ MapVector<StringRef, StringRef> &MetaData);
+
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 OpenMP SPIR-V image into an OffloadBinary image.
+/// \param Binary The SPIR-V binary to containerize.
+/// \param Triple The target triple to be associated with the image.
+/// \param CompileOpts Optional compilation options.
+/// \param LinkOpts Optional linking options.
+LLVM_ABI Error containerizeOpenMPSPIRVImage(
+ std::unique_ptr<MemoryBuffer> &Binary, llvm::Triple Triple,
+ StringRef CompileOpts = "", StringRef 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..44cef91bac495 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,49 @@ Error llvm::offloading::amdgpu::getAMDGPUMetaDataFromImage(
}
return Error::success();
}
+
+Error offloading::containerizeImage(std::unique_ptr<MemoryBuffer> &Img,
+ llvm::Triple Triple,
+ object::ImageKind ImageKind,
+ object::OffloadKind OffloadKind,
+ int32_t ImageFlags,
+ MapVector<StringRef, StringRef> &MetaData) {
+ using namespace object;
+
+ // Create inner OffloadBinary containing the raw image.
+ OffloadBinary::OffloadingImage InnerImage;
+ InnerImage.TheImageKind = ImageKind;
+ InnerImage.TheOffloadKind = OffloadKind;
+ InnerImage.Flags = ImageFlags;
+
+ InnerImage.StringData["triple"] = Triple.getTriple();
+ for (const auto &[Key, Value] : MetaData)
+ InnerImage.StringData[Key] = Value;
+
+ InnerImage.Image = std::move(Img);
+
+ SmallString<0> InnerBinaryData = OffloadBinary::write(InnerImage);
+
+ Img = MemoryBuffer::getMemBufferCopy(InnerBinaryData);
+ return Error::success();
+}
+
Error offloading::intel::containerizeOpenMPSPIRVImage(
- std::unique_ptr<MemoryBuffer> &Img) {
+ std::unique_ptr<MemoryBuffer> &Binary, llvm::Triple Triple,
+ StringRef CompileOpts, StringRef LinkOpts) {
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;
- Img = MemoryBuffer::getMemBufferCopy(YamlFile);
- return Error::success();
+ assert(Triple.isSPIRV() && Triple.getVendor() == llvm::Triple::Intel &&
+ "Expected SPIR-V triple with Intel vendor");
+
+ MapVector<StringRef, StringRef> MetaData;
+ MetaData["version"] = INTEL_ONEOMP_OFFLOAD_VERSION;
+ if (!CompileOpts.empty())
+ MetaData["compile-opts"] = CompileOpts;
+ if (!LinkOpts.empty())
+ MetaData["link-opts"] = LinkOpts;
+
+ return containerizeImage(Binary, Triple, object::ImageKind::IMG_SPIRV,
+ object::OffloadKind::OFK_OpenMP, /*ImageFlags=*/0,
+ MetaData);
}
More information about the cfe-commits
mailing list