[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-04-14 Thread Joseph Huber via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe471ba3d0122: [Object] Add binary format for bundling 
offloading metadata (authored by jhuber6).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

Files:
  llvm/include/llvm/Object/OffloadBinary.h
  llvm/lib/Object/CMakeLists.txt
  llvm/lib/Object/OffloadBinary.cpp
  llvm/unittests/Object/CMakeLists.txt
  llvm/unittests/Object/OffloadingTest.cpp

Index: llvm/unittests/Object/OffloadingTest.cpp
===
--- /dev/null
+++ llvm/unittests/Object/OffloadingTest.cpp
@@ -0,0 +1,65 @@
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+#include 
+
+TEST(OffloadingTest, checkOffloadingBinary) {
+  // Create random data to fill the image.
+  std::mt19937 Rng(std::random_device{}());
+  std::uniform_int_distribution SizeDist(0, 256);
+  std::uniform_int_distribution KindDist(0);
+  std::uniform_int_distribution BinaryDist(
+  std::numeric_limits::min(), std::numeric_limits::max());
+  std::uniform_int_distribution StringDist('!', '~');
+  std::vector Image(SizeDist(Rng));
+  std::generate(Image.begin(), Image.end(), [&]() { return BinaryDist(Rng); });
+  std::vector> Strings(SizeDist(Rng));
+  for (auto  : Strings) {
+std::string Key(SizeDist(Rng), '\0');
+std::string Value(SizeDist(Rng), '\0');
+
+std::generate(Key.begin(), Key.end(), [&]() { return StringDist(Rng); });
+std::generate(Value.begin(), Value.end(),
+  [&]() { return StringDist(Rng); });
+
+KeyAndValue = std::make_pair(Key, Value);
+  }
+
+  // Create the image.
+  llvm::StringMap StringData;
+  for (auto  : Strings)
+StringData[KeyAndValue.first] = KeyAndValue.second;
+  std::unique_ptr ImageData =
+  llvm::MemoryBuffer::getMemBuffer(
+  {reinterpret_cast(Image.data()), Image.size()}, "", false);
+
+  llvm::OffloadBinary::OffloadingImage Data;
+  Data.TheImageKind = static_cast(KindDist(Rng));
+  Data.TheOffloadKind = static_cast(KindDist(Rng));
+  Data.Flags = KindDist(Rng);
+  Data.StringData = StringData;
+  Data.Image = *ImageData;
+
+  auto BinaryBuffer = llvm::OffloadBinary::write(Data);
+
+  auto BinaryOrErr = llvm::OffloadBinary::create(*BinaryBuffer);
+  if (!BinaryOrErr)
+FAIL();
+
+  // Make sure we get the same data out.
+  auto  = **BinaryOrErr;
+  ASSERT_EQ(Data.TheImageKind, Binary.getImageKind());
+  ASSERT_EQ(Data.TheOffloadKind, Binary.getOffloadKind());
+  ASSERT_EQ(Data.Flags, Binary.getFlags());
+
+  for (auto  : Strings)
+ASSERT_TRUE(StringData[KeyAndValue.first] ==
+Binary.getString(KeyAndValue.first));
+
+  EXPECT_TRUE(Data.Image.getBuffer() == Binary.getImage());
+
+  // Ensure the size and alignment of the data is correct.
+  EXPECT_TRUE(Binary.getSize() % llvm::OffloadBinary::getAlignment() == 0);
+  EXPECT_TRUE(Binary.getSize() == BinaryBuffer->getBuffer().size());
+}
Index: llvm/unittests/Object/CMakeLists.txt
===
--- llvm/unittests/Object/CMakeLists.txt
+++ llvm/unittests/Object/CMakeLists.txt
@@ -11,6 +11,7 @@
   ELFTest.cpp
   MinidumpTest.cpp
   ObjectFileTest.cpp
+  OffloadingTest.cpp
   SymbolSizeTest.cpp
   SymbolicFileTest.cpp
   XCOFFObjectFileTest.cpp
Index: llvm/lib/Object/OffloadBinary.cpp
===
--- /dev/null
+++ llvm/lib/Object/OffloadBinary.cpp
@@ -0,0 +1,144 @@
+//===- Offloading.cpp - 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
+//
+//===--===//
+
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+Expected>
+OffloadBinary::create(MemoryBufferRef Buf) {
+  if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  // Check for 0x10FF1OAD magic bytes.
+  if (!Buf.getBuffer().startswith("\x10\xFF\x10\xAD"))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  const char *Start = Buf.getBufferStart();
+  const Header *TheHeader = reinterpret_cast(Start);
+  const Entry *TheEntry =
+  reinterpret_cast([TheHeader->EntryOffset]);
+
+  return std::unique_ptr(
+  new OffloadBinary(Buf.getBufferStart(), TheHeader, TheEntry));
+}
+
+std::unique_ptr
+OffloadBinary::write(const 

[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-04-13 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 422544.
jhuber6 added a comment.

Maxing suggested changes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

Files:
  llvm/include/llvm/Object/OffloadBinary.h
  llvm/lib/Object/CMakeLists.txt
  llvm/lib/Object/OffloadBinary.cpp
  llvm/unittests/Object/CMakeLists.txt
  llvm/unittests/Object/OffloadingTest.cpp

Index: llvm/unittests/Object/OffloadingTest.cpp
===
--- /dev/null
+++ llvm/unittests/Object/OffloadingTest.cpp
@@ -0,0 +1,65 @@
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+#include 
+
+TEST(OffloadingTest, checkOffloadingBinary) {
+  // Create random data to fill the image.
+  std::mt19937 Rng(std::random_device{}());
+  std::uniform_int_distribution SizeDist(0, 256);
+  std::uniform_int_distribution KindDist(0);
+  std::uniform_int_distribution BinaryDist(
+  std::numeric_limits::min(), std::numeric_limits::max());
+  std::uniform_int_distribution StringDist('!', '~');
+  std::vector Image(SizeDist(Rng));
+  std::generate(Image.begin(), Image.end(), [&]() { return BinaryDist(Rng); });
+  std::vector> Strings(SizeDist(Rng));
+  for (auto  : Strings) {
+std::string Key(SizeDist(Rng), '\0');
+std::string Value(SizeDist(Rng), '\0');
+
+std::generate(Key.begin(), Key.end(), [&]() { return StringDist(Rng); });
+std::generate(Value.begin(), Value.end(),
+  [&]() { return StringDist(Rng); });
+
+KeyAndValue = std::make_pair(Key, Value);
+  }
+
+  // Create the image.
+  llvm::StringMap StringData;
+  for (auto  : Strings)
+StringData[KeyAndValue.first] = KeyAndValue.second;
+  std::unique_ptr ImageData =
+  llvm::MemoryBuffer::getMemBuffer(
+  {reinterpret_cast(Image.data()), Image.size()}, "", false);
+
+  llvm::OffloadBinary::OffloadingImage Data;
+  Data.TheImageKind = static_cast(KindDist(Rng));
+  Data.TheOffloadKind = static_cast(KindDist(Rng));
+  Data.Flags = KindDist(Rng);
+  Data.StringData = StringData;
+  Data.Image = *ImageData;
+
+  auto BinaryBuffer = llvm::OffloadBinary::write(Data);
+
+  auto BinaryOrErr = llvm::OffloadBinary::create(*BinaryBuffer);
+  if (!BinaryOrErr)
+FAIL();
+
+  // Make sure we get the same data out.
+  auto  = **BinaryOrErr;
+  ASSERT_EQ(Data.TheImageKind, Binary.getImageKind());
+  ASSERT_EQ(Data.TheOffloadKind, Binary.getOffloadKind());
+  ASSERT_EQ(Data.Flags, Binary.getFlags());
+
+  for (auto  : Strings)
+ASSERT_TRUE(StringData[KeyAndValue.first] ==
+Binary.getString(KeyAndValue.first));
+
+  EXPECT_TRUE(Data.Image.getBuffer() == Binary.getImage());
+
+  // Ensure the size and alignment of the data is correct.
+  EXPECT_TRUE(Binary.getSize() % llvm::OffloadBinary::getAlignment() == 0);
+  EXPECT_TRUE(Binary.getSize() == BinaryBuffer->getBuffer().size());
+}
Index: llvm/unittests/Object/CMakeLists.txt
===
--- llvm/unittests/Object/CMakeLists.txt
+++ llvm/unittests/Object/CMakeLists.txt
@@ -11,6 +11,7 @@
   ELFTest.cpp
   MinidumpTest.cpp
   ObjectFileTest.cpp
+  OffloadingTest.cpp
   SymbolSizeTest.cpp
   SymbolicFileTest.cpp
   XCOFFObjectFileTest.cpp
Index: llvm/lib/Object/OffloadBinary.cpp
===
--- /dev/null
+++ llvm/lib/Object/OffloadBinary.cpp
@@ -0,0 +1,144 @@
+//===- Offloading.cpp - 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
+//
+//===--===//
+
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+Expected>
+OffloadBinary::create(MemoryBufferRef Buf) {
+  if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  // Check for 0x10FF1OAD magic bytes.
+  if (!Buf.getBuffer().startswith("\x10\xFF\x10\xAD"))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  const char *Start = Buf.getBufferStart();
+  const Header *TheHeader = reinterpret_cast(Start);
+  const Entry *TheEntry =
+  reinterpret_cast([TheHeader->EntryOffset]);
+
+  return std::unique_ptr(
+  new OffloadBinary(Buf.getBufferStart(), TheHeader, TheEntry));
+}
+
+std::unique_ptr
+OffloadBinary::write(const OffloadingImage ) {
+  // Create a null-terminated string table with all the used strings.
+  StringTableBuilder StrTab(StringTableBuilder::ELF);
+  for (auto  

[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-04-13 Thread Jon Chesterfield via Phabricator via cfe-commits
JonChesterfield accepted this revision.
JonChesterfield added a comment.
This revision is now accepted and ready to land.

Couple of nits above but basically I'm convinced. The gnarly part of binary 
formats is string tables and I'm delighted that part of MC was readily 
reusable. Wrapping the string table in different bytes to align with the elf 
format may still be a good idea but it's not an obvious correctness hazard.

I like msgpack as a format but the writing machinery in llvm is not very 
reusable. Likewise elf is a great format but quite interwoven with MC. Protobuf 
seems to have the nice property of concatenating objects yielding a valid 
protobuf but the cost of codegen that isn't presently part of the llvm core, 
and is a slightly hairy dependency to pull in.

Medium term, factoring out parts of the elf handling for use here (and in lld?) 
is probably reasonable, but the leading magic bytes here are sufficient that we 
could detect that in backwards-compat fashion if the release gets ahead of us. 
The format here is essentially a string map which is likely to meet future 
requirements from other platforms adequately.

Thanks for sticking with this!




Comment at: llvm/include/llvm/Object/OffloadBinary.h:74
+
+  uint16_t getImageKind() const { return TheEntry->ImageKind; }
+  uint16_t getOffloadKind() const { return TheEntry->OffloadKind; }

these should probably be returning the enum types



Comment at: llvm/include/llvm/Object/OffloadBinary.h:97
+  struct Entry {
+uint16_t ImageKind;// The kind of the image stored.
+uint16_t OffloadKind;  // The producer of this image.

enums here as well? They have uint16_t specified in the type so layout is stable



Comment at: llvm/lib/Object/OffloadBinary.cpp:20
+
+Expected>
+OffloadBinary::create(MemoryBufferRef Buf) {

Not sure Expected<> helps hugely here - stuff only goes wrong as 'parse_failed' 
or failed to allocate, which is kind of the same thing - so we could return a 
default-initialized (null) unique_ptr on failure without loss of information



Comment at: llvm/lib/Object/OffloadBinary.cpp:41
+  // Create a null-terminated string table with all the used strings.
+  StringTableBuilder StrTab(StringTableBuilder::ELF);
+  for (auto  : OffloadingData.StringData) {

this is good, string table building is by far the most tedious part of formats 
like this


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-04-11 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added a comment.

ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-31 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added a comment.

Ping, I'd like to finalize the new driver in time for the GPU newsletter and 
the LLVM Performance Workshop at CGO.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-30 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added a comment.

In D122069#3416694 , @saiislam wrote:

> Hey @jhuber6 , as discussed in multi-company meeting, I think that we will 
> need at least an arch field somewhere in this. We would like to create 
> multi-arch binaries so that runtime can load the compatible one on its own.
> You may even consider using TargetID Format 
>  to store the 
> list of archs.

The binary format contains a string map along with some integer fields. I have 
the `getArch()` function in the binary that just extracts the value get the 
`"arch"` key. This makes it easy to add some arbitrary data so I was planning 
on simply adding a `"features"` key as well. Then we can extract the associated 
image features and decide what to do with the image. I haven't thought of a 
good solution for allowing multiple compatible architectures, maybe a comma 
separated list of architectures. You can see the proposed usage right now in 
D122683  but more will be added.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-30 Thread Saiyedul Islam via Phabricator via cfe-commits
saiislam added a comment.

Hey @jhuber6 , as discussed in multi-company meeting, I think that we will need 
at least an arch field somewhere in this. We would like to create multi-arch 
binaries so that runtime can load the compatible one on its own.
You may even consider using TargetID Format 
 to store the 
list of archs.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-29 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added a comment.

In D122069#3413960 , @JonChesterfield 
wrote:

> Added some reviewers. I'd much prefer this used an existing binary format, 
> DIY is prone to errors and maintenance hassles down the road. Don't care as 
> much about which format as about it being one with an existing, tested 
> implementation and ideally existing inspection tools.

I'm not married to the idea, and worst case scenario we can replace it with 
something else in the future. I'd like to get something like this working so I 
can finally make the new driver the default, so I'll just outline the problem 
and some of the potential solutions.

The issue is that we need to store some metadata along with a binary image so 
we know how to handle it at a later date. Currently we shove this in the name 
of the ELF section and parse it there, but that's not idea because more 
metadata will be needed in the future and it prevents us from doing things like 
relocatable linking or other merging (e.g. we want to store both an sm_70 and 
sm_35 image in the same file). So we want a binary format that can store some 
strings, other data. I'll just go over a brief overview of the options:

YAML / JSON
---

+ Ubiquitous simple text format for encoding object data
+ In-tree implementation
x Requires encoding to store the device image
x Will need binary padding and size calculation to make sure these merge 
properly in a section

Protocol Buffers


+ Well-tested
+ Implicit appending, no additional code required to handle merged sections.
x Out-of-tree, requires external dependencies to build and maintain in the 
future. No other use in Clang / LLVM

ELF
---

+ Ubiquitous tooling. Object extraction and copying for free
+ Simple key-value storage 
x Difficult to calculate size, will need to figure out the size of the buffer 
and write it in later so we can read multiple appended sections.
x Difficult to create. The Elf object writer is completely tied to the MC 
backend. YAML2ELF would require base64 or similar again

MSGPACK
---

+ Exists in-tree in some form and well tested
+ Supports key-value storage
x Doesn't know its size, will need to add padding and a size field

Custom format
-

+ Relatively simple implementation that solves this specific problem
x No existing tooling support, more error prone

I decided to go with the custom format because it was the simplest to get 
working for a proof of concept to solve the problem I was immediately facing. I 
think ELF would be the next best if someones could suggest a way to write the 
data and get the size. MSGPACK seems to be @JonChesterfield's preferred method 
because it has a lot of use at AMD, it would work as long as we can figure out 
its size and get alignment. Let me know what suggestions you have because I 
really want to move forward with this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-29 Thread Jon Chesterfield via Phabricator via cfe-commits
JonChesterfield added reviewers: grokos, ABataev, ronlieb, tianshilei1992.
JonChesterfield added a comment.

Added some reviewers. I'd much prefer this used an existing binary format, DIY 
is prone to errors and maintenance hassles down the road. Don't care as much 
about which format as about it being one with an existing, tested 
implementation and ideally existing inspection tools.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122069: [Object] Add binary format for bundling offloading metadata

2022-03-25 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 418255.
jhuber6 added a comment.

Changing test, `uniform_int_distribution` doesn't support `char` or `uint8_t` 
according to the standard.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122069/new/

https://reviews.llvm.org/D122069

Files:
  llvm/include/llvm/Object/OffloadBinary.h
  llvm/lib/Object/CMakeLists.txt
  llvm/lib/Object/OffloadBinary.cpp
  llvm/unittests/Object/CMakeLists.txt
  llvm/unittests/Object/OffloadingTest.cpp

Index: llvm/unittests/Object/OffloadingTest.cpp
===
--- /dev/null
+++ llvm/unittests/Object/OffloadingTest.cpp
@@ -0,0 +1,67 @@
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+#include 
+
+TEST(OffloadingTest, checkOffloadingBinary) {
+  // Create random data to fill the image.
+  std::mt19937 Rng(std::random_device{}());
+  std::uniform_int_distribution SizeDist(0, 256);
+  std::uniform_int_distribution KindDist(0);
+  std::uniform_int_distribution BinaryDist(
+  std::numeric_limits::min(), std::numeric_limits::max());
+  std::uniform_int_distribution StringDist('!', '~');
+  std::vector Image(SizeDist(Rng));
+  std::generate(Image.begin(), Image.end(), [&]() { return BinaryDist(Rng); });
+  std::vector> Strings(SizeDist(Rng));
+  for (auto  : Strings) {
+std::string Key(SizeDist(Rng), '\0');
+std::string Value(SizeDist(Rng), '\0');
+
+std::generate(Key.begin(), Key.end(), [&]() { return StringDist(Rng); });
+std::generate(Value.begin(), Value.end(),
+  [&]() { return StringDist(Rng); });
+
+KeyAndValue = std::make_pair(Key, Value);
+  }
+
+  // Create the image.
+  llvm::StringMap StringData;
+  for (auto  : Strings)
+StringData[KeyAndValue.first] = KeyAndValue.second;
+  std::unique_ptr ImageData =
+  llvm::MemoryBuffer::getMemBuffer(
+  {reinterpret_cast(Image.data()), Image.size()}, "", false);
+
+  llvm::OffloadBinary::OffloadingImage Data;
+  Data.TheImageKind = static_cast(KindDist(Rng));
+  Data.TheOffloadKind = static_cast(KindDist(Rng));
+  Data.Flags = KindDist(Rng);
+  Data.StringData = StringData;
+  Data.Image = *ImageData;
+
+  auto BinaryBuffer = llvm::OffloadBinary::write(Data);
+
+  auto BinaryOrErr = llvm::OffloadBinary::create(*BinaryBuffer);
+  if (!BinaryOrErr)
+FAIL();
+
+  // Make sure we get the same data out.
+  auto  = **BinaryOrErr;
+  ASSERT_EQ(Data.TheImageKind,
+static_cast(Binary.getImageKind()));
+  ASSERT_EQ(Data.TheOffloadKind,
+static_cast(Binary.getOffloadKind()));
+  ASSERT_EQ(Data.Flags, Binary.getFlags());
+
+  for (auto  : Strings)
+ASSERT_TRUE(StringData[KeyAndValue.first] ==
+Binary.getString(KeyAndValue.first));
+
+  EXPECT_TRUE(Data.Image.getBuffer() == Binary.getImage());
+
+  // Ensure the size and alignment of the data is correct.
+  EXPECT_TRUE(Binary.getSize() % llvm::OffloadBinary::getAlignment() == 0);
+  EXPECT_TRUE(Binary.getSize() == BinaryBuffer->getBuffer().size());
+}
Index: llvm/unittests/Object/CMakeLists.txt
===
--- llvm/unittests/Object/CMakeLists.txt
+++ llvm/unittests/Object/CMakeLists.txt
@@ -11,6 +11,7 @@
   ELFTest.cpp
   MinidumpTest.cpp
   ObjectFileTest.cpp
+  OffloadingTest.cpp
   SymbolSizeTest.cpp
   SymbolicFileTest.cpp
   XCOFFObjectFileTest.cpp
Index: llvm/lib/Object/OffloadBinary.cpp
===
--- /dev/null
+++ llvm/lib/Object/OffloadBinary.cpp
@@ -0,0 +1,144 @@
+//===- Offloading.cpp - 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
+//
+//===--===//
+
+#include "llvm/Object/OffloadBinary.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+Expected>
+OffloadBinary::create(MemoryBufferRef Buf) {
+  if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  // Check for 0x10FF1OAD magic bytes.
+  if (!Buf.getBuffer().startswith("\x10\xFF\x10\xAD"))
+return errorCodeToError(llvm::object::object_error::parse_failed);
+
+  const char *Start = Buf.getBufferStart();
+  const Header *TheHeader = reinterpret_cast(Start);
+  const Entry *TheEntry =
+  reinterpret_cast([TheHeader->EntryOffset]);
+
+  return std::unique_ptr(
+  new OffloadBinary(Buf.getBufferStart(), TheHeader, TheEntry));
+}
+
+std::unique_ptr
+OffloadBinary::write(const OffloadingImage ) {
+  //