[llvm] Fix compress/decompress in LLVM Offloading API (PR #150064)

David Salinas via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 18 12:57:53 PDT 2025


https://github.com/david-salinas updated https://github.com/llvm/llvm-project/pull/150064

>From 8fd5968e77eab62bd000f42590bde1cda5c1ea89 Mon Sep 17 00:00:00 2001
From: dsalinas_amdeng <david.salinas at amd.com>
Date: Tue, 17 Jun 2025 19:03:35 +0000
Subject: [PATCH 1/8] SWDEV-52811 - fix compress/decompress in LLVM Offloading
 API

---
 llvm/include/llvm/Object/OffloadBundle.h |  79 ++--
 llvm/lib/Object/OffloadBundle.cpp        | 485 +++++++++++++++--------
 llvm/tools/llvm-objdump/OffloadDump.cpp  |  27 +-
 3 files changed, 391 insertions(+), 200 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index f4d5a1d878b8d..99f54ea4f28aa 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -32,29 +32,40 @@ namespace llvm {
 
 namespace object {
 
+// CompressedOffloadBundle represents the format for the compressed offload
+// bundles.
+//
+// The format is as follows:
+// - Magic Number (4 bytes) - A constant "CCOB".
+// - Version (2 bytes)
+// - Compression Method (2 bytes) - Uses the values from
+// llvm::compression::Format.
+// - Total file size (4 bytes in V2, 8 bytes in V3).
+// - Uncompressed Size (4 bytes in V1/V2, 8 bytes in V3).
+// - Truncated MD5 Hash (8 bytes).
+// - Compressed Data (variable length).
 class CompressedOffloadBundle {
 private:
-  static inline const size_t MagicSize = 4;
-  static inline const size_t VersionFieldSize = sizeof(uint16_t);
-  static inline const size_t MethodFieldSize = sizeof(uint16_t);
-  static inline const size_t FileSizeFieldSize = sizeof(uint32_t);
-  static inline const size_t UncompressedSizeFieldSize = sizeof(uint32_t);
-  static inline const size_t HashFieldSize = sizeof(uint64_t);
-  static inline const size_t V1HeaderSize =
-      MagicSize + VersionFieldSize + MethodFieldSize +
-      UncompressedSizeFieldSize + HashFieldSize;
-  static inline const size_t V2HeaderSize =
-      MagicSize + VersionFieldSize + FileSizeFieldSize + MethodFieldSize +
-      UncompressedSizeFieldSize + HashFieldSize;
   static inline const llvm::StringRef MagicNumber = "CCOB";
-  static inline const uint16_t Version = 2;
 
 public:
-  LLVM_ABI static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+  struct CompressedBundleHeader {
+    unsigned Version;
+    llvm::compression::Format CompressionFormat;
+    std::optional<size_t> FileSize;
+    size_t UncompressedFileSize;
+    uint64_t Hash;
+
+    static llvm::Expected<CompressedBundleHeader> tryParse(llvm::StringRef);
+  };
+
+  static inline const uint16_t DefaultVersion = 2;
+
+  static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
-           bool Verbose = false);
-  LLVM_ABI static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-  decompress(llvm::MemoryBufferRef &Input, bool Verbose = false);
+           uint16_t Version, bool Verbose = false);
+  static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+  decompress(const llvm::MemoryBuffer &Input, bool Verbose = false);
 };
 
 /// Bundle entry in binary clang-offload-bundler format.
@@ -62,12 +73,15 @@ struct OffloadBundleEntry {
   uint64_t Offset = 0u;
   uint64_t Size = 0u;
   uint64_t IDLength = 0u;
-  StringRef ID;
-  OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T)
-      : Offset(O), Size(S), IDLength(I), ID(T) {}
+  std::string ID;
+  OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, std::string T)
+      : Offset(O), Size(S), IDLength(I) {
+    ID.reserve(T.size());
+    ID = T;
+  }
   void dumpInfo(raw_ostream &OS) {
     OS << "Offset = " << Offset << ", Size = " << Size
-       << ", ID Length = " << IDLength << ", ID = " << ID;
+       << ", ID Length = " << IDLength << ", ID = " << ID << "\n";
   }
   void dumpURI(raw_ostream &OS, StringRef FilePath) {
     OS << ID.data() << "\tfile://" << FilePath << "#offset=" << Offset
@@ -82,15 +96,20 @@ class OffloadBundleFatBin {
   StringRef FileName;
   uint64_t NumberOfEntries;
   SmallVector<OffloadBundleEntry> Entries;
+  bool Decompressed;
 
 public:
+  std::unique_ptr<MemoryBuffer> DecompressedBuffer;
+
   SmallVector<OffloadBundleEntry> getEntries() { return Entries; }
   uint64_t getSize() const { return Size; }
   StringRef getFileName() const { return FileName; }
   uint64_t getNumEntries() const { return NumberOfEntries; }
+  bool isDecompressed() const { return Decompressed; }
 
   LLVM_ABI static Expected<std::unique_ptr<OffloadBundleFatBin>>
-  create(MemoryBufferRef, uint64_t SectionOffset, StringRef FileName);
+  create(MemoryBufferRef, uint64_t SectionOffset, StringRef FileName,
+         bool Decompress = false);
   LLVM_ABI Error extractBundle(const ObjectFile &Source);
 
   LLVM_ABI Error dumpEntryToCodeObject();
@@ -106,9 +125,15 @@ class OffloadBundleFatBin {
       Entry.dumpURI(outs(), FileName);
   }
 
-  OffloadBundleFatBin(MemoryBufferRef Source, StringRef File)
-      : FileName(File), NumberOfEntries(0),
-        Entries(SmallVector<OffloadBundleEntry>()) {}
+  OffloadBundleFatBin(MemoryBufferRef Source, StringRef File,
+                      bool Decompress = false)
+      : FileName(File), Decompressed(Decompress), NumberOfEntries(0),
+        Entries(SmallVector<OffloadBundleEntry>()) {
+    if (Decompress) {
+      DecompressedBuffer =
+          MemoryBuffer::getMemBufferCopy(Source.getBuffer(), File);
+    }
+  }
 };
 
 enum UriTypeT { FILE_URI, MEMORY_URI };
@@ -191,6 +216,10 @@ LLVM_ABI Error extractOffloadBundleFatBinary(
 LLVM_ABI Error extractCodeObject(const ObjectFile &Source, int64_t Offset,
                                  int64_t Size, StringRef OutputFileName);
 
+/// Extract code object memory from the given \p Source object file at \p Offset
+/// and of \p Size, and copy into \p OutputFileName.
+LLVM_ABI Error extractCodeObject(MemoryBufferRef Buffer, int64_t Offset,
+                                 int64_t Size, StringRef OutputFileName);
 /// Extracts an Offload Bundle Entry given by URI
 LLVM_ABI Error extractOffloadBundleByURI(StringRef URIstr);
 
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 1e1042ce2bc21..57a8244a9b0e5 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -37,26 +37,63 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
 
   size_t Offset = 0;
   size_t NextbundleStart = 0;
+  StringRef Magic;
+  std::unique_ptr<MemoryBuffer> Buffer;
 
   // There could be multiple offloading bundles stored at this section.
-  while (NextbundleStart != StringRef::npos) {
-    std::unique_ptr<MemoryBuffer> Buffer =
+  while ((NextbundleStart != StringRef::npos) &&
+         (Offset < Contents.getBuffer().size())) {
+    Buffer =
         MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "",
                                    /*RequiresNullTerminator=*/false);
 
-    // Create the FatBinBindle object. This will also create the Bundle Entry
-    // list info.
-    auto FatBundleOrErr =
-        OffloadBundleFatBin::create(*Buffer, SectionOffset + Offset, FileName);
-    if (!FatBundleOrErr)
-      return FatBundleOrErr.takeError();
-
-    // Add current Bundle to list.
-    Bundles.emplace_back(std::move(**FatBundleOrErr));
+    if (identify_magic((*Buffer).getBuffer()) ==
+        file_magic::offload_bundle_compressed) {
+      Magic = StringRef("CCOB");
+      // decompress this bundle first.
+      NextbundleStart = (*Buffer).getBuffer().find(Magic, Magic.size());
+      if (NextbundleStart == StringRef::npos) {
+        NextbundleStart = (*Buffer).getBuffer().size();
+      }
 
-    // Find the next bundle by searching for the magic string
-    StringRef Str = Buffer->getBuffer();
-    NextbundleStart = Str.find(StringRef("__CLANG_OFFLOAD_BUNDLE__"), 24);
+      ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+          MemoryBuffer::getMemBuffer((*Buffer).getBuffer().take_front(
+                                         NextbundleStart /*- Magic.size()*/),
+                                     FileName, false);
+      if (std::error_code EC = CodeOrErr.getError())
+        return createFileError(FileName, EC);
+
+      Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
+          CompressedOffloadBundle::decompress(**CodeOrErr, false);
+      if (!DecompressedBufferOrErr)
+        return createStringError(
+            inconvertibleErrorCode(),
+            "Failed to decompress input: " +
+                llvm::toString(DecompressedBufferOrErr.takeError()));
+
+      auto FatBundleOrErr = OffloadBundleFatBin::create(
+          **DecompressedBufferOrErr, Offset, FileName, true);
+      if (!FatBundleOrErr)
+        return FatBundleOrErr.takeError();
+
+      // Add current Bundle to list.
+      Bundles.emplace_back(std::move(**FatBundleOrErr));
+
+    } else if (identify_magic((*Buffer).getBuffer()) ==
+               file_magic::offload_bundle) {
+      // Create the FatBinBindle object. This will also create the Bundle Entry
+      // list info.
+      auto FatBundleOrErr = OffloadBundleFatBin::create(
+          *Buffer, SectionOffset + Offset, FileName);
+      if (!FatBundleOrErr)
+        return FatBundleOrErr.takeError();
+
+      // Add current Bundle to list.
+      Bundles.emplace_back(std::move(**FatBundleOrErr));
+
+      Magic = StringRef("__CLANG_OFFLOAD_BUNDLE__");
+      NextbundleStart = (*Buffer).getBuffer().find(Magic, Magic.size());
+    }
 
     if (NextbundleStart != StringRef::npos)
       Offset += NextbundleStart;
@@ -102,7 +139,8 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
       return errorCodeToError(object_error::parse_failed);
 
     auto Entry = std::make_unique<OffloadBundleEntry>(
-        EntryOffset + SectionOffset, EntrySize, EntryIDSize, EntryID);
+        EntryOffset + SectionOffset, EntrySize, EntryIDSize,
+        std::move(EntryID.str()));
 
     Entries.push_back(*Entry);
   }
@@ -112,18 +150,22 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
 
 Expected<std::unique_ptr<OffloadBundleFatBin>>
 OffloadBundleFatBin::create(MemoryBufferRef Buf, uint64_t SectionOffset,
-                            StringRef FileName) {
+                            StringRef FileName, bool Decompress) {
   if (Buf.getBufferSize() < 24)
     return errorCodeToError(object_error::parse_failed);
 
   // Check for magic bytes.
-  if (identify_magic(Buf.getBuffer()) != file_magic::offload_bundle)
+  if ((identify_magic(Buf.getBuffer()) != file_magic::offload_bundle) &&
+      (identify_magic(Buf.getBuffer()) !=
+       file_magic::offload_bundle_compressed))
     return errorCodeToError(object_error::parse_failed);
 
-  OffloadBundleFatBin *TheBundle = new OffloadBundleFatBin(Buf, FileName);
+  OffloadBundleFatBin *TheBundle =
+      new OffloadBundleFatBin(Buf, FileName, Decompress);
 
   // Read the Bundle Entries
-  Error Err = TheBundle->readEntries(Buf.getBuffer(), SectionOffset);
+  Error Err =
+      TheBundle->readEntries(Buf.getBuffer(), Decompress ? 0 : SectionOffset);
   if (Err)
     return errorCodeToError(object_error::parse_failed);
 
@@ -172,28 +214,9 @@ Error object::extractOffloadBundleFatBinary(
                                  "COFF object files not supported.\n");
 
       MemoryBufferRef Contents(*Buffer, Obj.getFileName());
-
-      if (llvm::identify_magic(*Buffer) ==
-          llvm::file_magic::offload_bundle_compressed) {
-        // Decompress the input if necessary.
-        Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
-            CompressedOffloadBundle::decompress(Contents, false);
-
-        if (!DecompressedBufferOrErr)
-          return createStringError(
-              inconvertibleErrorCode(),
-              "Failed to decompress input: " +
-                  llvm::toString(DecompressedBufferOrErr.takeError()));
-
-        MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
-        if (Error Err = extractOffloadBundle(DecompressedInput, SectionOffset,
-                                             Obj.getFileName(), Bundles))
-          return Err;
-      } else {
-        if (Error Err = extractOffloadBundle(Contents, SectionOffset,
-                                             Obj.getFileName(), Bundles))
-          return Err;
-      }
+      if (Error Err = extractOffloadBundle(Contents, SectionOffset,
+                                           Obj.getFileName(), Bundles))
+        return Err;
     }
   }
   return Error::success();
