1//===--- Offloading.h - Utilities for handling offloading code -*- 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_OFFLOADBINARY_H
18#define LLVM_OBJECT_OFFLOADBINARY_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/Support/Error.h"
25#include "llvm/Support/MemoryBuffer.h"
26#include <memory>
27
28namespace llvm {
29
30namespace object {
31
32/// The producer of the associated offloading image.
33enum OffloadKind : uint16_t {
34 OFK_None = 0,
35 OFK_OpenMP,
36 OFK_Cuda,
37 OFK_HIP,
38 OFK_LAST,
39};
40
41/// The type of contents the offloading image contains.
42enum ImageKind : uint16_t {
43 IMG_None = 0,
44 IMG_Object,
45 IMG_Bitcode,
46 IMG_Cubin,
47 IMG_Fatbinary,
48 IMG_PTX,
49 IMG_LAST,
50};
51
52/// A simple binary serialization of an offloading file. We use this format to
53/// embed the offloading image into the host executable so it can be extracted
54/// and used by the linker.
55///
56/// Many of these could be stored in the same section by the time the linker
57/// sees it so we mark this information with a header. The version is used to
58/// detect ABI stability and the size is used to find other offloading entries
59/// that may exist in the same section. All offsets are given as absolute byte
60/// offsets from the beginning of the file.
61class OffloadBinary : public Binary {
62public:
63 using string_iterator = MapVector<StringRef, StringRef>::const_iterator;
64 using string_iterator_range = iterator_range<string_iterator>;
65
66 /// The current version of the binary used for backwards compatibility.
67 static const uint32_t Version = 1;
68
69 /// The offloading metadata that will be serialized to a memory buffer.
70 struct OffloadingImage {
71 ImageKind TheImageKind;
72 OffloadKind TheOffloadKind;
73 uint32_t Flags;
74 MapVector<StringRef, StringRef> StringData;
75 std::unique_ptr<MemoryBuffer> Image;
76 };
77
78 /// Attempt to parse the offloading binary stored in \p Data.
79 static Expected<std::unique_ptr<OffloadBinary>> create(MemoryBufferRef);
80
81 /// Serialize the contents of \p File to a binary buffer to be read later.
82 static SmallString<0> write(const OffloadingImage &);
83
84 static uint64_t getAlignment() { return 8; }
85
86 ImageKind getImageKind() const { return TheEntry->TheImageKind; }
87 OffloadKind getOffloadKind() const { return TheEntry->TheOffloadKind; }
88 uint32_t getVersion() const { return TheHeader->Version; }
89 uint32_t getFlags() const { return TheEntry->Flags; }
90 uint64_t getSize() const { return TheHeader->Size; }
91
92 StringRef getTriple() const { return getString(Key: "triple"); }
93 StringRef getArch() const { return getString(Key: "arch"); }
94 StringRef getImage() const {
95 return StringRef(&Buffer[TheEntry->ImageOffset], TheEntry->ImageSize);
96 }
97
98 // Iterator over all the key and value pairs in the binary.
99 string_iterator_range strings() const {
100 return string_iterator_range(StringData.begin(), StringData.end());
101 }
102
103 StringRef getString(StringRef Key) const { return StringData.lookup(Key); }
104
105 static bool classof(const Binary *V) { return V->isOffloadFile(); }
106
107 struct Header {
108 uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes.
109 uint32_t Version = OffloadBinary::Version; // Version identifier.
110 uint64_t Size; // Size in bytes of this entire binary.
111 uint64_t EntryOffset; // Offset of the metadata entry in bytes.
112 uint64_t EntrySize; // Size of the metadata entry in bytes.
113 };
114
115 struct Entry {
116 ImageKind TheImageKind; // The kind of the image stored.
117 OffloadKind TheOffloadKind; // The producer of this image.
118 uint32_t Flags; // Additional flags associated with the image.
119 uint64_t StringOffset; // Offset in bytes to the string map.
120 uint64_t NumStrings; // Number of entries in the string map.
121 uint64_t ImageOffset; // Offset in bytes of the actual binary image.
122 uint64_t ImageSize; // Size in bytes of the binary image.
123 };
124
125 struct StringEntry {
126 uint64_t KeyOffset;
127 uint64_t ValueOffset;
128 };
129
130private:
131 OffloadBinary(MemoryBufferRef Source, const Header *TheHeader,
132 const Entry *TheEntry)
133 : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()),
134 TheHeader(TheHeader), TheEntry(TheEntry) {
135 const StringEntry *StringMapBegin =
136 reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]);
137 for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) {
138 StringRef Key = &Buffer[StringMapBegin[I].KeyOffset];
139 StringData[Key] = &Buffer[StringMapBegin[I].ValueOffset];
140 }
141 }
142
143 OffloadBinary(const OffloadBinary &Other) = delete;
144
145 /// Map from keys to offsets in the binary.
146 MapVector<StringRef, StringRef> StringData;
147 /// Raw pointer to the MemoryBufferRef for convenience.
148 const char *Buffer;
149 /// Location of the header within the binary.
150 const Header *TheHeader;
151 /// Location of the metadata entries within the binary.
152 const Entry *TheEntry;
153};
154
155/// A class to contain the binary information for a single OffloadBinary that
156/// owns its memory.
157class OffloadFile : public OwningBinary<OffloadBinary> {
158public:
159 using TargetID = std::pair<StringRef, StringRef>;
160
161 OffloadFile(std::unique_ptr<OffloadBinary> Binary,
162 std::unique_ptr<MemoryBuffer> Buffer)
163 : OwningBinary<OffloadBinary>(std::move(Binary), std::move(Buffer)) {}
164
165 /// Make a deep copy of this offloading file.
166 OffloadFile copy() const {
167 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBufferCopy(
168 InputData: getBinary()->getMemoryBufferRef().getBuffer());
169
170 // This parsing should never fail because it has already been parsed.
171 auto NewBinaryOrErr = OffloadBinary::create(*Buffer);
172 assert(NewBinaryOrErr && "Failed to parse a copy of the binary?");
173 if (!NewBinaryOrErr)
174 llvm::consumeError(Err: NewBinaryOrErr.takeError());
175 return OffloadFile(std::move(*NewBinaryOrErr), std::move(Buffer));
176 }
177
178 /// We use the Triple and Architecture pair to group linker inputs together.
179 /// This conversion function lets us use these inputs in a hash-map.
180 operator TargetID() const {
181 return std::make_pair(x: getBinary()->getTriple(), y: getBinary()->getArch());
182 }
183};
184
185/// Extracts embedded device offloading code from a memory \p Buffer to a list
186/// of \p Binaries.
187Error extractOffloadBinaries(MemoryBufferRef Buffer,
188 SmallVectorImpl<OffloadFile> &Binaries);
189
190/// Convert a string \p Name to an image kind.
191ImageKind getImageKind(StringRef Name);
192
193/// Convert an image kind to its string representation.
194StringRef getImageKindName(ImageKind Name);
195
196/// Convert a string \p Name to an offload kind.
197OffloadKind getOffloadKind(StringRef Name);
198
199/// Convert an offload kind to its string representation.
200StringRef getOffloadKindName(OffloadKind Name);
201
202/// If the target is AMD we check the target IDs for mutual compatibility. A
203/// target id is a string conforming to the folowing BNF syntax:
204///
205/// target-id ::= '<arch> ( : <feature> ( '+' | '-' ) )*'
206///
207/// The features 'xnack' and 'sramecc' are currently supported. These can be in
208/// the state of on, off, and any when unspecified. A target marked as any can
209/// bind with either on or off. This is used to link mutually compatible
210/// architectures together. Returns false in the case of an exact match.
211bool areTargetsCompatible(const OffloadFile::TargetID &LHS,
212 const OffloadFile::TargetID &RHS);
213
214} // namespace object
215
216} // namespace llvm
217#endif
218

source code of llvm/include/llvm/Object/OffloadBinary.h