Skip to content

Commit b495ef3

Browse files
committed
Write DXIL with debug info to ILDB part
1 parent 574243d commit b495ef3

15 files changed

Lines changed: 212 additions & 33 deletions

llvm/lib/MC/MCDXContainerWriter.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ uint64_t DXContainerObjectWriter::writeObject() {
3939
PartOffset = alignTo(PartOffset, Align(4ul));
4040
// The DXIL part also writes a program header, so we need to include its
4141
// size when computing the offset for a part after the DXIL part.
42-
if (Sec.getName() == "DXIL")
42+
if (Sec.getName() == "DXIL" || Sec.getName() == "ILDB")
4343
PartOffset += sizeof(dxbc::ProgramHeader);
4444
}
4545
assert(PartOffset < std::numeric_limits<uint32_t>::max() &&
@@ -78,12 +78,12 @@ uint64_t DXContainerObjectWriter::writeObject() {
7878

7979
uint64_t PartSize = SectionSize;
8080

81-
if (Sec.getName() == "DXIL")
81+
if (Sec.getName() == "DXIL" || Sec.getName() == "ILDB")
8282
PartSize += sizeof(dxbc::ProgramHeader);
8383
// DXContainer parts should be 4-byte aligned.
8484
PartSize = alignTo(PartSize, Align(4));
8585
W.write<uint32_t>(static_cast<uint32_t>(PartSize));
86-
if (Sec.getName() == "DXIL") {
86+
if (Sec.getName() == "DXIL" || Sec.getName() == "ILDB") {
8787
dxbc::ProgramHeader Header;
8888
memset(reinterpret_cast<void *>(&Header), 0, sizeof(dxbc::ProgramHeader));
8989

llvm/lib/Target/DirectX/DXContainerGlobals.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,13 @@ void DXContainerGlobals::addSection(Module &M,
111111

112112
void DXContainerGlobals::computeShaderHashAndDebugName(
113113
Module &M, SmallVector<GlobalValue *> &Globals) {
114+
// TODO: Add -Zss flag to enable/disable calculating shader hash from ILDB.
114115
auto *DXILConstant =
115116
cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
116117
MD5 Digest;
117118
Digest.update(DXILConstant->getRawDataValues());
118119
MD5::MD5Result Result = Digest.final();
119-
120120
dxbc::ShaderHash HashData = {0, {0}};
121-
// The Hash's IncludesSource flag gets set whenever the hashed shader includes
122-
// debug information.
123-
if (!M.debug_compile_units().empty())
124-
HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
125121

126122
memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
127123
if (sys::IsBigEndianHost)

llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/ADT/StringRef.h"
1919
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
2020
#include "llvm/IR/Constants.h"
21+
#include "llvm/IR/DebugInfo.h"
2122
#include "llvm/IR/DerivedTypes.h"
2223
#include "llvm/IR/GlobalVariable.h"
2324
#include "llvm/IR/IntrinsicInst.h"
@@ -28,6 +29,7 @@
2829
#include "llvm/InitializePasses.h"
2930
#include "llvm/Pass.h"
3031
#include "llvm/Support/Alignment.h"
32+
#include "llvm/Transforms/Utils/Cloning.h"
3133
#include "llvm/Transforms/Utils/ModuleUtils.h"
3234

3335
using namespace llvm;
@@ -138,7 +140,75 @@ static void removeLifetimeIntrinsics(Module &M) {
138140
}
139141
}
140142

143+
static void replaceNamedMetadataArray(Module &M, StringRef Name,
144+
ArrayRef<Metadata *> NewOps) {
145+
NamedMDNode *NMD = M.getNamedMetadata(Name);
146+
if (!NMD)
147+
return;
148+
NMD->eraseFromParent();
149+
M.getOrInsertNamedMetadata(Name)->addOperand(
150+
MDTuple::get(M.getContext(), NewOps));
151+
}
152+
141153
class EmbedDXILPass : public llvm::ModulePass {
154+
std::string writeModule(Module &M, bool HasDebugInfo, bool IsDebug) {
155+
std::string Data;
156+
llvm::raw_string_ostream OS(Data);
157+
158+
if (HasDebugInfo) {
159+
if (IsDebug) {
160+
// Replace dx.source metadata nodes with stubs.
161+
// TODO: Add /Qsource_in_debug_module flag to enable/disable this.
162+
LLVMContext &Ctx = M.getContext();
163+
MDString *EmptyString = MDString::get(Ctx, "");
164+
replaceNamedMetadataArray(M, "dx.source.contents",
165+
{EmptyString, EmptyString});
166+
replaceNamedMetadataArray(M, "dx.source.defines", {});
167+
replaceNamedMetadataArray(M, "dx.source.mainFileName", {EmptyString});
168+
replaceNamedMetadataArray(M, "dx.source.args", {});
169+
} else {
170+
// If we have an ILDB part, strip DXIL from all debug info.
171+
StripDebugInfo(M);
172+
173+
// Also, manually remove debug version flags and dx.source nodes.
174+
if (NamedMDNode *Flags = M.getModuleFlagsMetadata()) {
175+
SmallVector<llvm::Module::ModuleFlagEntry, 4> FlagEntries;
176+
M.getModuleFlagsMetadata(FlagEntries);
177+
Flags->eraseFromParent();
178+
for (unsigned I : seq(FlagEntries.size())) {
179+
llvm::Module::ModuleFlagEntry &Entry = FlagEntries[I];
180+
if (Entry.Key->getString() == "Dwarf Version" ||
181+
Entry.Key->getString() == "Debug Info Version") {
182+
continue;
183+
}
184+
M.addModuleFlag(Entry.Behavior, Entry.Key->getString(),
185+
cast<ConstantAsMetadata>(Entry.Val)->getValue());
186+
}
187+
}
188+
for (NamedMDNode &NMD : llvm::make_early_inc_range(M.named_metadata()))
189+
if (NMD.getName().starts_with("dx.source"))
190+
NMD.eraseFromParent();
191+
}
192+
}
193+
194+
const auto DIMap = DXILDebugInfoPass::run(M);
195+
WriteDXILToFile(M, OS, DIMap);
196+
return Data;
197+
}
198+
199+
GlobalVariable *createSectionGlobal(Module &M, StringRef Data,
200+
StringRef GlobalName,
201+
StringRef SectionName) {
202+
Constant *ModuleConstant =
203+
ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
204+
auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
205+
GlobalValue::PrivateLinkage,
206+
ModuleConstant, GlobalName);
207+
GV->setSection(SectionName);
208+
GV->setAlignment(Align(4));
209+
return GV;
210+
}
211+
142212
public:
143213
static char ID; // Pass identification, replacement for typeid
144214
EmbedDXILPass() : ModulePass(ID) {
@@ -148,29 +218,38 @@ class EmbedDXILPass : public llvm::ModulePass {
148218
StringRef getPassName() const override { return "DXIL Embedder"; }
149219

150220
bool runOnModule(Module &M) override {
151-
std::string Data;
152-
llvm::raw_string_ostream OS(Data);
153-
154221
// Perform late legalization of lifetime intrinsics that would otherwise
155222
// fail the Module Verifier if performed in an earlier pass
156223
legalizeLifetimeIntrinsics(M);
157224

158-
const auto DIMap = DXILDebugInfoPass::run(M);
159-
WriteDXILToFile(M, OS, DIMap);
225+
bool HasDebugInfo = !M.debug_compile_units().empty();
226+
std::string ILDBData;
227+
if (HasDebugInfo) {
228+
// Write DXIL with debug info to ILDB part.
229+
// Clone the module to avoid alternating it with DebugInfoPass
230+
// before stripping the debug info later.
231+
ILDBData =
232+
writeModule(*llvm::CloneModule(M), HasDebugInfo, /*IsDebug=*/true);
233+
}
234+
235+
// Clone the module to save dx.source metadata nodes from stripping, as they
236+
// are needed for DXILMetadataAnalysisWrapperPass.
237+
std::string DXILData =
238+
writeModule(*llvm::CloneModule(M), HasDebugInfo, /*IsDebug=*/false);
160239

161240
// We no longer need lifetime intrinsics after bitcode serialization, so we
162241
// simply remove them to keep the Module Verifier happy after our
163242
// not-so-legal legalizations
164243
removeLifetimeIntrinsics(M);
165244

166-
Constant *ModuleConstant =
167-
ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
168-
auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
169-
GlobalValue::PrivateLinkage,
170-
ModuleConstant, "dx.dxil");
171-
GV->setSection("DXIL");
172-
GV->setAlignment(Align(4));
173-
appendToCompilerUsed(M, {GV});
245+
SmallVector<GlobalValue *, 2> Globals;
246+
if (HasDebugInfo) {
247+
// Create a GV after both parts are written, otherwise it gets
248+
// added to DXIL when `writeModule` is called the second time.
249+
Globals.emplace_back(createSectionGlobal(M, ILDBData, "dx.ildb", "ILDB"));
250+
}
251+
Globals.emplace_back(createSectionGlobal(M, DXILData, "dx.dxil", "DXIL"));
252+
appendToCompilerUsed(M, Globals);
174253
return true;
175254
}
176255

llvm/test/CodeGen/DirectX/ContainerData/DebugShaderHash.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
33
target triple = "dxil-unknown-shadermodel6.5-library"
44

5-
; CHECK: @dx.hash = private constant [20 x i8] c"\01\00\00\00{{.*}}", section "HASH", align 4
5+
; CHECK: @dx.hash = private constant [20 x i8] c"\00\00\00\00{{.*}}", section "HASH", align 4
66

77
define i32 @add(i32 %a, i32 %b) {
88
%sum = add i32 %a, %b
@@ -21,5 +21,5 @@ define i32 @add(i32 %a, i32 %b) {
2121
; DXC: - Name: HASH
2222
; DXC: Size: 20
2323
; DXC: Hash:
24-
; DXC: IncludesSource: true
24+
; DXC: IncludesSource: false
2525
; DXC: Digest: [
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s
2+
; RUN: llc %s --filetype=obj -o %t.bc
3+
; RUN: obj2yaml %t.bc | FileCheck %s --check-prefix=YAML
4+
; RUN: llvm-objcopy --dump-section=ILDB=%t.ildb %t.bc
5+
; RUN: llvm-objcopy --dump-section=DXIL=%t.dxil %t.bc
6+
; RUN: llvm-dis %t.ildb -o - | FileCheck %s --check-prefix=ILDB-DIS
7+
; RUN: llvm-dis %t.dxil -o - | FileCheck %s --check-prefix=DXIL-DIS
8+
9+
target triple = "dxil-unknown-shadermodel6.5-library"
10+
; CHECK: target triple = "dxil-unknown-shadermodel6.5-library"
11+
12+
define i32 @add(i32 %a, i32 %b) {
13+
%sum = add i32 %a, %b
14+
ret i32 %sum
15+
}
16+
17+
!llvm.dbg.cu = !{!0}
18+
!llvm.module.flags = !{!3, !4}
19+
20+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
21+
!1 = !DIFile(filename: "hlsl.hlsl", directory: "/some-path")
22+
!2 = !{}
23+
!3 = !{i32 7, !"Dwarf Version", i32 2}
24+
!4 = !{i32 2, !"Debug Info Version", i32 3}
25+
26+
; Check that both parts are emitted as a GV and used by the compiler.
27+
28+
; CHECK: @dx.ildb = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "ILDB", align 4
29+
; CHECK: @dx.dxil = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "DXIL", align 4
30+
; CHECK: @llvm.compiler.used = appending global {{\[[0-9]+ x ptr\]}} [ptr @dx.ildb, ptr @dx.dxil
31+
32+
; This is using regex matches on some sizes, offsets and fields. These are all
33+
; going to change as the DirectX backend continues to evolve and implement more
34+
; features. Rather than extending this test to cover those future features, this
35+
; test's matches are extremely fuzzy so that it won't break.
36+
37+
; YAML: --- !dxcontainer
38+
; YAML-NEXT: Header:
39+
; YAML-NEXT: Hash: [ 0x0, 0x0, 0x0,
40+
; YAML: Version:
41+
; YAML-NEXT: Major: 1
42+
; YAML-NEXT: Minor: 0
43+
; YAML-NEXT: FileSize: [[#]]
44+
; YAML-NEXT: PartCount: [[#]]
45+
; YAML-NEXT: PartOffsets: [ {{[0-9, ]+}} ]
46+
; YAML-NEXT: Parts:
47+
48+
; In verifying the DXIL and ILDB parts, this test captures the size of the part,
49+
; and derives the program header and dxil size fields from the part's size.
50+
51+
; YAML: - Name: ILDB
52+
; YAML-NEXT: Size: [[#ILDBSIZE:]]
53+
; YAML-NEXT: Program:
54+
; YAML-NEXT: MajorVersion: 6
55+
; YAML-NEXT: MinorVersion: 5
56+
; YAML-NEXT: ShaderKind: 6
57+
; YAML-NEXT: Size: [[#div(ILDBSIZE,4)]]
58+
; YAML-NEXT: DXILMajorVersion: 1
59+
; YAML-NEXT: DXILMinorVersion: 5
60+
; YAML-NEXT: DXILSize: [[#ILDBSIZE - 24]]
61+
; YAML-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE,
62+
; YAML: - Name: DXIL
63+
; YAML-NEXT: Size: [[#DXILSIZE:]]
64+
; YAML-NEXT: Program:
65+
; YAML-NEXT: MajorVersion: 6
66+
; YAML-NEXT: MinorVersion: 5
67+
; YAML-NEXT: ShaderKind: 6
68+
; YAML-NEXT: Size: [[#div(DXILSIZE,4)]]
69+
; YAML-NEXT: DXILMajorVersion: 1
70+
; YAML-NEXT: DXILMinorVersion: 5
71+
; YAML-NEXT: DXILSize: [[#DXILSIZE - 24]]
72+
; YAML-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE,
73+
74+
; Check that ILDB has the debug info, and DXIL does not:
75+
76+
; ILDB-DIS: define i32 @add(i32 %a, i32 %b)
77+
; ILDB-DIS: !llvm.dbg.cu
78+
; ILDB-DIS: !DICompileUnit
79+
; ILDB-DIS: !DIFile
80+
81+
; DXIL-DIS: define i32 @add(i32 %a, i32 %b)
82+
; DXIL-DIS-NOT: !llvm.dbg.cu
83+
; DXIL-DIS-NOT: !DICompileUnit
84+
; DXIL-DIS-NOT: !DIFile

llvm/test/tools/dxil-dis/dbg-declare-undef.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
1+
; RUN: llc --filetype=obj %s -o %t.dxbc
2+
; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
3+
; RUN: dxil-dis %t.bc -o - | FileCheck %s
24

35
target triple = "dxil-pc-shadermodel6.3-library"
46

llvm/test/tools/dxil-dis/dbg-value.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
1+
; RUN: llc --filetype=obj %s -o %t.dxbc
2+
; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
3+
; RUN: dxil-dis %t.bc -o - | FileCheck %s
24

35
target triple = "dxil-pc-shadermodel6.3-library"
46

llvm/test/tools/dxil-dis/debug-info.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
1+
; RUN: llc --filetype=obj %s -o %t.dxbc
2+
; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
3+
; RUN: dxil-dis %t.bc -o - | FileCheck %s
24

35
target triple = "dxil-unknown-shadermodel6.7-library"
46
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"

llvm/test/tools/dxil-dis/di-compile-unit-versioned-language.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
1+
; RUN: llc --filetype=obj %s -o %t.dxbc
2+
; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
3+
; RUN: dxil-dis %t.bc -o - | FileCheck %s
24

35
target triple = "dxil-unknown-shadermodel6.3-library"
46

llvm/test/tools/dxil-dis/di-compile-unit.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
1+
; RUN: llc --filetype=obj %s -o %t.dxbc
2+
; RUN: llvm-objcopy --dump-section=ILDB=%t.bc %t.dxbc
3+
; RUN: dxil-dis %t.bc -o - | FileCheck %s
24
target triple = "dxil-unknown-shadermodel6.7-library"
35

46
!llvm.dbg.cu = !{!0}

0 commit comments

Comments
 (0)