@@ -221,6 +244,22 @@ Error object::extractCodeObject(const ObjectFile &Source, int64_t Offset,
   return Error::success();
 }
 
+Error object::extractCodeObject(const MemoryBufferRef Buffer, int64_t Offset,
+                                int64_t Size, StringRef OutputFileName) {
+  Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(OutputFileName, Size);
+  if (!BufferOrErr)
+    return BufferOrErr.takeError();
+
+  std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
+  std::copy(Buffer.getBufferStart() + Offset,
+            Buffer.getBufferStart() + Offset + Size, Buf->getBufferStart());
+  if (Error E = Buf->commit())
+    return E;
+
+  return Error::success();
+}
+
 // given a file name, offset, and size, extract data into a code object file,
 // into file <SourceFile>-offset<Offset>-size<Size>.co
 Error object::extractOffloadBundleByURI(StringRef URIstr) {
@@ -260,11 +299,233 @@ static std::string formatWithCommas(unsigned long long Value) {
 }
 
 llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
+CompressedOffloadBundle::compress(llvm::compression::Params P,
+                                  const llvm::MemoryBuffer &Input,
+                                  uint16_t Version, bool Verbose) {
+  if (!llvm::compression::zstd::isAvailable() &&
+      !llvm::compression::zlib::isAvailable())
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "Compression not supported");
+  llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
+                        OffloadBundlerTimerGroup);
+  if (Verbose)
+    HashTimer.startTimer();
+  llvm::MD5 Hash;
+  llvm::MD5::MD5Result Result;
+  Hash.update(Input.getBuffer());
+  Hash.final(Result);
+  uint64_t TruncatedHash = Result.low();
+  if (Verbose)
+    HashTimer.stopTimer();
+
+  SmallVector<uint8_t, 0> CompressedBuffer;
+  auto BufferUint8 = llvm::ArrayRef<uint8_t>(
+      reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
+      Input.getBuffer().size());
+  llvm::Timer CompressTimer("Compression Timer", "Compression time",
+                            OffloadBundlerTimerGroup);
+  if (Verbose)
+    CompressTimer.startTimer();
+  llvm::compression::compress(P, BufferUint8, CompressedBuffer);
+  if (Verbose)
+    CompressTimer.stopTimer();
+
+  uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
+
+  // Store sizes in 64-bit variables first
+  uint64_t UncompressedSize64 = Input.getBuffer().size();
+  uint64_t TotalFileSize64;
+
+  // Calculate total file size based on version
+  if (Version == 2) {
+    // For V2, ensure the sizes don't exceed 32-bit limit
+    if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
+      return createStringError(llvm::inconvertibleErrorCode(),
+                               "Uncompressed size exceeds version 2 limit");
+    if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
+         sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +
+         CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
+      return createStringError(llvm::inconvertibleErrorCode(),
+                               "Total file size exceeds version 2 limit");
+
+    TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
+                      sizeof(CompressionMethod) + sizeof(uint32_t) +
+                      sizeof(TruncatedHash) + CompressedBuffer.size();
+  } else { // Version 3
+    TotalFileSize64 = MagicNumber.size() + sizeof(uint64_t) + sizeof(Version) +
+                      sizeof(CompressionMethod) + sizeof(uint64_t) +
+                      sizeof(TruncatedHash) + CompressedBuffer.size();
+  }
+
+  SmallVector<char, 0> FinalBuffer;
+  llvm::raw_svector_ostream OS(FinalBuffer);
+  OS << MagicNumber;
+  OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
+  OS.write(reinterpret_cast<const char *>(&CompressionMethod),
+           sizeof(CompressionMethod));
+
+  // Write size fields according to version
+  if (Version == 2) {
+    uint32_t TotalFileSize32 = static_cast<uint32_t>(TotalFileSize64);
+    uint32_t UncompressedSize32 = static_cast<uint32_t>(UncompressedSize64);
+    OS.write(reinterpret_cast<const char *>(&TotalFileSize32),
+             sizeof(TotalFileSize32));
+    OS.write(reinterpret_cast<const char *>(&UncompressedSize32),
+             sizeof(UncompressedSize32));
+  } else { // Version 3
+    OS.write(reinterpret_cast<const char *>(&TotalFileSize64),
+             sizeof(TotalFileSize64));
+    OS.write(reinterpret_cast<const char *>(&UncompressedSize64),
+             sizeof(UncompressedSize64));
+  }
+
+  OS.write(reinterpret_cast<const char *>(&TruncatedHash),
+           sizeof(TruncatedHash));
+  OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),
+           CompressedBuffer.size());
+
+  if (Verbose) {
+    auto MethodUsed =
+        P.format == llvm::compression::Format::Zstd ? "zstd" : "zlib";
+    double CompressionRate =
+        static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
+    double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
+    double CompressionSpeedMBs =
+        (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
+    llvm::errs() << "Compressed bundle format version: " << Version << "\n"
+                 << "Total file size (including headers): "
+                 << formatWithCommas(TotalFileSize64) << " bytes\n"
+                 << "Compression method used: " << MethodUsed << "\n"
+                 << "Compression level: " << P.level << "\n"
+                 << "Binary size before compression: "
+                 << formatWithCommas(UncompressedSize64) << " bytes\n"
+                 << "Binary size after compression: "
+                 << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
+                 << "Compression rate: "
+                 << llvm::format("%.2lf", CompressionRate) << "\n"
+                 << "Compression ratio: "
+                 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+                 << "Compression speed: "
+                 << llvm::format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
+                 << "Truncated MD5 hash: "
+                 << llvm::format_hex(TruncatedHash, 16) << "\n";
+  }
+
+  return llvm::MemoryBuffer::getMemBufferCopy(
+      llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
+}
+
+// Use packed structs to avoid padding, such that the structs map the serialized
+// format.
+LLVM_PACKED_START
+union RawCompressedBundleHeader {
+  struct CommonFields {
+    uint32_t Magic;
+    uint16_t Version;
+    uint16_t Method;
+  };
+
+  struct V1Header {
+    CommonFields Common;
+    uint32_t UncompressedFileSize;
+    uint64_t Hash;
+  };
+
+  struct V2Header {
+    CommonFields Common;
+    uint32_t FileSize;
+    uint32_t UncompressedFileSize;
+    uint64_t Hash;
+  };
+
+  struct V3Header {
+    CommonFields Common;
+    uint64_t FileSize;
+    uint64_t UncompressedFileSize;
+    uint64_t Hash;
+  };
+
+  CommonFields Common;
+  V1Header V1;
+  V2Header V2;
+  V3Header V3;
+};
+LLVM_PACKED_END
+
+// Helper method to get header size based on version
+static size_t getHeaderSize(uint16_t Version) {
+  switch (Version) {
+  case 1:
+    return sizeof(RawCompressedBundleHeader::V1Header);
+  case 2:
+    return sizeof(RawCompressedBundleHeader::V2Header);
+  case 3:
+    return sizeof(RawCompressedBundleHeader::V3Header);
+  default:
+    llvm_unreachable("Unsupported version");
+  }
+}
+
+Expected<CompressedOffloadBundle::CompressedBundleHeader>
+CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
+  assert(Blob.size() >= sizeof(RawCompressedBundleHeader::CommonFields));
+  assert(llvm::identify_magic(Blob) ==
+         llvm::file_magic::offload_bundle_compressed);
+
+  RawCompressedBundleHeader Header;
+  memcpy(&Header, Blob.data(), std::min(Blob.size(), sizeof(Header)));
+
+  CompressedBundleHeader Normalized;
+  Normalized.Version = Header.Common.Version;
+
+  size_t RequiredSize = getHeaderSize(Normalized.Version);
+
+  if (Blob.size() < RequiredSize)
+    return createStringError(inconvertibleErrorCode(),
+                             "Compressed bundle header size too small");
+
+  switch (Normalized.Version) {
+  case 1:
+    Normalized.UncompressedFileSize = Header.V1.UncompressedFileSize;
+    Normalized.Hash = Header.V1.Hash;
+    break;
+  case 2:
+    Normalized.FileSize = Header.V2.FileSize;
+    Normalized.UncompressedFileSize = Header.V2.UncompressedFileSize;
+    Normalized.Hash = Header.V2.Hash;
+    break;
+  case 3:
+    Normalized.FileSize = Header.V3.FileSize;
+    Normalized.UncompressedFileSize = Header.V3.UncompressedFileSize;
+    Normalized.Hash = Header.V3.Hash;
+    break;
+  default:
+    return createStringError(inconvertibleErrorCode(),
+                             "Unknown compressed bundle version");
+  }
+
+  // Determine compression format
+  switch (Header.Common.Method) {
+  case static_cast<uint16_t>(compression::Format::Zlib):
+  case static_cast<uint16_t>(compression::Format::Zstd):
+    Normalized.CompressionFormat =
+        static_cast<compression::Format>(Header.Common.Method);
+    break;
+  default:
+    return createStringError(inconvertibleErrorCode(),
+                             "Unknown compressing method");
+  }
+
+  return Normalized;
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
                                     bool Verbose) {
   StringRef Blob = Input.getBuffer();
 
-  if (Blob.size() < V1HeaderSize)
+  // Check minimum header size (using V1 as it's the smallest)
+  if (Blob.size() < sizeof(RawCompressedBundleHeader::CommonFields))
     return llvm::MemoryBuffer::getMemBufferCopy(Blob);
 
   if (llvm::identify_magic(Blob) !=
@@ -274,43 +535,20 @@ CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
     return llvm::MemoryBuffer::getMemBufferCopy(Blob);
   }
 
-  size_t CurrentOffset = MagicSize;
-
-  uint16_t ThisVersion;
-  memcpy(&ThisVersion, Blob.data() + CurrentOffset, sizeof(uint16_t));
-  CurrentOffset += VersionFieldSize;
+  Expected<CompressedBundleHeader> HeaderOrErr =
+      CompressedBundleHeader::tryParse(Blob);
+  if (!HeaderOrErr)
+    return HeaderOrErr.takeError();
 
-  uint16_t CompressionMethod;
-  memcpy(&CompressionMethod, Blob.data() + CurrentOffset, sizeof(uint16_t));
-  CurrentOffset += MethodFieldSize;
+  const CompressedBundleHeader &Normalized = *HeaderOrErr;
+  unsigned ThisVersion = Normalized.Version;
+  size_t HeaderSize = getHeaderSize(ThisVersion);
 
-  uint32_t TotalFileSize;
-  if (ThisVersion >= 2) {
-    if (Blob.size() < V2HeaderSize)
-      return createStringError(inconvertibleErrorCode(),
-                               "Compressed bundle header size too small");
-    memcpy(&TotalFileSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
-    CurrentOffset += FileSizeFieldSize;
-  }
+  llvm::compression::Format CompressionFormat = Normalized.CompressionFormat;
 
-  uint32_t UncompressedSize;
-  memcpy(&UncompressedSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
-  CurrentOffset += UncompressedSizeFieldSize;
-
-  uint64_t StoredHash;
-  memcpy(&StoredHash, Blob.data() + CurrentOffset, sizeof(uint64_t));
-  CurrentOffset += HashFieldSize;
-
-  llvm::compression::Format CompressionFormat;
-  if (CompressionMethod ==
-      static_cast<uint16_t>(llvm::compression::Format::Zlib))
-    CompressionFormat = llvm::compression::Format::Zlib;
-  else if (CompressionMethod ==
-           static_cast<uint16_t>(llvm::compression::Format::Zstd))
-    CompressionFormat = llvm::compression::Format::Zstd;
-  else
-    return createStringError(inconvertibleErrorCode(),
-                             "Unknown compressing method");
+  size_t TotalFileSize = Normalized.FileSize.value_or(0);
+  size_t UncompressedSize = Normalized.UncompressedFileSize;
+  auto StoredHash = Normalized.Hash;
 
   llvm::Timer DecompressTimer("Decompression Timer", "Decompression time",
                               OffloadBundlerTimerGroup);
@@ -318,7 +556,9 @@ CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
     DecompressTimer.startTimer();
 
   SmallVector<uint8_t, 0> DecompressedData;
-  StringRef CompressedData = Blob.substr(CurrentOffset);
+  StringRef CompressedData =
+      Blob.substr(HeaderSize, TotalFileSize - HeaderSize);
+
   if (llvm::Error DecompressionError = llvm::compression::decompress(
           CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
           DecompressedData, UncompressedSize))
@@ -332,7 +572,7 @@ CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
     double DecompressionTimeSeconds =
         DecompressTimer.getTotalTime().getWallTime();
 
-    // Recalculate MD5 hash for integrity check.
+    // Recalculate MD5 hash for integrity check
     llvm::Timer HashRecalcTimer("Hash Recalculation Timer",
                                 "Hash recalculation time",
                                 OffloadBundlerTimerGroup);
@@ -378,90 +618,3 @@ CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
   return llvm::MemoryBuffer::getMemBufferCopy(
       llvm::toStringRef(DecompressedData));
 }
-
-llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-CompressedOffloadBundle::compress(llvm::compression::Params P,
-                                  const llvm::MemoryBuffer &Input,
-                                  bool Verbose) {
-  if (!llvm::compression::zstd::isAvailable() &&
-      !llvm::compression::zlib::isAvailable())
-    return createStringError(llvm::inconvertibleErrorCode(),
-                             "Compression not supported");
-
-  llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
-                        OffloadBundlerTimerGroup);
-  if (Verbose)
-    HashTimer.startTimer();
-  llvm::MD5 Hash;
-  llvm::MD5::MD5Result Result;
-  Hash.update(Input.getBuffer());
-  Hash.final(Result);
-  uint64_t TruncatedHash = Result.low();
-  if (Verbose)
-    HashTimer.stopTimer();
-
-  SmallVector<uint8_t, 0> CompressedBuffer;
-  auto BufferUint8 = llvm::ArrayRef<uint8_t>(
-      reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
-      Input.getBuffer().size());
-
-  llvm::Timer CompressTimer("Compression Timer", "Compression time",
-                            OffloadBundlerTimerGroup);
-  if (Verbose)
-    CompressTimer.startTimer();
-  llvm::compression::compress(P, BufferUint8, CompressedBuffer);
-  if (Verbose)
-    CompressTimer.stopTimer();
-
-  uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
-  uint32_t UncompressedSize = Input.getBuffer().size();
-  uint32_t TotalFileSize = MagicNumber.size() + sizeof(TotalFileSize) +
-                           sizeof(Version) + sizeof(CompressionMethod) +
-                           sizeof(UncompressedSize) + sizeof(TruncatedHash) +
-                           CompressedBuffer.size();
-
-  SmallVector<char, 0> FinalBuffer;
-  llvm::raw_svector_ostream OS(FinalBuffer);
-  OS << MagicNumber;
-  OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
-  OS.write(reinterpret_cast<const char *>(&CompressionMethod),
-           sizeof(CompressionMethod));
-  OS.write(reinterpret_cast<const char *>(&TotalFileSize),
-           sizeof(TotalFileSize));
-  OS.write(reinterpret_cast<const char *>(&UncompressedSize),
-           sizeof(UncompressedSize));
-  OS.write(reinterpret_cast<const char *>(&TruncatedHash),
-           sizeof(TruncatedHash));
-  OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),
-           CompressedBuffer.size());
-
-  if (Verbose) {
-    auto MethodUsed =
-        P.format == llvm::compression::Format::Zstd ? "zstd" : "zlib";
-    double CompressionRate =
-        static_cast<double>(UncompressedSize) / CompressedBuffer.size();
-    double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
-    double CompressionSpeedMBs =
-        (UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;
-
-    llvm::errs() << "Compressed bundle format version: " << Version << "\n"
-                 << "Total file size (including headers): "
-                 << formatWithCommas(TotalFileSize) << " bytes\n"
-                 << "Compression method used: " << MethodUsed << "\n"
-                 << "Compression level: " << P.level << "\n"
-                 << "Binary size before compression: "
-                 << formatWithCommas(UncompressedSize) << " bytes\n"
-                 << "Binary size after compression: "
-                 << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
-                 << "Compression rate: "
-                 << llvm::format("%.2lf", CompressionRate) << "\n"
-                 << "Compression ratio: "
-                 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
-                 << "Compression speed: "
-                 << llvm::format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
-                 << "Truncated MD5 hash: "
-                 << llvm::format_hex(TruncatedHash, 16) << "\n";
-  }
-  return llvm::MemoryBuffer::getMemBufferCopy(
-      llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
-}
diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp
index 8a0deb35ba151..8a34d0f60a2ac 100644
--- a/llvm/tools/llvm-objdump/OffloadDump.cpp
+++ b/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -87,21 +87,30 @@ void llvm::dumpOffloadBundleFatBinary(const ObjectFile &O, StringRef ArchName) {
   if (Error Err = llvm::object::extractOffloadBundleFatBinary(O, FoundBundles))
     reportError(O.getFileName(), "while extracting offload FatBin bundles: " +
                                      toString(std::move(Err)));
-
   for (const auto &[BundleNum, Bundle] : llvm::enumerate(FoundBundles)) {
     for (OffloadBundleEntry &Entry : Bundle.getEntries()) {
-      if (!ArchName.empty() && !Entry.ID.contains(ArchName))
+      if (!ArchName.empty() && (Entry.ID.find(ArchName) != std::string::npos))
         continue;
 
       // create file name for this object file:  <source-filename>.<Bundle
       // Number>.<EntryID>
-      std::string str = Bundle.getFileName().str() + "." + itostr(BundleNum) +
-                        "." + Entry.ID.str();
-      if (Error Err = object::extractCodeObject(O, Entry.Offset, Entry.Size,
-                                                StringRef(str)))
-        reportError(O.getFileName(),
-                    "while extracting offload Bundle Entries: " +
-                        toString(std::move(Err)));
+      std::string str =
+          Bundle.getFileName().str() + "." + itostr(BundleNum) + "." + Entry.ID;
+
+      if (Bundle.isDecompressed()) {
+        if (Error Err = object::extractCodeObject(
+                Bundle.DecompressedBuffer->getMemBufferRef(), Entry.Offset,
+                Entry.Size, StringRef(str)))
+          reportError(O.getFileName(),
+                      "while extracting offload Bundle Entries: " +
+                          toString(std::move(Err)));
+      } else {
+        if (Error Err = object::extractCodeObject(O, Entry.Offset, Entry.Size,
+                                                  StringRef(str)))
+          reportError(O.getFileName(),
+                      "while extracting offload Bundle Entries: " +
+                          toString(std::move(Err)));
+      }
       outs() << "Extracting offload bundle: " << str << "\n";
     }
   }

>From 5a70f7d2fcb1297f22e0f6eeeff63de777f2a255 Mon Sep 17 00:00:00 2001
From: dsalinas_amdeng <david.salinas at amd.com>
Date: Tue, 12 Aug 2025 16:38:54 +0000
Subject: [PATCH 2/8] Clean-up from review comments.

---
 llvm/include/llvm/Object/OffloadBundle.h |   3 +-
 llvm/lib/Object/OffloadBundle.cpp        | 145 +++++++++++------------
 llvm/tools/llvm-objdump/OffloadDump.cpp  |   2 +-
 3 files changed, 73 insertions(+), 77 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index 99f54ea4f28aa..0ee2b3bc17ea8 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -129,10 +129,9 @@ class OffloadBundleFatBin {
                       bool Decompress = false)
       : FileName(File), Decompressed(Decompress), NumberOfEntries(0),
         Entries(SmallVector<OffloadBundleEntry>()) {
-    if (Decompress) {
+    if (Decompress)
       DecompressedBuffer =
           MemoryBuffer::getMemBufferCopy(Source.getBuffer(), File);
-    }
   }
 };
 
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 57a8244a9b0e5..5f86b17e2ecb1 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -25,7 +25,7 @@
 using namespace llvm;
 using namespace llvm::object;
 
-static llvm::TimerGroup
+static TimerGroup
     OffloadBundlerTimerGroup("Offload Bundler Timer Group",
                              "Timer group for offload bundler");
 
@@ -49,16 +49,15 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
 
     if (identify_magic((*Buffer).getBuffer()) ==
         file_magic::offload_bundle_compressed) {
-      Magic = StringRef("CCOB");
-      // decompress this bundle first.
+      Magic = "CCOB";
+      // Decompress this bundle first.
       NextbundleStart = (*Buffer).getBuffer().find(Magic, Magic.size());
-      if (NextbundleStart == StringRef::npos) {
+      if (NextbundleStart == StringRef::npos)
         NextbundleStart = (*Buffer).getBuffer().size();
-      }
 
       ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
           MemoryBuffer::getMemBuffer((*Buffer).getBuffer().take_front(
-                                         NextbundleStart /*- Magic.size()*/),
+                                         NextbundleStart),
                                      FileName, false);
       if (std::error_code EC = CodeOrErr.getError())
         return createFileError(FileName, EC);
@@ -68,8 +67,8 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
       if (!DecompressedBufferOrErr)
         return createStringError(
             inconvertibleErrorCode(),
-            "Failed to decompress input: " +
-                llvm::toString(DecompressedBufferOrErr.takeError()));
+            "failed to decompress input: " +
+                toString(DecompressedBufferOrErr.takeError()));
 
       auto FatBundleOrErr = OffloadBundleFatBin::create(
           **DecompressedBufferOrErr, Offset, FileName, true);
