[llvm] 4070aa0 - [Object][DX] Initial DXContainer parsing support

Chris Bieneman via llvm-commits llvm-commits at lists.llvm.org
Mon May 2 11:57:11 PDT 2022


Author: Chris Bieneman
Date: 2022-05-02T13:56:33-05:00
New Revision: 4070aa01561c6bf2a5954d68228f373386658cde

URL: https://github.com/llvm/llvm-project/commit/4070aa01561c6bf2a5954d68228f373386658cde
DIFF: https://github.com/llvm/llvm-project/commit/4070aa01561c6bf2a5954d68228f373386658cde.diff

LOG: [Object][DX] Initial DXContainer parsing support

This patch begins adding DXContainer parsing support to libObject.
Following the pattern used by ELFFile my goal here is to write a
standalone DXContainer parser and later write an adapter interface to
support a subset of the ObjectFile interfaces so that we can add
limited objdump support. I will also be adding ObjectYAML support to
help drive testing of the object tools and MC-level object writers as
those come together.

DXContainer is a slightly odd format. It is arranged in "parts" that
are semantically similar to sections, but it doesn't support symbol
listing.

Reviewed By: MaskRay

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

Added: 
    llvm/include/llvm/BinaryFormat/DXContainer.h
    llvm/include/llvm/Object/DXContainer.h
    llvm/lib/Object/DXContainer.cpp
    llvm/unittests/Object/DXContainerTest.cpp

Modified: 
    llvm/lib/Object/CMakeLists.txt
    llvm/unittests/Object/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
new file mode 100644
index 0000000000000..f9ec9fe45a0cb
--- /dev/null
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -0,0 +1,91 @@
+//===-- llvm/BinaryFormat/DXContainer.h - The DXBC file format --*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines manifest constants for the DXContainer object file format.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_DXCONTAINER_H
+#define LLVM_BINARYFORMAT_DXCONTAINER_H
+
+#include "llvm/Support/SwapByteOrder.h"
+
+#include <stdint.h>
+
+namespace llvm {
+
+// The DXContainer file format is arranged as a header and "parts". Semantically
+// parts are similar to sections in other object file formats. The File format
+// structure is roughly:
+
+// ┌────────────────────────────────┐
+// │             Header             │
+// ├────────────────────────────────┤
+// │              Part              │
+// ├────────────────────────────────┤
+// │              Part              │
+// ├────────────────────────────────┤
+// │              ...               │
+// └────────────────────────────────┘
+
+namespace dxbc {
+
+struct Hash {
+  uint8_t Digest[16];
+};
+
+enum class HashFlags : uint32_t {
+  None = 0,           // No flags defined.
+  IncludesSource = 1, // This flag indicates that the shader hash was computed
+                      // taking into account source information (-Zss)
+};
+
+struct ShaderHash {
+  uint32_t Flags; // DxilShaderHashFlags
+  uint8_t Digest[16];
+
+  void byteSwap() { sys::swapByteOrder(Flags); }
+};
+
+struct ContainerVersion {
+  uint16_t Major;
+  uint16_t Minor;
+
+  void byteSwap() {
+    sys::swapByteOrder(Major);
+    sys::swapByteOrder(Minor);
+  }
+};
+
+struct Header {
+  uint8_t Magic[4]; // "DXBC"
+  Hash Hash;
+  ContainerVersion Version;
+  uint32_t FileSize;
+  uint32_t PartCount;
+
+  void byteSwap() {
+    Version.byteSwap();
+    sys::swapByteOrder(FileSize);
+    sys::swapByteOrder(PartCount);
+  }
+  // Structure is followed by part offsets: uint32_t PartOffset[PartCount];
+  // The offset is to a PartHeader, which is followed by the Part Data.
+};
+
+/// Use this type to describe the size and type of a DXIL container part.
+struct PartHeader {
+  uint8_t Name[4];
+  uint32_t Size;
+  // Structure is followed directly by part data: uint8_t PartData[PartSize].
+};
+
+} // namespace dxbc
+} // namespace llvm
+
+#endif // LLVM_BINARYFORMAT_DXCONTAINER_H

diff  --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
new file mode 100644
index 0000000000000..69a5e28539d6c
--- /dev/null
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -0,0 +1,44 @@
+//===- DXContainer.h - DXContainer file 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the DXContainerFile class, which implements the ObjectFile
+// interface for DXContainer files.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_DXCONTAINER_H
+#define LLVM_OBJECT_DXCONTAINER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBufferRef.h"
+
+namespace llvm {
+namespace object {
+class DXContainer {
+private:
+  DXContainer(MemoryBufferRef O);
+
+  MemoryBufferRef Data;
+  dxbc::Header Header;
+
+  Error parseHeader();
+
+public:
+  StringRef getData() const { return Data.getBuffer(); }
+  static Expected<DXContainer> create(MemoryBufferRef Object);
+
+  const dxbc::Header &getHeader() const { return Header; }
+};
+
+} // namespace object
+} // namespace llvm
+
+#endif // LLVM_OBJECT_DXCONTAINERFILE_H

diff  --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt
index 082521049439a..ba612e3d95e9b 100644
--- a/llvm/lib/Object/CMakeLists.txt
+++ b/llvm/lib/Object/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMObject
   COFFModuleDefinition.cpp
   COFFObjectFile.cpp
   Decompressor.cpp
+  DXContainer.cpp
   ELF.cpp
   ELFObjectFile.cpp
   Error.cpp

diff  --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
new file mode 100644
index 0000000000000..05d7bc6264a4b
--- /dev/null
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -0,0 +1,44 @@
+//===- DXContainer.cpp - DXContainer object file 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/DXContainer.h"
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/Object/Error.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static Error parseFailed(const Twine &Msg) {
+  return make_error<GenericBinaryError>(Msg.str(), object_error::parse_failed);
+}
+
+template <typename T>
+static Error readStruct(StringRef Buffer, const char *P, T &Struct) {
+  // Don't read before the beginning or past the end of the file
+  if (P < Buffer.begin() || P + sizeof(T) > Buffer.end())
+    return parseFailed("Reading structure out of file bounds");
+
+  memcpy(&Struct, P, sizeof(T));
+  // DXContainer is always BigEndian
+  if (sys::IsBigEndianHost)
+    Struct.byteSwap();
+  return Error::success();
+}
+
+DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {}
+
+Error DXContainer::parseHeader() {
+  return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header);
+}
+
+Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) {
+  DXContainer Container(Object);
+  if (Error Err = Container.parseHeader())
+    return Err;
+  return Container;
+}

diff  --git a/llvm/unittests/Object/CMakeLists.txt b/llvm/unittests/Object/CMakeLists.txt
index ea7df2246b4df..d30125d862eb7 100644
--- a/llvm/unittests/Object/CMakeLists.txt
+++ b/llvm/unittests/Object/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(ObjectTests
   ArchiveTest.cpp
+  DXContainerTest.cpp
   ELFObjectFileTest.cpp
   ELFTypesTest.cpp
   ELFTest.cpp

diff  --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
new file mode 100644
index 0000000000000..846176a089fbc
--- /dev/null
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -0,0 +1,43 @@
+//===- 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/Object/DXContainer.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+template <std::size_t X> MemoryBufferRef getMemoryBuffer(uint8_t Data[X]) {
+  StringRef Obj(reinterpret_cast<char *>(&Data[0]), X);
+  return MemoryBufferRef(Obj, "");
+}
+
+TEST(DXCFile, ParseHeaderErrors) {
+  uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43};
+  EXPECT_THAT_EXPECTED(
+      DXContainer::create(getMemoryBuffer<4>(Buffer)),
+      FailedWithMessage("Reading structure out of file bounds"));
+}
+
+TEST(DXCFile, ParseHeader) {
+  uint8_t 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,
+                      0x70, 0x0D, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00};
+  DXContainer C =
+      llvm::cantFail(DXContainer::create(getMemoryBuffer<32>(Buffer)));
+  EXPECT_TRUE(memcmp(C.getHeader().Magic, "DXBC", 4) == 0);
+  EXPECT_TRUE(memcmp(C.getHeader().Hash.Digest,
+                     "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0);
+  EXPECT_EQ(C.getHeader().Version.Major, 1u);
+  EXPECT_EQ(C.getHeader().Version.Minor, 0u);
+}


        


More information about the llvm-commits mailing list