Skip to content

Commit 450bbe5

Browse files
authored
Added debug info for localized global variables for inlined scopes. (#7799)
Previously, global variables converted to `alloca`'s, their debug info is written as a `dbg.value` for a fake local variable prefixed with "global.". This was only done for the entry function's `DISubprogram`, which makes the variable inaccessible for all inlined function scopes. This change creates a `dbg.value` for each inlined `DISubprogram`, each pointing to a new `DILocalVariable` with the inlined `DISubprogram` as its scope.
1 parent 025ca7b commit 450bbe5

File tree

3 files changed

+347
-27
lines changed

3 files changed

+347
-27
lines changed

lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6498,8 +6498,55 @@ ModulePass *llvm::createSROA_Parameter_HLSL() {
64986498
//===----------------------------------------------------------------------===//
64996499

65006500
namespace {
6501+
6502+
struct GVDebugInfoPatchCache {
6503+
DenseMap<Function *, SetVector<DISubprogram *>> SubprogramsForFunction;
6504+
DenseSet<DILocation *> Seen;
6505+
DITypeIdentifierMap EmptyMap;
6506+
6507+
void CollectSubprograms(DILocation *Loc, SetVector<DISubprogram *> &Set) {
6508+
while (Loc) {
6509+
// This is potentially very expensive. Avoid repeatedly looking for
6510+
// DISubprogram's
6511+
if (Seen.count(Loc))
6512+
return;
6513+
Seen.insert(Loc);
6514+
auto *Scope = dyn_cast<DIScope>(Loc->getScope());
6515+
while (Scope) {
6516+
if (auto SubP = dyn_cast<DISubprogram>(Scope)) {
6517+
Set.insert(SubP);
6518+
break;
6519+
}
6520+
Scope = Scope->getScope().resolve(EmptyMap);
6521+
}
6522+
Loc = Loc->getInlinedAt();
6523+
}
6524+
}
6525+
6526+
SetVector<DISubprogram *> &
6527+
GetSubprogramsForFunction(Function *F, DebugInfoFinder &DbgFinder) {
6528+
auto It = SubprogramsForFunction.find(F);
6529+
if (It != SubprogramsForFunction.end())
6530+
return It->second;
6531+
6532+
SetVector<DISubprogram *> &Ret = SubprogramsForFunction[F];
6533+
for (DISubprogram *SP : DbgFinder.subprograms()) {
6534+
if (SP->getFunction() == F) {
6535+
Ret.insert(SP);
6536+
break;
6537+
}
6538+
}
6539+
6540+
for (BasicBlock &BB : *F)
6541+
for (Instruction &I : BB)
6542+
CollectSubprograms(I.getDebugLoc(), Ret);
6543+
return Ret;
6544+
}
6545+
};
6546+
65016547
class LowerStaticGlobalIntoAlloca : public ModulePass {
65026548
DebugInfoFinder m_DbgFinder;
6549+
GVDebugInfoPatchCache m_GVDebugInfoCache;
65036550

65046551
public:
65056552
static char ID; // Pass identification, replacement for typeid
@@ -6687,28 +6734,15 @@ FindGlobalVariableFragment(const DebugInfoFinder &DbgFinder,
66876734
// Create a fake local variable for the GlobalVariable GV that has just been
66886735
// lowered to local Alloca.
66896736
//
6690-
static void PatchDebugInfo(DebugInfoFinder &DbgFinder, Function *F,
6737+
static void PatchDebugInfo(GVDebugInfoPatchCache &Cache,
6738+
DebugInfoFinder &DbgFinder, Function *F,
66916739
GlobalVariable *GV, AllocaInst *AI) {
6692-
if (!DbgFinder.compile_unit_count())
6693-
return;
6694-
6695-
// Find the subprogram for function
6696-
DISubprogram *Subprogram = nullptr;
6697-
for (DISubprogram *SP : DbgFinder.subprograms()) {
6698-
if (SP->getFunction() == F) {
6699-
Subprogram = SP;
6700-
break;
6701-
}
6702-
}
6703-
67046740
DIGlobalVariable *DGV = dxilutil::FindGlobalVariableDebugInfo(GV, DbgFinder);
67056741
if (!DGV)
67066742
return;
67076743

6708-
DITypeIdentifierMap EmptyMap;
6709-
DIBuilder DIB(*GV->getParent());
6710-
DIScope *Scope = Subprogram;
6711-
DebugLoc Loc = DebugLoc::get(DGV->getLine(), 0, Scope);
6744+
if (!DbgFinder.compile_unit_count())
6745+
return;
67126746

67136747
// If the variable is a member of another variable, find the offset and size
67146748
bool IsFragment = false;
@@ -6725,20 +6759,30 @@ static void PatchDebugInfo(DebugInfoFinder &DbgFinder, Function *F,
67256759
// Subprogram as its scope, so we don't have to make one up for it.
67266760
llvm::dwarf::Tag Tag = llvm::dwarf::Tag::DW_TAG_arg_variable;
67276761

6762+
DITypeIdentifierMap EmptyMap;
67286763
DIType *Ty = DGV->getType().resolve(EmptyMap);
67296764
DXASSERT(Ty->getTag() != dwarf::DW_TAG_member,
67306765
"Member type is not allowed for variables.");
6731-
DILocalVariable *ConvertedLocalVar = DIB.createLocalVariable(
6732-
Tag, Scope, Name, DGV->getFile(), DGV->getLine(), Ty);
67336766

6734-
DIExpression *Expr = nullptr;
6735-
if (IsFragment) {
6736-
Expr = DIB.createBitPieceExpression(OffsetInBits, SizeInBits);
6737-
} else {
6738-
Expr = DIB.createExpression(ArrayRef<int64_t>());
6739-
}
6767+
DIBuilder DIB(*GV->getParent());
6768+
6769+
SetVector<DISubprogram *> &Subprograms =
6770+
Cache.GetSubprogramsForFunction(F, DbgFinder);
6771+
for (DISubprogram *Subprogram : Subprograms) {
6772+
DIScope *Scope = Subprogram;
6773+
DebugLoc Loc = DebugLoc::get(DGV->getLine(), 0, Scope);
67406774

6741-
DIB.insertDeclare(AI, ConvertedLocalVar, Expr, Loc, AI->getNextNode());
6775+
DILocalVariable *ConvertedLocalVar = DIB.createLocalVariable(
6776+
Tag, Scope, Name, DGV->getFile(), DGV->getLine(), Ty);
6777+
6778+
DIExpression *Expr = nullptr;
6779+
if (IsFragment)
6780+
Expr = DIB.createBitPieceExpression(OffsetInBits, SizeInBits);
6781+
else
6782+
Expr = DIB.createExpression(ArrayRef<int64_t>());
6783+
6784+
DIB.insertDeclare(AI, ConvertedLocalVar, Expr, Loc, AI->getNextNode());
6785+
}
67426786
}
67436787

67446788
// Collect instructions using GV and the value used by the instruction.
@@ -6816,7 +6860,7 @@ bool LowerStaticGlobalIntoAlloca::lowerStaticGlobalIntoAlloca(
68166860
if (AI->user_empty())
68176861
AI->eraseFromParent();
68186862
else
6819-
PatchDebugInfo(m_DbgFinder, F, GV, AI);
6863+
PatchDebugInfo(m_GVDebugInfoCache, m_DbgFinder, F, GV, AI);
68206864
}
68216865

68226866
GV->removeDeadConstantUsers();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %dxc -E main -T ps_6_0 -Od -Zi %s | FileCheck %s
2+
3+
// Check that the debug info for a global variable is present for every inlined scope
4+
5+
// CHECK: @main
6+
7+
// CHECK-DAG: ![[main_scope:[0-9]+]] = !DISubprogram(name: "main"
8+
// CHECK-DAG: ![[main_var:[0-9]+]] = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.g_cond", arg: {{[0-9]+}}, scope: ![[main_scope]],
9+
// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, metadata ![[main_var]],
10+
11+
// CHECK-DAG: ![[foo_scope:[0-9]+]] = !DISubprogram(name: "foo"
12+
// CHECK-DAG: ![[foo_var:[0-9]+]] = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.g_cond", arg: {{[0-9]+}}, scope: ![[foo_scope]],
13+
// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, metadata ![[foo_var]],
14+
15+
// CHECK-DAG: ![[bar_scope:[0-9]+]] = !DISubprogram(name: "bar"
16+
// CHECK-DAG: ![[bar_var:[0-9]+]] = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.g_cond", arg: {{[0-9]+}}, scope: ![[bar_scope]],
17+
// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, metadata ![[bar_var]],
18+
19+
static bool g_cond;
20+
21+
Texture2D tex0 : register(t0);
22+
Texture2D tex1 : register(t1);
23+
24+
float4 bar() {
25+
if (g_cond)
26+
return tex0.Load(1);
27+
return 0;
28+
}
29+
30+
float4 foo() {
31+
float4 ret = g_cond ? tex0.Load(0) : tex1.Load(0);
32+
ret += bar();
33+
return ret;
34+
}
35+
36+
[RootSignature("DescriptorTable(SRV(t0, numDescriptors=2))")]
37+
float4 main(uint a : A) : sv_target {
38+
g_cond = a != 0;
39+
return foo();
40+
};
41+
42+
43+

0 commit comments

Comments
 (0)