[llvm] 228c8f9 - [ObjectYAML] Add offloading binary implementations for obj2yaml and yaml2obj

Joseph Huber via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 1 18:13:42 PDT 2022


Author: Joseph Huber
Date: 2022-07-01T21:13:18-04:00
New Revision: 228c8f9cc0b2bf615706567f121a422b1b0e7f83

URL: https://github.com/llvm/llvm-project/commit/228c8f9cc0b2bf615706567f121a422b1b0e7f83
DIFF: https://github.com/llvm/llvm-project/commit/228c8f9cc0b2bf615706567f121a422b1b0e7f83.diff

LOG: [ObjectYAML] Add offloading binary implementations for obj2yaml and yaml2obj

This patchs adds the necessary code for inspecting or creating offloading
binaries using the standing `obj2yaml` and `yaml2obj` features in LLVM.

Depends on D127774

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D127776

Added: 
    llvm/include/llvm/ObjectYAML/OffloadYAML.h
    llvm/lib/ObjectYAML/OffloadEmitter.cpp
    llvm/lib/ObjectYAML/OffloadYAML.cpp
    llvm/test/ObjectYAML/Offload/binary.yaml
    llvm/test/ObjectYAML/Offload/default.yaml
    llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml
    llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml
    llvm/test/ObjectYAML/Offload/malformed-offset.yaml
    llvm/test/ObjectYAML/Offload/malformed-size.yaml
    llvm/test/ObjectYAML/Offload/malformed-version.yaml
    llvm/test/ObjectYAML/Offload/multiple_members.yaml
    llvm/tools/obj2yaml/offload2yaml.cpp

Modified: 
    llvm/include/llvm/Object/OffloadBinary.h
    llvm/include/llvm/ObjectYAML/ObjectYAML.h
    llvm/include/llvm/ObjectYAML/yaml2obj.h
    llvm/lib/ObjectYAML/CMakeLists.txt
    llvm/lib/ObjectYAML/ObjectYAML.cpp
    llvm/lib/ObjectYAML/yaml2obj.cpp
    llvm/tools/obj2yaml/CMakeLists.txt
    llvm/tools/obj2yaml/obj2yaml.cpp
    llvm/tools/obj2yaml/obj2yaml.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/OffloadBinary.h b/llvm/include/llvm/Object/OffloadBinary.h
