Skip to content

Commit a6e8e21

Browse files
david-salinasDavid Salinas
authored andcommitted
Extend LLVM Offloading API for binary fatbin Bundles
With the intention to provide a common API for offloading, this extension to the existing LLVM Offloading API adds support for Binary Fatbin Bundles; moving some support from the Clang offloading API. The intention is to add functionality to LLVM tooling for Binary Fatbin Bundles in subsequent commits. Change-Id: I907fdcbcd0545162a0ce1cf17ebf7c9f3a4dbde6
1 parent 920c589 commit a6e8e21

File tree

2 files changed

+636
-0
lines changed

2 files changed

+636
-0
lines changed

llvm/include/llvm/Object/OffloadBinary.h

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "llvm/ADT/SmallString.h"
2222
#include "llvm/ADT/StringRef.h"
2323
#include "llvm/Object/Binary.h"
24+
#include "llvm/Object/ObjectFile.h"
25+
#include "llvm/Support/Compression.h"
2426
#include "llvm/Support/Error.h"
2527
#include "llvm/Support/MemoryBuffer.h"
2628
#include <memory>
@@ -49,6 +51,31 @@ enum ImageKind : uint16_t {
4951
IMG_LAST,
5052
};
5153

54+
class CompressedOffloadBundle {
55+
private:
56+
static inline const size_t MagicSize = 4;
57+
static inline const size_t VersionFieldSize = sizeof(uint16_t);
58+
static inline const size_t MethodFieldSize = sizeof(uint16_t);
59+
static inline const size_t FileSizeFieldSize = sizeof(uint32_t);
60+
static inline const size_t UncompressedSizeFieldSize = sizeof(uint32_t);
61+
static inline const size_t HashFieldSize = sizeof(uint64_t);
62+
static inline const size_t V1HeaderSize =
63+
MagicSize + VersionFieldSize + MethodFieldSize +
64+
UncompressedSizeFieldSize + HashFieldSize;
65+
static inline const size_t V2HeaderSize =
66+
MagicSize + VersionFieldSize + FileSizeFieldSize + MethodFieldSize +
67+
UncompressedSizeFieldSize + HashFieldSize;
68+
static inline const llvm::StringRef MagicNumber = "CCOB";
69+
static inline const uint16_t Version = 2;
70+
71+
public:
72+
static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
73+
compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
74+
bool Verbose = false);
75+
static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
76+
decompress(llvm::MemoryBufferRef &Input, bool Verbose = false);
77+
};
78+
5279
/// A simple binary serialization of an offloading file. We use this format to
5380
/// embed the offloading image into the host executable so it can be extracted
5481
/// and used by the linker.
@@ -183,11 +210,160 @@ class OffloadFile : public OwningBinary<OffloadBinary> {
183210
}
184211
};
185212

