https://github.com/dzhidzhoev created https://github.com/llvm/llvm-project/pull/199555
This change modifies DXContainerGlobals pass to generate debug name (ILDN) part in DXContainer. ILDN part allows consumers to find PDB file containing shader debug info. As ILDB emission PR is not merged yet, and PDB file creation is not upstreamed yet, debug name is generated based on MD5-hash of bitcode module in DXIL part. This corresponds to DXC behavior when a shader is compiled with `/Zi /Qembed_debug /Zsb` flags (with `/Qembed_debug`, DXC does not produce an actual PDB file, but still emits ILDN, `/Zsb` tells DXC to use bitcode from DXIL to compute hash). However, here ILDN is emitted for any debug info flag configuration. assuming that it won't break debug info consumers, and that PDB creation will be added later. >From 51d3f4824bb39518d22a3dce35ab464bab92d459 Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev <[email protected]> Date: Sun, 3 May 2026 20:51:25 +0200 Subject: [PATCH] [DirectX] Generate shader debug file name part in llc This change modifies DXContainerGlobals pass to generate debug name (ILDN) part in DXContainer. ILDN part allows consumers to find PDB file containing shader debug info. As ILDB emission PR is not merged yet, and PDB file creation is not upstreamed yet, debug name is generated based on MD5-hash of bitcode module in DXIL part. This corresponds to DXC behavior when a shader is compiled with `/Zi /Qembed_debug /Zsb` flags (with `/Qembed_debug`, DXC does not produce an actual PDB file, but still emits ILDN, `/Zsb` tells DXC to use bitcode from DXIL to compute hash). Support for other modes should be added later. --- clang/test/Driver/dxc_section_emission.hlsl | 25 +++++++++ .../lib/Target/DirectX/DXContainerGlobals.cpp | 52 +++++++++++++++---- .../DirectX/ContainerData/DebugName-DXIL.ll | 38 ++++++++++++++ llvm/test/CodeGen/DirectX/lit.local.cfg | 12 +++++ 4 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 clang/test/Driver/dxc_section_emission.hlsl create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/DebugName-DXIL.ll diff --git a/clang/test/Driver/dxc_section_emission.hlsl b/clang/test/Driver/dxc_section_emission.hlsl new file mode 100644 index 0000000000000..b27232f6b7d27 --- /dev/null +++ b/clang/test/Driver/dxc_section_emission.hlsl @@ -0,0 +1,25 @@ +// Check that debug-info-related parts are emitted when clang-dxc is invoked with debug option. + +// REQUIRES: directx-registered-target +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -g %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc /Zi %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc /Zi /Qembed_debug %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -Zi %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -Zi -Qembed_debug %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -Zi -gcodeview %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -Zi -gdwarf %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -gcodeview -Zi %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 /Fo %t.dxbc -gdwarf -Zi %s 2>&1 +// RUN: obj2yaml %t.dxbc | FileCheck %s + +// CHECK: - Name: ILDN + +[numthreads(1, 1, 1)] void main() {} diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp index 5fdc498db57e1..cd1a526539f31 100644 --- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/MC/DXContainerInfo.h" #include "llvm/MC/DXContainerPSVInfo.h" #include "llvm/Pass.h" #include "llvm/Support/MD5.h" @@ -39,8 +40,12 @@ class DXContainerGlobals : public llvm::ModulePass { GlobalVariable *buildContainerGlobal(Module &M, Constant *Content, StringRef Name, StringRef SectionName); + void addSection(Module &M, SmallVector<GlobalValue *> &Globals, + StringRef SectionData, StringRef MetadataName, + StringRef SectionName); GlobalVariable *getFeatureFlags(Module &M); - GlobalVariable *computeShaderHash(Module &M); + void computeShaderHashAndDebugName(Module &M, + SmallVector<GlobalValue *> &Globals); GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name, StringRef SectionName); void addSignature(Module &M, SmallVector<GlobalValue *> &Globals); @@ -74,7 +79,7 @@ class DXContainerGlobals : public llvm::ModulePass { bool DXContainerGlobals::runOnModule(Module &M) { llvm::SmallVector<GlobalValue *> Globals; Globals.push_back(getFeatureFlags(M)); - Globals.push_back(computeShaderHash(M)); + computeShaderHashAndDebugName(M, Globals); addSignature(M, Globals); addRootSignature(M, Globals); addPipelineStateValidationInfo(M, Globals); @@ -93,7 +98,19 @@ GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) { return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0"); } -GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) { +void DXContainerGlobals::addSection(Module &M, + SmallVector<GlobalValue *> &Globals, + StringRef SectionData, + StringRef MetadataName, + StringRef SectionName) { + Constant *SectionConstant = ConstantDataArray::getString( + M.getContext(), SectionData, /*AddNull*/ false); + Globals.emplace_back( + buildContainerGlobal(M, SectionConstant, MetadataName, SectionName)); +} + +void DXContainerGlobals::computeShaderHashAndDebugName( + Module &M, SmallVector<GlobalValue *> &Globals) { auto *DXILConstant = cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer()); MD5 Digest; @@ -113,7 +130,26 @@ GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) { Constant *ModuleConstant = ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data)); - return buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH"); + Globals.emplace_back( + buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH")); + + // Emit ILDN part in debug info mode. + // DXIL bitcode hash is used, which corresponds to DXC behavior with + // `/Zi /Qembed_debug /Zsb` flags. + if (M.debug_compile_units().empty()) + return; + + SmallString<40> DebugNameStr; + Digest.stringifyResult(Result, DebugNameStr); + DebugNameStr += ".pdb"; + + mcdxbc::DebugName DebugName; + DebugName.setFilename(DebugNameStr); + + SmallString<64> ILDNData; + raw_svector_ostream OS(ILDNData); + DebugName.write(OS); + addSection(M, Globals, ILDNData, "dx.ildn", "ILDN"); } GlobalVariable *DXContainerGlobals::buildContainerGlobal( @@ -175,9 +211,7 @@ void DXContainerGlobals::addRootSignature(Module &M, RS->write(OS); - Constant *Constant = - ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); - Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.rts0", "RTS0")); + addSection(M, Globals, Data, "dx.rts0", "RTS0"); } void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) { @@ -302,9 +336,7 @@ void DXContainerGlobals::addPipelineStateValidationInfo( PSV.finalize(MMI.ShaderProfile); PSV.write(OS); - Constant *Constant = - ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); - Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.psv0", "PSV0")); + addSection(M, Globals, Data, "dx.psv0", "PSV0"); } char DXContainerGlobals::ID = 0; diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-DXIL.ll b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-DXIL.ll new file mode 100644 index 0000000000000..0a22e65e59af3 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-DXIL.ll @@ -0,0 +1,38 @@ +; Verify that ILDN part is created when debug info is on. + +; RUN: llc %s --filetype=obj -o %t.dxbc +; RUN: obj2yaml %t.dxbc >%t.yaml +; RUN: llvm-objcopy --dump-section=DXIL=%t0.bc %t.dxbc +; RUN: %md5sum %t0.bc >%t0.bc.md5 +; RUN: cat %t.yaml %t0.bc.md5 | FileCheck %s + +; Verify that ILDN part is not created when debug info is off. +; RUN: opt -strip-debug < %s | llc --filetype=obj | obj2yaml | \ +; RUN: FileCheck --implicit-check-not=ILDN --check-prefix=NODEBUG %s + +; CHECK: - Name: ILDN +; CHECK-NEXT: Size: 44 +; CHECK-NEXT: DebugName: +; CHECK-NEXT: Flags: 0 +; CHECK-NEXT: NameLength: 36 +; CHECK-NEXT: DebugName: [[MD5:[0-9a-f]+]].pdb +; CHECK: ... +; CHECK-NEXT: [[MD5]] + +; NODEBUG: - Name: DXIL + +target triple = "dxilv1.3-pc-shadermodel6.3-library" + +define float @_Z3fooff(float %a, float %b) { +entry1: + %add = fadd float %a, %b + ret float %add +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) +!1 = !DIFile(filename: "dx-source-metadata.hlsl", directory: "C:\\") +!2 = !{i32 2, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/llvm/test/CodeGen/DirectX/lit.local.cfg b/llvm/test/CodeGen/DirectX/lit.local.cfg index 72de724f06d79..d40234d1e598c 100644 --- a/llvm/test/CodeGen/DirectX/lit.local.cfg +++ b/llvm/test/CodeGen/DirectX/lit.local.cfg @@ -1,2 +1,14 @@ if not "DirectX" in config.root.targets: config.unsupported = True + +# Insert at 0 to prevent '%p' from being substituted with test directory in '%python'. +config.substitutions.insert( + 0, + ( + "%md5sum", + '%python -c "import sys,hashlib; ' + "p=sys.argv[1]; " + "h=hashlib.md5(open(p,'rb').read()).hexdigest(); " + 'print(h)"', + ), +) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
