blob: 446d52327066b0c7d8b40502b68aedf0c502a2e8 [file] [log] [blame]
//===--- Offloading.h - Utilities for handling offloading code -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the binary format used for budingling device metadata with
// an associated device image. The data can then be stored inside a host object
// file to create a fat binary and read by the linker. This is intended to be a
// thin wrapper around the image itself. If this format becomes sufficiently
// complex it should be moved to a standard binary format like msgpack or ELF.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_BINARYFORMAT_OFFLOADING_H
#define LLVM_BINARYFORMAT_OFFLOADING_H
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Binary.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
namespace llvm {
namespace object {
/// The producer of the associated offloading image.
enum OffloadKind : uint16_t {
OFK_None = 0,
OFK_OpenMP,
OFK_Cuda,
OFK_HIP,
OFK_LAST,
};
/// The type of contents the offloading image contains.
enum ImageKind : uint16_t {
IMG_None = 0,
IMG_Object,
IMG_Bitcode,
IMG_Cubin,
IMG_Fatbinary,
IMG_PTX,
IMG_LAST,
};
/// A simple binary serialization of an offloading file. We use this format to
/// embed the offloading image into the host executable so it can be extracted
/// and used by the linker.
///
/// Many of these could be stored in the same section by the time the linker
/// sees it so we mark this information with a header. The version is used to
/// detect ABI stability and the size is used to find other offloading entries
/// that may exist in the same section. All offsets are given as absolute byte
/// offsets from the beginning of the file.
class OffloadBinary : public Binary {
public:
using string_iterator = StringMap<StringRef>::const_iterator;
using string_iterator_range = iterator_range<string_iterator>;
/// The offloading metadata that will be serialized to a memory buffer.
struct OffloadingImage {
ImageKind TheImageKind;
OffloadKind TheOffloadKind;
uint32_t Flags;
StringMap<StringRef> StringData;
std::unique_ptr<MemoryBuffer> Image;
};
/// Attempt to parse the offloading binary stored in \p Data.
static Expected<std::unique_ptr<OffloadBinary>> create(MemoryBufferRef);
/// Serialize the contents of \p File to a binary buffer to be read later.
static std::unique_ptr<MemoryBuffer> write(const OffloadingImage &);
static uint64_t getAlignment() { return alignof(Header); }
ImageKind getImageKind() const { return TheEntry->TheImageKind; }
OffloadKind getOffloadKind() const { return TheEntry->TheOffloadKind; }
uint32_t getVersion() const { return TheHeader->Version; }
uint32_t getFlags() const { return TheEntry->Flags; }
uint64_t getSize() const { return TheHeader->Size; }
StringRef getTriple() const { return getString("triple"); }
StringRef getArch() const { return getString("arch"); }
StringRef getImage() const {
return StringRef(&Buffer[TheEntry->ImageOffset], TheEntry->ImageSize);
}
// Iterator over all the key and value pairs in the binary.
string_iterator_range strings() const {
return string_iterator_range(StringData.begin(), StringData.end());
}
StringRef getString(StringRef Key) const { return StringData.lookup(Key); }
static bool classof(const Binary *V) { return V->isOffloadFile(); }
private:
struct Header {
uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes.
uint32_t Version = 1; // Version identifier.
uint64_t Size; // Size in bytes of this entire binary.
uint64_t EntryOffset; // Offset of the metadata entry in bytes.
uint64_t EntrySize; // Size of the metadata entry in bytes.
};
struct Entry {
ImageKind TheImageKind; // The kind of the image stored.
OffloadKind TheOffloadKind; // The producer of this image.
uint32_t Flags; // Additional flags associated with the image.
uint64_t StringOffset; // Offset in bytes to the string map.
uint64_t NumStrings; // Number of entries in the string map.
uint64_t ImageOffset; // Offset in bytes of the actual binary image.
uint64_t ImageSize; // Size in bytes of the binary image.
};
struct StringEntry {
uint64_t KeyOffset;
uint64_t ValueOffset;
};
OffloadBinary(MemoryBufferRef Source, const Header *TheHeader,
const Entry *TheEntry)
: Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()),
TheHeader(TheHeader), TheEntry(TheEntry) {
const StringEntry *StringMapBegin =
reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]);
for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) {
StringRef Key = &Buffer[StringMapBegin[I].KeyOffset];
StringData[Key] = &Buffer[StringMapBegin[I].ValueOffset];
}
}
OffloadBinary(const OffloadBinary &Other) = delete;
/// Map from keys to offsets in the binary.
StringMap<StringRef> StringData;
/// Raw pointer to the MemoryBufferRef for convenience.
const char *Buffer;
/// Location of the header within the binary.
const Header *TheHeader;
/// Location of the metadata entries within the binary.
const Entry *TheEntry;
};
/// Convert a string \p Name to an image kind.
ImageKind getImageKind(StringRef Name);
/// Convert an image kind to its string representation.
StringRef getImageKindName(ImageKind Name);
/// Convert a string \p Name to an offload kind.
OffloadKind getOffloadKind(StringRef Name);
/// Convert an offload kind to its string representation.
StringRef getOffloadKindName(OffloadKind Name);
} // namespace object
} // namespace llvm
#endif