213+
/// Bundle entry in binary clang-offload-bundler format.
214+
struct OffloadBundleEntry {
215+
uint64_t Offset = 0u;
216+
uint64_t Size = 0u;
217+
uint64_t IDLength = 0u;
218+
StringRef ID;
219+
OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T)
220+
: Offset(O), Size(S), IDLength(I), ID(T) {}
221+
void dumpInfo(raw_ostream &OS) {
222+
OS << "Offset = " << Offset << ", Size = " << Size
223+
<< ", ID Length = " << IDLength << ", ID = " << ID;
224+
}
225+
void dumpURI(raw_ostream &OS, StringRef filePath) {
226+
OS << ID.data() << "\tfile://" << filePath << "#offset=" << Offset
227+
<< "&size=" << Size << "\n";
228+
}
229+
};
230+
231+
/// Fat binary embedded in object files in clang-offload-bundler format
232+
class OffloadBundleFatBin {
233+
234+
private:
235+
uint64_t Size = 0u;
236+
StringRef FileName;
237+
uint64_t NumberOfEntries;
238+
SmallVector<OffloadBundleEntry> Entries;
239+
240+
public:
241+
SmallVector<OffloadBundleEntry> getEntries() { return Entries; }
242+
uint64_t getSize() const { return Size; }
243+
StringRef getFileName() const { return FileName; }
244+
uint64_t getNumEntries() const { return NumberOfEntries; }
245+
246+
static Expected<std::unique_ptr<OffloadBundleFatBin>>
247+
create(MemoryBufferRef, uint64_t SectionOffset, StringRef fileName);
248+
Error extractBundle(const ObjectFile &Source);
249+
250+
Error dumpEntryToCodeObject();
251+
252+
Error ReadEntries(StringRef Section, uint64_t SectionOffset);
253+
void DumpEntries() {
254+
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
255+
for (uint64_t I = 0; I < Entries.size(); I++) {
256+
it->dumpInfo(outs());
257+
++it;
258+
}
259+
}
260+
261+
void PrintEntriesAsURI() {
262+
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
263+
for (uint64_t I = 0; I < Entries.size(); I++) {
264+
it->dumpURI(outs(), FileName);
265+
++it;
266+
}
267+
}
268+
269+
OffloadBundleFatBin(MemoryBufferRef Source, StringRef file) : FileName(file),
270+
NumberOfEntries(0),
271+
Entries(SmallVector<OffloadBundleEntry>()) {
272+
}
273+
274+
SmallVector<OffloadBundleEntry> EntryIDContains(StringRef str) {
275+
SmallVector<OffloadBundleEntry> found = SmallVector<OffloadBundleEntry>();
276+
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
277+
for (uint64_t I = 0; I < Entries.size() ; I++) {
278+
if (it->ID.contains(str)) {
279+
found.push_back(*it);
280+
}
281+
282+
++it;
283+
}
284+
return found;
285+
}
286+
};
287+
288+
enum uri_type_t { FILE_URI, MEMORY_URI };
289+
290+
struct OffloadBundleURI {
291+
int64_t Offset = 0;
292+
int64_t Size = 0;
293+
uint64_t ProcessID = 0;
294+
StringRef FileName;
295+
uri_type_t URIType;
296+
297+
// Constructors
298+
// TODO: add a Copy ctor ?
299+
OffloadBundleURI(StringRef file, int64_t off, int64_t size)
300+
: Offset(off), Size(size), ProcessID(0), FileName(file),
301+
URIType(FILE_URI) {}
302+
303+
OffloadBundleURI(StringRef str, uri_type_t type) {
304+
URIType = type;
305+
switch (URIType) {
306+
case FILE_URI:
307+
parseFileName(str);
308+
break;
309+
case MEMORY_URI:
310+
parseMemoryURI(str);
311+
break;
312+
default:
313+
report_fatal_error("Unrecognized URI type.");
314+
}
315+
}
316+
317+
void parseFileName(StringRef str) {
318+
ProcessID = 0;
319+
URIType = FILE_URI;
320+
if (str.consume_front("file://")) {
321+
StringRef FilePathname =
322+
str.take_until([](char c) { return (c == '#') || (c == '?'); });
323+
FileName = FilePathname;
324+
str = str.drop_front(FilePathname.size());
325+
326+
if (str.consume_front("#offset=")) {
327+
StringRef OffsetStr = str.take_until([](char c) { return c == '&'; });
328+
OffsetStr.getAsInteger(10, Offset);
329+
str = str.drop_front(OffsetStr.size());
330+
331+
if (str.consume_front("&size=")) {
332+
// Size;
333+
str.getAsInteger(10, Size);
334+
} else
335+
report_fatal_error("Reading 'size' in URI.");
336+
} else
337+
report_fatal_error("Reading 'offset' in URI.");
338+
} else
339+
report_fatal_error("Reading type of URI.");
340+
}
341+
342+
void parseMemoryURI(StringRef str) {
343+
// TODO: add parseMemoryURI type
344+
}
345+
346+
StringRef getFileName() const { return FileName; }
347+
};
348+
186349
/// Extracts embedded device offloading code from a memory \p Buffer to a list
187350
/// of \p Binaries.
188351
Error extractOffloadBinaries(MemoryBufferRef Buffer,
189352
SmallVectorImpl<OffloadFile> &Binaries);
190353

354+
/// Extracts fat binary in binary clang-offload-bundler format from object \p
355+
/// Obj and return it in \p Bundles
356+
Error extractOffloadBundleFatBinary(
357+
const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles);
358+
359+
/// Extract code object memory from the given \p Source object file at \p Offset
360+
/// and of \p Size, and copy into \p OutputFileName.
361+
Error extractCodeObject(const ObjectFile &Source, int64_t Offset, int64_t Size,
362+
StringRef OutputFileName);
363+
364+
/// Extracts an Offload Bundle Entry given by URI
365+
Error extractOffloadBundleByURI(StringRef URIstr);
366+
191367
/// Convert a string \p Name to an image kind.
192368
ImageKind getImageKind(StringRef Name);
193369

0 commit comments

Comments
 (0)