[llvm] [DirectX] Write DXIL with debug info to ILDB part (PR #201423)

Ilia Kuklin via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 03:43:31 PDT 2026


https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/201423

>From 7e1d20d0fc04a3799b768be838eb741cd90b4284 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 3 Jun 2026 01:43:03 +0500
Subject: [PATCH 1/3] [DirectX] Write DXIL with debug info to ILDB part

---
 llvm/include/llvm/BinaryFormat/DXContainer.h  |   1 +
 llvm/lib/BinaryFormat/DXContainer.cpp         |   4 +
 llvm/lib/MC/MCDXContainerWriter.cpp           |   6 +-
 .../lib/Target/DirectX/DXContainerGlobals.cpp |   6 +-
 .../DirectX/DXILWriter/DXILWriterPass.cpp     | 102 +++++++++++++++---
 .../DirectX/ContainerData/DebugShaderHash.ll  |   4 +-
 llvm/test/CodeGen/DirectX/embed-ildb.ll       |  98 +++++++++++++++++
 llvm/test/tools/dxil-dis/dbg-declare-undef.ll |   4 +-
 llvm/test/tools/dxil-dis/dbg-value.ll         |   4 +-
 llvm/test/tools/dxil-dis/debug-info.ll        |   4 +-
 .../di-compile-unit-versioned-language.ll     |   4 +-
 llvm/test/tools/dxil-dis/di-compile-unit.ll   |   4 +-
 llvm/test/tools/dxil-dis/di-label.ll          |   4 +-
 llvm/test/tools/dxil-dis/di-subprogram.ll     |   4 +-
 llvm/test/tools/dxil-dis/di-subrange.ll       |   4 +-
 llvm/test/tools/dxil-dis/di-subrangetype.ll   |   4 +-
 llvm/test/tools/dxil-dis/vla.ll               |   4 +-
 17 files changed, 228 insertions(+), 33 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/embed-ildb.ll

diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index a93d99693eb87..84c822ddbd2cb 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -263,6 +263,7 @@ LLVM_ABI PartType parsePartType(StringRef S);
 bool isDebugProgramPart(PartType PT);
 
 const char *getProgramPartName(bool IsDebug);
+bool isProgramPart(StringRef PartName);
 
 struct VertexPSVInfo {
   uint8_t OutputPositionPresent;
diff --git a/llvm/lib/BinaryFormat/DXContainer.cpp b/llvm/lib/BinaryFormat/DXContainer.cpp
index b980f2cf1865c..46d91347742b2 100644
--- a/llvm/lib/BinaryFormat/DXContainer.cpp
+++ b/llvm/lib/BinaryFormat/DXContainer.cpp
@@ -133,6 +133,10 @@ const char *dxbc::getProgramPartName(bool IsDebug) {
   return IsDebug ? "ILDB" : "DXIL";
 }
 
+bool dxbc::isProgramPart(StringRef PartName) {
+  return PartName == "DXIL" || PartName == "ILDB";
+}
+
 bool ShaderHash::isPopulated() {
   static uint8_t Zeros[16] = {0};
   return Flags > 0 || 0 != memcmp(&Digest, &Zeros, 16);
diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
index ebed411454087..e027d543ce5d8 100644
--- a/llvm/lib/MC/MCDXContainerWriter.cpp
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -39,7 +39,7 @@ uint64_t DXContainerObjectWriter::writeObject() {
     PartOffset = alignTo(PartOffset, Align(4ul));
     // The DXIL part also writes a program header, so we need to include its
     // size when computing the offset for a part after the DXIL part.
-    if (Sec.getName() == "DXIL")
+    if (dxbc::isProgramPart(Sec.getName()))
       PartOffset += sizeof(dxbc::ProgramHeader);
   }
   assert(PartOffset < std::numeric_limits<uint32_t>::max() &&
@@ -78,12 +78,12 @@ uint64_t DXContainerObjectWriter::writeObject() {
 
     uint64_t PartSize = SectionSize;
 
-    if (Sec.getName() == "DXIL")
+    if (dxbc::isProgramPart(Sec.getName()))
       PartSize += sizeof(dxbc::ProgramHeader);
     // DXContainer parts should be 4-byte aligned.
     PartSize = alignTo(PartSize, Align(4));
     W.write<uint32_t>(static_cast<uint32_t>(PartSize));
-    if (Sec.getName() == "DXIL") {
+    if (dxbc::isProgramPart(Sec.getName())) {
       dxbc::ProgramHeader Header;
       memset(reinterpret_cast<void *>(&Header), 0, sizeof(dxbc::ProgramHeader));
 
diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
index 7fef7436f3874..9a68961473dbd 100644
--- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
@@ -113,17 +113,13 @@ void DXContainerGlobals::addSection(Module &M,
 
 void DXContainerGlobals::computeShaderHashAndDebugName(
     Module &M, SmallVector<GlobalValue *> &Globals) {
+  // TODO: Add -Zss flag to enable/disable calculating shader hash from ILDB.
   auto *DXILConstant =
       cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
   MD5 Digest;
   Digest.update(DXILConstant->getRawDataValues());
   MD5::MD5Result Result = Digest.final();
-
   dxbc::ShaderHash HashData = {0, {0}};
-  // The Hash's IncludesSource flag gets set whenever the hashed shader includes
-  // debug information.
-  if (!M.debug_compile_units().empty())
-    HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
 
   memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
   if (sys::IsBigEndianHost)
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
index f74accc3b8619..6b249a5b309e5 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
@@ -18,6 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/ModuleSummaryAnalysis.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -28,6 +29,7 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Alignment.h"
+#include "llvm/Transforms/Utils/Cloning.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace llvm;
@@ -138,7 +140,72 @@ static void removeLifetimeIntrinsics(Module &M) {
   }
 }
 
+static void replaceNamedMetadataArray(Module &M, StringRef Name,
+                                      ArrayRef<Metadata *> NewOps) {
+  NamedMDNode *NMD = M.getNamedMetadata(Name);
+  if (!NMD)
+    return;
+  NMD->eraseFromParent();
+  M.getOrInsertNamedMetadata(Name)->addOperand(
+      MDTuple::get(M.getContext(), NewOps));
+}
+
 class EmbedDXILPass : public llvm::ModulePass {
+  std::string writeModule(Module &M, bool HasDebugInfo, bool WriteDebug) {
+    std::string Data;
+    llvm::raw_string_ostream OS(Data);
+
+    if (HasDebugInfo) {
+      if (WriteDebug) {
+        // Replace dx.source metadata nodes with stubs.
+        // TODO: Add /Qsource_in_debug_module flag to enable/disable this.
+        LLVMContext &Ctx = M.getContext();
+        MDString *EmptyString = MDString::get(Ctx, "");
+        replaceNamedMetadataArray(M, "dx.source.contents",
+                                  {EmptyString, EmptyString});
+        replaceNamedMetadataArray(M, "dx.source.defines", {});
+        replaceNamedMetadataArray(M, "dx.source.mainFileName", {EmptyString});
+        replaceNamedMetadataArray(M, "dx.source.args", {});
+      } else {
+        // If we have an ILDB part, strip DXIL from all debug info.
+        StripDebugInfo(M);
+
+        // Also, manually remove debug version flags and dx.source nodes.
+        if (NamedMDNode *Flags = M.getModuleFlagsMetadata()) {
+          SmallVector<llvm::Module::ModuleFlagEntry, 4> FlagEntries;
+          M.getModuleFlagsMetadata(FlagEntries);
+          Flags->eraseFromParent();
+          for (llvm::Module::ModuleFlagEntry &Entry : FlagEntries) {
+            if (Entry.Key->getString() == "Dwarf Version" ||
+                Entry.Key->getString() == "Debug Info Version") {
+              continue;
+            }
+            M.addModuleFlag(Entry.Behavior, Entry.Key->getString(), Entry.Val);
+          }
+        }
+        for (NamedMDNode &NMD : llvm::make_early_inc_range(M.named_metadata()))
+          if (NMD.getName().starts_with("dx.source"))
+            NMD.eraseFromParent();
+      }
+    }
+    const auto DIMap = DXILDebugInfoPass::run(M);
+    WriteDXILToFile(M, OS, DIMap);
+    return Data;
+  }
+
+  GlobalVariable *createSectionGlobal(Module &M, StringRef Data,
+                                      StringRef GlobalName,
+                                      StringRef SectionName) {
+    Constant *ModuleConstant =
+        ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
+    auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
+                                        GlobalValue::PrivateLinkage,
+                                        ModuleConstant, GlobalName);
+    GV->setSection(SectionName);
+    GV->setAlignment(Align(4));
+    return GV;
+  }
+
 public:
   static char ID; // Pass identification, replacement for typeid
   EmbedDXILPass() : ModulePass(ID) {
@@ -148,29 +215,38 @@ class EmbedDXILPass : public llvm::ModulePass {
   StringRef getPassName() const override { return "DXIL Embedder"; }
 
   bool runOnModule(Module &M) override {
-    std::string Data;
-    llvm::raw_string_ostream OS(Data);
-
     // Perform late legalization of lifetime intrinsics that would otherwise
     // fail the Module Verifier if performed in an earlier pass
     legalizeLifetimeIntrinsics(M);
 
-    const auto DIMap = DXILDebugInfoPass::run(M);
-    WriteDXILToFile(M, OS, DIMap);
+    bool HasDebugInfo = !M.debug_compile_units().empty();
+    std::string ILDBData;
+    if (HasDebugInfo) {
+      // Write DXIL with debug info to ILDB part.
+      // Clone the module to avoid alternating it with DebugInfoPass
+      // before stripping the debug info later.
+      ILDBData =
+          writeModule(*llvm::CloneModule(M), HasDebugInfo, /*WriteDebug=*/true);
+    }
+
+    // Clone the module to save dx.source metadata nodes from stripping, as they
+    // are needed for DXILMetadataAnalysisWrapperPass.
+    std::string DXILData =
+        writeModule(*llvm::CloneModule(M), HasDebugInfo, /*WriteDebug=*/false);
 
     // We no longer need lifetime intrinsics after bitcode serialization, so we
     // simply remove them to keep the Module Verifier happy after our
     // not-so-legal legalizations
     removeLifetimeIntrinsics(M);
 
-    Constant *ModuleConstant =
-        ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
-    auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
-                                        GlobalValue::PrivateLinkage,
-                                        ModuleConstant, "dx.dxil");
-    GV->setSection("DXIL");
-    GV->setAlignment(Align(4));
-    appendToCompilerUsed(M, {GV});
+    SmallVector<GlobalValue *, 2> Globals;
+    if (HasDebugInfo) {
+      // Create a GV after both parts are written, otherwise it gets
+      // added to DXIL when `writeModule` is called the second time.
+      Globals.emplace_back(createSectionGlobal(M, ILDBData, "dx.ildb", "ILDB"));
+    }
+    Globals.emplace_back(createSectionGlobal(M, DXILData, "dx.dxil", "DXIL"));
+    appendToCompilerUsed(M, Globals);
     return true;
   }
 
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugShaderHash.ll b/llvm/test/CodeGen/DirectX/ContainerData/DebugShaderHash.ll
index eda0d6850bde5..c0febd5bf758d 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/DebugShaderHash.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugShaderHash.ll
@@ -2,7 +2,7 @@
 ; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
 target triple = "dxil-unknown-shadermodel6.5-library"
 
-; CHECK: @dx.hash = private constant [20 x i8] c"\01\00\00\00{{.*}}", section "HASH", align 4
+; CHECK: @dx.hash = private constant [20 x i8] c"\00\00\00\00{{.*}}", section "HASH", align 4
 
 define i32 @add(i32 %a, i32 %b) {
   %sum = add i32 %a, %b
@@ -21,5 +21,5 @@ define i32 @add(i32 %a, i32 %b) {
 ; DXC: - Name:            HASH
 ; DXC:   Size:            20
 ; DXC:   Hash:
-; DXC:     IncludesSource:  true
+; DXC:     IncludesSource:  false
 ; DXC:     Digest:          [ 
diff --git a/llvm/test/CodeGen/DirectX/embed-ildb.ll b/llvm/test/CodeGen/DirectX/embed-ildb.ll
new file mode 100644
index 0000000000000..1f4289f3b725e
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/embed-ildb.ll
@@ -0,0 +1,98 @@
+; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s
+; RUN: llc %s --filetype=obj -o %t.bc
+; RUN: obj2yaml %t.bc | FileCheck %s --check-prefix=YAML
+; RUN: llvm-objcopy --dump-section=ILDB=%t.ildb %t.bc
+; RUN: llvm-objcopy --dump-section=DXIL=%t.dxil %t.bc
+; RUN: llvm-dis %t.ildb -o - | FileCheck %s --check-prefix=ILDB-DIS
+; RUN: llvm-dis %t.dxil -o - | FileCheck %s --check-prefix=DXIL-DIS
+
+target triple = "dxil-unknown-shadermodel6.5-library"
+; CHECK: target triple = "dxil-unknown-shadermodel6.5-library"
+
+define i32 @add(i32 %a, i32 %b) {
+  %sum = add i32 %a, %b
+  ret i32 %sum
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!dx.source.contents = !{!5}
+!dx.source.defines = !{!6}
+!dx.source.mainFileName = !{!7}
+!dx.source.args = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "hlsl.hlsl", directory: "/some-path")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 2}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"hlsl.hlsl", !"int add(int a, int b) { return a + b; }"}
+!6 = !{}
+!7 = !{!"hlsl.hlsl"}
+!8 = !{!"-T", !"lib_6_5", !"-g", !"hlsl.hlsl"}
+
+; Check that both parts are emitted as a GV and used by the compiler.
+
+; CHECK: @dx.ildb = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "ILDB", align 4
+; CHECK: @dx.dxil = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "DXIL", align 4
+; CHECK: @llvm.compiler.used = appending global {{\[[0-9]+ x ptr\]}} [ptr @dx.ildb, ptr @dx.dxil
+
+; This is using regex matches on some sizes, offsets and fields. These are all
+; going to change as the DirectX backend continues to evolve and implement more
+; features. Rather than extending this test to cover those future features, this
+; test's matches are extremely fuzzy so that it won't break.
+
+; YAML: --- !dxcontainer
+; YAML-NEXT: Header:
+; YAML-NEXT:   Hash:            [ 0x0, 0x0, 0x0,
+; YAML:   Version:
+; YAML-NEXT:     Major:           1
+; YAML-NEXT:     Minor:           0
+; YAML-NEXT:   FileSize:        [[#]]
+; YAML-NEXT:   PartCount:       [[#]]
+; YAML-NEXT:   PartOffsets:     [ {{[0-9, ]+}}
+; YAML:   Parts:
+
+; In verifying the DXIL and ILDB parts, this test captures the size of the part,
+; and derives the program header and dxil size fields from the part's size.
+
+; YAML:   - Name:            ILDB
+; YAML-NEXT:     Size:            [[#ILDBSIZE:]]
+; YAML-NEXT:     Program:
+; YAML-NEXT:       MajorVersion:    6
+; YAML-NEXT:       MinorVersion:    5
+; YAML-NEXT:       ShaderKind:      6
+; YAML-NEXT:       Size:            [[#div(ILDBSIZE,4)]]
+; YAML-NEXT:       DXILMajorVersion: 1
+; YAML-NEXT:       DXILMinorVersion: 5
+; YAML-NEXT:       DXILSize:        [[#ILDBSIZE - 24]]
+; YAML-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE,
+; YAML:   - Name:            DXIL
+; YAML-NEXT:     Size:            [[#DXILSIZE:]]
+; YAML-NEXT:     Program:
+; YAML-NEXT:       MajorVersion:    6
+; YAML-NEXT:       MinorVersion:    5
+; YAML-NEXT:       ShaderKind:      6
+; YAML-NEXT:       Size:            [[#div(DXILSIZE,4)]]
+; YAML-NEXT:       DXILMajorVersion: 1
+; YAML-NEXT:       DXILMinorVersion: 5
+; YAML-NEXT:       DXILSize:        [[#DXILSIZE - 24]]
+; YAML-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE,
+
+; Check that ILDB has the debug info, and DXIL does not:
+
+; ILDB-DIS: define i32 @add(i32 %a, i32 %b)
+; ILDB-DIS: !llvm.dbg.cu
+; ILDB-DIS: !DICompileUnit
+; ILDB-DIS: !DIFile
+; ILDB-DIS: !"Dwarf Version"
+; ILDB-DIS: !"Debug Info Version"
+
+; DXIL-DIS: define i32 @add(i32 %a, i32 %b)
+; DXIL-DIS-NOT: !llvm.dbg.cu
+; DXIL-DIS-NOT: !dx.source
+; DXIL-DIS-NOT: !DICompileUnit
+; DXIL-DIS-NOT: !DIFile
+; DXIL-DIS-NOT: !"Dwarf Version"
+; DXIL-DIS-NOT: !"Debug Info Version"
+; DXIL-DIS-NOT: "hlsl.hlsl"
diff --git a/llvm/test/tools/dxil-dis/dbg-declare-undef.ll b/llvm/test/tools/dxil-dis/dbg-declare-undef.ll
index fa599ea02d912..e816f44c2e7df 100644
--- a/llvm/test/tools/dxil-dis/dbg-declare-undef.ll
+++ b/llvm/test/tools/dxil-dis/dbg-declare-undef.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o  - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.3-library"
 
diff --git a/llvm/test/tools/dxil-dis/dbg-value.ll b/llvm/test/tools/dxil-dis/dbg-value.ll
index 51dc2fa968efa..64f62e34e6b5f 100644
--- a/llvm/test/tools/dxil-dis/dbg-value.ll
+++ b/llvm/test/tools/dxil-dis/dbg-value.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o  - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.3-library"
 
diff --git a/llvm/test/tools/dxil-dis/debug-info.ll b/llvm/test/tools/dxil-dis/debug-info.ll
index 783c652f5df0a..ba4a0adb6e5b2 100644
--- a/llvm/test/tools/dxil-dis/debug-info.ll
+++ b/llvm/test/tools/dxil-dis/debug-info.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o  - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-unknown-shadermodel6.7-library"
 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
diff --git a/llvm/test/tools/dxil-dis/di-compile-unit-versioned-language.ll b/llvm/test/tools/dxil-dis/di-compile-unit-versioned-language.ll
index 42c469acfd810..4ac9fa17477b9 100644
--- a/llvm/test/tools/dxil-dis/di-compile-unit-versioned-language.ll
+++ b/llvm/test/tools/dxil-dis/di-compile-unit-versioned-language.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-unknown-shadermodel6.3-library"
 
diff --git a/llvm/test/tools/dxil-dis/di-compile-unit.ll b/llvm/test/tools/dxil-dis/di-compile-unit.ll
index 10988fc3defe4..c080a6b05e678 100644
--- a/llvm/test/tools/dxil-dis/di-compile-unit.ll
+++ b/llvm/test/tools/dxil-dis/di-compile-unit.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
 !llvm.dbg.cu = !{!0}
diff --git a/llvm/test/tools/dxil-dis/di-label.ll b/llvm/test/tools/dxil-dis/di-label.ll
index 7b66ba8ec4893..43a6377ec89d0 100644
--- a/llvm/test/tools/dxil-dis/di-label.ll
+++ b/llvm/test/tools/dxil-dis/di-label.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.3-library"
 
diff --git a/llvm/test/tools/dxil-dis/di-subprogram.ll b/llvm/test/tools/dxil-dis/di-subprogram.ll
index 9d31b611e71df..aed4690a38e26 100644
--- a/llvm/test/tools/dxil-dis/di-subprogram.ll
+++ b/llvm/test/tools/dxil-dis/di-subprogram.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
 define float @fmaf(float %x, float %y, float %z) !dbg !4 {
diff --git a/llvm/test/tools/dxil-dis/di-subrange.ll b/llvm/test/tools/dxil-dis/di-subrange.ll
index 5141fe509d647..339410e7b6eb3 100644
--- a/llvm/test/tools/dxil-dis/di-subrange.ll
+++ b/llvm/test/tools/dxil-dis/di-subrange.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
 !llvm.module.flags = !{!0, !1}
diff --git a/llvm/test/tools/dxil-dis/di-subrangetype.ll b/llvm/test/tools/dxil-dis/di-subrangetype.ll
index cb81a9d072f31..5d2601ea00da8 100644
--- a/llvm/test/tools/dxil-dis/di-subrangetype.ll
+++ b/llvm/test/tools/dxil-dis/di-subrangetype.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.3-library"
 
diff --git a/llvm/test/tools/dxil-dis/vla.ll b/llvm/test/tools/dxil-dis/vla.ll
index 2287999d134cc..491cea0626862 100644
--- a/llvm/test/tools/dxil-dis/vla.ll
+++ b/llvm/test/tools/dxil-dis/vla.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.3-library"
 

>From c2581e782dfb001f056203b8a114c80fdcb89cb0 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 3 Jun 2026 22:50:23 +0500
Subject: [PATCH 2/3] Add an assert for when the module has some debug info,
 but no compile units.

---
 llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
index 6b249a5b309e5..e78e6775403fa 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
@@ -187,6 +187,13 @@ class EmbedDXILPass : public llvm::ModulePass {
           if (NMD.getName().starts_with("dx.source"))
             NMD.eraseFromParent();
       }
+    } else {
+#ifdef EXPENSIVE_CHECKS
+      assert(
+          StripDebugInfo(M) == false &&
+          "The module must not contain any debug info here."
+          "Shader modules with debug info must have !DICompileUnit metadata.");
+#endif
     }
     const auto DIMap = DXILDebugInfoPass::run(M);
     WriteDXILToFile(M, OS, DIMap);

>From eaa16e4b548b8d63844ba1e9a7443ada3cf517dc Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 8 Jun 2026 15:35:56 +0500
Subject: [PATCH 3/3] Fix a new test after rebasing

---
 llvm/test/tools/dxil-dis/di-globalvariable.ll | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/llvm/test/tools/dxil-dis/di-globalvariable.ll b/llvm/test/tools/dxil-dis/di-globalvariable.ll
index effa606b81283..ed864cccc4354 100644
--- a/llvm/test/tools/dxil-dis/di-globalvariable.ll
+++ b/llvm/test/tools/dxil-dis/di-globalvariable.ll
@@ -1,4 +1,6 @@
-; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
+; RUN: llc --filetype=obj %s -o %t.dxbc
+; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
+; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
 target triple = "dxil-unknown-shadermodel6.3-library"
 



More information about the llvm-commits mailing list