@@ -81,7 +80,7 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
 
     } else if (identify_magic((*Buffer).getBuffer()) ==
                file_magic::offload_bundle) {
-      // Create the FatBinBindle object. This will also create the Bundle Entry
+      // Create the OffloadBundleFatBin object. This will also create the Bundle Entry
       // list info.
       auto FatBundleOrErr = OffloadBundleFatBin::create(
           *Buffer, SectionOffset + Offset, FileName);
@@ -91,7 +90,7 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
       // Add current Bundle to list.
       Bundles.emplace_back(std::move(**FatBundleOrErr));
 
-      Magic = StringRef("__CLANG_OFFLOAD_BUNDLE__");
+      Magic = "__CLANG_OFFLOAD_BUNDLE__";
       NextbundleStart = (*Buffer).getBuffer().find(Magic, Magic.size());
     }
 
@@ -106,7 +105,7 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
                                        uint64_t SectionOffset) {
   uint64_t NumOfEntries = 0;
 
-  BinaryStreamReader Reader(Buffer, llvm::endianness::little);
+  BinaryStreamReader Reader(Buffer, endianness::little);
 
   // Read the Magic String first.
   StringRef Magic;
@@ -202,9 +201,9 @@ Error object::extractOffloadBundleFatBinary(
       return Buffer.takeError();
 
     // If it does not start with the reserved suffix, just skip this section.
-    if ((llvm::identify_magic(*Buffer) == llvm::file_magic::offload_bundle) ||
-        (llvm::identify_magic(*Buffer) ==
-         llvm::file_magic::offload_bundle_compressed)) {
+    if ((identify_magic(*Buffer) == file_magic::offload_bundle) ||
+        (identify_magic(*Buffer) ==
+         file_magic::offload_bundle_compressed)) {
 
       uint64_t SectionOffset = 0;
       if (Obj.isELF()) {
@@ -254,10 +253,8 @@ Error object::extractCodeObject(const MemoryBufferRef Buffer, int64_t Offset,
   std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
   std::copy(Buffer.getBufferStart() + Offset,
             Buffer.getBufferStart() + Offset + Size, Buf->getBufferStart());
-  if (Error E = Buf->commit())
-    return E;
 
-  return Error::success();
+  return Buf->commit();
 }
 
 // given a file name, offset, and size, extract data into a code object file,
@@ -298,20 +295,20 @@ static std::string formatWithCommas(unsigned long long Value) {
   return Num;
 }
 
-llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-CompressedOffloadBundle::compress(llvm::compression::Params P,
-                                  const llvm::MemoryBuffer &Input,
+Expected<std::unique_ptr<MemoryBuffer>>
+CompressedOffloadBundle::compress(compression::Params P,
+                                  const MemoryBuffer &Input,
                                   uint16_t Version, bool Verbose) {
-  if (!llvm::compression::zstd::isAvailable() &&
-      !llvm::compression::zlib::isAvailable())
-    return createStringError(llvm::inconvertibleErrorCode(),
+  if (!compression::zstd::isAvailable() &&
+      !compression::zlib::isAvailable())
+    return createStringError(
                              "Compression not supported");
-  llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
+  Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
                         OffloadBundlerTimerGroup);
   if (Verbose)
     HashTimer.startTimer();
-  llvm::MD5 Hash;
-  llvm::MD5::MD5Result Result;
+  MD5 Hash;
+  MD5::MD5Result Result;
   Hash.update(Input.getBuffer());
   Hash.final(Result);
   uint64_t TruncatedHash = Result.low();
@@ -319,33 +316,33 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
     HashTimer.stopTimer();
 
   SmallVector<uint8_t, 0> CompressedBuffer;
-  auto BufferUint8 = llvm::ArrayRef<uint8_t>(
+  auto BufferUint8 = ArrayRef<uint8_t>(
       reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
       Input.getBuffer().size());
-  llvm::Timer CompressTimer("Compression Timer", "Compression time",
+  Timer CompressTimer("Compression Timer", "Compression time",
                             OffloadBundlerTimerGroup);
   if (Verbose)
     CompressTimer.startTimer();
-  llvm::compression::compress(P, BufferUint8, CompressedBuffer);
+  compression::compress(P, BufferUint8, CompressedBuffer);
   if (Verbose)
     CompressTimer.stopTimer();
 
   uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
 
-  // Store sizes in 64-bit variables first
+  // Store sizes in 64-bit variables first.
   uint64_t UncompressedSize64 = Input.getBuffer().size();
   uint64_t TotalFileSize64;
 
-  // Calculate total file size based on version
+  // Calculate total file size based on version.
   if (Version == 2) {
-    // For V2, ensure the sizes don't exceed 32-bit limit
+    // For V2, ensure the sizes don't exceed 32-bit limit.
     if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
-      return createStringError(llvm::inconvertibleErrorCode(),
+      return createStringError(inconvertibleErrorCode(),
                                "Uncompressed size exceeds version 2 limit");
     if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
          sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +
          CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
-      return createStringError(llvm::inconvertibleErrorCode(),
+      return createStringError(inconvertibleErrorCode(),
                                "Total file size exceeds version 2 limit");
 
     TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
@@ -358,7 +355,7 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
   }
 
   SmallVector<char, 0> FinalBuffer;
-  llvm::raw_svector_ostream OS(FinalBuffer);
+  raw_svector_ostream OS(FinalBuffer);
   OS << MagicNumber;
   OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
   OS.write(reinterpret_cast<const char *>(&CompressionMethod),
@@ -386,13 +383,13 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
 
   if (Verbose) {
     auto MethodUsed =
-        P.format == llvm::compression::Format::Zstd ? "zstd" : "zlib";
+        P.format == compression::Format::Zstd ? "zstd" : "zlib";
     double CompressionRate =
         static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
     double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
     double CompressionSpeedMBs =
         (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
-    llvm::errs() << "Compressed bundle format version: " << Version << "\n"
+    errs() << "Compressed bundle format version: " << Version << "\n"
                  << "Total file size (including headers): "
                  << formatWithCommas(TotalFileSize64) << " bytes\n"
                  << "Compression method used: " << MethodUsed << "\n"
@@ -402,17 +399,17 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
                  << "Binary size after compression: "
                  << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
                  << "Compression rate: "
-                 << llvm::format("%.2lf", CompressionRate) << "\n"
+                 << format("%.2lf", CompressionRate) << "\n"
                  << "Compression ratio: "
-                 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+                 << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
                  << "Compression speed: "
-                 << llvm::format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
+                 << format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
                  << "Truncated MD5 hash: "
-                 << llvm::format_hex(TruncatedHash, 16) << "\n";
+                 << format_hex(TruncatedHash, 16) << "\n";
   }
 
-  return llvm::MemoryBuffer::getMemBufferCopy(
-      llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
+  return MemoryBuffer::getMemBufferCopy(
+      StringRef(FinalBuffer.data(), FinalBuffer.size()));
 }
 
 // Use packed structs to avoid padding, such that the structs map the serialized
@@ -452,7 +449,7 @@ union RawCompressedBundleHeader {
 };
 LLVM_PACKED_END
 
-// Helper method to get header size based on version
+// Helper method to get header size based on version.
 static size_t getHeaderSize(uint16_t Version) {
   switch (Version) {
   case 1:
@@ -469,11 +466,11 @@ static size_t getHeaderSize(uint16_t Version) {
 Expected<CompressedOffloadBundle::CompressedBundleHeader>
 CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
   assert(Blob.size() >= sizeof(RawCompressedBundleHeader::CommonFields));
-  assert(llvm::identify_magic(Blob) ==
-         llvm::file_magic::offload_bundle_compressed);
+  assert(identify_magic(Blob) ==
+         file_magic::offload_bundle_compressed);
 
   RawCompressedBundleHeader Header;
-  memcpy(&Header, Blob.data(), std::min(Blob.size(), sizeof(Header)));
+  std::memcpy(&Header, Blob.data(), std::min(Blob.size(), sizeof(Header)));
 
   CompressedBundleHeader Normalized;
   Normalized.Version = Header.Common.Version;
@@ -519,20 +516,20 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
   return Normalized;
 }
 
-llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
+Expected<std::unique_ptr<MemoryBuffer>>
+CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
                                     bool Verbose) {
   StringRef Blob = Input.getBuffer();
 
   // Check minimum header size (using V1 as it's the smallest)
   if (Blob.size() < sizeof(RawCompressedBundleHeader::CommonFields))
-    return llvm::MemoryBuffer::getMemBufferCopy(Blob);
+    return MemoryBuffer::getMemBufferCopy(Blob);
 
-  if (llvm::identify_magic(Blob) !=
-      llvm::file_magic::offload_bundle_compressed) {
+  if (identify_magic(Blob) !=
+      file_magic::offload_bundle_compressed) {
     if (Verbose)
-      llvm::errs() << "Uncompressed bundle.\n";
-    return llvm::MemoryBuffer::getMemBufferCopy(Blob);
+      errs() << "Uncompressed bundle.\n";
+    return MemoryBuffer::getMemBufferCopy(Blob);
   }
 
   Expected<CompressedBundleHeader> HeaderOrErr =
@@ -544,13 +541,13 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
   unsigned ThisVersion = Normalized.Version;
   size_t HeaderSize = getHeaderSize(ThisVersion);
 
-  llvm::compression::Format CompressionFormat = Normalized.CompressionFormat;
+  compression::Format CompressionFormat = Normalized.CompressionFormat;
 
   size_t TotalFileSize = Normalized.FileSize.value_or(0);
   size_t UncompressedSize = Normalized.UncompressedFileSize;
   auto StoredHash = Normalized.Hash;
 
-  llvm::Timer DecompressTimer("Decompression Timer", "Decompression time",
+  Timer DecompressTimer("Decompression Timer", "Decompression time",
                               OffloadBundlerTimerGroup);
   if (Verbose)
     DecompressTimer.startTimer();
@@ -559,12 +556,12 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
   StringRef CompressedData =
       Blob.substr(HeaderSize, TotalFileSize - HeaderSize);
 
-  if (llvm::Error DecompressionError = llvm::compression::decompress(
-          CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
+  if (Error DecompressionError = compression::decompress(
+          CompressionFormat, arrayRefFromStringRef(CompressedData),
           DecompressedData, UncompressedSize))
     return createStringError(inconvertibleErrorCode(),
                              "Could not decompress embedded file contents: " +
-                                 llvm::toString(std::move(DecompressionError)));
+                                 toString(std::move(DecompressionError)));
 
   if (Verbose) {
     DecompressTimer.stopTimer();
@@ -573,13 +570,13 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
         DecompressTimer.getTotalTime().getWallTime();
 
     // Recalculate MD5 hash for integrity check
-    llvm::Timer HashRecalcTimer("Hash Recalculation Timer",
+    Timer HashRecalcTimer("Hash Recalculation Timer",
                                 "Hash recalculation time",
                                 OffloadBundlerTimerGroup);
     HashRecalcTimer.startTimer();
-    llvm::MD5 Hash;
-    llvm::MD5::MD5Result Result;
-    Hash.update(llvm::ArrayRef<uint8_t>(DecompressedData));
+    MD5 Hash;
+    MD5::MD5Result Result;
+    Hash.update(ArrayRef<uint8_t>(DecompressedData));
     Hash.final(Result);
     uint64_t RecalculatedHash = Result.low();
     HashRecalcTimer.stopTimer();
@@ -590,12 +587,12 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
     double DecompressionSpeedMBs =
         (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
 
-    llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n";
+    errs() << "Compressed bundle format version: " << ThisVersion << "\n";
     if (ThisVersion >= 2)
-      llvm::errs() << "Total file size (from header): "
+      errs() << "Total file size (from header): "
                    << formatWithCommas(TotalFileSize) << " bytes\n";
-    llvm::errs() << "Decompression method: "
-                 << (CompressionFormat == llvm::compression::Format::Zlib
+    errs() << "Decompression method: "
+                 << (CompressionFormat == compression::Format::Zlib
                          ? "zlib"
                          : "zstd")
                  << "\n"
@@ -604,17 +601,17 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
                  << "Size after decompression: "
                  << formatWithCommas(UncompressedSize) << " bytes\n"
                  << "Compression rate: "
-                 << llvm::format("%.2lf", CompressionRate) << "\n"
+                 << format("%.2lf", CompressionRate) << "\n"
                  << "Compression ratio: "
-                 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+                 << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
                  << "Decompression speed: "
-                 << llvm::format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
-                 << "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n"
+                 << format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
+                 << "Stored hash: " << format_hex(StoredHash, 16) << "\n"
                  << "Recalculated hash: "
-                 << llvm::format_hex(RecalculatedHash, 16) << "\n"
+                 << format_hex(RecalculatedHash, 16) << "\n"
                  << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
   }
 
-  return llvm::MemoryBuffer::getMemBufferCopy(
-      llvm::toStringRef(DecompressedData));
+  return MemoryBuffer::getMemBufferCopy(
+      toStringRef(DecompressedData));
 }
diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp
index 8a34d0f60a2ac..a77537dd90eeb 100644
--- a/llvm/tools/llvm-objdump/OffloadDump.cpp
+++ b/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -89,7 +89,7 @@ void llvm::dumpOffloadBundleFatBinary(const ObjectFile &O, StringRef ArchName) {
                                      toString(std::move(Err)));
   for (const auto &[BundleNum, Bundle] : llvm::enumerate(FoundBundles)) {
     for (OffloadBundleEntry &Entry : Bundle.getEntries()) {
-      if (!ArchName.empty() && (Entry.ID.find(ArchName) != std::string::npos))
+      if (!ArchName.empty() && Entry.ID.find(ArchName) != std::string::npos)
         continue;
 
       // create file name for this object file:  <source-filename>.<Bundle

>From bd67241c8919b8fc270e327aac84dfd01eba4164 Mon Sep 17 00:00:00 2001
From: dsalinas_amdeng <david.salinas at amd.com>
Date: Tue, 19 Aug 2025 15:51:24 +0000
Subject: [PATCH 3/8] Resolve PR comments.

---
 llvm/include/llvm/Object/OffloadBundle.h |   2 +-
 llvm/lib/Object/OffloadBundle.cpp        | 158 ++++++++++-------------
 2 files changed, 72 insertions(+), 88 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index 0ee2b3bc17ea8..2ddb388c1f63d 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -59,7 +59,7 @@ class CompressedOffloadBundle {
     static llvm::Expected<CompressedBundleHeader> tryParse(llvm::StringRef);
   };
 
-  static inline const uint16_t DefaultVersion = 2;
+  static inline const uint16_t DefaultVersion = 3;
 
   static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 5f86b17e2ecb1..3b0c063b8fd18 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -25,12 +25,11 @@
 using namespace llvm;
 using namespace llvm::object;
 
-static TimerGroup
-    OffloadBundlerTimerGroup("Offload Bundler Timer Group",
-                             "Timer group for offload bundler");
+static TimerGroup OffloadBundlerTimerGroup("Offload Bundler Timer Group",
+                                           "Timer group for offload bundler");
 
 // Extract an Offload bundle (usually a Offload Bundle) from a fat_bin
-// section
+// section.
 Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
                            StringRef FileName,
                            SmallVectorImpl<OffloadBundleFatBin> &Bundles) {
@@ -56,9 +55,9 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
         NextbundleStart = (*Buffer).getBuffer().size();
 
       ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
-          MemoryBuffer::getMemBuffer((*Buffer).getBuffer().take_front(
-                                         NextbundleStart),
-                                     FileName, false);
+          MemoryBuffer::getMemBuffer(
+              (*Buffer).getBuffer().take_front(NextbundleStart), FileName,
+              false);
       if (std::error_code EC = CodeOrErr.getError())
         return createFileError(FileName, EC);
 
@@ -80,8 +79,8 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
 
     } else if (identify_magic((*Buffer).getBuffer()) ==
                file_magic::offload_bundle) {
-      // Create the OffloadBundleFatBin object. This will also create the Bundle Entry
-      // list info.
+      // Create the OffloadBundleFatBin object. This will also create the Bundle
+      // Entry list info.
       auto FatBundleOrErr = OffloadBundleFatBin::create(
           *Buffer, SectionOffset + Offset, FileName);
       if (!FatBundleOrErr)
@@ -118,7 +117,7 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
 
   NumberOfEntries = NumOfEntries;
 
-  // For each Bundle Entry (code object)
+  // For each Bundle Entry (code object).
   for (uint64_t I = 0; I < NumOfEntries; I++) {
     uint64_t EntrySize;
     uint64_t EntryOffset;
@@ -162,7 +161,7 @@ OffloadBundleFatBin::create(MemoryBufferRef Buf, uint64_t SectionOffset,
   OffloadBundleFatBin *TheBundle =
       new OffloadBundleFatBin(Buf, FileName, Decompress);
 
-  // Read the Bundle Entries
+  // Read the Bundle Entries.
   Error Err =
       TheBundle->readEntries(Buf.getBuffer(), Decompress ? 0 : SectionOffset);
   if (Err)
@@ -172,7 +171,7 @@ OffloadBundleFatBin::create(MemoryBufferRef Buf, uint64_t SectionOffset,
 }
 
 Error OffloadBundleFatBin::extractBundle(const ObjectFile &Source) {
-  // This will extract all entries in the Bundle
+  // This will extract all entries in the Bundle.
   for (OffloadBundleEntry &Entry : Entries) {
 
     if (Entry.Size == 0)
@@ -202,13 +201,12 @@ Error object::extractOffloadBundleFatBinary(
 
     // If it does not start with the reserved suffix, just skip this section.
     if ((identify_magic(*Buffer) == file_magic::offload_bundle) ||
-        (identify_magic(*Buffer) ==
-         file_magic::offload_bundle_compressed)) {
+        (identify_magic(*Buffer) == file_magic::offload_bundle_compressed)) {
 
       uint64_t SectionOffset = 0;
       if (Obj.isELF()) {
         SectionOffset = ELFSectionRef(Sec).getOffset();
-      } else if (Obj.isCOFF()) // TODO: add COFF Support
+      } else if (Obj.isCOFF()) // TODO: add COFF Support.
         return createStringError(object_error::parse_failed,
                                  "COFF object files not supported.\n");
 
@@ -258,7 +256,7 @@ Error object::extractCodeObject(const MemoryBufferRef Buffer, int64_t Offset,
 }
 
 // given a file name, offset, and size, extract data into a code object file,
-// into file <SourceFile>-offset<Offset>-size<Size>.co
+// into file "<SourceFile>-offset<Offset>-size<Size>.co".
 Error object::extractOffloadBundleByURI(StringRef URIstr) {
   // create a URI object
   Expected<std::unique_ptr<OffloadBundleURI>> UriOrErr(
@@ -271,7 +269,7 @@ Error object::extractOffloadBundleByURI(StringRef URIstr) {
   OutputFile +=
       "-offset" + itostr(Uri.Offset) + "-size" + itostr(Uri.Size) + ".co";
 
-  // Create an ObjectFile object from uri.file_uri
+  // Create an ObjectFile object from uri.file_uri.
   auto ObjOrErr = ObjectFile::createObjectFile(Uri.FileName);
   if (!ObjOrErr)
     return ObjOrErr.takeError();
@@ -284,7 +282,7 @@ Error object::extractOffloadBundleByURI(StringRef URIstr) {
   return Error::success();
 }
 
-// Utility function to format numbers with commas
+// Utility function to format numbers with commas.
 static std::string formatWithCommas(unsigned long long Value) {
   std::string Num = std::to_string(Value);
   int InsertPosition = Num.length() - 3;
@@ -297,14 +295,12 @@ static std::string formatWithCommas(unsigned long long Value) {
 
 Expected<std::unique_ptr<MemoryBuffer>>
 CompressedOffloadBundle::compress(compression::Params P,
-                                  const MemoryBuffer &Input,
-                                  uint16_t Version, bool Verbose) {
-  if (!compression::zstd::isAvailable() &&
-      !compression::zlib::isAvailable())
-    return createStringError(
-                             "Compression not supported");
+                                  const MemoryBuffer &Input, uint16_t Version,
+                                  bool Verbose) {
+  if (!compression::zstd::isAvailable() && !compression::zlib::isAvailable())
+    return createStringError("compression not supported.");
   Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
-                        OffloadBundlerTimerGroup);
+                  OffloadBundlerTimerGroup);
   if (Verbose)
     HashTimer.startTimer();
   MD5 Hash;
@@ -320,7 +316,7 @@ CompressedOffloadBundle::compress(compression::Params P,
       reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
       Input.getBuffer().size());
   Timer CompressTimer("Compression Timer", "Compression time",
-                            OffloadBundlerTimerGroup);
+                      OffloadBundlerTimerGroup);
   if (Verbose)
     CompressTimer.startTimer();
   compression::compress(P, BufferUint8, CompressedBuffer);
@@ -338,17 +334,17 @@ CompressedOffloadBundle::compress(compression::Params P,
     // For V2, ensure the sizes don't exceed 32-bit limit.
     if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
       return createStringError(inconvertibleErrorCode(),
-                               "Uncompressed size exceeds version 2 limit");
+                               "uncompressed size exceeds version 2 limit.");
     if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
          sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +
          CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
       return createStringError(inconvertibleErrorCode(),
-                               "Total file size exceeds version 2 limit");
+                               "total file size exceeds version 2 limit.");
 
     TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
                       sizeof(CompressionMethod) + sizeof(uint32_t) +
                       sizeof(TruncatedHash) + CompressedBuffer.size();
-  } else { // Version 3
+  } else { // Version 3.
     TotalFileSize64 = MagicNumber.size() + sizeof(uint64_t) + sizeof(Version) +
                       sizeof(CompressionMethod) + sizeof(uint64_t) +
                       sizeof(TruncatedHash) + CompressedBuffer.size();
@@ -361,7 +357,7 @@ CompressedOffloadBundle::compress(compression::Params P,
   OS.write(reinterpret_cast<const char *>(&CompressionMethod),
            sizeof(CompressionMethod));
 
-  // Write size fields according to version
+  // Write size fields according to version.
   if (Version == 2) {
     uint32_t TotalFileSize32 = static_cast<uint32_t>(TotalFileSize64);
     uint32_t UncompressedSize32 = static_cast<uint32_t>(UncompressedSize64);
@@ -369,7 +365,7 @@ CompressedOffloadBundle::compress(compression::Params P,
              sizeof(TotalFileSize32));
     OS.write(reinterpret_cast<const char *>(&UncompressedSize32),
              sizeof(UncompressedSize32));
-  } else { // Version 3
+  } else { // Version 3.
     OS.write(reinterpret_cast<const char *>(&TotalFileSize64),
              sizeof(TotalFileSize64));
     OS.write(reinterpret_cast<const char *>(&UncompressedSize64),
@@ -382,30 +378,27 @@ CompressedOffloadBundle::compress(compression::Params P,
            CompressedBuffer.size());
 
   if (Verbose) {
-    auto MethodUsed =
-        P.format == compression::Format::Zstd ? "zstd" : "zlib";
+    auto MethodUsed = P.format == compression::Format::Zstd ? "zstd" : "zlib";
     double CompressionRate =
         static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
     double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
     double CompressionSpeedMBs =
         (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
     errs() << "Compressed bundle format version: " << Version << "\n"
-                 << "Total file size (including headers): "
-                 << formatWithCommas(TotalFileSize64) << " bytes\n"
-                 << "Compression method used: " << MethodUsed << "\n"
-                 << "Compression level: " << P.level << "\n"
-                 << "Binary size before compression: "
-                 << formatWithCommas(UncompressedSize64) << " bytes\n"
-                 << "Binary size after compression: "
-                 << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
-                 << "Compression rate: "
-                 << format("%.2lf", CompressionRate) << "\n"
-                 << "Compression ratio: "
-                 << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
-                 << "Compression speed: "
-                 << format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
-                 << "Truncated MD5 hash: "
-                 << format_hex(TruncatedHash, 16) << "\n";
+           << "Total file size (including headers): "
+           << formatWithCommas(TotalFileSize64) << " bytes\n"
+           << "Compression method used: " << MethodUsed << "\n"
+           << "Compression level: " << P.level << "\n"
+           << "Binary size before compression: "
+           << formatWithCommas(UncompressedSize64) << " bytes\n"
+           << "Binary size after compression: "
+           << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
+           << "Compression rate: " << format("%.2lf", CompressionRate) << "\n"
+           << "Compression ratio: "
+           << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+           << "Compression speed: " << format("%.2lf MB/s", CompressionSpeedMBs)
+           << "\n"
+           << "Truncated MD5 hash: " << format_hex(TruncatedHash, 16) << "\n";
   }
 
   return MemoryBuffer::getMemBufferCopy(
@@ -466,8 +459,7 @@ static size_t getHeaderSize(uint16_t Version) {
 Expected<CompressedOffloadBundle::CompressedBundleHeader>
 CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
   assert(Blob.size() >= sizeof(RawCompressedBundleHeader::CommonFields));
-  assert(identify_magic(Blob) ==
-         file_magic::offload_bundle_compressed);
+  assert(identify_magic(Blob) == file_magic::offload_bundle_compressed);
 
   RawCompressedBundleHeader Header;
   std::memcpy(&Header, Blob.data(), std::min(Blob.size(), sizeof(Header)));
@@ -479,7 +471,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
 
   if (Blob.size() < RequiredSize)
     return createStringError(inconvertibleErrorCode(),
-                             "Compressed bundle header size too small");
+                             "compressed bundle header size too small.");
 
   switch (Normalized.Version) {
   case 1:
@@ -498,10 +490,10 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
     break;
   default:
     return createStringError(inconvertibleErrorCode(),
-                             "Unknown compressed bundle version");
+                             "unknown compressed bundle version.");
   }
 
-  // Determine compression format
+  // Determine compression format.
   switch (Header.Common.Method) {
   case static_cast<uint16_t>(compression::Format::Zlib):
   case static_cast<uint16_t>(compression::Format::Zstd):
@@ -510,23 +502,21 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
     break;
   default:
     return createStringError(inconvertibleErrorCode(),
-                             "Unknown compressing method");
+                             "unknown compressing method.");
   }
 
   return Normalized;
 }
 
 Expected<std::unique_ptr<MemoryBuffer>>
-CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
-                                    bool Verbose) {
+CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose) {
   StringRef Blob = Input.getBuffer();
 
-  // Check minimum header size (using V1 as it's the smallest)
+  // Check minimum header size (using V1 as it's the smallest).
   if (Blob.size() < sizeof(RawCompressedBundleHeader::CommonFields))
     return MemoryBuffer::getMemBufferCopy(Blob);
 
-  if (identify_magic(Blob) !=
-      file_magic::offload_bundle_compressed) {
+  if (identify_magic(Blob) != file_magic::offload_bundle_compressed) {
     if (Verbose)
       errs() << "Uncompressed bundle.\n";
     return MemoryBuffer::getMemBufferCopy(Blob);
@@ -548,7 +538,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
   auto StoredHash = Normalized.Hash;
 
   Timer DecompressTimer("Decompression Timer", "Decompression time",
-                              OffloadBundlerTimerGroup);
+                        OffloadBundlerTimerGroup);
   if (Verbose)
     DecompressTimer.startTimer();
 
@@ -560,7 +550,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
           CompressionFormat, arrayRefFromStringRef(CompressedData),
           DecompressedData, UncompressedSize))
     return createStringError(inconvertibleErrorCode(),
-                             "Could not decompress embedded file contents: " +
+                             "could not decompress embedded file contents: " +
                                  toString(std::move(DecompressionError)));
 
   if (Verbose) {
@@ -569,10 +559,9 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
     double DecompressionTimeSeconds =
         DecompressTimer.getTotalTime().getWallTime();
 
-    // Recalculate MD5 hash for integrity check
-    Timer HashRecalcTimer("Hash Recalculation Timer",
-                                "Hash recalculation time",
-                                OffloadBundlerTimerGroup);
+    // Recalculate MD5 hash for integrity check.
+    Timer HashRecalcTimer("Hash Recalculation Timer", "Hash recalculation time",
+                          OffloadBundlerTimerGroup);
     HashRecalcTimer.startTimer();
     MD5 Hash;
     MD5::MD5Result Result;
@@ -590,28 +579,23 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
     errs() << "Compressed bundle format version: " << ThisVersion << "\n";
     if (ThisVersion >= 2)
       errs() << "Total file size (from header): "
-                   << formatWithCommas(TotalFileSize) << " bytes\n";
+             << formatWithCommas(TotalFileSize) << " bytes\n";
     errs() << "Decompression method: "
-                 << (CompressionFormat == compression::Format::Zlib
-                         ? "zlib"
-                         : "zstd")
-                 << "\n"
-                 << "Size before decompression: "
-                 << formatWithCommas(CompressedData.size()) << " bytes\n"
-                 << "Size after decompression: "
-                 << formatWithCommas(UncompressedSize) << " bytes\n"
-                 << "Compression rate: "
-                 << format("%.2lf", CompressionRate) << "\n"
-                 << "Compression ratio: "
-                 << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
-                 << "Decompression speed: "
-                 << format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
-                 << "Stored hash: " << format_hex(StoredHash, 16) << "\n"
-                 << "Recalculated hash: "
-                 << format_hex(RecalculatedHash, 16) << "\n"
-                 << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
+           << (CompressionFormat == compression::Format::Zlib ? "zlib" : "zstd")
+           << "\n"
+           << "Size before decompression: "
+           << formatWithCommas(CompressedData.size()) << " bytes\n"
+           << "Size after decompression: " << formatWithCommas(UncompressedSize)
+           << " bytes\n"
+           << "Compression rate: " << format("%.2lf", CompressionRate) << "\n"
+           << "Compression ratio: "
+           << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+           << "Decompression speed: "
+           << format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
+           << "Stored hash: " << format_hex(StoredHash, 16) << "\n"
+           << "Recalculated hash: " << format_hex(RecalculatedHash, 16) << "\n"
+           << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
   }
 
-  return MemoryBuffer::getMemBufferCopy(
-      toStringRef(DecompressedData));
+  return MemoryBuffer::getMemBufferCopy(toStringRef(DecompressedData));
 }

>From 98f59d41d0ac3bee691c9bf0d64b825468f10a4b Mon Sep 17 00:00:00 2001
From: david-salinas <dsalinas at amd.com>
Date: Thu, 28 Aug 2025 19:53:07 +0000
Subject: [PATCH 4/8] Resolve PR comments part 2

---
 llvm/lib/Object/OffloadBundle.cpp | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 3b0c063b8fd18..bf7dc267de207 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -104,7 +104,7 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
                                        uint64_t SectionOffset) {
   uint64_t NumOfEntries = 0;
 
-  BinaryStreamReader Reader(Buffer, endianness::little);
+  BinaryStreamReader Reader(Buffer, llvm::endianness::little);
 
   // Read the Magic String first.
   StringRef Magic;
@@ -200,15 +200,16 @@ Error object::extractOffloadBundleFatBinary(
       return Buffer.takeError();
 
     // If it does not start with the reserved suffix, just skip this section.
-    if ((identify_magic(*Buffer) == file_magic::offload_bundle) ||
-        (identify_magic(*Buffer) == file_magic::offload_bundle_compressed)) {
+    if ((llvm::identify_magic(*Buffer) == file_magic::offload_bundle) ||
+        (llvm::identify_magic(*Buffer) ==
+         file_magic::offload_bundle_compressed)) {
 
       uint64_t SectionOffset = 0;
       if (Obj.isELF()) {
         SectionOffset = ELFSectionRef(Sec).getOffset();
       } else if (Obj.isCOFF()) // TODO: add COFF Support.
         return createStringError(object_error::parse_failed,
-                                 "COFF object files not supported.\n");
+                                 "COFF object files not supported");
 
       MemoryBufferRef Contents(*Buffer, Obj.getFileName());
       if (Error Err = extractOffloadBundle(Contents, SectionOffset,
@@ -334,12 +335,12 @@ CompressedOffloadBundle::compress(compression::Params P,
     // For V2, ensure the sizes don't exceed 32-bit limit.
     if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
       return createStringError(inconvertibleErrorCode(),
-                               "uncompressed size exceeds version 2 limit.");
+                               "uncompressed size exceeds version 2 limit");
     if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
          sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +
          CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
       return createStringError(inconvertibleErrorCode(),
-                               "total file size exceeds version 2 limit.");
+                               "total file size exceeds version 2 limit");
 
     TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
                       sizeof(CompressionMethod) + sizeof(uint32_t) +
@@ -471,7 +472,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
 
   if (Blob.size() < RequiredSize)
     return createStringError(inconvertibleErrorCode(),
-                             "compressed bundle header size too small.");
+                             "compressed bundle header size too small");
 
   switch (Normalized.Version) {
   case 1:
@@ -490,7 +491,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
     break;
   default:
     return createStringError(inconvertibleErrorCode(),
-                             "unknown compressed bundle version.");
+                             "unknown compressed bundle version");
   }
 
   // Determine compression format.
@@ -502,7 +503,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
     break;
   default:
     return createStringError(inconvertibleErrorCode(),
-                             "unknown compressing method.");
+                             "unknown compressing method");
   }
 
   return Normalized;
@@ -518,7 +519,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose) {
 
   if (identify_magic(Blob) != file_magic::offload_bundle_compressed) {
     if (Verbose)
-      errs() << "Uncompressed bundle.\n";
+      errs() << "Uncompressed bundle\n";
     return MemoryBuffer::getMemBufferCopy(Blob);
   }
 

>From d3c9a79428d724e51566aa8ba069191298e62ecd Mon Sep 17 00:00:00 2001
From: david-salinas <dsalinas at amd.com>
Date: Thu, 4 Sep 2025 20:37:09 +0000
Subject: [PATCH 5/8] Change Offloading API to require a output stream to be
 passed for decompress/compress.

  Default the output stream to errs().
---
 llvm/include/llvm/Object/OffloadBundle.h |  4 ++--
 llvm/lib/Object/OffloadBundle.cpp        | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index 2ddb388c1f63d..442530b2d4af4 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -63,9 +63,9 @@ class CompressedOffloadBundle {
 
   static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
-           uint16_t Version, bool Verbose = false);
+           uint16_t Version, bool Verbose = false, raw_ostream &OutS = errs());
   static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-  decompress(const llvm::MemoryBuffer &Input, bool Verbose = false);
+  decompress(const llvm::MemoryBuffer &Input, bool Verbose = false, raw_ostream &OS = errs());
 };
 
 /// Bundle entry in binary clang-offload-bundler format.
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index bf7dc267de207..072dc36227ab3 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -62,7 +62,7 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
         return createFileError(FileName, EC);
 
       Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
-          CompressedOffloadBundle::decompress(**CodeOrErr, false);
+          CompressedOffloadBundle::decompress(**CodeOrErr, false, errs());
       if (!DecompressedBufferOrErr)
         return createStringError(
             inconvertibleErrorCode(),
@@ -297,7 +297,7 @@ static std::string formatWithCommas(unsigned long long Value) {
 Expected<std::unique_ptr<MemoryBuffer>>
 CompressedOffloadBundle::compress(compression::Params P,
                                   const MemoryBuffer &Input, uint16_t Version,
-                                  bool Verbose) {
+                                  bool Verbose, raw_ostream &OutS) {
   if (!compression::zstd::isAvailable() && !compression::zlib::isAvailable())
     return createStringError("compression not supported.");
   Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
@@ -385,7 +385,7 @@ CompressedOffloadBundle::compress(compression::Params P,
     double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
     double CompressionSpeedMBs =
         (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
-    errs() << "Compressed bundle format version: " << Version << "\n"
+    OutS << "Compressed bundle format version: " << Version << "\n"
            << "Total file size (including headers): "
            << formatWithCommas(TotalFileSize64) << " bytes\n"
            << "Compression method used: " << MethodUsed << "\n"
@@ -510,7 +510,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
 }
 
 Expected<std::unique_ptr<MemoryBuffer>>
-CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose) {
+CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw_ostream &OS) {
   StringRef Blob = Input.getBuffer();
 
   // Check minimum header size (using V1 as it's the smallest).
@@ -519,7 +519,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose) {
 
   if (identify_magic(Blob) != file_magic::offload_bundle_compressed) {
     if (Verbose)
-      errs() << "Uncompressed bundle\n";
+      OS << "Uncompressed bundle\n";
     return MemoryBuffer::getMemBufferCopy(Blob);
   }
 
@@ -577,11 +577,11 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose) {
     double DecompressionSpeedMBs =
         (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
 
-    errs() << "Compressed bundle format version: " << ThisVersion << "\n";
+    OS << "Compressed bundle format version: " << ThisVersion << "\n";
     if (ThisVersion >= 2)
-      errs() << "Total file size (from header): "
+      OS << "Total file size (from header): "
              << formatWithCommas(TotalFileSize) << " bytes\n";
-    errs() << "Decompression method: "
+    OS << "Decompression method: "
            << (CompressionFormat == compression::Format::Zlib ? "zlib" : "zstd")
            << "\n"
            << "Size before decompression: "

>From de45503267dff3b5cfffabe7431ecb776a520b9a Mon Sep 17 00:00:00 2001
From: david-salinas <dsalinas at amd.com>
Date: Wed, 10 Sep 2025 16:11:28 +0000
Subject: [PATCH 6/8] Refactor API change for user specified output stream

---
 llvm/include/llvm/Object/OffloadBundle.h |  5 +-
 llvm/lib/Object/OffloadBundle.cpp        | 95 +++++++++++++-----------
 2 files changed, 53 insertions(+), 47 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index 442530b2d4af4..1cfa92ed2b38f 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -63,9 +63,10 @@ class CompressedOffloadBundle {
 
   static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
-           uint16_t Version, bool Verbose = false, raw_ostream &OutS = errs());
+           uint16_t Version, raw_ostream *VerboseStream = nullptr);
   static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-  decompress(const llvm::MemoryBuffer &Input, bool Verbose = false, raw_ostream &OS = errs());
+  decompress(const llvm::MemoryBuffer &Input,
+             raw_ostream *VerboseStream = nullptr);
 };
 
 /// Bundle entry in binary clang-offload-bundler format.
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 072dc36227ab3..8d9f42e5da3c6 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -62,7 +62,7 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
         return createFileError(FileName, EC);
 
       Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
-          CompressedOffloadBundle::decompress(**CodeOrErr, false, errs());
+          CompressedOffloadBundle::decompress(**CodeOrErr, &nulls());
       if (!DecompressedBufferOrErr)
         return createStringError(
             inconvertibleErrorCode(),
@@ -297,19 +297,19 @@ static std::string formatWithCommas(unsigned long long Value) {
 Expected<std::unique_ptr<MemoryBuffer>>
 CompressedOffloadBundle::compress(compression::Params P,
                                   const MemoryBuffer &Input, uint16_t Version,
-                                  bool Verbose, raw_ostream &OutS) {
+                                  raw_ostream *VerboseStream) {
   if (!compression::zstd::isAvailable() && !compression::zlib::isAvailable())
     return createStringError("compression not supported.");
   Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
                   OffloadBundlerTimerGroup);
-  if (Verbose)
+  if (VerboseStream)
     HashTimer.startTimer();
   MD5 Hash;
   MD5::MD5Result Result;
   Hash.update(Input.getBuffer());
   Hash.final(Result);
   uint64_t TruncatedHash = Result.low();
-  if (Verbose)
+  if (VerboseStream)
     HashTimer.stopTimer();
 
   SmallVector<uint8_t, 0> CompressedBuffer;
@@ -318,10 +318,10 @@ CompressedOffloadBundle::compress(compression::Params P,
       Input.getBuffer().size());
   Timer CompressTimer("Compression Timer", "Compression time",
                       OffloadBundlerTimerGroup);
-  if (Verbose)
+  if (VerboseStream)
     CompressTimer.startTimer();
   compression::compress(P, BufferUint8, CompressedBuffer);
-  if (Verbose)
+  if (VerboseStream)
     CompressTimer.stopTimer();
 
   uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
@@ -378,28 +378,30 @@ CompressedOffloadBundle::compress(compression::Params P,
   OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),
            CompressedBuffer.size());
 
-  if (Verbose) {
+  if (VerboseStream) {
     auto MethodUsed = P.format == compression::Format::Zstd ? "zstd" : "zlib";
     double CompressionRate =
         static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
     double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
     double CompressionSpeedMBs =
         (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
-    OutS << "Compressed bundle format version: " << Version << "\n"
-           << "Total file size (including headers): "
-           << formatWithCommas(TotalFileSize64) << " bytes\n"
-           << "Compression method used: " << MethodUsed << "\n"
-           << "Compression level: " << P.level << "\n"
-           << "Binary size before compression: "
-           << formatWithCommas(UncompressedSize64) << " bytes\n"
-           << "Binary size after compression: "
-           << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
-           << "Compression rate: " << format("%.2lf", CompressionRate) << "\n"
-           << "Compression ratio: "
-           << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
-           << "Compression speed: " << format("%.2lf MB/s", CompressionSpeedMBs)
-           << "\n"
-           << "Truncated MD5 hash: " << format_hex(TruncatedHash, 16) << "\n";
+    *VerboseStream << "Compressed bundle format version: " << Version << "\n"
+                   << "Total file size (including headers): "
+                   << formatWithCommas(TotalFileSize64) << " bytes\n"
+                   << "Compression method used: " << MethodUsed << "\n"
+                   << "Compression level: " << P.level << "\n"
+                   << "Binary size before compression: "
+                   << formatWithCommas(UncompressedSize64) << " bytes\n"
+                   << "Binary size after compression: "
+                   << formatWithCommas(CompressedBuffer.size()) << " bytes\n"
+                   << "Compression rate: " << format("%.2lf", CompressionRate)
+                   << "\n"
+                   << "Compression ratio: "
+                   << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
+                   << "Compression speed: "
+                   << format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
+                   << "Truncated MD5 hash: " << format_hex(TruncatedHash, 16)
+                   << "\n";
   }
 
   return MemoryBuffer::getMemBufferCopy(
@@ -510,7 +512,8 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
 }
 
 Expected<std::unique_ptr<MemoryBuffer>>
-CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw_ostream &OS) {
+CompressedOffloadBundle::decompress(const MemoryBuffer &Input,
+                                    raw_ostream *VerboseStream) {
   StringRef Blob = Input.getBuffer();
 
   // Check minimum header size (using V1 as it's the smallest).
@@ -518,8 +521,8 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw
     return MemoryBuffer::getMemBufferCopy(Blob);
 
   if (identify_magic(Blob) != file_magic::offload_bundle_compressed) {
-    if (Verbose)
-      OS << "Uncompressed bundle\n";
+    if (VerboseStream)
+      *VerboseStream << "Uncompressed bundle\n";
     return MemoryBuffer::getMemBufferCopy(Blob);
   }
 
@@ -540,7 +543,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw
 
   Timer DecompressTimer("Decompression Timer", "Decompression time",
                         OffloadBundlerTimerGroup);
-  if (Verbose)
+  if (VerboseStream)
     DecompressTimer.startTimer();
 
   SmallVector<uint8_t, 0> DecompressedData;
@@ -554,7 +557,7 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw
                              "could not decompress embedded file contents: " +
                                  toString(std::move(DecompressionError)));
 
-  if (Verbose) {
+  if (VerboseStream) {
     DecompressTimer.stopTimer();
 
     double DecompressionTimeSeconds =
@@ -577,25 +580,27 @@ CompressedOffloadBundle::decompress(const MemoryBuffer &Input, bool Verbose, raw
     double DecompressionSpeedMBs =
         (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
 
-    OS << "Compressed bundle format version: " << ThisVersion << "\n";
+    *VerboseStream << "Compressed bundle format version: " << ThisVersion
+                   << "\n";
     if (ThisVersion >= 2)
-      OS << "Total file size (from header): "
-             << formatWithCommas(TotalFileSize) << " bytes\n";
-    OS << "Decompression method: "
-           << (CompressionFormat == compression::Format::Zlib ? "zlib" : "zstd")
-           << "\n"
-           << "Size before decompression: "
-           << formatWithCommas(CompressedData.size()) << " bytes\n"
-           << "Size after decompression: " << formatWithCommas(UncompressedSize)
-           << " bytes\n"
-           << "Compression rate: " << format("%.2lf", CompressionRate) << "\n"
-           << "Compression ratio: "
-           << format("%.2lf%%", 100.0 / CompressionRate) << "\n"
-           << "Decompression speed: "
-           << format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
-           << "Stored hash: " << format_hex(StoredHash, 16) << "\n"
-           << "Recalculated hash: " << format_hex(RecalculatedHash, 16) << "\n"
-           << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
+      *VerboseStream << "Total file size (from header): "
+                     << formatWithCommas(TotalFileSize) << " bytes\n";
+    *VerboseStream
+        << "Decompression method: "
+        << (CompressionFormat == compression::Format::Zlib ? "zlib" : "zstd")
+        << "\n"
+        << "Size before decompression: "
+        << formatWithCommas(CompressedData.size()) << " bytes\n"
+        << "Size after decompression: " << formatWithCommas(UncompressedSize)
+        << " bytes\n"
+        << "Compression rate: " << format("%.2lf", CompressionRate) << "\n"
+        << "Compression ratio: " << format("%.2lf%%", 100.0 / CompressionRate)
+        << "\n"
+        << "Decompression speed: "
+        << format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
+        << "Stored hash: " << format_hex(StoredHash, 16) << "\n"
+        << "Recalculated hash: " << format_hex(RecalculatedHash, 16) << "\n"
+        << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
   }
 
   return MemoryBuffer::getMemBufferCopy(toStringRef(DecompressedData));

>From 589e8980a93719c319a3ab271ce2142f274f7743 Mon Sep 17 00:00:00 2001
From: david-salinas <dsalinas at amd.com>
Date: Mon, 15 Sep 2025 18:11:53 +0000
Subject: [PATCH 7/8] Resolve build issue and address PR comments.

---
 llvm/include/llvm/Object/OffloadBundle.h | 11 ++++-------
 llvm/lib/Object/OffloadBundle.cpp        |  5 ++---
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Object/OffloadBundle.h b/llvm/include/llvm/Object/OffloadBundle.h
index 1cfa92ed2b38f..7217ec669467e 100644
--- a/llvm/include/llvm/Object/OffloadBundle.h
+++ b/llvm/include/llvm/Object/OffloadBundle.h
@@ -75,11 +75,8 @@ struct OffloadBundleEntry {
   uint64_t Size = 0u;
   uint64_t IDLength = 0u;
   std::string ID;
-  OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, std::string T)
-      : Offset(O), Size(S), IDLength(I) {
-    ID.reserve(T.size());
-    ID = T;
-  }
+  OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T)
+      : Offset(O), Size(S), IDLength(I), ID(T.str()) {}
   void dumpInfo(raw_ostream &OS) {
     OS << "Offset = " << Offset << ", Size = " << Size
        << ", ID Length = " << IDLength << ", ID = " << ID << "\n";
@@ -96,8 +93,8 @@ class OffloadBundleFatBin {
   uint64_t Size = 0u;
   StringRef FileName;
   uint64_t NumberOfEntries;
-  SmallVector<OffloadBundleEntry> Entries;
   bool Decompressed;
+  SmallVector<OffloadBundleEntry> Entries;
 
 public:
   std::unique_ptr<MemoryBuffer> DecompressedBuffer;
@@ -128,7 +125,7 @@ class OffloadBundleFatBin {
 
   OffloadBundleFatBin(MemoryBufferRef Source, StringRef File,
                       bool Decompress = false)
-      : FileName(File), Decompressed(Decompress), NumberOfEntries(0),
+      : FileName(File), NumberOfEntries(0), Decompressed(Decompress),
         Entries(SmallVector<OffloadBundleEntry>()) {
     if (Decompress)
       DecompressedBuffer =
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 8d9f42e5da3c6..1c45dd233a56c 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -62,7 +62,7 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
         return createFileError(FileName, EC);
 
       Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
-          CompressedOffloadBundle::decompress(**CodeOrErr, &nulls());
+          CompressedOffloadBundle::decompress(**CodeOrErr, nullptr);
       if (!DecompressedBufferOrErr)
         return createStringError(
             inconvertibleErrorCode(),
@@ -137,8 +137,7 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
       return errorCodeToError(object_error::parse_failed);
 
     auto Entry = std::make_unique<OffloadBundleEntry>(
-        EntryOffset + SectionOffset, EntrySize, EntryIDSize,
-        std::move(EntryID.str()));
+        EntryOffset + SectionOffset, EntrySize, EntryIDSize, EntryID);
 
     Entries.push_back(*Entry);
   }

>From 7ce94fe5b6300d41b2fd612c0324688d1fb811e5 Mon Sep 17 00:00:00 2001
From: david-salinas <dsalinas at amd.com>
Date: Thu, 18 Sep 2025 19:56:26 +0000
Subject: [PATCH 8/8] Address PR comment.

---
 llvm/lib/Object/OffloadBundle.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 1c45dd233a56c..040ecc0a41619 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -333,13 +333,15 @@ CompressedOffloadBundle::compress(compression::Params P,
   if (Version == 2) {
     // For V2, ensure the sizes don't exceed 32-bit limit.
     if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
-      return createStringError(inconvertibleErrorCode(),
-                               "uncompressed size exceeds version 2 limit");
+      return createStringError(
+          inconvertibleErrorCode(),
+          "uncompressed size exceeds version 2 unsigned 32-bit integer limit");
     if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
          sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +
          CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
-      return createStringError(inconvertibleErrorCode(),
-                               "total file size exceeds version 2 limit");
+      return createStringError(
+          inconvertibleErrorCode(),
+          "total file size exceeds version 2 unsigned 32-bit integer limit");
 
     TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +
                       sizeof(CompressionMethod) + sizeof(uint32_t) +



More information about the llvm-commits mailing list