[llvm] [DirectX][ObjectYAML] Add ILDB program part support (PR #189685)

via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 31 07:50:16 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-directx

Author: Vladislav Dzhidzhoev (dzhidzhoev)

<details>
<summary>Changes</summary>

Add support for DXContainer ILDB parts in the ObjectYAML pipeline so they can be represented in structured YAML and round-tripped through yaml2obj/obj2yaml.

ILDB payloads use the same layout as DXIL, but contain debug IR. This change treats ILDB as a DXIL-shaped program part.

FileSize and DXIL ProgramHeader Size values in DXILPart.yaml were modified to make output binary correct/parseable by dxa utility.

---
Full diff: https://github.com/llvm/llvm-project/pull/189685.diff


9 Files Affected:

- (modified) llvm/include/llvm/BinaryFormat/DXContainer.h (+4) 
- (modified) llvm/include/llvm/BinaryFormat/DXContainerConstants.def (+1) 
- (modified) llvm/include/llvm/Object/DXContainer.h (+5-2) 
- (modified) llvm/lib/BinaryFormat/DXContainer.cpp (+6) 
- (modified) llvm/lib/Object/DXContainer.cpp (+9-3) 
- (modified) llvm/lib/ObjectYAML/DXContainerEmitter.cpp (+2) 
- (modified) llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml (+27-5) 
- (modified) llvm/tools/obj2yaml/dxcontainer2yaml.cpp (+8-5) 
- (modified) llvm/unittests/Object/DXContainerTest.cpp (+47-1) 


``````````diff
diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index 1756ab0b555ff..3da36f6da525d 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -258,6 +258,10 @@ LLVM_ABI ArrayRef<EnumEntry<StaticBorderColor>> getStaticBorderColors();
 
 LLVM_ABI PartType parsePartType(StringRef S);
 
+bool isDebugProgramPart(PartType PT);
+
+const char *getProgramPartName(bool IsDebug);
+
 struct VertexPSVInfo {
   uint8_t OutputPositionPresent;
   uint8_t Unused[3];
diff --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
index f576d958037cd..f9f4472b0ebce 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
+++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
@@ -1,6 +1,7 @@
 
 #ifdef CONTAINER_PART
 CONTAINER_PART(DXIL)
+CONTAINER_PART(ILDB)
 CONTAINER_PART(SFI0)
 CONTAINER_PART(HASH)
 CONTAINER_PART(PSV0)
diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index c5888b87d6ad7..b70d6a960c130 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -468,6 +468,7 @@ class DXContainer {
   dxbc::Header Header;
   SmallVector<uint32_t, 4> PartOffsets;
   std::optional<DXILData> DXIL;
+  std::optional<DXILData> DebugDXIL;
   std::optional<uint64_t> ShaderFeatureFlags;
   std::optional<dxbc::ShaderHash> Hash;
   std::optional<DirectX::PSVRuntimeInfo> PSVInfo;
@@ -478,7 +479,7 @@ class DXContainer {
 
   Error parseHeader();
   Error parsePartOffsets();
-  Error parseDXILHeader(StringRef Part);
+  Error parseDXILHeader(dxbc::PartType PT, StringRef Part);
   Error parseShaderFeatureFlags(StringRef Part);
   Error parseHash(StringRef Part);
   Error parseRootSignature(StringRef Part);
@@ -561,7 +562,9 @@ class DXContainer {
 
   const dxbc::Header &getHeader() const { return Header; }
 
-  const std::optional<DXILData> &getDXIL() const { return DXIL; }
+  const std::optional<DXILData> &getDXIL(bool Debug) const {
+    return Debug ? DebugDXIL : DXIL;
+  }
 
   std::optional<uint64_t> getShaderFeatureFlags() const {
     return ShaderFeatureFlags;
diff --git a/llvm/lib/BinaryFormat/DXContainer.cpp b/llvm/lib/BinaryFormat/DXContainer.cpp
index 22f518067b318..384ef6811346c 100644
--- a/llvm/lib/BinaryFormat/DXContainer.cpp
+++ b/llvm/lib/BinaryFormat/DXContainer.cpp
@@ -110,6 +110,12 @@ dxbc::PartType dxbc::parsePartType(StringRef S) {
       .Default(dxbc::PartType::Unknown);
 }
 
+bool dxbc::isDebugProgramPart(PartType PT) { return PT == PartType::ILDB; }
+
+const char *dxbc::getProgramPartName(bool IsDebug) {
+  return IsDebug ? "ILDB" : "DXIL";
+}
+
 bool ShaderHash::isPopulated() {
   static uint8_t Zeros[16] = {0};
   return Flags > 0 || 0 != memcmp(&Digest, &Zeros, 16);
diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
index 7b7b8d88c63fc..bcc692f51405a 100644
--- a/llvm/lib/Object/DXContainer.cpp
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -61,9 +61,13 @@ Error DXContainer::parseHeader() {
   return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header);
 }
 
-Error DXContainer::parseDXILHeader(StringRef Part) {
+Error DXContainer::parseDXILHeader(dxbc::PartType PT, StringRef Part) {
+  bool IsDebug = dxbc::isDebugProgramPart(PT);
+  std::optional<DXILData> &DXIL = IsDebug ? this->DebugDXIL : this->DXIL;
+
   if (DXIL)
-    return parseFailed("More than one DXIL part is present in the file");
+    return parseFailed(formatv("More than one {0} part is present in the file",
+                               dxbc::getProgramPartName(IsDebug)));
   const char *Current = Part.begin();
   dxbc::ProgramHeader Header;
   if (Error Err = readStruct(Part, Current, Header))
@@ -173,8 +177,10 @@ Error DXContainer::parsePartOffsets() {
     StringRef PartData = Data.getBuffer().substr(PartDataStart, PartSize);
     LastOffset = PartOffset + PartSize;
     switch (PT) {
+    case dxbc::PartType::ILDB:
+      [[fallthrough]];
     case dxbc::PartType::DXIL:
-      if (Error Err = parseDXILHeader(PartData))
+      if (Error Err = parseDXILHeader(PT, PartData))
         return Err;
       break;
     case dxbc::PartType::SFI0:
diff --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
index b00e45d912be1..225ab0ef39bb4 100644
--- a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
@@ -128,6 +128,8 @@ Error DXContainerWriter::writeParts(raw_ostream &OS) {
 
     uint64_t DataStart = OS.tell();
     switch (PT) {
+    case dxbc::PartType::ILDB:
+      [[fallthrough]];
     case dxbc::PartType::DXIL: {
       if (!P.Program)
         continue;
diff --git a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml
index 58508f2dcc1e4..1749c7bd44d48 100644
--- a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml
+++ b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml
@@ -11,9 +11,9 @@ Header:
   Version:
     Major:           1
     Minor:           0
-  FileSize:        3548
-  PartCount:       7
-  PartOffsets:     [ 60, 76, 92, 108, 236, 1932, 1960 ]
+  FileSize:        2040
+  PartCount:       8
+  PartOffsets:     [ 64, 80, 96, 112, 240, 1936, 1964, 2000 ]
 Parts:
   - Name:            FKE0
     Size:            8
@@ -33,11 +33,22 @@ Parts:
       MajorVersion:    6
       MinorVersion:    5
       ShaderKind:      5
-      Size:            8
+      Size:            7
       DXILMajorVersion: 1
       DXILMinorVersion: 5
       DXILSize:        4
       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE, ]
+  - Name:            ILDB
+    Size:            32
+    Program:
+      MajorVersion:    6
+      MinorVersion:    5
+      ShaderKind:      5
+      Size:            8
+      DXILMajorVersion: 1
+      DXILMinorVersion: 5
+      DXILSize:        8
+      DXIL:            [ 0x42, 0x43, 0xC0, 0xDE, 0x21, 0x0C, 0x00, 0x00, ]
 ...
 
 
@@ -49,8 +60,19 @@ Parts:
 #CHECK-NEXT:       MajorVersion:    6
 #CHECK-NEXT:       MinorVersion:    5
 #CHECK-NEXT:       ShaderKind:      5
-#CHECK-NEXT:       Size:            8
+#CHECK-NEXT:       Size:            7
 #CHECK-NEXT:       DXILMajorVersion: 1
 #CHECK-NEXT:       DXILMinorVersion: 5
 #CHECK-NEXT:       DXILSize:        4
 #CHECK-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE
+#CHECK:        - Name:            ILDB
+#CHECK-NEXT:     Size:            32
+#CHECK-NEXT:     Program:
+#CHECK-NEXT:       MajorVersion:    6
+#CHECK-NEXT:       MinorVersion:    5
+#CHECK-NEXT:       ShaderKind:      5
+#CHECK-NEXT:       Size:            8
+#CHECK-NEXT:       DXILMajorVersion: 1
+#CHECK-NEXT:       DXILMinorVersion: 5
+#CHECK-NEXT:       DXILSize:        8
+#CHECK-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE, 0x21, 0xC, 0x0, 0x0
diff --git a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
index c727595406767..99a4fed92c139 100644
--- a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
+++ b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
@@ -53,9 +53,12 @@ dumpDXContainer(MemoryBufferRef Source) {
     DXContainerYAML::Part &NewPart = Obj->Parts.back();
     dxbc::PartType PT = dxbc::parsePartType(P.Part.getName());
     switch (PT) {
+    case dxbc::PartType::ILDB:
+      [[fallthrough]];
     case dxbc::PartType::DXIL: {
-      std::optional<DXContainer::DXILData> DXIL = Container.getDXIL();
-      assert(DXIL && "Since we are iterating and found a DXIL part, "
+      std::optional<DXContainer::DXILData> DXIL =
+          Container.getDXIL(dxbc::isDebugProgramPart(PT));
+      assert(DXIL && "Since we are iterating and found a DXIL/ILDB part, "
                      "this should never not have a value");
       NewPart.Program = DXContainerYAML::DXILProgram{
           DXIL->first.getMajorVersion(),
@@ -89,10 +92,10 @@ dumpDXContainer(MemoryBufferRef Source) {
         break;
       if (const auto *P =
               std::get_if<dxbc::PSV::v0::RuntimeInfo>(&PSVInfo->getInfo())) {
-        if (!Container.getDXIL())
+        if (!Container.getDXIL(false))
           break;
-        NewPart.Info =
-            DXContainerYAML::PSVInfo(P, Container.getDXIL()->first.ShaderKind);
+        NewPart.Info = DXContainerYAML::PSVInfo(
+            P, Container.getDXIL(false)->first.ShaderKind);
       } else if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(
                      &PSVInfo->getInfo()))
         NewPart.Info = DXContainerYAML::PSVInfo(P);
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index d6f7b26b99cd7..309063631ec99 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -209,7 +209,7 @@ TEST(DXCFile, ParseDXILPart) {
   DXContainer C =
       llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
   EXPECT_EQ(C.getHeader().PartCount, 1u);
-  const std::optional<object::DXContainer::DXILData> &DXIL = C.getDXIL();
+  const std::optional<object::DXContainer::DXILData> &DXIL = C.getDXIL(false);
   EXPECT_TRUE(DXIL.has_value());
   dxbc::ProgramHeader Header = DXIL->first;
   EXPECT_EQ(Header.getMajorVersion(), 6u);
@@ -220,6 +220,52 @@ TEST(DXCFile, ParseDXILPart) {
   EXPECT_EQ(Header.Bitcode.MinorVersion, 5u);
 }
 
+// This test verifies that ILDB part is correctly parsed.
+// This test is based on the binary output constructed from this yaml.
+// --- !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:       1
+// Parts:
+//   - Name:            ILDB
+//     Size:            28
+//     Program:
+//       MajorVersion:    6
+//       MinorVersion:    5
+//       ShaderKind:      5
+//       Size:            8
+//       DXILMajorVersion: 1
+//       DXILMinorVersion: 5
+//       DXILSize:        4
+//       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE, ]
+// ...
+TEST(DXCFile, ParseILDBPart) {
+  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,
+      0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+      0x49, 0x4c, 0x44, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00,
+      0x08, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00,
+      0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde};
+  DXContainer C =
+      llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
+  EXPECT_EQ(C.getHeader().PartCount, 1u);
+  const std::optional<object::DXContainer::DXILData> &DXIL = C.getDXIL(true);
+  EXPECT_TRUE(DXIL.has_value());
+  dxbc::ProgramHeader Header = DXIL->first;
+  EXPECT_EQ(Header.getMajorVersion(), 6u);
+  EXPECT_EQ(Header.getMinorVersion(), 5u);
+  EXPECT_EQ(Header.ShaderKind, 5u);
+  EXPECT_EQ(Header.Size, 8u);
+  EXPECT_EQ(Header.Bitcode.MajorVersion, 1u);
+  EXPECT_EQ(Header.Bitcode.MinorVersion, 5u);
+  EXPECT_TRUE(memcmp(DXIL->second, "\x42\x43\xc0\xde", 4) == 0);
+}
+
 static Expected<DXContainer>
 generateDXContainer(StringRef Yaml, SmallVectorImpl<char> &BinaryData) {
   DXContainerYAML::Object Obj;

``````````

</details>


https://github.com/llvm/llvm-project/pull/189685


More information about the llvm-commits mailing list