[llvm] 129c056 - [ObjectYAML][DX] Support yaml2dxcontainer

Chris Bieneman via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 1 13:34:14 PDT 2022


Author: Chris Bieneman
Date: 2022-06-01T15:34:00-05:00
New Revision: 129c056d626986eb95f9724283b8f6106cdde2e9

URL: https://github.com/llvm/llvm-project/commit/129c056d626986eb95f9724283b8f6106cdde2e9
DIFF: https://github.com/llvm/llvm-project/commit/129c056d626986eb95f9724283b8f6106cdde2e9.diff

LOG: [ObjectYAML][DX] Support yaml2dxcontainer

This patch adds a the first bits of support for a yaml representation
of dxcontainer files.

Since the YAML representation's primary purpose is testing
infrastructure, the yaml representation supports both verbose and a
more friendly format by making computable sizes and offsets optional.
If provided they are validated to be correct, otherwise they are
computed on the fly during emission.

As I expand the format I'll be able to make more size fields optional,
and I will continue to make the format easier to work with.

Depends on D124804

Reviewed By: lhames

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

Added: 
    llvm/include/llvm/ObjectYAML/DXContainerYAML.h
    llvm/lib/ObjectYAML/DXContainerEmitter.cpp
    llvm/lib/ObjectYAML/DXContainerYAML.cpp
    llvm/test/tools/obj2yaml/DXContainer/InvalidOffset.yaml
    llvm/test/tools/obj2yaml/DXContainer/InvalidSize.yaml
    llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp

Modified: 
    llvm/include/llvm/BinaryFormat/DXContainer.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/unittests/ObjectYAML/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index 85706d55bd8e2..d9a231d25f69a 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_BINARYFORMAT_DXCONTAINER_H
 #define LLVM_BINARYFORMAT_DXCONTAINER_H
 
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/SwapByteOrder.h"
 
 #include <stdint.h>
@@ -84,6 +85,9 @@ struct PartHeader {
   uint32_t Size;
 
   void swapBytes() { sys::swapByteOrder(Size); }
+  StringRef getName() const {
+    return StringRef(reinterpret_cast<const char *>(&Name[0]), 4);
+  }
   // Structure is followed directly by part data: uint8_t PartData[PartSize].
 };
 

diff  --git a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h
new file mode 100644
index 0000000000000..e4acec0370f5e
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h
@@ -0,0 +1,84 @@
+//===- DXContainerYAML.h - DXContainer 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 DXContainer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_DXCONTAINERYAML_H
+#define LLVM_OBJECTYAML_DXCONTAINERYAML_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ObjectYAML/YAML.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace DXContainerYAML {
+
+struct VersionTuple {
+  uint16_t Major;
+  uint16_t Minor;
+};
+
+// The optional header fields are required in the binary and will be populated
+// when reading from binary, but can be omitted in the YAML text because the
+// emitter can calculate them.
+struct FileHeader {
+  std::vector<llvm::yaml::Hex8> Hash;
+  VersionTuple Version;
+  Optional<uint32_t> FileSize;
+  uint32_t PartCount;
+  Optional<std::vector<uint32_t>> PartOffsets;
+};
+
+struct Part {
+  std::string Name;
+  uint32_t Size;
+};
+
+struct Object {
+  FileHeader Header;
+  std::vector<Part> Parts;
+};
+
+} // namespace DXContainerYAML
+} // namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::Part)
+namespace llvm {
+
+class raw_ostream;
+
+namespace yaml {
+
+template <> struct MappingTraits<DXContainerYAML::VersionTuple> {
+  static void mapping(IO &IO, DXContainerYAML::VersionTuple &Version);
+};
+
+template <> struct MappingTraits<DXContainerYAML::FileHeader> {
+  static void mapping(IO &IO, DXContainerYAML::FileHeader &Header);
+};
+
+template <> struct MappingTraits<DXContainerYAML::Part> {
+  static void mapping(IO &IO, DXContainerYAML::Part &Version);
+};
+
+template <> struct MappingTraits<DXContainerYAML::Object> {
+  static void mapping(IO &IO, DXContainerYAML::Object &Obj);
+};
+
+} // namespace yaml
+
+} // namespace llvm
+
+#endif // LLVM_OBJECTYAML_DXCONTAINERYAML_H

diff  --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
index 312777aadd4c3..bc9d76b36fd97 100644
--- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
@@ -11,6 +11,7 @@
 
 #include "llvm/ObjectYAML/ArchiveYAML.h"
 #include "llvm/ObjectYAML/COFFYAML.h"