index 17e5a062d0262..5afc3ed295aef 100644
--- a/llvm/include/llvm/Object/OffloadBinary.h
+++ b/llvm/include/llvm/Object/OffloadBinary.h
@@ -103,7 +103,6 @@ class OffloadBinary : public Binary {
 
   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 = OffloadBinary::Version;   // Version identifier.
@@ -127,6 +126,7 @@ class OffloadBinary : public Binary {
     uint64_t ValueOffset;
   };
 
+private:
   OffloadBinary(MemoryBufferRef Source, const Header *TheHeader,
                 const Entry *TheEntry)
       : Binary(Binary::ID_Offload, Source), Buffer(Source.getBufferStart()),

diff  --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
index bc9d76b36fd97..b63607e6796b0 100644
--- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
@@ -15,6 +15,7 @@
 #include "llvm/ObjectYAML/ELFYAML.h"
 #include "llvm/ObjectYAML/MachOYAML.h"
 #include "llvm/ObjectYAML/MinidumpYAML.h"
+#include "llvm/ObjectYAML/OffloadYAML.h"
 #include "llvm/ObjectYAML/WasmYAML.h"
 #include "llvm/ObjectYAML/XCOFFYAML.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -32,6 +33,7 @@ struct YamlObjectFile {
   std::unique_ptr<MachOYAML::Object> MachO;
   std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
   std::unique_ptr<MinidumpYAML::Object> Minidump;
+  std::unique_ptr<OffloadYAML::Binary> Offload;
   std::unique_ptr<WasmYAML::Object> Wasm;
   std::unique_ptr<XCOFFYAML::Object> Xcoff;
   std::unique_ptr<DXContainerYAML::Object> DXContainer;

diff  --git a/llvm/include/llvm/ObjectYAML/OffloadYAML.h b/llvm/include/llvm/ObjectYAML/OffloadYAML.h
new file mode 100644
index 0000000000000..a4fdbce0b320c
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/OffloadYAML.h
@@ -0,0 +1,79 @@
+//===- OffloadYAML.h - Offload Binary YAMLIO implementation -----*- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares classes for handling the YAML representation of
+/// offloading binaries.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_OFFLOADYAML_H
+#define LLVM_OBJECTYAML_OFFLOADYAML_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Object/OffloadBinary.h"
+#include "llvm/ObjectYAML/YAML.h"
+#include "llvm/Support/YAMLTraits.h"
+
+namespace llvm {
+namespace OffloadYAML {
+
+struct Binary {
+  struct StringEntry {
+    StringRef Key;
+    StringRef Value;
+  };
+
+  struct Member {
+    Optional<object::ImageKind> ImageKind;
+    Optional<object::OffloadKind> OffloadKind;
+    Optional<uint32_t> Flags;
+    Optional<std::vector<StringEntry>> StringEntries;
+    Optional<yaml::BinaryRef> Content;
+  };
+
+  Optional<uint32_t> Version;
+  Optional<uint64_t> Size;
+  Optional<uint64_t> EntryOffset;
+  Optional<uint64_t> EntrySize;
+  std::vector<Member> Members;
+};
+
+} // end namespace OffloadYAML
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::OffloadYAML::Binary::Member)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::OffloadYAML::Binary::StringEntry)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct ScalarEnumerationTraits<object::ImageKind> {
+  static void enumeration(IO &IO, object::ImageKind &Value);
+};
+
+template <> struct ScalarEnumerationTraits<object::OffloadKind> {
+  static void enumeration(IO &IO, object::OffloadKind &Value);
+};
+
+template <> struct MappingTraits<OffloadYAML::Binary> {
+  static void mapping(IO &IO, OffloadYAML::Binary &O);
+};
+
+template <> struct MappingTraits<OffloadYAML::Binary::StringEntry> {
+  static void mapping(IO &IO, OffloadYAML::Binary::StringEntry &M);
+};
+
+template <> struct MappingTraits<OffloadYAML::Binary::Member> {
+  static void mapping(IO &IO, OffloadYAML::Binary::Member &M);
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_ARCHIVEYAML_H

diff  --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index da12b75ba2253..000da077bb18c 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -36,6 +36,10 @@ namespace MinidumpYAML {
 struct Object;
 }
 
+namespace OffloadYAML {
+struct Binary;
+}
+
 namespace WasmYAML {
 struct Object;
 }
@@ -65,6 +69,7 @@ bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
 bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out,
                    ErrorHandler EH);
