Skip to content

Commit 910220b

Browse files
david-salinasdsalinas
and
dsalinas
authored
Reapply: [llvm-objdump] Add support for HIP offload bundles (#140128)
Utilize the new extensions to the LLVM Offloading API to extend to llvm-objdump to handle dumping fatbin offload bundles generated by HIP. This extension to llvm-objdump adds the option --offload-fatbin. Specifying this option will take the input object/executable and extract all offload fatbin bundle entries into distinct code object files with names reflecting the source file name combined with the Bundle Entry ID. Users can also use the --arch-name option to filter offload fatbin bundle entries by their target triple. --------- Co-authored-by: dsalinas <[email protected]>
1 parent 689a960 commit 910220b

File tree

10 files changed

+888
-4
lines changed

10 files changed

+888
-4
lines changed

llvm/docs/CommandGuide/llvm-objdump.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ OPTIONS
217217

218218
.. option:: --offloading
219219

220-
Display the content of the LLVM offloading section.
220+
Display the content of the LLVM offloading sections and HIP offload bundles.
221221

222222
.. option:: --prefix=<prefix>
223223

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
//===- OffloadBundle.h - Utilities for offload bundles---*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===-------------------------------------------------------------------------===//
8+
//
9+
// This file contains the binary format used for budingling device metadata with
10+
// an associated device image. The data can then be stored inside a host object
11+
// file to create a fat binary and read by the linker. This is intended to be a
12+
// thin wrapper around the image itself. If this format becomes sufficiently
13+
// complex it should be moved to a standard binary format like msgpack or ELF.
14+
//
15+
//===-------------------------------------------------------------------------===//
16+
17+
#ifndef LLVM_OBJECT_OFFLOADBUNDLE_H
18+
#define LLVM_OBJECT_OFFLOADBUNDLE_H
19+
20+
#include "llvm/ADT/MapVector.h"
21+
#include "llvm/ADT/SmallString.h"
22+
#include "llvm/ADT/StringRef.h"
23+
#include "llvm/Object/Binary.h"
24+
#include "llvm/Object/ObjectFile.h"
25+
#include "llvm/Support/Compression.h"
26+
#include "llvm/Support/Error.h"
27+
#include "llvm/Support/MemoryBuffer.h"
28+
#include <memory>
29+
30+
namespace llvm {
31+
32+
namespace object {
33+
34+
class CompressedOffloadBundle {
35+
private:
36+
static inline const size_t MagicSize = 4;
37+
static inline const size_t VersionFieldSize = sizeof(uint16_t);
38+
static inline const size_t MethodFieldSize = sizeof(uint16_t);
39+
static inline const size_t FileSizeFieldSize = sizeof(uint32_t);
40+
static inline const size_t UncompressedSizeFieldSize = sizeof(uint32_t);
41+
static inline const size_t HashFieldSize = sizeof(uint64_t);
42+
static inline const size_t V1HeaderSize =
43+
MagicSize + VersionFieldSize + MethodFieldSize +
44+
UncompressedSizeFieldSize + HashFieldSize;
45+
static inline const size_t V2HeaderSize =
46+
MagicSize + VersionFieldSize + FileSizeFieldSize + MethodFieldSize +
47+
UncompressedSizeFieldSize + HashFieldSize;
48+
static inline const llvm::StringRef MagicNumber = "CCOB";
49+
static inline const uint16_t Version = 2;
50+
51+
public:
52+
static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
53+
compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
54+
bool Verbose = false);
55+
static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
56+
decompress(llvm::MemoryBufferRef &Input, bool Verbose = false);
57+
};
58+
59+
/// Bundle entry in binary clang-offload-bundler format.
60+
struct OffloadBundleEntry {
61+
uint64_t Offset = 0u;
62+
uint64_t Size = 0u;
63+
uint64_t IDLength = 0u;
64+
StringRef ID;
65+
OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T)
66+
: Offset(O), Size(S), IDLength(I), ID(T) {}
67+
void dumpInfo(raw_ostream &OS) {
68+
OS << "Offset = " << Offset << ", Size = " << Size
69+
<< ", ID Length = " << IDLength << ", ID = " << ID;
70+
}
71+
void dumpURI(raw_ostream &OS, StringRef FilePath) {
72+
OS << ID.data() << "\tfile://" << FilePath << "#offset=" << Offset
73+
<< "&size=" << Size << "\n";
74+
}
75+
};
76+
77+
/// Fat binary embedded in object files in clang-offload-bundler format
78+
class OffloadBundleFatBin {
79+
80+
uint64_t Size = 0u;
81+
StringRef FileName;
82+
uint64_t NumberOfEntries;
83+
SmallVector<OffloadBundleEntry> Entries;
84+
85+
public:
86+
SmallVector<OffloadBundleEntry> getEntries() { return Entries; }
87+
uint64_t getSize() const { return Size; }
88+
StringRef getFileName() const { return FileName; }
89+
uint64_t getNumEntries() const { return NumberOfEntries; }
90+
91+
static Expected<std::unique_ptr<OffloadBundleFatBin>>
92+
create(MemoryBufferRef, uint64_t SectionOffset, StringRef FileName);
93+
Error extractBundle(const ObjectFile &Source);
94+
95+
Error dumpEntryToCodeObject();
96+
97+
Error readEntries(StringRef Section, uint64_t SectionOffset);
98+
void dumpEntries() {
99+
for (OffloadBundleEntry &Entry : Entries)
100+
Entry.dumpInfo(outs());
101+
}
102+
103+
void printEntriesAsURI() {
104+
for (OffloadBundleEntry &Entry : Entries)
105+
Entry.dumpURI(outs(), FileName);
106+
}
107+
108+
OffloadBundleFatBin(MemoryBufferRef Source, StringRef File)
109+
: FileName(File), NumberOfEntries(0),
110+
Entries(SmallVector<OffloadBundleEntry>()) {}
111+
112+
SmallVector<OffloadBundleEntry> entryIDContains(StringRef Str) {
113+
114+
SmallVector<OffloadBundleEntry> Found = SmallVector<OffloadBundleEntry>();
115+
llvm::transform(Entries, std::back_inserter(Found), [Str](auto &X) {
116+
if (X.ID.contains(Str))
117+
return X;
118+
});
119+
return Found;
120+
}
121+
};
122+
123+
enum UriTypeT { FILE_URI, MEMORY_URI };
124+
125+
struct OffloadBundleURI {
126+
int64_t Offset = 0;
127+
int64_t Size = 0;
128+
uint64_t ProcessID = 0;
129+
StringRef FileName;
130+
UriTypeT URIType;
131+
132+
// Constructors
133+
// TODO: add a Copy ctor ?
134+
OffloadBundleURI(StringRef File, int64_t Off, int64_t Size)
135+
: Offset(Off), Size(Size), ProcessID(0), FileName(File),
136+
URIType(FILE_URI) {}
137+
138+
public:
139+
static Expected<std::unique_ptr<OffloadBundleURI>>
140+
createOffloadBundleURI(StringRef Str, UriTypeT Type) {
141+
switch (Type) {
142+
case FILE_URI:
143+
return createFileURI(Str);
144+
break;
145+
case MEMORY_URI:
146+
return createMemoryURI(Str);
147+
break;
148+
default:
149+
return createStringError(object_error::parse_failed,
150+
"Unrecognized URI type");
151+
}
152+
}
153+
154+
static Expected<std::unique_ptr<OffloadBundleURI>>
155+
createFileURI(StringRef Str) {
156+
int64_t O = 0;
157+
int64_t S = 0;
158+
159+
if (!Str.consume_front("file://"))
160+
return createStringError(object_error::parse_failed,
161+
"Reading type of URI");
162+
163+
StringRef FilePathname =
164+
Str.take_until([](char C) { return (C == '#') || (C == '?'); });
165+
Str = Str.drop_front(FilePathname.size());
166+
167+
if (!Str.consume_front("#offset="))
168+
return createStringError(object_error::parse_failed,
169+
"Reading 'offset' in URI");
170+
171+
StringRef OffsetStr = Str.take_until([](char C) { return C == '&'; });
172+
OffsetStr.getAsInteger(10, O);
173+
Str = Str.drop_front(OffsetStr.size());
174+
175+
if (Str.consume_front("&size="))
176+
return createStringError(object_error::parse_failed,
177+
"Reading 'size' in URI");
178+
179+
Str.getAsInteger(10, S);
180+
std::unique_ptr<OffloadBundleURI> OffloadingURI(
181+
new OffloadBundleURI(FilePathname, O, S));
182+
return OffloadingURI;
183+
}
184+
185+
static Expected<std::unique_ptr<OffloadBundleURI>>
186+
createMemoryURI(StringRef Str) {
187+
// TODO: add parseMemoryURI type
188+
return createStringError(object_error::parse_failed,
189+
"Memory Type URI is not currently supported.");
190+
}
191+
192+
StringRef getFileName() const { return FileName; }
193+
};
194+
195+
/// Extracts fat binary in binary clang-offload-bundler format from object \p
196+
/// Obj and return it in \p Bundles
197+
Error extractOffloadBundleFatBinary(
198+
const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles);
199+
200+
/// Extract code object memory from the given \p Source object file at \p Offset
201+
/// and of \p Size, and copy into \p OutputFileName.
202+
Error extractCodeObject(const ObjectFile &Source, int64_t Offset, int64_t Size,
203+
StringRef OutputFileName);
204+
205+
/// Extracts an Offload Bundle Entry given by URI
206+
Error extractOffloadBundleByURI(StringRef URIstr);
207+
208+
} // namespace object
209+
210+
} // namespace llvm
211+
#endif

llvm/lib/Object/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_llvm_component_library(LLVMObject
2222
Object.cpp
2323
ObjectFile.cpp
2424
OffloadBinary.cpp
25+
OffloadBundle.cpp
2526
RecordStreamer.cpp
2627
RelocationResolver.cpp
2728
SymbolicFile.cpp

0 commit comments

Comments
 (0)