+#include "llvm/ObjectYAML/DXContainerYAML.h"
 #include "llvm/ObjectYAML/ELFYAML.h"
 #include "llvm/ObjectYAML/MachOYAML.h"
 #include "llvm/ObjectYAML/MinidumpYAML.h"
@@ -33,6 +34,7 @@ struct YamlObjectFile {
   std::unique_ptr<MinidumpYAML::Object> Minidump;
   std::unique_ptr<WasmYAML::Object> Wasm;
   std::unique_ptr<XCOFFYAML::Object> Xcoff;
+  std::unique_ptr<DXContainerYAML::Object> DXContainer;
 };
 
 template <> struct MappingTraits<YamlObjectFile> {

diff  --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index 468f673fd4510..da12b75ba2253 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -48,6 +48,10 @@ namespace ArchYAML {
 struct Archive;
 }
 
+namespace DXContainerYAML {
+struct Object;
+} // namespace DXContainerYAML
+
 namespace yaml {
 class Input;
 struct YamlObjectFile;
@@ -63,6 +67,8 @@ bool yaml2minidump(MinidumpYAML::Object &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,
+                      ErrorHandler EH);
 
 bool convertYAML(Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
                  unsigned DocNum = 1, uint64_t MaxSize = UINT64_MAX);

diff  --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt
index acb9f7cd11aea..818a174c61938 100644
--- a/llvm/lib/ObjectYAML/CMakeLists.txt
+++ b/llvm/lib/ObjectYAML/CMakeLists.txt
@@ -9,6 +9,8 @@ add_llvm_component_library(LLVMObjectYAML
   COFFYAML.cpp
   DWARFEmitter.cpp
   DWARFYAML.cpp
+  DXContainerEmitter.cpp
+  DXContainerYAML.cpp
   ELFEmitter.cpp
   ELFYAML.cpp
   MachOEmitter.cpp

diff  --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
new file mode 100644
index 0000000000000..5400f070d637f
--- /dev/null
+++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
@@ -0,0 +1,148 @@
+//===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
+//
+// 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
+/// Binary emitter for yaml to DXContainer binary
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+class DXContainerWriter {
+public:
+  DXContainerWriter(DXContainerYAML::Object &ObjectFile)
+      : ObjectFile(ObjectFile) {}
+
+  Error write(raw_ostream &OS);
+
+private:
+  DXContainerYAML::Object &ObjectFile;
+
+  Error computePartOffsets();
+  Error validatePartOffsets();
+  Error validateSize(uint32_t Computed);
+
+  void writeHeader(raw_ostream &OS);
+  void writeParts(raw_ostream &OS);
+};
+} // namespace
+
+Error DXContainerWriter::validateSize(uint32_t Computed) {
+  if (!ObjectFile.Header.FileSize)
+    ObjectFile.Header.FileSize = Computed;
+  else if (*ObjectFile.Header.FileSize < Computed)
+    return createStringError(errc::result_out_of_range,
+                             "File size specified is too small.");
+  return Error::success();
+}
+
+Error DXContainerWriter::validatePartOffsets() {
+  if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
+    return createStringError(
+        errc::invalid_argument,
+        "Mismatch between number of parts and part offsets.");
+  uint32_t RollingOffset =
+      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
+  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
+    if (RollingOffset > std::get<1>(I))
+      return createStringError(errc::invalid_argument,
+                               "Offset mismatch, not enough space for data.");
+    RollingOffset =
+        std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
+  }
+  if (Error Err = validateSize(RollingOffset))
+    return Err;
+
+  return Error::success();
+}
+
+Error DXContainerWriter::computePartOffsets() {
+  if (ObjectFile.Header.PartOffsets)
+    return validatePartOffsets();
+  uint32_t RollingOffset =
+      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
+  ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
+  for (const auto &Part : ObjectFile.Parts) {
+    ObjectFile.Header.PartOffsets->push_back(RollingOffset);
+    RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
+  }
+  if (Error Err = validateSize(RollingOffset))
+    return Err;
+
+  return Error::success();
+}
+
+void DXContainerWriter::writeHeader(raw_ostream &OS) {
+  dxbc::Header Header;
+  memcpy(Header.Magic, "DXBC", 4);
+  memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
+  Header.Version.Major = ObjectFile.Header.Version.Major;
+  Header.Version.Minor = ObjectFile.Header.Version.Minor;
+  Header.FileSize = *ObjectFile.Header.FileSize;
+  Header.PartCount = ObjectFile.Parts.size();
+  if (sys::IsBigEndianHost)
+    Header.swapBytes();
+  OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
+  for (auto &O : *ObjectFile.Header.PartOffsets)
+    if (sys::IsBigEndianHost)
+      sys::swapByteOrder(O);
+  OS.write(reinterpret_cast<char *>(ObjectFile.Header.PartOffsets->data()),
+           ObjectFile.Header.PartOffsets->size() * sizeof(uint32_t));
+}
+void DXContainerWriter::writeParts(raw_ostream &OS) {
+  uint32_t RollingOffset =
+      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
+  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
+    if (RollingOffset < std::get<1>(I)) {
+      uint32_t PadBytes = std::get<1>(I) - RollingOffset;
+      std::vector<uint8_t> FillData(PadBytes, 0);
+      OS.write(reinterpret_cast<char *>(FillData.data()), PadBytes);
+    }
+    DXContainerYAML::Part P = std::get<0>(I);
+    OS.write(P.Name.c_str(), 4);
+    if (sys::IsBigEndianHost)
+      sys::swapByteOrder(P.Size);
+    OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
+    RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
+
+    // TODO: Write Part data
+  }
+}
+
+Error DXContainerWriter::write(raw_ostream &OS) {
+  if (Error Err = computePartOffsets())
+    return Err;
+  writeHeader(OS);
+  writeParts(OS);
+  return Error::success();
+}
+
+namespace llvm {
+namespace yaml {
+
+bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
+                      ErrorHandler EH) {
+  DXContainerWriter Writer(Doc);
+  if (Error Err = Writer.write(Out)) {
+    handleAllErrors(std::move(Err),
+                    [&](const ErrorInfoBase &Err) { EH(Err.message()); });
+    return false;
+  }
+  return true;
+}
+
+} // namespace yaml
+} // namespace llvm

