forked from OSchip/llvm-project
[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:
parent
909a78b3a4
commit
afd2f7e991
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,8 @@ typedef enum {
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue