From ce7ab7652cf29469a8addea8ebe67f408b4b03af Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" Date: Tue, 25 Nov 2025 00:40:45 +0100 Subject: [PATCH 1/5] [Offloading] Extend OffloadBinary format to support multiple metadata entries --- llvm/include/llvm/Object/OffloadBinary.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Object/OffloadBinary.h b/llvm/include/llvm/Object/OffloadBinary.h index f3847c1624977..cf25c02bc43fd 100644 --- a/llvm/include/llvm/Object/OffloadBinary.h +++ b/llvm/include/llvm/Object/OffloadBinary.h @@ -67,7 +67,7 @@ class OffloadBinary : public Binary { using string_iterator_range = iterator_range; /// The current version of the binary used for backwards compatibility. - static const uint32_t Version = 1; + static const uint32_t Version = 2; /// The offloading metadata that will be serialized to a memory buffer. struct OffloadingImage { @@ -109,9 +109,12 @@ class OffloadBinary : public Binary { struct Header { uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. uint32_t Version = OffloadBinary::Version; // Version identifier. - uint64_t Size; // Size in bytes of this entire binary. - uint64_t EntryOffset; // Offset of the metadata entry in bytes. - uint64_t EntrySize; // Size of the metadata entry in bytes. + uint64_t Size; // Size in bytes of this entire binary. + uint64_t EntriesCount; // Number of metadata entries in the binary. + uint64_t EntriesOffset; // Offset in bytes to the start of entries block. + uint64_t EntriesSize; // Size of the entries block in bytes. + uint64_t StringOffset; // Offset in bytes to the global string map + uint64_t NumStrings; // Number of entries in the global string map. }; struct Entry { @@ -127,6 +130,7 @@ class OffloadBinary : public Binary { struct StringEntry { uint64_t KeyOffset; uint64_t ValueOffset; + uint64_t ValueSize; // Size of the value in bytes. }; private: From f66ae8cca8d7678ba900c15eef1fa5fdb83a70dc Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" Date: Tue, 25 Nov 2025 21:04:43 +0100 Subject: [PATCH 2/5] updated offloadbinary per discussion --- llvm/include/llvm/Object/OffloadBinary.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/Object/OffloadBinary.h b/llvm/include/llvm/Object/OffloadBinary.h index cf25c02bc43fd..bdcacce204966 100644 --- a/llvm/include/llvm/Object/OffloadBinary.h +++ b/llvm/include/llvm/Object/OffloadBinary.h @@ -52,6 +52,13 @@ enum ImageKind : uint16_t { IMG_LAST, }; +/// Flags associated with the Entry. +enum OffloadEntryFlags : uint32_t { + OIF_None = 0, + // Entry doesn't contain image. Used to keep metadata only entries. + OIF_NoImage = (1 << 0), +}; + /// A simple binary serialization of an offloading file. We use this format to /// embed the offloading image into the host executable so it can be extracted /// and used by the linker. @@ -110,17 +117,14 @@ class OffloadBinary : public Binary { uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. uint32_t Version = OffloadBinary::Version; // Version identifier. uint64_t Size; // Size in bytes of this entire binary. - uint64_t EntriesCount; // Number of metadata entries in the binary. uint64_t EntriesOffset; // Offset in bytes to the start of entries block. - uint64_t EntriesSize; // Size of the entries block in bytes. - uint64_t StringOffset; // Offset in bytes to the global string map - uint64_t NumStrings; // Number of entries in the global string map. + uint64_t EntriesCount; // Number of metadata entries in the binary. }; struct Entry { ImageKind TheImageKind; // The kind of the image stored. OffloadKind TheOffloadKind; // The producer of this image. - uint32_t Flags; // Additional flags associated with the image. + uint32_t Flags; // Additional flags associated with the entry. uint64_t StringOffset; // Offset in bytes to the string map. uint64_t NumStrings; // Number of entries in the string map. uint64_t ImageOffset; // Offset in bytes of the actual binary image. From 98ad7e9b818a68029b4f8d1b274d5165d8dd1bdf Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" Date: Wed, 26 Nov 2025 03:16:48 +0100 Subject: [PATCH 3/5] Minimal changes to make build and lit tests pass with new OffloadBinary format. --- clang/test/Driver/linker-wrapper-image.c | 2 +- llvm/include/llvm/Object/OffloadBinary.h | 2 +- llvm/include/llvm/ObjectYAML/OffloadYAML.h | 4 ++-- .../Frontend/Offloading/OffloadWrapper.cpp | 2 +- llvm/lib/Object/OffloadBinary.cpp | 24 +++++++++++-------- llvm/lib/ObjectYAML/OffloadEmitter.cpp | 8 +++---- llvm/lib/ObjectYAML/OffloadYAML.cpp | 4 ++-- ...size.yaml => malformed-entries-count.yaml} | 2 +- .../ObjectYAML/Offload/malformed-offset.yaml | 2 +- .../ObjectYAML/Offload/malformed-version.yaml | 2 +- 10 files changed, 28 insertions(+), 24 deletions(-) rename llvm/test/ObjectYAML/Offload/{malformed-entry-size.yaml => malformed-entries-count.yaml} (94%) diff --git a/clang/test/Driver/linker-wrapper-image.c b/clang/test/Driver/linker-wrapper-image.c index b9327121edcf9..2c0df8c6be925 100644 --- a/clang/test/Driver/linker-wrapper-image.c +++ b/clang/test/Driver/linker-wrapper-image.c @@ -25,7 +25,7 @@ // OPENMP-REL: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading.relocatable", align 8 // OPENMP: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8 -// OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 144), ptr getelementptr ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 144), ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries }] +// OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr ([[[IMG_OFF:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 [[IMG_OFF]]), ptr getelementptr ([[[IMG_OFF]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 [[IMG_OFF]]), ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries }] // OPENMP-NEXT: @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries } // OPENMP-NEXT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.omp_offloading.descriptor_reg, ptr null }] diff --git a/llvm/include/llvm/Object/OffloadBinary.h b/llvm/include/llvm/Object/OffloadBinary.h index bdcacce204966..74dcd5cc7384b 100644 --- a/llvm/include/llvm/Object/OffloadBinary.h +++ b/llvm/include/llvm/Object/OffloadBinary.h @@ -134,7 +134,7 @@ class OffloadBinary : public Binary { struct StringEntry { uint64_t KeyOffset; uint64_t ValueOffset; - uint64_t ValueSize; // Size of the value in bytes. + uint64_t ValueSize; // Size of the value in bytes. }; private: diff --git a/llvm/include/llvm/ObjectYAML/OffloadYAML.h b/llvm/include/llvm/ObjectYAML/OffloadYAML.h index f897b52aa8b0e..63ff561f3fcbf 100644 --- a/llvm/include/llvm/ObjectYAML/OffloadYAML.h +++ b/llvm/include/llvm/ObjectYAML/OffloadYAML.h @@ -39,8 +39,8 @@ struct Binary { std::optional Version; std::optional Size; - std::optional EntryOffset; - std::optional EntrySize; + std::optional EntriesOffset; + std::optional EntriesCount; std::vector Members; }; diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp index 288fa10fc04bb..f1602765dbaa7 100644 --- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp +++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp @@ -161,7 +161,7 @@ GlobalVariable *createBinDesc(Module &M, ArrayRef> Bufs, Binary.bytes_begin()); const auto *Entry = reinterpret_cast( - Binary.bytes_begin() + Header->EntryOffset); + Binary.bytes_begin() + Header->EntriesOffset); BeginOffset = Entry->ImageOffset; EndOffset = Entry->ImageOffset + Entry->ImageSize; } diff --git a/llvm/lib/Object/OffloadBinary.cpp b/llvm/lib/Object/OffloadBinary.cpp index 3fff6b6a09e08..8e51b94b92951 100644 --- a/llvm/lib/Object/OffloadBinary.cpp +++ b/llvm/lib/Object/OffloadBinary.cpp @@ -189,19 +189,23 @@ OffloadBinary::create(MemoryBufferRef Buf) { TheHeader->Size < sizeof(Entry) || TheHeader->Size < sizeof(Header)) return errorCodeToError(object_error::unexpected_eof); - if (TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || - TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) + uint64_t EntriesSize = sizeof(Entry) * TheHeader->EntriesCount; + if (TheHeader->EntriesOffset > TheHeader->Size - EntriesSize || + EntriesSize > TheHeader->Size - sizeof(Header)) return errorCodeToError(object_error::unexpected_eof); - const Entry *TheEntry = - reinterpret_cast(&Start[TheHeader->EntryOffset]); + const Entry *Entries = + reinterpret_cast(&Start[TheHeader->EntriesOffset]); + for (uint32_t I = 0; I < TheHeader->EntriesCount; ++I) { + const Entry *TheEntry = &Entries[I]; - if (TheEntry->ImageOffset > Buf.getBufferSize() || - TheEntry->StringOffset > Buf.getBufferSize()) - return errorCodeToError(object_error::unexpected_eof); + if (TheEntry->ImageOffset > Buf.getBufferSize() || + TheEntry->StringOffset > Buf.getBufferSize()) + return errorCodeToError(object_error::unexpected_eof); + } return std::unique_ptr( - new OffloadBinary(Buf, TheHeader, TheEntry)); + new OffloadBinary(Buf, TheHeader, Entries)); } SmallString<0> OffloadBinary::write(const OffloadingImage &OffloadingData) { @@ -227,8 +231,8 @@ SmallString<0> OffloadBinary::write(const OffloadingImage &OffloadingData) { Header TheHeader; TheHeader.Size = alignTo( BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); - TheHeader.EntryOffset = sizeof(Header); - TheHeader.EntrySize = sizeof(Entry); + TheHeader.EntriesOffset = sizeof(Header); + TheHeader.EntriesCount = 1; // Create the entry using the string table offsets. The string table will be // placed directly after the entry in memory, and the image after that. diff --git a/llvm/lib/ObjectYAML/OffloadEmitter.cpp b/llvm/lib/ObjectYAML/OffloadEmitter.cpp index 131da68d77506..34eca4d61a410 100644 --- a/llvm/lib/ObjectYAML/OffloadEmitter.cpp +++ b/llvm/lib/ObjectYAML/OffloadEmitter.cpp @@ -45,10 +45,10 @@ bool yaml2offload(Binary &Doc, raw_ostream &Out, ErrorHandler EH) { TheHeader->Version = *Doc.Version; if (Doc.Size) TheHeader->Size = *Doc.Size; - if (Doc.EntryOffset) - TheHeader->EntryOffset = *Doc.EntryOffset; - if (Doc.EntrySize) - TheHeader->EntrySize = *Doc.EntrySize; + if (Doc.EntriesOffset) + TheHeader->EntriesOffset = *Doc.EntriesOffset; + if (Doc.EntriesCount) + TheHeader->EntriesCount = *Doc.EntriesCount; Out.write(Buffer.begin(), Buffer.size()); } diff --git a/llvm/lib/ObjectYAML/OffloadYAML.cpp b/llvm/lib/ObjectYAML/OffloadYAML.cpp index d5a0edde2179f..cab5a39741294 100644 --- a/llvm/lib/ObjectYAML/OffloadYAML.cpp +++ b/llvm/lib/ObjectYAML/OffloadYAML.cpp @@ -50,8 +50,8 @@ void MappingTraits::mapping(IO &IO, IO.mapTag("!Offload", true); IO.mapOptional("Version", O.Version); IO.mapOptional("Size", O.Size); - IO.mapOptional("EntryOffset", O.EntryOffset); - IO.mapOptional("EntrySize", O.EntrySize); + IO.mapOptional("EntriesOffset", O.EntriesOffset); + IO.mapOptional("EntriesCount", O.EntriesCount); IO.mapRequired("Members", O.Members); IO.setContext(nullptr); } diff --git a/llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml b/llvm/test/ObjectYAML/Offload/malformed-entries-count.yaml similarity index 94% rename from llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml rename to llvm/test/ObjectYAML/Offload/malformed-entries-count.yaml index 3194607ae39a5..bb2a34277963f 100644 --- a/llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml +++ b/llvm/test/ObjectYAML/Offload/malformed-entries-count.yaml @@ -1,6 +1,6 @@ # RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s !Offload -EntrySize: 999999999 +EntriesCount: 999999999 Members: - ImageKind: IMG_Cubin OffloadKind: OFK_OpenMP diff --git a/llvm/test/ObjectYAML/Offload/malformed-offset.yaml b/llvm/test/ObjectYAML/Offload/malformed-offset.yaml index 03c0431053cce..5aecfffd937bf 100644 --- a/llvm/test/ObjectYAML/Offload/malformed-offset.yaml +++ b/llvm/test/ObjectYAML/Offload/malformed-offset.yaml @@ -1,6 +1,6 @@ # RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s !Offload -EntryOffset: 999999999 +EntriesOffset: 999999999 Members: - ImageKind: IMG_Cubin OffloadKind: OFK_OpenMP diff --git a/llvm/test/ObjectYAML/Offload/malformed-version.yaml b/llvm/test/ObjectYAML/Offload/malformed-version.yaml index f9279a52e2764..99383491acce0 100644 --- a/llvm/test/ObjectYAML/Offload/malformed-version.yaml +++ b/llvm/test/ObjectYAML/Offload/malformed-version.yaml @@ -1,6 +1,6 @@ # RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s !Offload -Version: 2 +Version: 3 Members: - ImageKind: IMG_Cubin OffloadKind: OFK_OpenMP From a28aa79becd0b7dfec37cb16bcd522f366c56e85 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" Date: Thu, 27 Nov 2025 02:33:41 +0100 Subject: [PATCH 4/5] Just a snapshot of work in progress. --- llvm/include/llvm/Object/OffloadBinary.h | 117 +++++++++++------- llvm/lib/Object/OffloadBinary.cpp | 92 +++++++++----- llvm/tools/llvm-objdump/OffloadDump.cpp | 5 +- .../llvm-offload-binary.cpp | 10 +- llvm/tools/obj2yaml/offload2yaml.cpp | 28 +++-- 5 files changed, 157 insertions(+), 95 deletions(-) diff --git a/llvm/include/llvm/Object/OffloadBinary.h b/llvm/include/llvm/Object/OffloadBinary.h index 74dcd5cc7384b..84ebf51db3813 100644 --- a/llvm/include/llvm/Object/OffloadBinary.h +++ b/llvm/include/llvm/Object/OffloadBinary.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains the binary format used for budingling device metadata with +// This file contains the binary format used for bundling device metadata with // an associated device image. The data can then be stored inside a host object // file to create a fat binary and read by the linker. This is intended to be a // thin wrapper around the image itself. If this format becomes sufficiently @@ -70,6 +70,33 @@ enum OffloadEntryFlags : uint32_t { /// offsets from the beginning of the file. class OffloadBinary : public Binary { public: + struct Header { + uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. + uint32_t Version = OffloadBinary::Version; // Version identifier. + uint64_t Size; // Size in bytes of this entire binary. + uint64_t EntriesOffset; // Offset in bytes to the start of entries block. + uint64_t EntriesCount; // Number of metadata entries in the binary. + }; + + struct Entry { + ImageKind TheImageKind; // The kind of the image stored. + OffloadKind TheOffloadKind; // The producer of this image. + uint32_t Flags; // Additional flags associated with the entry. + uint64_t StringOffset; // Offset in bytes to the string map. + uint64_t NumStrings; // Number of entries in the string map. + uint64_t ImageOffset; // Offset in bytes of the actual binary image. + uint64_t ImageSize; // Size in bytes of the binary image. + }; + + struct StringEntry { + uint64_t KeyOffset; + uint64_t ValueOffset; + uint64_t ValueSize; // Size of the value in bytes. + }; + + using StringMap = MapVector; + using entry_iterator = SmallVector, 1>::const_iterator; + using entry_iterator_range = iterator_range; using string_iterator = MapVector::const_iterator; using string_iterator_range = iterator_range; @@ -89,77 +116,79 @@ class OffloadBinary : public Binary { LLVM_ABI static Expected> create(MemoryBufferRef); - /// Serialize the contents of \p File to a binary buffer to be read later. - LLVM_ABI static SmallString<0> write(const OffloadingImage &); + /// Serialize the contents of \p OffloadingData to a binary buffer to be read + /// later. + LLVM_ABI static SmallString<0> + write(ArrayRef OffloadingData); static uint64_t getAlignment() { return 8; } - ImageKind getImageKind() const { return TheEntry->TheImageKind; } - OffloadKind getOffloadKind() const { return TheEntry->TheOffloadKind; } + ImageKind getOnlyImageKind() const { + assert(getEntriesCount() == 1 && "Expected exactly one entry."); + return Entries[0].first->TheImageKind; + } + + OffloadKind getOffloadKind() const { return Entries[0].first->TheOffloadKind; } uint32_t getVersion() const { return TheHeader->Version; } - uint32_t getFlags() const { return TheEntry->Flags; } + uint32_t getFlags() const { return Entries[0].first->Flags; } uint64_t getSize() const { return TheHeader->Size; } + uint64_t getEntriesCount() const { return TheHeader->EntriesCount; } StringRef getTriple() const { return getString("triple"); } StringRef getArch() const { return getString("arch"); } StringRef getImage() const { - return StringRef(&Buffer[TheEntry->ImageOffset], TheEntry->ImageSize); + return StringRef(&Buffer[Entries[0].first->ImageOffset], Entries[0].first->ImageSize); } - // Iterator over all the key and value pairs in the binary. - string_iterator_range strings() const { return StringData; } - - StringRef getString(StringRef Key) const { return StringData.lookup(Key); } + // Iterator access to all entries in the binary + entry_iterator_range entries() const { + return make_range(Entries.begin(), Entries.end()); + } + entry_iterator entries_begin() const { return Entries.begin(); } + entry_iterator entries_end() const { return Entries.end(); } - static bool classof(const Binary *V) { return V->isOffloadFile(); } + // Access specific entry by index. + const std::pair &getEntry(size_t Index) const { + assert(Index < Entries.size() && "Entry index out of bounds"); + return Entries[Index]; + } - struct Header { - uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. - uint32_t Version = OffloadBinary::Version; // Version identifier. - uint64_t Size; // Size in bytes of this entire binary. - uint64_t EntriesOffset; // Offset in bytes to the start of entries block. - uint64_t EntriesCount; // Number of metadata entries in the binary. - }; + // Iterator over all the key and value pairs in the binary. + string_iterator_range strings() const { return Entries[0].second; } - struct Entry { - ImageKind TheImageKind; // The kind of the image stored. - OffloadKind TheOffloadKind; // The producer of this image. - uint32_t Flags; // Additional flags associated with the entry. - uint64_t StringOffset; // Offset in bytes to the string map. - uint64_t NumStrings; // Number of entries in the string map. - uint64_t ImageOffset; // Offset in bytes of the actual binary image. - uint64_t ImageSize; // Size in bytes of the binary image. - }; + StringRef getString(StringRef Key) const { return Entries[0].second.lookup(Key); } - struct StringEntry { - uint64_t KeyOffset; - uint64_t ValueOffset; - uint64_t ValueSize; // Size of the value in bytes. - }; + static bool classof(const Binary *V) { return V->isOffloadFile(); } private: OffloadBinary(MemoryBufferRef Source, const Header *TheHeader, - const Entry *TheEntry) + const Entry *EntriesBegin) : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()), - TheHeader(TheHeader), TheEntry(TheEntry) { - const StringEntry *StringMapBegin = - reinterpret_cast(&Buffer[TheEntry->StringOffset]); - for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) { - StringRef Key = &Buffer[StringMapBegin[I].KeyOffset]; - StringData[Key] = &Buffer[StringMapBegin[I].ValueOffset]; + TheHeader(TheHeader) { + for (uint64_t EI = 0, EE = TheHeader->EntriesCount; EI != EE; ++EI) { + const Entry *TheEntry = &EntriesBegin[EI]; + const StringEntry *StringMapBegin = reinterpret_cast( + &Buffer[TheEntry->StringOffset]); + StringMap Strings; + for (uint64_t SI = 0, SE = TheEntry->NumStrings; SI != SE; ++SI) { + StringRef Key = &Buffer[StringMapBegin[SI].KeyOffset]; + StringRef Value = StringRef( + &Buffer[StringMapBegin[SI].ValueOffset], StringMapBegin[SI].ValueSize); + Strings.insert({Key, Value}); + } + Entries.push_back(std::make_pair(TheEntry, std::move(Strings))); } } OffloadBinary(const OffloadBinary &Other) = delete; - /// Map from keys to offsets in the binary. - MapVector StringData; + /// Location of the metadata entries within the binary mapped to + /// the key-value string data. + SmallVector, 1> Entries; /// Raw pointer to the MemoryBufferRef for convenience. const char *Buffer; /// Location of the header within the binary. const Header *TheHeader; - /// Location of the metadata entries within the binary. - const Entry *TheEntry; }; /// A class to contain the binary information for a single OffloadBinary that diff --git a/llvm/lib/Object/OffloadBinary.cpp b/llvm/lib/Object/OffloadBinary.cpp index 8e51b94b92951..609b0896a0ba7 100644 --- a/llvm/lib/Object/OffloadBinary.cpp +++ b/llvm/lib/Object/OffloadBinary.cpp @@ -208,59 +208,85 @@ OffloadBinary::create(MemoryBufferRef Buf) { new OffloadBinary(Buf, TheHeader, Entries)); } -SmallString<0> OffloadBinary::write(const OffloadingImage &OffloadingData) { +SmallString<0> OffloadBinary::write(ArrayRef OffloadingData) { + uint64_t EntriesCount = OffloadingData.size(); + assert(EntriesCount > 0 && "At least one offloading image is required"); + // Create a null-terminated string table with all the used strings. + // Also calculate total size of images. StringTableBuilder StrTab(StringTableBuilder::ELF); - for (auto &KeyAndValue : OffloadingData.StringData) { - StrTab.add(KeyAndValue.first); - StrTab.add(KeyAndValue.second); + uint64_t TotalStringEntries = 0; + uint64_t TotalImagesSize = 0; + for (const OffloadingImage &Img : OffloadingData) { + for (auto &KeyAndValue : Img.StringData) { + StrTab.add(KeyAndValue.first); + StrTab.add(KeyAndValue.second); + } + TotalStringEntries += Img.StringData.size(); + TotalImagesSize += Img.Image->getBufferSize(); } StrTab.finalize(); - uint64_t StringEntrySize = - sizeof(StringEntry) * OffloadingData.StringData.size(); + uint64_t StringEntrySize = sizeof(StringEntry) * TotalStringEntries; + uint64_t EntriesSize = sizeof(Entry) * EntriesCount; + uint64_t StrTabOffset = sizeof(Header) + EntriesSize + StringEntrySize; // Make sure the image we're wrapping around is aligned as well. - uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) + - StringEntrySize + StrTab.getSize(), - getAlignment()); + uint64_t BinaryDataSize = + alignTo(StrTabOffset + StrTab.getSize(), getAlignment()); - // Create the header and fill in the offsets. The entry will be directly + // Create the header and fill in the offsets. The entries will be directly // placed after the header in memory. Align the size to the alignment of the // header so this can be placed contiguously in a single section. Header TheHeader; - TheHeader.Size = alignTo( - BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); + TheHeader.Size = alignTo(BinaryDataSize + TotalImagesSize, getAlignment()); TheHeader.EntriesOffset = sizeof(Header); - TheHeader.EntriesCount = 1; - - // Create the entry using the string table offsets. The string table will be - // placed directly after the entry in memory, and the image after that. - Entry TheEntry; - TheEntry.TheImageKind = OffloadingData.TheImageKind; - TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; - TheEntry.Flags = OffloadingData.Flags; - TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); - TheEntry.NumStrings = OffloadingData.StringData.size(); - - TheEntry.ImageOffset = BinaryDataSize; - TheEntry.ImageSize = OffloadingData.Image->getBufferSize(); + TheHeader.EntriesCount = EntriesCount; SmallString<0> Data; Data.reserve(TheHeader.Size); raw_svector_ostream OS(Data); OS << StringRef(reinterpret_cast(&TheHeader), sizeof(Header)); - OS << StringRef(reinterpret_cast(&TheEntry), sizeof(Entry)); - for (auto &KeyAndValue : OffloadingData.StringData) { - uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; - StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.first), - Offset + StrTab.getOffset(KeyAndValue.second)}; - OS << StringRef(reinterpret_cast(&Map), sizeof(StringEntry)); + + // Create the entries using the string table offsets. The string table will be + // placed directly after the set of entries in memory, and all the images are + // after that. + uint64_t StringEntryOffset = sizeof(Header) + EntriesSize; + uint64_t ImageOffset = BinaryDataSize; + for (const OffloadingImage &Img : OffloadingData) { + Entry TheEntry; + + TheEntry.TheImageKind = Img.TheImageKind; + TheEntry.TheOffloadKind = Img.TheOffloadKind; + TheEntry.Flags = Img.Flags; + + TheEntry.StringOffset = StringEntryOffset; + StringEntryOffset += sizeof(StringEntry) * Img.StringData.size(); + TheEntry.NumStrings = Img.StringData.size(); + + TheEntry.ImageOffset = ImageOffset; + ImageOffset += Img.Image->getBufferSize(); + TheEntry.ImageSize = Img.Image->getBufferSize(); + + OS << StringRef(reinterpret_cast(&TheEntry), sizeof(Entry)); } + + // Create the string map entries. + for (const OffloadingImage &Img : OffloadingData) { + for (auto &KeyAndValue : Img.StringData) { + StringEntry Map{StrTabOffset + StrTab.getOffset(KeyAndValue.first), + StrTabOffset + StrTab.getOffset(KeyAndValue.second), + KeyAndValue.second.size()}; + OS << StringRef(reinterpret_cast(&Map), sizeof(StringEntry)); + } + } + StrTab.write(OS); // Add padding to required image alignment. - OS.write_zeros(TheEntry.ImageOffset - OS.tell()); - OS << OffloadingData.Image->getBuffer(); + OS.write_zeros(BinaryDataSize - OS.tell()); + + for (const OffloadingImage &Img : OffloadingData) + OS << Img.Image->getBuffer(); // Add final padding to required alignment. assert(TheHeader.Size >= OS.tell() && "Too much data written?"); diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp index a77537dd90eeb..35003fa9c8cc5 100644 --- a/llvm/tools/llvm-objdump/OffloadDump.cpp +++ b/llvm/tools/llvm-objdump/OffloadDump.cpp @@ -25,7 +25,10 @@ void disassembleObject(llvm::object::ObjectFile *, bool InlineRelocs); /// Get the printable name of the image kind. static StringRef getImageName(const OffloadBinary &OB) { - switch (OB.getImageKind()) { + if (OB.getEntriesCount() > 1) + return "bundle"; + + switch (OB.getOnlyImageKind()) { case IMG_Object: return "elf"; case IMG_Bitcode: diff --git a/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp b/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp index e22d13b946651..811daf24c2af5 100644 --- a/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp +++ b/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp @@ -202,10 +202,12 @@ static Error unbundleImages() { } else { uint64_t Idx = 0; for (const OffloadBinary *Binary : Extracted) { - StringRef Filename = - Saver.save(sys::path::stem(InputFile) + "-" + Binary->getTriple() + - "-" + Binary->getArch() + "." + std::to_string(Idx++) + - "." + getImageKindName(Binary->getImageKind())); + StringRef FileExt = Binary->getEntriesCount() == 1 + ? getImageKindName(Binary->getOnlyImageKind()) + : "bundle"; + StringRef Filename = Saver.save( + sys::path::stem(InputFile) + "-" + Binary->getTriple() + "-" + + Binary->getArch() + "." + std::to_string(Idx++) + "." + FileExt); if (Error E = writeFile(Filename, Binary->getImage())) return E; } diff --git a/llvm/tools/obj2yaml/offload2yaml.cpp b/llvm/tools/obj2yaml/offload2yaml.cpp index 2b63e1278cd22..f9c6369b4e484 100644 --- a/llvm/tools/obj2yaml/offload2yaml.cpp +++ b/llvm/tools/obj2yaml/offload2yaml.cpp @@ -18,20 +18,22 @@ namespace { void populateYAML(OffloadYAML::Binary &YAMLBinary, object::OffloadBinary &OB, UniqueStringSaver Saver) { - YAMLBinary.Members.emplace_back(); - auto &Member = YAMLBinary.Members.back(); - Member.ImageKind = OB.getImageKind(); - Member.OffloadKind = OB.getOffloadKind(); - Member.Flags = OB.getFlags(); - if (!OB.strings().empty()) { - Member.StringEntries = std::vector(); - for (const auto &Entry : OB.strings()) - Member.StringEntries->emplace_back(OffloadYAML::Binary::StringEntry( - {Saver.save(Entry.first), Saver.save(Entry.second)})); + for (const auto &Entry : OB.entries()) { + YAMLBinary.Members.emplace_back(); + auto &Member = YAMLBinary.Members.back(); + Member.ImageKind = Entry.first->TheImageKind; + Member.OffloadKind = Entry.first->TheOffloadKind; + Member.Flags = Entry.first->Flags; + if (!Entry.second.empty()) { + Member.StringEntries = std::vector(); + for (const auto &StringEntry : Entry.second) + Member.StringEntries->emplace_back(OffloadYAML::Binary::StringEntry( + {Saver.save(StringEntry.first), Saver.save(StringEntry.second)})); + } + + if (!OB.getImage().empty()) + Member.Content = arrayRefFromStringRef(OB.getImage()); } - - if (!OB.getImage().empty()) - Member.Content = arrayRefFromStringRef(OB.getImage()); } Expected dump(MemoryBufferRef Source, From df65ae903d3b66c0570d10d04925c287ad4d6163 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" Date: Thu, 27 Nov 2025 02:46:00 +0100 Subject: [PATCH 5/5] one more minor change to make build pass for now --- llvm/lib/Frontend/Offloading/OffloadWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp index f1602765dbaa7..744aae947f8af 100644 --- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp +++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp @@ -952,7 +952,7 @@ class SYCLWrapper { Constant *OffloadKindConstant = ConstantInt::get( Type::getInt8Ty(C), static_cast(OB.getOffloadKind())); Constant *ImageKindConstant = ConstantInt::get( - Type::getInt8Ty(C), static_cast(OB.getImageKind())); + Type::getInt8Ty(C), static_cast(OB.getOnlyImageKind())); StringRef Triple = OB.getString("triple"); Constant *TripleConstant = addStringToModule(Triple, Twine(OffloadKindTag) + "target." + ImageID);