diff  --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
new file mode 100644
index 0000000000000..52f1205375677
--- /dev/null
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -0,0 +1,48 @@
+//===- DXContainerYAML.cpp - DXContainer 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
+// DXContainerYAML.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/DXContainerYAML.h"
+
+namespace llvm {
+namespace yaml {
+
+void MappingTraits<DXContainerYAML::VersionTuple>::mapping(
+    IO &IO, DXContainerYAML::VersionTuple &Version) {
+  IO.mapRequired("Major", Version.Major);
+  IO.mapRequired("Minor", Version.Minor);
+}
+
+void MappingTraits<DXContainerYAML::FileHeader>::mapping(
+    IO &IO, DXContainerYAML::FileHeader &Header) {
+  IO.mapRequired("Hash", Header.Hash);
+  IO.mapRequired("Version", Header.Version);
+  IO.mapOptional("FileSize", Header.FileSize);
+  IO.mapRequired("PartCount", Header.PartCount);
+  IO.mapOptional("PartOffsets", Header.PartOffsets);
+}
+
+void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
+                                                   DXContainerYAML::Part &P) {
+  IO.mapRequired("Name", P.Name);
+  IO.mapRequired("Size", P.Size);
+}
+
+void MappingTraits<DXContainerYAML::Object>::mapping(
+    IO &IO, DXContainerYAML::Object &Obj) {
+  IO.mapTag("!dxcontainer", true);
+  IO.mapRequired("Header", Obj.Header);
+  IO.mapRequired("Parts", Obj.Parts);
+}
+
+} // namespace yaml
+} // namespace llvm

