Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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/StringMap.h" |
||
| 21 | #include "llvm/ADT/StringRef.h" |
||
| 22 | #include "llvm/Object/Binary.h" |
||
| 23 | #include "llvm/Support/Error.h" |
||
| 24 | #include "llvm/Support/MemoryBuffer.h" |
||
| 25 | #include <memory> |
||
| 26 | |||
| 27 | namespace llvm { |
||
| 28 | |||
| 29 | namespace object { |
||
| 30 | |||
| 31 | /// The producer of the associated offloading image. |
||
| 32 | enum OffloadKind : uint16_t { |
||
| 33 | OFK_None = 0, |
||
| 34 | OFK_OpenMP, |
||
| 35 | OFK_Cuda, |
||
| 36 | OFK_HIP, |
||
| 37 | OFK_LAST, |
||
| 38 | }; |
||
| 39 | |||
| 40 | /// The type of contents the offloading image contains. |
||
| 41 | enum ImageKind : uint16_t { |
||
| 42 | IMG_None = 0, |
||
| 43 | IMG_Object, |
||
| 44 | IMG_Bitcode, |
||
| 45 | IMG_Cubin, |
||
| 46 | IMG_Fatbinary, |
||
| 47 | IMG_PTX, |
||
| 48 | IMG_LAST, |
||
| 49 | }; |
||
| 50 | |||
| 51 | /// A simple binary serialization of an offloading file. We use this format to |
||
| 52 | /// embed the offloading image into the host executable so it can be extracted |
||
| 53 | /// and used by the linker. |
||
| 54 | /// |
||
| 55 | /// Many of these could be stored in the same section by the time the linker |
||
| 56 | /// sees it so we mark this information with a header. The version is used to |
||
| 57 | /// detect ABI stability and the size is used to find other offloading entries |
||
| 58 | /// that may exist in the same section. All offsets are given as absolute byte |
||
| 59 | /// offsets from the beginning of the file. |
||
| 60 | class OffloadBinary : public Binary { |
||
| 61 | public: |
||
| 62 | using string_iterator = StringMap<StringRef>::const_iterator; |
||
| 63 | using string_iterator_range = iterator_range<string_iterator>; |
||
| 64 | |||
| 65 | /// The current version of the binary used for backwards compatibility. |
||
| 66 | static const uint32_t Version = 1; |
||
| 67 | |||
| 68 | /// The offloading metadata that will be serialized to a memory buffer. |
||
| 69 | struct OffloadingImage { |
||
| 70 | ImageKind TheImageKind; |
||
| 71 | OffloadKind TheOffloadKind; |
||
| 72 | uint32_t Flags; |
||
| 73 | StringMap<StringRef> StringData; |
||
| 74 | std::unique_ptr<MemoryBuffer> Image; |
||
| 75 | }; |
||
| 76 | |||
| 77 | /// Attempt to parse the offloading binary stored in \p Data. |
||
| 78 | static Expected<std::unique_ptr<OffloadBinary>> create(MemoryBufferRef); |
||
| 79 | |||
| 80 | /// Serialize the contents of \p File to a binary buffer to be read later. |
||
| 81 | static std::unique_ptr<MemoryBuffer> write(const OffloadingImage &); |
||
| 82 | |||
| 83 | static uint64_t getAlignment() { return 8; } |
||
| 84 | |||
| 85 | ImageKind getImageKind() const { return TheEntry->TheImageKind; } |
||
| 86 | OffloadKind getOffloadKind() const { return TheEntry->TheOffloadKind; } |
||
| 87 | uint32_t getVersion() const { return TheHeader->Version; } |
||
| 88 | uint32_t getFlags() const { return TheEntry->Flags; } |
||
| 89 | uint64_t getSize() const { return TheHeader->Size; } |
||
| 90 | |||
| 91 | StringRef getTriple() const { return getString("triple"); } |
||
| 92 | StringRef getArch() const { return getString("arch"); } |
||
| 93 | StringRef getImage() const { |
||
| 94 | return StringRef(&Buffer[TheEntry->ImageOffset], TheEntry->ImageSize); |
||
| 95 | } |
||
| 96 | |||
| 97 | // Iterator over all the key and value pairs in the binary. |
||
| 98 | string_iterator_range strings() const { |
||
| 99 | return string_iterator_range(StringData.begin(), StringData.end()); |
||
| 100 | } |
||
| 101 | |||
| 102 | StringRef getString(StringRef Key) const { return StringData.lookup(Key); } |
||
| 103 | |||
| 104 | static bool classof(const Binary *V) { return V->isOffloadFile(); } |
||
| 105 | |||
| 106 | struct Header { |
||
| 107 | uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. |
||
| 108 | uint32_t Version = OffloadBinary::Version; // Version identifier. |
||
| 109 | uint64_t Size; // Size in bytes of this entire binary. |
||
| 110 | uint64_t EntryOffset; // Offset of the metadata entry in bytes. |
||
| 111 | uint64_t EntrySize; // Size of the metadata entry in bytes. |
||
| 112 | }; |
||
| 113 | |||
| 114 | struct Entry { |
||
| 115 | ImageKind TheImageKind; // The kind of the image stored. |
||
| 116 | OffloadKind TheOffloadKind; // The producer of this image. |
||
| 117 | uint32_t Flags; // Additional flags associated with the image. |
||
| 118 | uint64_t StringOffset; // Offset in bytes to the string map. |
||
| 119 | uint64_t NumStrings; // Number of entries in the string map. |
||
| 120 | uint64_t ImageOffset; // Offset in bytes of the actual binary image. |
||
| 121 | uint64_t ImageSize; // Size in bytes of the binary image. |
||
| 122 | }; |
||
| 123 | |||
| 124 | struct StringEntry { |
||
| 125 | uint64_t KeyOffset; |
||
| 126 | uint64_t ValueOffset; |
||
| 127 | }; |
||
| 128 | |||
| 129 | private: |
||
| 130 | OffloadBinary(MemoryBufferRef Source, const Header *TheHeader, |
||
| 131 | const Entry *TheEntry) |
||
| 132 | : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()), |
||
| 133 | TheHeader(TheHeader), TheEntry(TheEntry) { |
||
| 134 | const StringEntry *StringMapBegin = |
||
| 135 | reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]); |
||
| 136 | for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) { |
||
| 137 | StringRef Key = &Buffer[StringMapBegin[I].KeyOffset]; |
||
| 138 | StringData[Key] = &Buffer[StringMapBegin[I].ValueOffset]; |
||
| 139 | } |
||
| 140 | } |
||
| 141 | |||
| 142 | OffloadBinary(const OffloadBinary &Other) = delete; |
||
| 143 | |||
| 144 | /// Map from keys to offsets in the binary. |
||
| 145 | StringMap<StringRef> StringData; |
||
| 146 | /// Raw pointer to the MemoryBufferRef for convenience. |
||
| 147 | const char *Buffer; |
||
| 148 | /// Location of the header within the binary. |
||
| 149 | const Header *TheHeader; |
||
| 150 | /// Location of the metadata entries within the binary. |
||
| 151 | const Entry *TheEntry; |
||
| 152 | }; |
||
| 153 | |||
| 154 | /// A class to contain the binary information for a single OffloadBinary that |
||
| 155 | /// owns its memory. |
||
| 156 | class OffloadFile : public OwningBinary<OffloadBinary> { |
||
| 157 | public: |
||
| 158 | using TargetID = std::pair<StringRef, StringRef>; |
||
| 159 | |||
| 160 | OffloadFile(std::unique_ptr<OffloadBinary> Binary, |
||
| 161 | std::unique_ptr<MemoryBuffer> Buffer) |
||
| 162 | : OwningBinary<OffloadBinary>(std::move(Binary), std::move(Buffer)) {} |
||
| 163 | |||
| 164 | /// We use the Triple and Architecture pair to group linker inputs together. |
||
| 165 | /// This conversion function lets us use these inputs in a hash-map. |
||
| 166 | operator TargetID() const { |
||
| 167 | return std::make_pair(getBinary()->getTriple(), getBinary()->getArch()); |
||
| 168 | } |
||
| 169 | }; |
||
| 170 | |||
| 171 | /// Extracts embedded device offloading code from a memory \p Buffer to a list |
||
| 172 | /// of \p Binaries. |
||
| 173 | Error extractOffloadBinaries(MemoryBufferRef Buffer, |
||
| 174 | SmallVectorImpl<OffloadFile> &Binaries); |
||
| 175 | |||
| 176 | /// Convert a string \p Name to an image kind. |
||
| 177 | ImageKind getImageKind(StringRef Name); |
||
| 178 | |||
| 179 | /// Convert an image kind to its string representation. |
||
| 180 | StringRef getImageKindName(ImageKind Name); |
||
| 181 | |||
| 182 | /// Convert a string \p Name to an offload kind. |
||
| 183 | OffloadKind getOffloadKind(StringRef Name); |
||
| 184 | |||
| 185 | /// Convert an offload kind to its string representation. |
||
| 186 | StringRef getOffloadKindName(OffloadKind Name); |
||
| 187 | |||
| 188 | } // namespace object |
||
| 189 | |||
| 190 | } // namespace llvm |
||
| 191 | #endif |