[Binary] Promote OffloadBinary to inherit from Binary

We use the `OffloadBinary` to create binary images of offloading files
and their corresonding metadata. This patch changes this to inherit from
the base `Binary` class. This allows us to create and insepect these
more generically. This patch includes all the necessary glue to
implement this as a new binary format, along with added the magic bytes
we use to distinguish the offloading binary to the `file_magic`
implementation.

Reviewed By: tra

Differential Revision: https://reviews.llvm.org/D126812
This commit is contained in:
Joseph Huber 2022-06-01 15:28:34 -04:00
parent 909a78b3a4
commit afd2f7e991
11 changed files with 67 additions and 37 deletions

View File

@ -1221,6 +1221,6 @@ void clang::EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts,
} }
llvm::embedBufferInModule(*M, **ObjectOrErr, ".llvm.offloading", llvm::embedBufferInModule(*M, **ObjectOrErr, ".llvm.offloading",
Align(OffloadBinary::getAlignment())); Align(object::OffloadBinary::getAlignment()));
} }
} }

View File

@ -38,21 +38,23 @@ typedef struct LLVMOpaqueSymbolIterator *LLVMSymbolIteratorRef;
typedef struct LLVMOpaqueRelocationIterator *LLVMRelocationIteratorRef; typedef struct LLVMOpaqueRelocationIterator *LLVMRelocationIteratorRef;
typedef enum { typedef enum {
LLVMBinaryTypeArchive, /**< Archive file. */ LLVMBinaryTypeArchive, /**< Archive file. */
LLVMBinaryTypeMachOUniversalBinary, /**< Mach-O Universal Binary file. */ LLVMBinaryTypeMachOUniversalBinary, /**< Mach-O Universal Binary file. */
LLVMBinaryTypeCOFFImportFile, /**< COFF Import file. */ LLVMBinaryTypeCOFFImportFile, /**< COFF Import file. */
LLVMBinaryTypeIR, /**< LLVM IR. */ LLVMBinaryTypeIR, /**< LLVM IR. */
LLVMBinaryTypeWinRes, /**< Windows resource (.res) file. */ LLVMBinaryTypeWinRes, /**< Windows resource (.res) file. */
LLVMBinaryTypeCOFF, /**< COFF Object file. */ LLVMBinaryTypeCOFF, /**< COFF Object file. */
LLVMBinaryTypeELF32L, /**< ELF 32-bit, little endian. */ LLVMBinaryTypeELF32L, /**< ELF 32-bit, little endian. */
LLVMBinaryTypeELF32B, /**< ELF 32-bit, big endian. */ LLVMBinaryTypeELF32B, /**< ELF 32-bit, big endian. */
LLVMBinaryTypeELF64L, /**< ELF 64-bit, little endian. */ LLVMBinaryTypeELF64L, /**< ELF 64-bit, little endian. */
LLVMBinaryTypeELF64B, /**< ELF 64-bit, big endian. */ LLVMBinaryTypeELF64B, /**< ELF 64-bit, big endian. */
LLVMBinaryTypeMachO32L, /**< MachO 32-bit, little endian. */ LLVMBinaryTypeMachO32L, /**< MachO 32-bit, little endian. */
LLVMBinaryTypeMachO32B, /**< MachO 32-bit, big endian. */ LLVMBinaryTypeMachO32B, /**< MachO 32-bit, big endian. */
LLVMBinaryTypeMachO64L, /**< MachO 64-bit, little endian. */ LLVMBinaryTypeMachO64L, /**< MachO 64-bit, little endian. */
LLVMBinaryTypeMachO64B, /**< MachO 64-bit, big endian. */ LLVMBinaryTypeMachO64B, /**< MachO 64-bit, big endian. */
LLVMBinaryTypeWasm, /**< Web Assembly. */ LLVMBinaryTypeWasm, /**< Web Assembly. */
LLVMBinaryTypeOffload, /**< Offloading fatbinary. */
} LLVMBinaryType; } LLVMBinaryType;
/** /**

View File

@ -52,6 +52,7 @@ struct file_magic {
pdb, ///< Windows PDB debug info file pdb, ///< Windows PDB debug info file
tapi_file, ///< Text-based Dynamic Library Stub file tapi_file, ///< Text-based Dynamic Library Stub file
cuda_fatbinary, ///< CUDA Fatbinary object file cuda_fatbinary, ///< CUDA Fatbinary object file
offload_binary, ///< LLVM offload object file
dxcontainer_object, ///< DirectX container file dxcontainer_object, ///< DirectX container file
}; };

View File

@ -69,6 +69,8 @@ protected:
ID_Wasm, ID_Wasm,
ID_Offload, // Offloading binary file.
ID_EndObjects ID_EndObjects
}; };
@ -133,6 +135,8 @@ public:
bool isWasm() const { return TypeID == ID_Wasm; } bool isWasm() const { return TypeID == ID_Wasm; }
bool isOffloadFile() const { return TypeID == ID_Offload; }
bool isCOFFImportFile() const { bool isCOFFImportFile() const {
return TypeID == ID_COFFImportFile; return TypeID == ID_COFFImportFile;
} }

View File

@ -19,12 +19,15 @@
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Object/Binary.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include <memory> #include <memory>
namespace llvm { namespace llvm {
namespace object {
/// The producer of the associated offloading image. /// The producer of the associated offloading image.
enum OffloadKind : uint16_t { enum OffloadKind : uint16_t {
OFK_None = 0, OFK_None = 0,
@ -54,7 +57,7 @@ enum ImageKind : uint16_t {
/// detect ABI stability and the size is used to find other offloading entries /// 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 /// that may exist in the same section. All offsets are given as absolute byte
/// offsets from the beginning of the file. /// offsets from the beginning of the file.
class OffloadBinary { class OffloadBinary : public Binary {
public: public:
/// The offloading metadata that will be serialized to a memory buffer. /// The offloading metadata that will be serialized to a memory buffer.
struct OffloadingImage { struct OffloadingImage {
@ -87,6 +90,8 @@ public:
StringRef getString(StringRef Key) const { return StringData.lookup(Key); } StringRef getString(StringRef Key) const { return StringData.lookup(Key); }
static bool classof(const Binary *V) { return V->isOffloadFile(); }
private: private:
struct Header { struct Header {
uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes. uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD}; // 0x10FF10AD magic bytes.
@ -111,10 +116,10 @@ private:
uint64_t ValueOffset; uint64_t ValueOffset;
}; };
OffloadBinary(const char *Buffer, const Header *TheHeader, OffloadBinary(MemoryBufferRef Source, const Header *TheHeader,
const Entry *TheEntry) const Entry *TheEntry)
: Buffer(Buffer), TheHeader(TheHeader), TheEntry(TheEntry) { : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()),
TheHeader(TheHeader), TheEntry(TheEntry) {
const StringEntry *StringMapBegin = const StringEntry *StringMapBegin =
reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]); reinterpret_cast<const StringEntry *>(&Buffer[TheEntry->StringOffset]);
for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) { for (uint64_t I = 0, E = TheEntry->NumStrings; I != E; ++I) {
@ -127,7 +132,7 @@ private:
/// Map from keys to offsets in the binary. /// Map from keys to offsets in the binary.
StringMap<StringRef> StringData; StringMap<StringRef> StringData;
/// Pointer to the beginning of the memory buffer for convenience. /// Raw pointer to the MemoryBufferRef for convenience.
const char *Buffer; const char *Buffer;
/// Location of the header within the binary. /// Location of the header within the binary.
const Header *TheHeader; const Header *TheHeader;
@ -147,5 +152,7 @@ OffloadKind getOffloadKind(StringRef Name);
/// Convert an offload kind to its string representation. /// Convert an offload kind to its string representation.
StringRef getOffloadKindName(OffloadKind Name); StringRef getOffloadKindName(OffloadKind Name);
} // namespace object
} // namespace llvm } // namespace llvm
#endif #endif

View File

@ -74,6 +74,11 @@ file_magic llvm::identify_magic(StringRef Magic) {
return file_magic::goff_object; return file_magic::goff_object;
break; break;
case 0x10:
if (startswith(Magic, "\x10\xFF\x10\xAD"))
return file_magic::offload_binary;
break;
case 0xDE: // 0x0B17C0DE = BC wraper case 0xDE: // 0x0B17C0DE = BC wraper
if (startswith(Magic, "\xDE\xC0\x17\x0B")) if (startswith(Magic, "\xDE\xC0\x17\x0B"))
return file_magic::bitcode; return file_magic::bitcode;

View File

@ -18,6 +18,7 @@
#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/Minidump.h" #include "llvm/Object/Minidump.h"
#include "llvm/Object/ObjectFile.h" #include "llvm/Object/ObjectFile.h"
#include "llvm/Object/OffloadBinary.h"
#include "llvm/Object/TapiUniversal.h" #include "llvm/Object/TapiUniversal.h"
#include "llvm/Object/WindowsResource.h" #include "llvm/Object/WindowsResource.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
@ -87,6 +88,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
case file_magic::dxcontainer_object: case file_magic::dxcontainer_object:
// Unrecognized object file format. // Unrecognized object file format.
return errorCodeToError(object_error::invalid_file_type); return errorCodeToError(object_error::invalid_file_type);
case file_magic::offload_binary:
return OffloadBinary::create(Buffer);
case file_magic::minidump: case file_magic::minidump:
return MinidumpFile::create(Buffer); return MinidumpFile::create(Buffer);
case file_magic::tapi_file: case file_magic::tapi_file:

View File

@ -120,6 +120,8 @@ LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) {
return LLVMBinaryTypeMachO64L; return LLVMBinaryTypeMachO64L;
case ID_MachO64B: case ID_MachO64B:
return LLVMBinaryTypeMachO64B; return LLVMBinaryTypeMachO64B;
case ID_Offload:
return LLVMBinaryTypeOffload;
case ID_Wasm: case ID_Wasm:
return LLVMBinaryTypeWasm; return LLVMBinaryTypeWasm;
case ID_StartObjects: case ID_StartObjects:

View File

@ -147,6 +147,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
case file_magic::minidump: case file_magic::minidump:
case file_magic::goff_object: case file_magic::goff_object:
case file_magic::cuda_fatbinary: case file_magic::cuda_fatbinary:
case file_magic::offload_binary:
case file_magic::dxcontainer_object: case file_magic::dxcontainer_object:
return errorCodeToError(object_error::invalid_file_type); return errorCodeToError(object_error::invalid_file_type);
case file_magic::tapi_file: case file_magic::tapi_file:

View File

@ -9,22 +9,23 @@
#include "llvm/Object/OffloadBinary.h" #include "llvm/Object/OffloadBinary.h"
#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringSwitch.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/MC/StringTableBuilder.h" #include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/Error.h" #include "llvm/Object/Error.h"
#include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileOutputBuffer.h"
using namespace llvm;
namespace llvm { namespace llvm {
namespace object {
Expected<std::unique_ptr<OffloadBinary>> Expected<std::unique_ptr<OffloadBinary>>
OffloadBinary::create(MemoryBufferRef Buf) { OffloadBinary::create(MemoryBufferRef Buf) {
if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry))
return errorCodeToError(llvm::object::object_error::parse_failed); return errorCodeToError(object_error::parse_failed);
// Check for 0x10FF1OAD magic bytes. // Check for 0x10FF1OAD magic bytes.
if (!Buf.getBuffer().startswith("\x10\xFF\x10\xAD")) if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary)
return errorCodeToError(llvm::object::object_error::parse_failed); return errorCodeToError(object_error::parse_failed);
const char *Start = Buf.getBufferStart(); const char *Start = Buf.getBufferStart();
const Header *TheHeader = reinterpret_cast<const Header *>(Start); const Header *TheHeader = reinterpret_cast<const Header *>(Start);
@ -32,7 +33,7 @@ OffloadBinary::create(MemoryBufferRef Buf) {
reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]);
return std::unique_ptr<OffloadBinary>( return std::unique_ptr<OffloadBinary>(
new OffloadBinary(Buf.getBufferStart(), TheHeader, TheEntry)); new OffloadBinary(Buf, TheHeader, TheEntry));
} }
std::unique_ptr<MemoryBuffer> std::unique_ptr<MemoryBuffer>
@ -141,4 +142,6 @@ StringRef getImageKindName(ImageKind Kind) {
} }
} }
} // namespace object
} // namespace llvm } // namespace llvm

View File

@ -4,6 +4,9 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <random> #include <random>
using namespace llvm;
using namespace llvm::object;
TEST(OffloadingTest, checkOffloadingBinary) { TEST(OffloadingTest, checkOffloadingBinary) {
// Create random data to fill the image. // Create random data to fill the image.
std::mt19937 Rng(std::random_device{}()); std::mt19937 Rng(std::random_device{}());
@ -27,23 +30,22 @@ TEST(OffloadingTest, checkOffloadingBinary) {
} }
// Create the image. // Create the image.
llvm::StringMap<llvm::StringRef> StringData; StringMap<StringRef> StringData;
for (auto &KeyAndValue : Strings) for (auto &KeyAndValue : Strings)
StringData[KeyAndValue.first] = KeyAndValue.second; StringData[KeyAndValue.first] = KeyAndValue.second;
std::unique_ptr<llvm::MemoryBuffer> ImageData = std::unique_ptr<MemoryBuffer> ImageData = MemoryBuffer::getMemBuffer(
llvm::MemoryBuffer::getMemBuffer( {reinterpret_cast<char *>(Image.data()), Image.size()}, "", false);
{reinterpret_cast<char *>(Image.data()), Image.size()}, "", false);
llvm::OffloadBinary::OffloadingImage Data; OffloadBinary::OffloadingImage Data;
Data.TheImageKind = static_cast<llvm::ImageKind>(KindDist(Rng)); Data.TheImageKind = static_cast<ImageKind>(KindDist(Rng));
Data.TheOffloadKind = static_cast<llvm::OffloadKind>(KindDist(Rng)); Data.TheOffloadKind = static_cast<OffloadKind>(KindDist(Rng));
Data.Flags = KindDist(Rng); Data.Flags = KindDist(Rng);
Data.StringData = StringData; Data.StringData = StringData;
Data.Image = *ImageData; Data.Image = *ImageData;
auto BinaryBuffer = llvm::OffloadBinary::write(Data); auto BinaryBuffer = OffloadBinary::write(Data);
auto BinaryOrErr = llvm::OffloadBinary::create(*BinaryBuffer); auto BinaryOrErr = OffloadBinary::create(*BinaryBuffer);
if (!BinaryOrErr) if (!BinaryOrErr)
FAIL(); FAIL();
@ -60,6 +62,6 @@ TEST(OffloadingTest, checkOffloadingBinary) {
EXPECT_TRUE(Data.Image.getBuffer() == Binary.getImage()); EXPECT_TRUE(Data.Image.getBuffer() == Binary.getImage());
// Ensure the size and alignment of the data is correct. // Ensure the size and alignment of the data is correct.
EXPECT_TRUE(Binary.getSize() % llvm::OffloadBinary::getAlignment() == 0); EXPECT_TRUE(Binary.getSize() % OffloadBinary::getAlignment() == 0);
EXPECT_TRUE(Binary.getSize() == BinaryBuffer->getBuffer().size()); EXPECT_TRUE(Binary.getSize() == BinaryBuffer->getBuffer().size());
} }