diff  --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp
index 63769d2eba0e4..8d7220506b0da 100644
--- a/llvm/lib/ObjectYAML/ObjectYAML.cpp
+++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp
@@ -62,6 +62,10 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
     } else if (IO.mapTag("!XCOFF")) {
       ObjectFile.Xcoff.reset(new XCOFFYAML::Object());
       MappingTraits<XCOFFYAML::Object>::mapping(IO, *ObjectFile.Xcoff);
+    } else if (IO.mapTag("!dxcontainer")) {
+      ObjectFile.DXContainer.reset(new DXContainerYAML::Object());
+      MappingTraits<DXContainerYAML::Object>::mapping(IO,
+                                                      *ObjectFile.DXContainer);
     } else if (const Node *N = In.getCurrentNode()) {
       if (N->getRawTag().empty())
         IO.setError("YAML Object File missing document type tag!");

diff  --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp
index d19fa0a525302..64c2599f616eb 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -46,6 +46,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
       return yaml2wasm(*Doc.Wasm, Out, ErrHandler);
     if (Doc.Xcoff)
       return yaml2xcoff(*Doc.Xcoff, Out, ErrHandler);
+    if (Doc.DXContainer)
+      return yaml2dxcontainer(*Doc.DXContainer, Out, ErrHandler);
 
     ErrHandler("unknown document type");
     return false;

diff  --git a/llvm/test/tools/obj2yaml/DXContainer/InvalidOffset.yaml b/llvm/test/tools/obj2yaml/DXContainer/InvalidOffset.yaml
new file mode 100644
index 0000000000000..b7e25e433e837
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/DXContainer/InvalidOffset.yaml
@@ -0,0 +1,17 @@
+# RUN: not yaml2obj %s 2>&1 | FileCheck %s 
+
+# CHECK: yaml2obj: error: Offset mismatch, not enough space for data.
+--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  FileSize:        32
+  PartCount:       1
+  PartOffsets:     [ 0 ]
+Parts:
+  - Name:            SFI0
+    Size:            8
+...

diff  --git a/llvm/test/tools/obj2yaml/DXContainer/InvalidSize.yaml b/llvm/test/tools/obj2yaml/DXContainer/InvalidSize.yaml
new file mode 100644
index 0000000000000..e79aa4cb2ef87
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/DXContainer/InvalidSize.yaml
@@ -0,0 +1,18 @@
+# RUN: not yaml2obj %s 2>&1 | FileCheck %s 
+
+# CHECK: yaml2obj: error: File size specified is too small.
+--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  FileSize:        64
+  PartCount:       2
+Parts:
+  - Name:            SFI0
+    Size:            8
+  - Name:            ISG1
+    Size:            8
+...

diff  --git a/llvm/unittests/ObjectYAML/CMakeLists.txt b/llvm/unittests/ObjectYAML/CMakeLists.txt
index c20f792657637..17772ce494710 100644
--- a/llvm/unittests/ObjectYAML/CMakeLists.txt
+++ b/llvm/unittests/ObjectYAML/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(ObjectYAMLTests
   DWARFYAMLTest.cpp
+  DXContainerYAMLTest.cpp
   ELFYAMLTest.cpp
   MinidumpYAMLTest.cpp
   YAML2ObjTest.cpp

diff  --git a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
new file mode 100644
index 0000000000000..4055222ab6839
--- /dev/null
+++ b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
@@ -0,0 +1,109 @@
+//===- DXContainerTest.cpp - Tests for DXContainerFile --------------------===//
+//
+// 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/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static bool convert(SmallVectorImpl<char> &Output, const char *YAML) {
+  raw_svector_ostream OS(Output);
+  yaml::Input YIn(YAML);
+  return convertYAML(YIn, OS, [](const Twine &Err) { errs() << Err; });
+}
+
+TEST(DXCFile, ParseEmptyParts) {
+  SmallString<128> Storage;
+
+  // First read a fully explicit yaml with all sizes and offsets provided
+  ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  FileSize:        116
+  PartCount:       7
+  PartOffsets:     [ 60, 68, 76, 84, 92, 100, 108 ]
+Parts:
+  - Name:            SFI0
+    Size:            0
+  - Name:            ISG1
+    Size:            0
+  - Name:            OSG1
+    Size:            0
+  - Name:            PSV0
+    Size:            0
+  - Name:            STAT
+    Size:            0
+  - Name:            DXIL
+    Size:            0
+  - Name:            DEAD
+    Size:            0
+...
+  )"));
+
+  // Result
+  char Buffer[] = {
+      0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x74, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
+      0x44, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+      0x5C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
+      0x53, 0x46, 0x49, 0x30, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31,
+      0x00, 0x00, 0x00, 0x00, 0x4F, 0x53, 0x47, 0x31, 0x00, 0x00, 0x00, 0x00,
+      0x50, 0x53, 0x56, 0x30, 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54,
+      0x00, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x00, 0x00, 0x00, 0x00,
+      0x44, 0x45, 0x41, 0x44, 0x00, 0x00, 0x00, 0x00,
+  };
+
+  EXPECT_EQ(Storage.size(), 116u);
+  EXPECT_TRUE(memcmp(Buffer, Storage.data(), 116) == 0);
+
+  Storage.clear();
+
+  // Next, read the same file without the part offsets or file size. Both cases
+  // should result in the same final output.
+  ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  PartCount:       7
+Parts:
+  - Name:            SFI0
+    Size:            0
+  - Name:            ISG1
+    Size:            0
+  - Name:            OSG1
+    Size:            0
+  - Name:            PSV0
+    Size:            0
+  - Name:            STAT
+    Size:            0
+  - Name:            DXIL
+    Size:            0
+  - Name:            DEAD
+    Size:            0
+...
+  )"));
+
+  EXPECT_EQ(Storage.size(), 116u);
+  EXPECT_TRUE(memcmp(Buffer, Storage.data(), 116) == 0);
+}


        


More information about the llvm-commits mailing list