+bool yaml2offload(OffloadYAML::Binary &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2wasm(WasmYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,

diff  --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt
index 818a174c61938..15f8d8528ad76 100644
--- a/llvm/lib/ObjectYAML/CMakeLists.txt
+++ b/llvm/lib/ObjectYAML/CMakeLists.txt
@@ -18,6 +18,8 @@ add_llvm_component_library(LLVMObjectYAML
   ObjectYAML.cpp
   MinidumpEmitter.cpp
   MinidumpYAML.cpp
+  OffloadEmitter.cpp
+  OffloadYAML.cpp
   WasmEmitter.cpp
   WasmYAML.cpp
   XCOFFEmitter.cpp

diff  --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp
index 8d7220506b0da..d57e5583016b5 100644
--- a/llvm/lib/ObjectYAML/ObjectYAML.cpp
+++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp
@@ -56,6 +56,9 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
     } else if (IO.mapTag("!minidump")) {
       ObjectFile.Minidump.reset(new MinidumpYAML::Object());
       MappingTraits<MinidumpYAML::Object>::mapping(IO, *ObjectFile.Minidump);
+    } else if (IO.mapTag("!Offload")) {
+      ObjectFile.Offload.reset(new OffloadYAML::Binary());
+      MappingTraits<OffloadYAML::Binary>::mapping(IO, *ObjectFile.Offload);
     } else if (IO.mapTag("!WASM")) {
       ObjectFile.Wasm.reset(new WasmYAML::Object());
       MappingTraits<WasmYAML::Object>::mapping(IO, *ObjectFile.Wasm);

diff  --git a/llvm/lib/ObjectYAML/OffloadEmitter.cpp b/llvm/lib/ObjectYAML/OffloadEmitter.cpp
new file mode 100644
index 0000000000000..3ffbc4ff0e11e
--- /dev/null
+++ b/llvm/lib/ObjectYAML/OffloadEmitter.cpp
@@ -0,0 +1,68 @@
+//===- OffloadEmitter.cpp -------------------------------------------------===//
+//
+// 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/ObjectYAML/OffloadYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace OffloadYAML;
+
+namespace llvm {
+namespace yaml {
+
+bool yaml2offload(Binary &Doc, raw_ostream &Out, ErrorHandler EH) {
+  for (const auto &Member : Doc.Members) {
+    object::OffloadBinary::OffloadingImage Image{};
+    if (Member.ImageKind)
+      Image.TheImageKind = *Member.ImageKind;
+    if (Member.OffloadKind)
+      Image.TheOffloadKind = *Member.OffloadKind;
+    if (Member.Flags)
+      Image.Flags = *Member.Flags;
+
+    StringMap<StringRef> &StringData = Image.StringData;
+    if (Member.StringEntries) {
+      for (const auto &Entry : *Member.StringEntries) {
+        StringData[Entry.Key] = Entry.Value;
+      }
+    }
+
+    SmallVector<char, 1024> Data;
+    raw_svector_ostream OS(Data);
+    if (Member.Content)
+      Member.Content->writeAsBinary(OS);
+    Image.Image = MemoryBuffer::getMemBufferCopy(OS.str());
+
+    std::unique_ptr<MemoryBuffer> Binary = object::OffloadBinary::write(Image);
+
+    // Copy the data to a new buffer so we can modify the bytes directly.
+    SmallVector<char> NewBuffer;
+    std::copy(Binary->getBufferStart(), Binary->getBufferEnd(),
+              std::back_inserter(NewBuffer));
+    auto *TheHeader =
+        reinterpret_cast<object::OffloadBinary::Header *>(&NewBuffer[0]);
+    if (Doc.Version)
+      TheHeader->Version = *Doc.Version;
+    if (Doc.Size)
+      TheHeader->Size = *Doc.Size;
+    if (Doc.EntryOffset)
+      TheHeader->EntryOffset = *Doc.EntryOffset;
+    if (Doc.EntrySize)
+      TheHeader->EntrySize = *Doc.EntrySize;
+
+    Out.write(NewBuffer.begin(), NewBuffer.size());
+  }
+
+  return true;
+}
+
+} // namespace yaml
+} // namespace llvm

diff  --git a/llvm/lib/ObjectYAML/OffloadYAML.cpp b/llvm/lib/ObjectYAML/OffloadYAML.cpp
new file mode 100644
index 0000000000000..d5a0edde2179f
--- /dev/null
+++ b/llvm/lib/ObjectYAML/OffloadYAML.cpp
@@ -0,0 +1,78 @@
+//===- OffloadYAML.cpp - Offload Binary YAMLIO implementation -------------===//
+//
+// 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 defines classes for handling the YAML representation of offload
+// binaries.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ObjectYAML/OffloadYAML.h>
+
+namespace llvm {
+
+namespace yaml {
+
+void ScalarEnumerationTraits<object::ImageKind>::enumeration(
+    IO &IO, object::ImageKind &Value) {
+#define ECase(X) IO.enumCase(Value, #X, object::X)
+  ECase(IMG_None);
+  ECase(IMG_Object);
+  ECase(IMG_Bitcode);
+  ECase(IMG_Cubin);
+  ECase(IMG_Fatbinary);
+  ECase(IMG_PTX);
+  ECase(IMG_LAST);
+#undef ECase
+  IO.enumFallback<Hex16>(Value);
+}
+
+void ScalarEnumerationTraits<object::OffloadKind>::enumeration(
+    IO &IO, object::OffloadKind &Value) {
+#define ECase(X) IO.enumCase(Value, #X, object::X)
+  ECase(OFK_None);
+  ECase(OFK_OpenMP);
+  ECase(OFK_Cuda);
+  ECase(OFK_HIP);
+  ECase(OFK_LAST);
+#undef ECase
+  IO.enumFallback<Hex16>(Value);
+}
+
+void MappingTraits<OffloadYAML::Binary>::mapping(IO &IO,
+                                                 OffloadYAML::Binary &O) {
+  assert(!IO.getContext() && "The IO context is initialized already");
+  IO.setContext(&O);
+  IO.mapTag("!Offload", true);
+  IO.mapOptional("Version", O.Version);
+  IO.mapOptional("Size", O.Size);
+  IO.mapOptional("EntryOffset", O.EntryOffset);
+  IO.mapOptional("EntrySize", O.EntrySize);
+  IO.mapRequired("Members", O.Members);
+  IO.setContext(nullptr);
+}
+
+void MappingTraits<OffloadYAML::Binary::StringEntry>::mapping(
+    IO &IO, OffloadYAML::Binary::StringEntry &SE) {
+  assert(IO.getContext() && "The IO context is not initialized");
+  IO.mapRequired("Key", SE.Key);
+  IO.mapRequired("Value", SE.Value);
+}
+
+void MappingTraits<OffloadYAML::Binary::Member>::mapping(
+    IO &IO, OffloadYAML::Binary::Member &M) {
+  assert(IO.getContext() && "The IO context is not initialized");
+  IO.mapOptional("ImageKind", M.ImageKind);
+  IO.mapOptional("OffloadKind", M.OffloadKind);
+  IO.mapOptional("Flags", M.Flags);
+  IO.mapOptional("String", M.StringEntries);
+  IO.mapOptional("Content", M.Content);
+}
+
+} // namespace yaml
+
+} // namespace llvm

diff  --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp
index 64c2599f616eb..06050e246fbff 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -42,6 +42,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
       return yaml2macho(Doc, Out, ErrHandler);
     if (Doc.Minidump)
       return yaml2minidump(*Doc.Minidump, Out, ErrHandler);
+    if (Doc.Offload)
+      return yaml2offload(*Doc.Offload, Out, ErrHandler);
     if (Doc.Wasm)
       return yaml2wasm(*Doc.Wasm, Out, ErrHandler);
     if (Doc.Xcoff)

diff  --git a/llvm/test/ObjectYAML/Offload/binary.yaml b/llvm/test/ObjectYAML/Offload/binary.yaml
new file mode 100644
index 0000000000000..9cab37d47cd79
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/binary.yaml
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+!Offload
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+
+     # CHECK: --- !Offload
+# CHECK-NEXT: Members:
+# CHECK-NEXT:   - ImageKind:       IMG_Cubin
+# CHECK-NEXT:     OffloadKind:     OFK_OpenMP
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:     String:
+# CHECK-NEXT:       - Key:             triple
+# CHECK-NEXT:         Value:           nvptx64-nvidia-cuda
+# CHECK-NEXT:       - Key:             arch
+# CHECK-NEXT:         Value:           sm_70
+# CHECK-NEXT:     Content:         DEADBEEF
+# CHECK-NEXT: ...

diff  --git a/llvm/test/ObjectYAML/Offload/default.yaml b/llvm/test/ObjectYAML/Offload/default.yaml
new file mode 100644
index 0000000000000..7b147b8526457
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/default.yaml
@@ -0,0 +1,11 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+!Offload
+Members:
+  - 
+
+# CHECK: --- !Offload
+# CHECK-NEXT: Members:
+# CHECK-NEXT:   - ImageKind:       IMG_None
+# CHECK-NEXT:     OffloadKind:     OFK_None
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT: ...

diff  --git a/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml b/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml
new file mode 100644
index 0000000000000..3e4e68e46c4fb
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml
@@ -0,0 +1,40 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+!Offload
+Members:
+  - ImageKind:        IMG_None
+    OffloadKind:      OFK_None
+  - ImageKind:        IMG_Object
+    OffloadKind:      OFK_OpenMP
+  - ImageKind:        IMG_Bitcode
+    OffloadKind:      OFK_Cuda
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_HIP
+  - ImageKind:        IMG_Fatbinary
+  - ImageKind:        IMG_PTX
+  - ImageKind:        999
+    OffloadKind:      999
+
+#      CHECK:       --- !Offload
+# CHECK-NEXT: Members:
+# CHECK-NEXT:   - ImageKind:       IMG_None
+# CHECK-NEXT:     OffloadKind:     OFK_None
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       IMG_Object
+# CHECK-NEXT:     OffloadKind:     OFK_OpenMP
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       IMG_Bitcode
+# CHECK-NEXT:     OffloadKind:     OFK_Cuda
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       IMG_Cubin
+# CHECK-NEXT:     OffloadKind:     OFK_HIP
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       IMG_Fatbinary
+# CHECK-NEXT:     OffloadKind:     OFK_None
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       IMG_PTX
+# CHECK-NEXT:     OffloadKind:     OFK_None
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:   - ImageKind:       0x3E7
+# CHECK-NEXT:     OffloadKind:     0x3E7
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT: ...

diff  --git a/llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml b/llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml
new file mode 100644
index 0000000000000..3194607ae39a5
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
+!Offload
+EntrySize: 999999999
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+
+# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered

diff  --git a/llvm/test/ObjectYAML/Offload/malformed-offset.yaml b/llvm/test/ObjectYAML/Offload/malformed-offset.yaml
new file mode 100644
index 0000000000000..03c0431053cce
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/malformed-offset.yaml
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
+!Offload
+EntryOffset: 999999999
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+
+# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered

diff  --git a/llvm/test/ObjectYAML/Offload/malformed-size.yaml b/llvm/test/ObjectYAML/Offload/malformed-size.yaml
new file mode 100644
index 0000000000000..ecdd3849ecc75
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/malformed-size.yaml
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
+!Offload
+Size: 999999999
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+
+# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered

diff  --git a/llvm/test/ObjectYAML/Offload/malformed-version.yaml b/llvm/test/ObjectYAML/Offload/malformed-version.yaml
new file mode 100644
index 0000000000000..f9279a52e2764
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/malformed-version.yaml
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
+!Offload
+Version: 2
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+
+# CHECK: Error reading file: <stdin>: Invalid data was encountered while parsing the file

diff  --git a/llvm/test/ObjectYAML/Offload/multiple_members.yaml b/llvm/test/ObjectYAML/Offload/multiple_members.yaml
new file mode 100644
index 0000000000000..ac73d16e429a9
--- /dev/null
+++ b/llvm/test/ObjectYAML/Offload/multiple_members.yaml
@@ -0,0 +1,43 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+!Offload
+Members:
+  - ImageKind:        IMG_Cubin
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "nvptx64-nvidia-cuda"
+    - Key:              "arch"
+      Value:            "sm_70"
+    Content:          "deadbeef"  
+  - ImageKind:        IMG_Bitcode
+    OffloadKind:      OFK_OpenMP
+    Flags:            0
+    String:
+    - Key:              "triple"
+      Value:            "amdgcn-amd-amdhsa"
+    - Key:              "arch"
+      Value:            "gfx908"
+    Content:          "cafefeed"  
+
+# CHECK: --- !Offload
+# CHECK-NEXT: Members:
+# CHECK-NEXT:   - ImageKind:       IMG_Cubin
+# CHECK-NEXT:     OffloadKind:     OFK_OpenMP
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:     String:
+# CHECK-NEXT:       - Key:             triple
+# CHECK-NEXT:         Value:           nvptx64-nvidia-cuda
+# CHECK-NEXT:       - Key:             arch
+# CHECK-NEXT:         Value:           sm_70
+# CHECK-NEXT:     Content:         DEADBEEF
+# CHECK-NEXT:   - ImageKind:       IMG_Bitcode
+# CHECK-NEXT:     OffloadKind:     OFK_OpenMP
+# CHECK-NEXT:     Flags:           0
+# CHECK-NEXT:     String:
+# CHECK-NEXT:       - Key:             triple
+# CHECK-NEXT:         Value:           amdgcn-amd-amdhsa
+# CHECK-NEXT:       - Key:             arch
+# CHECK-NEXT:         Value:           gfx908
+# CHECK-NEXT:     Content:         CAFEFEED
+# CHECK-NEXT: ...

diff  --git a/llvm/tools/obj2yaml/CMakeLists.txt b/llvm/tools/obj2yaml/CMakeLists.txt
index c948d49a449da..ac8ff8c85dd9c 100644
--- a/llvm/tools/obj2yaml/CMakeLists.txt
+++ b/llvm/tools/obj2yaml/CMakeLists.txt
@@ -16,6 +16,7 @@ add_llvm_utility(obj2yaml
   elf2yaml.cpp
   macho2yaml.cpp
   minidump2yaml.cpp
+  offload2yaml.cpp
   xcoff2yaml.cpp
   wasm2yaml.cpp
   )

diff  --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp
index 769983a5176d0..4aa154a8d819c 100644
--- a/llvm/tools/obj2yaml/obj2yaml.cpp
+++ b/llvm/tools/obj2yaml/obj2yaml.cpp
@@ -55,6 +55,8 @@ static Error dumpInput(StringRef File) {
     return archive2yaml(outs(), MemBuf);
   case file_magic::dxcontainer_object:
     return dxcontainer2yaml(outs(), MemBuf);
+  case file_magic::offload_binary:
+    return offload2yaml(outs(), MemBuf);
   default:
     break;
   }

diff  --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h
index 8d4e6e2e028bc..e0204c6c608f4 100644
--- a/llvm/tools/obj2yaml/obj2yaml.h
+++ b/llvm/tools/obj2yaml/obj2yaml.h
@@ -16,15 +16,15 @@
 #include "llvm/Object/Minidump.h"
 #include "llvm/Object/Wasm.h"
 #include "llvm/Object/XCOFFObjectFile.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/raw_ostream.h"
 #include <system_error>
 
 enum RawSegments : unsigned { none = 0, data = 1, linkedit = 1 << 1 };
 std::error_code coff2yaml(llvm::raw_ostream &Out,
                           const llvm::object::COFFObjectFile &Obj);
 llvm::Error elf2yaml(llvm::raw_ostream &Out,
-                         const llvm::object::ObjectFile &Obj);
+                     const llvm::object::ObjectFile &Obj);
 llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj,
                        unsigned RawSegments);
 llvm::Error minidump2yaml(llvm::raw_ostream &Out,
@@ -34,6 +34,7 @@ llvm::Error xcoff2yaml(llvm::raw_ostream &Out,
 std::error_code wasm2yaml(llvm::raw_ostream &Out,
                           const llvm::object::WasmObjectFile &Obj);
 llvm::Error archive2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source);
+llvm::Error offload2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source);
 llvm::Error dxcontainer2yaml(llvm::raw_ostream &Out,
                              llvm::MemoryBufferRef Source);
 
@@ -43,7 +44,7 @@ class DWARFContext;
 namespace DWARFYAML {
 struct Data;
 }
-}
+} // namespace llvm
 
 void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
 llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);

