[clang] 0041fa4 - [llvm][tools] Extend llvm-objdump to support nested OffloadBinaries (#185425)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 8 02:32:34 PDT 2026
Author: Alex Duran
Date: 2026-05-08T11:32:29+02:00
New Revision: 0041fa4aeb725a422399c48d7e6d933246e22bfe
URL: https://github.com/llvm/llvm-project/commit/0041fa4aeb725a422399c48d7e6d933246e22bfe
DIFF: https://github.com/llvm/llvm-project/commit/0041fa4aeb725a422399c48d7e6d933246e22bfe.diff
LOG: [llvm][tools] Extend llvm-objdump to support nested OffloadBinaries (#185425)
Extends llvm-objdump to print the information of images contained in
nested OffloadBinaries. For example, for a binary compiled with #185413
it shows
```
$llvm-objdump --offloading ./a.out
./a.out: file format elf64-x86-64
OFFLOADING IMAGE [0]:
kind elf
arch
triple spirv64-intel
producer openmp
image size 43104 bytes
[Nested OffloadBinary format detected]
Number of inner images: 1
kind spir-v
arch
triple spirv64-intel
producer openmp
image size 42944 bytes
```
New tests are added for clang-ling-wrapper and llvm-offload-binary using
this new functionality.
Depends on #185413
---------
Co-authored-by: Yury Plyakhin <yury.plyakhin at intel.com>
Added:
clang/test/Tooling/clang-linker-wrapper-spirv.cpp
llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary-fails.test
llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary.test
Modified:
llvm/test/tools/llvm-objdump/Offloading/coff.test
llvm/test/tools/llvm-objdump/Offloading/elf.test
llvm/test/tools/llvm-offload-binary/llvm-offload-binary.ll
llvm/tools/llvm-objdump/OffloadDump.cpp
Removed:
################################################################################
diff --git a/clang/test/Tooling/clang-linker-wrapper-spirv.cpp b/clang/test/Tooling/clang-linker-wrapper-spirv.cpp
new file mode 100644
index 0000000000000..ecbfe626129db
--- /dev/null
+++ b/clang/test/Tooling/clang-linker-wrapper-spirv.cpp
@@ -0,0 +1,13 @@
+// Verify the ELF packaging of OpenMP SPIR-V device images.
+// REQUIRES: system-linux
+// REQUIRES: spirv-tools
+// REQUIRES: spirv-registered-target
+// RUN: %clangxx -fopenmp -fopenmp-targets=spirv64-intel -nogpulib -o %t %s
+// RUN: llvm-objdump --offloading %t | FileCheck -check-prefix=CHECK %s
+
+// CHECK: nested images 1
+// CHECK: triple spirv64-intel
+
+int main(int argc, char** argv) {
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-objdump/Offloading/coff.test b/llvm/test/tools/llvm-objdump/Offloading/coff.test
index 022277d137bd4..5bec7d60cb83e 100644
--- a/llvm/test/tools/llvm-objdump/Offloading/coff.test
+++ b/llvm/test/tools/llvm-objdump/Offloading/coff.test
@@ -22,21 +22,25 @@ symbols:
# CHECK-NEXT:arch gfx908
# CHECK-NEXT:triple amdgcn-amd-amdhsa
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [1]:
# CHECK-NEXT:kind llvm ir
# CHECK-NEXT:arch gfx90a
# CHECK-NEXT:triple amdgcn-amd-amdhsa
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [2]:
# CHECK-NEXT:kind cubin
# CHECK-NEXT:arch sm_52
# CHECK-NEXT:triple nvptx64-nvidia-cuda
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [3]:
# CHECK-NEXT:kind <none>
# CHECK-NEXT:arch sm_70
# CHECK-NEXT:triple nvptx64-nvidia-cuda
# CHECK-NEXT:producer none
+# CHECK-NEXT:image size 0 bytes
diff --git a/llvm/test/tools/llvm-objdump/Offloading/elf.test b/llvm/test/tools/llvm-objdump/Offloading/elf.test
index 10182aeb856cd..3064286b9fea1 100644
--- a/llvm/test/tools/llvm-objdump/Offloading/elf.test
+++ b/llvm/test/tools/llvm-objdump/Offloading/elf.test
@@ -31,21 +31,25 @@ Sections:
# CHECK-NEXT:arch gfx908
# CHECK-NEXT:triple amdgcn-amd-amdhsa
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [1]:
# CHECK-NEXT:kind llvm ir
# CHECK-NEXT:arch gfx90a
# CHECK-NEXT:triple amdgcn-amd-amdhsa
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [2]:
# CHECK-NEXT:kind cubin
# CHECK-NEXT:arch sm_52
# CHECK-NEXT:triple nvptx64-nvidia-cuda
# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size 0 bytes
# CHECK-EMPTY:
# CHECK-NEXT:OFFLOADING IMAGE [3]:
# CHECK-NEXT:kind <none>
# CHECK-NEXT:arch sm_70
# CHECK-NEXT:triple nvptx64-nvidia-cuda
# CHECK-NEXT:producer none
+# CHECK-NEXT:image size 0 bytes
diff --git a/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary-fails.test b/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary-fails.test
new file mode 100644
index 0000000000000..cb16915d5feb2
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary-fails.test
@@ -0,0 +1,19 @@
+## Test that llvm-objdump will display an error for incorrect nested OffloadBinary images.
+
+# RUN: yaml2obj %s -o %t.bin
+# RUN: llvm-objdump --offloading %t.bin 2>&1 | FileCheck %s -DFILENAME=%t.bin "-DROOT=OFFLOADING IMAGE"
+
+!Offload
+Members:
+ - ImageKind: IMG_Object
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "x-y-z"
+ - Key: "arch"
+ Value: "none"
+ Content: 10ff10ad
+
+# CHECK: [[ROOT]]
+# CHECK-NOT: [[ROOT]]
+# CHECK: warning: '[[FILENAME]]': failed to extract nested OffloadBinary: Invalid data was encountered while parsing the file
diff --git a/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary.test b/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary.test
new file mode 100644
index 0000000000000..d46180242144e
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/nested-offload-binary.test
@@ -0,0 +1,85 @@
+## Test that llvm-objdump can display nested OffloadBinary images.
+
+## The content blobs below were generated from the following YAML Input
+##!Offload
+##Members:
+## - ImageKind: IMG_Bitcode
+## OffloadKind: OFK_OpenMP
+## String:
+## - Key: "triple"
+## Value: "x-y-z"
+## - Key: "arch"
+## Value: "arch1"
+## - ImageKind: IMG_Bitcode
+## OffloadKind: OFK_OpenMP
+## String:
+## - Key: "triple"
+## Value: "x-y-z"
+## - Key: "arch"
+## Value: "arch2"
+
+# RUN: yaml2obj %s -o %t.bin
+# RUN: llvm-objdump --offloading %t.bin | FileCheck --match-full-lines --strict-whitespace --implicit-check-not={{.}} %s
+
+!Offload
+Members:
+ - ImageKind: IMG_Object
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "x-y-z"
+ - Key: "arch"
+ Value: "none"
+ Content: 10ff10ad02000000f00000000000000020000000000000000200000000000000020001000000000070000000000000000200000000000000f00000000000000000000000000000000200010000000000a0000000000000000200000000000000f0000000000000000000000000000000dc00000000000000d1000000000000000500000000000000d700000000000000e9000000000000000500000000000000dc00000000000000d1000000000000000500000000000000d700000000000000e300000000000000050000000000000000782d792d7a006172636800747269706c650061726368320061726368310000
+ - ImageKind: IMG_Object
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "a-b-c"
+ - Key: "arch"
+ Value: "none"
+ Content: 10ff10ad02000000f00000000000000020000000000000000200000000000000020001000000000070000000000000000200000000000000f00000000000000000000000000000000200010000000000a0000000000000000200000000000000f0000000000000000000000000000000dc00000000000000d1000000000000000500000000000000d700000000000000e9000000000000000500000000000000dc00000000000000d1000000000000000500000000000000d700000000000000e300000000000000050000000000000000782d792d7a006172636800747269706c650061726368320061726368310000
+
+# CHECK:OFFLOADING IMAGE [0]:
+# CHECK-NEXT:kind elf
+# CHECK-NEXT:arch none
+# CHECK-NEXT:triple x-y-z
+# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size {{[0-9]+}} bytes
+# CHECK-NEXT:nested images 2
+# CHECK-EMPTY:
+# CHECK-NEXT: OFFLOADING IMAGE [0.0]:
+# CHECK-NEXT: kind llvm ir
+# CHECK-NEXT: arch arch1
+# CHECK-NEXT: triple x-y-z
+# CHECK-NEXT: producer openmp
+# CHECK-NEXT: image size {{[0-9]+}} bytes
+# CHECK-EMPTY:
+# CHECK-NEXT: OFFLOADING IMAGE [0.1]:
+# CHECK-NEXT: kind llvm ir
+# CHECK-NEXT: arch arch2
+# CHECK-NEXT: triple x-y-z
+# CHECK-NEXT: producer openmp
+# CHECK-NEXT: image size {{[0-9]+}} bytes
+# CHECK-EMPTY:
+# CHECK-NEXT:OFFLOADING IMAGE [1]:
+# CHECK-NEXT:kind elf
+# CHECK-NEXT:arch none
+# CHECK-NEXT:triple a-b-c
+# CHECK-NEXT:producer openmp
+# CHECK-NEXT:image size {{[0-9]+}} bytes
+# CHECK-NEXT:nested images 2
+# CHECK-EMPTY:
+# CHECK-NEXT: OFFLOADING IMAGE [1.0]:
+# CHECK-NEXT: kind llvm ir
+# CHECK-NEXT: arch arch1
+# CHECK-NEXT: triple x-y-z
+# CHECK-NEXT: producer openmp
+# CHECK-NEXT: image size {{[0-9]+}} bytes
+# CHECK-EMPTY:
+# CHECK-NEXT: OFFLOADING IMAGE [1.1]:
+# CHECK-NEXT: kind llvm ir
+# CHECK-NEXT: arch arch2
+# CHECK-NEXT: triple x-y-z
+# CHECK-NEXT: producer openmp
+# CHECK-NEXT: image size {{[0-9]+}} bytes
diff --git a/llvm/test/tools/llvm-offload-binary/llvm-offload-binary.ll b/llvm/test/tools/llvm-offload-binary/llvm-offload-binary.ll
index df46ad3a0d38a..31ee5e286717f 100644
--- a/llvm/test/tools/llvm-offload-binary/llvm-offload-binary.ll
+++ b/llvm/test/tools/llvm-offload-binary/llvm-offload-binary.ll
@@ -15,3 +15,41 @@
; RUN: llvm-offload-binary -o %t3 --image=file=%s
; RUN: llvm-offload-binary %t3 --image=file=%t4
; RUN:
diff %s %t4
+
+; Test nested OffloadBinary construction with multiple inner images.
+; RUN: llvm-offload-binary -o %t5 --image=file=%s,arch=abc,triple=x-y-z --image=file=%s,arch=def,triple=x-y-z
+; RUN: llvm-offload-binary -o %t6 --image=file=%t5,arch=nested,triple=x-y-z
+; RUN: llvm-objdump --offloading %t6 | FileCheck %s --check-prefix=NESTED
+
+; NESTED: OFFLOADING IMAGE [0]:
+; NESTED: arch nested
+; NESTED: nested images 2
+; NESTED: OFFLOADING IMAGE [0.0]:
+; NESTED: arch abc
+; NESTED: OFFLOADING IMAGE [0.1]:
+; NESTED: arch def
+
+; Test complex nested OffloadBinary construction with multiple levels.
+; RUN: llvm-offload-binary -o %t7 --image=file=%s,arch=abc,triple=x-y-z --image=file=%t5,arch=nested,triple=x-y-z
+; RUN: llvm-offload-binary -o %t8 --image=file=%t7,arch=nested,triple=x-y-z --image=file=%t5,arch=nested2,triple=x-y-z
+; RUN: llvm-objdump --offloading %t8 | FileCheck %s --check-prefix=NESTED2
+
+; NESTED2: OFFLOADING IMAGE [0]:
+; NESTED2: arch nested
+; NESTED2: nested images 2
+; NESTED2: OFFLOADING IMAGE [0.0]:
+; NESTED2: arch abc
+; NESTED2: OFFLOADING IMAGE [0.1]:
+; NESTED2: arch nested
+; NESTED2: nested images 2
+; NESTED2: OFFLOADING IMAGE [0.1.0]:
+; NESTED2: arch abc
+; NESTED2: OFFLOADING IMAGE [0.1.1]:
+; NESTED2: arch def
+; NESTED2: OFFLOADING IMAGE [1]:
+; NESTED2: arch nested2
+; NESTED2: nested images 2
+; NESTED2: OFFLOADING IMAGE [1.0]:
+; NESTED2: arch abc
+; NESTED2: OFFLOADING IMAGE [1.1]:
+; NESTED2: arch def
diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp
index cd2727069c2e9..c0ba4d86d9209 100644
--- a/llvm/tools/llvm-objdump/OffloadDump.cpp
+++ b/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -13,6 +13,7 @@
#include "OffloadDump.h"
#include "llvm-objdump.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/OffloadBinary.h"
#include "llvm/Object/OffloadBundle.h"
@@ -43,13 +44,54 @@ static StringRef getImageName(const OffloadBinary &OB) {
}
}
-static void printBinary(const OffloadBinary &OB, uint64_t Index) {
- outs() << "\nOFFLOADING IMAGE [" << Index << "]:\n";
- outs() << left_justify("kind", 16) << getImageName(OB) << "\n";
- outs() << left_justify("arch", 16) << OB.getArch() << "\n";
- outs() << left_justify("triple", 16) << OB.getTriple() << "\n";
- outs() << left_justify("producer", 16)
- << getOffloadKindName(OB.getOffloadKind()) << "\n";
+/// Print metadata from an OffloadBinary.
+static void printOffloadBinaryMetadata(const OffloadBinary &OB,
+ uint64_t Level) {
+ outs().indent(Level * 2) << left_justify("kind", 16) << getImageName(OB)
+ << "\n";
+ outs().indent(Level * 2) << left_justify("arch", 16) << OB.getArch() << "\n";
+ outs().indent(Level * 2) << left_justify("triple", 16) << OB.getTriple()
+ << "\n";
+ outs().indent(Level * 2) << left_justify("producer", 16)
+ << getOffloadKindName(OB.getOffloadKind()) << "\n";
+
+ StringRef InnerImage = OB.getImage();
+ outs().indent(Level * 2) << left_justify("image size", 16)
+ << InnerImage.size() << " bytes\n";
+}
+
+static void printBinary(const OffloadBinary &OB, uint64_t Index,
+ uint64_t Level = 0, Twine ParentIndexPrefix = "") {
+ outs() << "\n";
+ outs().indent(Level * 2) << "OFFLOADING IMAGE [" << ParentIndexPrefix << Index
+ << "]:\n";
+
+ printOffloadBinaryMetadata(OB, Level);
+
+ StringRef ImageData = OB.getImage();
+ if (identify_magic(ImageData) != file_magic::offload_binary)
+ return;
+
+ MemoryBufferRef InnerBuffer(ImageData, "inner-offload-binary");
+ SmallVector<OffloadFile> InnerBinaries;
+ Error Err = extractOffloadBinaries(InnerBuffer, InnerBinaries);
+ if (Err) {
+ reportWarning("failed to extract nested OffloadBinary: " +
+ toString(std::move(Err)),
+ OB.getFileName());
+ return;
+ }
+ assert(!InnerBinaries.empty() &&
+ "An offload binary with a magic number should contain at least one "
+ "binary");
+
+ outs().indent(Level * 2) << left_justify("nested images", 16)
+ << InnerBinaries.size() << "\n";
+
+ for (uint64_t I = 0, E = InnerBinaries.size(); I != E; ++I) {
+ const OffloadBinary *InnerOB = InnerBinaries[I].getBinary();
+ printBinary(*InnerOB, I, Level + 1, ParentIndexPrefix + Twine(Index) + ".");
+ }
}
/// Print the embedded offloading contents of an ObjectFile \p O.
More information about the cfe-commits
mailing list