Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:20

0001 //===--- Offloading.h - Utilities for handling offloading code  -*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file contains the binary format used for budingling device metadata with
0010 // an associated device image. The data can then be stored inside a host object
0011 // file to create a fat binary and read by the linker. This is intended to be a
0012 // thin wrapper around the image itself. If this format becomes sufficiently
0013 // complex it should be moved to a standard binary format like msgpack or ELF.
0014 //
0015 //===----------------------------------------------------------------------===//
0016 
0017 #ifndef LLVM_OBJECT_OFFLOADBINARY_H
0018 #define LLVM_OBJECT_OFFLOADBINARY_H
0019 
0020 #include "llvm/ADT/MapVector.h"
0021 #include "llvm/ADT/SmallString.h"
0022 #include "llvm/ADT/StringRef.h"
0023 #include "llvm/Object/Binary.h"
0024 #include "llvm/Support/Error.h"
0025 #include "llvm/Support/MemoryBuffer.h"
0026 #include <memory>
0027 
0028 namespace llvm {
0029 
0030 namespace object {
0031 
0032 /// The producer of the associated offloading image.
0033 enum OffloadKind : uint16_t {
0034   OFK_None = 0,
0035   OFK_OpenMP,
0036   OFK_Cuda,
0037   OFK_HIP,
0038   OFK_LAST,
0039 };
0040 
0041 /// The type of contents the offloading image contains.
0042 enum ImageKind : uint16_t {
0043   IMG_None = 0,
0044   IMG_Object,
0045   IMG_Bitcode,
0046   IMG_Cubin,
0047   IMG_Fatbinary,
0048   IMG_PTX,
0049   IMG_LAST,
0050 };
0051 
0052 /// A simple binary serialization of an offloading file. We use this format to
0053 /// embed the offloading image into the host executable so it can be extracted
0054 /// and used by the linker.
0055 ///
0056 /// Many of these could be stored in the same section by the time the linker
0057 /// sees it so we mark this information with a header. The version is used to
0058 /// detect ABI stability and the size is used to find other offloading entries
0059 /// that may exist in the same section. All offsets are given as absolute byte
0060 /// offsets from the beginning of the file.
0061 class OffloadBinary : public Binary {
0062 public:
0063   using string_iterator = MapVector<StringRef, StringRef>::const_iterator;
0064   using string_iterator_range = iterator_range<string_iterator>;
0065 
0066   /// The current version of the binary used for backwards compatibility.
0067   static const uint32_t Version = 1;
0068 
0069   /// The offloading metadata that will be serialized to a memory buffer.
0070   struct OffloadingImage {
0071     ImageKind TheImageKind;
0072     OffloadKind TheOffloadKind;
0073     uint32_t Flags;
0074     MapVector<StringRef, StringRef> StringData;
0075     std::unique_ptr<MemoryBuffer> Image;
0076   };
0077 
0078   /// Attempt to parse the offloading binary stored in \p Data.
0079   static Expected<std::unique_ptr<OffloadBinary>> create(MemoryBufferRef);
0080 
0081   /// Serialize the contents of \p File to a binary buffer to be read later.
0082   static SmallString<0> write(const OffloadingImage &);
0083 
0084   static uint64_t getAlignment() { return 8; }
0085 
0086   ImageKind getImageKind() const { return TheEntry->TheImageKind; }
0087   OffloadKind getOffloadKind() const { return TheEntry->TheOffloadKind; }
0088   uint32_t getVersion() const { return TheHeader->Version; }
0089   uint32_t getFlags() const { return TheEntry->Flags; }
0090   uint64_t getSize() const { return TheHeader->Size; }
0091 
0092   StringRef getTriple() const { return getString("triple"); }
0093   StringRef getArch() const { return getString("arch"); }
0094   StringRef getImage() const {
0095     return StringRef(&Buffer[TheEntry->ImageOffset], TheEntry->ImageSize);
0096   }
0097 
0098   // Iterator over all the key and value pairs in the binary.
0099   string_iterator_range strings() const {
0100     return string_iterator_range(StringData.begin(), StringData.end());
0101   }
0102 
0103   StringRef getString(StringRef Key) const { return StringData.lookup(Key); }
0104 
0105   static bool classof(const Binary *V) { return V->isOffloadFile(); }
0106 
0107   struct Header {
0108     uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes.
0109     uint32_t Version = OffloadBinary::Version;   // Version identifier.
0110     uint64_t Size;        // Size in bytes of this entire binary.
0111     uint64_t EntryOffset; // Offset of the metadata entry in bytes.
0112     uint64_t EntrySize;   // Size of the metadata entry in bytes.
0113   };
0114 
0115   struct Entry {
0116     ImageKind TheImageKind;     // The kind of the image stored.
0117     OffloadKind TheOffloadKind; // The producer of this image.
0118     uint32_t Flags;             // Additional flags associated with the image.
0119     uint64_t StringOffset;      // Offset in bytes to the string map.
0120     uint64_t NumStrings;        // Number of entries in the string map.
0121     uint64_t ImageOffset;       // Offset in bytes of the actual binary image.
0122     uint64_t ImageSize;         // Size in bytes of the binary image.
0123   };
0124 
0125   struct StringEntry {
0126     uint64_t KeyOffset;
0127     uint64_t ValueOffset;
0128   };
0129 
0130 private:
0131   OffloadBinary(MemoryBufferRef Source, const Header *TheHeader,
0132                 const Entry *TheEntry)
0133       : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()),
0134         TheHeader(TheHeader), TheEntry(TheEntry) {
0135     const StringEntry *StringMapBegin =
0136         reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]);
0137     for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) {
0138       StringRef Key = &Buffer[StringMapBegin[I].KeyOffset];
0139       StringData[Key] = &Buffer[StringMapBegin[I].ValueOffset];
0140     }
0141   }
0142 
0143   OffloadBinary(const OffloadBinary &Other) = delete;
0144 
0145   /// Map from keys to offsets in the binary.
0146   MapVector<StringRef, StringRef> StringData;
0147   /// Raw pointer to the MemoryBufferRef for convenience.
0148   const char *Buffer;
0149   /// Location of the header within the binary.
0150   const Header *TheHeader;
0151   /// Location of the metadata entries within the binary.
0152   const Entry *TheEntry;
0153 };
0154 
0155 /// A class to contain the binary information for a single OffloadBinary that
0156 /// owns its memory.
0157 class OffloadFile : public OwningBinary<OffloadBinary> {
0158 public:
0159   using TargetID = std::pair<StringRef, StringRef>;
0160 
0161   OffloadFile(std::unique_ptr<OffloadBinary> Binary,
0162               std::unique_ptr<MemoryBuffer> Buffer)
0163       : OwningBinary<OffloadBinary>(std::move(Binary), std::move(Buffer)) {}
0164 
0165   /// Make a deep copy of this offloading file.
0166   OffloadFile copy() const {
0167     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBufferCopy(
0168         getBinary()->getMemoryBufferRef().getBuffer(),
0169         getBinary()->getMemoryBufferRef().getBufferIdentifier());
0170 
0171     // This parsing should never fail because it has already been parsed.
0172     auto NewBinaryOrErr = OffloadBinary::create(*Buffer);
0173     assert(NewBinaryOrErr && "Failed to parse a copy of the binary?");
0174     if (!NewBinaryOrErr)
0175       llvm::consumeError(NewBinaryOrErr.takeError());
0176     return OffloadFile(std::move(*NewBinaryOrErr), std::move(Buffer));
0177   }
0178 
0179   /// We use the Triple and Architecture pair to group linker inputs together.
0180   /// This conversion function lets us use these inputs in a hash-map.
0181   operator TargetID() const {
0182     return std::make_pair(getBinary()->getTriple(), getBinary()->getArch());
0183   }
0184 };
0185 
0186 /// Extracts embedded device offloading code from a memory \p Buffer to a list
0187 /// of \p Binaries.
0188 Error extractOffloadBinaries(MemoryBufferRef Buffer,
0189                              SmallVectorImpl<OffloadFile> &Binaries);
0190 
0191 /// Convert a string \p Name to an image kind.
0192 ImageKind getImageKind(StringRef Name);
0193 
0194 /// Convert an image kind to its string representation.
0195 StringRef getImageKindName(ImageKind Name);
0196 
0197 /// Convert a string \p Name to an offload kind.
0198 OffloadKind getOffloadKind(StringRef Name);
0199 
0200 /// Convert an offload kind to its string representation.
0201 StringRef getOffloadKindName(OffloadKind Name);
0202 
0203 /// If the target is AMD we check the target IDs for mutual compatibility. A
0204 /// target id is a string conforming to the folowing BNF syntax:
0205 ///
0206 ///  target-id ::= '<arch> ( : <feature> ( '+' | '-' ) )*'
0207 ///
0208 /// The features 'xnack' and 'sramecc' are currently supported. These can be in
0209 /// the state of on, off, and any when unspecified. A target marked as any can
0210 /// bind with either on or off. This is used to link mutually compatible
0211 /// architectures together. Returns false in the case of an exact match.
0212 bool areTargetsCompatible(const OffloadFile::TargetID &LHS,
0213                           const OffloadFile::TargetID &RHS);
0214 
0215 } // namespace object
0216 
0217 } // namespace llvm
0218 #endif