diff  --git a/llvm/tools/obj2yaml/offload2yaml.cpp b/llvm/tools/obj2yaml/offload2yaml.cpp
new file mode 100644
index 0000000000000..10de0a0fbcb1c
--- /dev/null
+++ b/llvm/tools/obj2yaml/offload2yaml.cpp
@@ -0,0 +1,82 @@
+//===------ offload2yaml.cpp - obj2yaml conversion tool ---*- 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 "obj2yaml.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/OffloadBinary.h"
+#include "llvm/ObjectYAML/OffloadYAML.h"
+#include "llvm/Support/StringSaver.h"
+
+using namespace llvm;
+
+namespace {
+
+void populateYAML(OffloadYAML::Binary &YAMLBinary, object::OffloadBinary &OB,
+                  UniqueStringSaver Saver) {
+  YAMLBinary.Members.emplace_back();
+  auto &Member = YAMLBinary.Members.back();
+  Member.ImageKind = OB.getImageKind();
+  Member.OffloadKind = OB.getOffloadKind();
+  Member.Flags = OB.getFlags();
+  if (!OB.strings().empty()) {
+    Member.StringEntries = std::vector<OffloadYAML::Binary::StringEntry>();
+    for (const auto &Entry : OB.strings())
+      Member.StringEntries->emplace_back(OffloadYAML::Binary::StringEntry(
+          {Saver.save(Entry.getKey()), Saver.save(Entry.getValue())}));
+  }
+
+  if (!OB.getImage().empty())
+    Member.Content = arrayRefFromStringRef(OB.getImage());
+}
+
+Expected<OffloadYAML::Binary *> dump(MemoryBufferRef Source,
+                                     UniqueStringSaver Saver) {
+  Expected<std::unique_ptr<object::OffloadBinary>> OB =
+      object::OffloadBinary::create(Source);
+  if (!OB)
+    return OB.takeError();
+
+  std::unique_ptr<OffloadYAML::Binary> YAMLBinary =
+      std::make_unique<OffloadYAML::Binary>();
+
+  YAMLBinary->Members = std::vector<OffloadYAML::Binary::Member>();
+
+  uint64_t Offset = 0;
+  while (Offset < (*OB)->getMemoryBufferRef().getBufferSize()) {
+    MemoryBufferRef Buffer = MemoryBufferRef(
+        (*OB)->getData().drop_front(Offset), (*OB)->getFileName());
+    auto BinaryOrErr = object::OffloadBinary::create(Buffer);
+    if (!BinaryOrErr)
+      return BinaryOrErr.takeError();
+
+    object::OffloadBinary &Binary = **BinaryOrErr;
+
+    populateYAML(*YAMLBinary, Binary, Saver);
+
+    Offset += Binary.getSize();
+  }
+
+  return YAMLBinary.release();
+}
+
+} // namespace
+
+Error offload2yaml(raw_ostream &Out, MemoryBufferRef Source) {
+  BumpPtrAllocator Alloc;
+  UniqueStringSaver Saver(Alloc);
+
+  Expected<OffloadYAML::Binary *> YAMLOrErr = dump(Source, Saver);
+  if (!YAMLOrErr)
+    return YAMLOrErr.takeError();
+
+  std::unique_ptr<OffloadYAML::Binary> YAML(YAMLOrErr.get());
+  yaml::Output Yout(Out);
+  Yout << *YAML;
+
+  return Error::success();
+}


        


More information about the llvm-commits mailing list