microsoft / microsoft/DirectXShaderCompiler

[Feature Request][Debug info] Globals lowered to `global.<name>` locals should link to their declaring scope

Open
#8,750 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement needs-triage
Dominant language
C++
Stars
3.7k
Forks
900
Avg merge
2d 11h
Merged PRs (30d)
44

Description

Version: dxcompiler.dll 1.9(5402-0d3ee6b5)(1.9.0.5402) - 1.9.0.5402 (0d3ee6b55-dirty)

lowered_global.zip

Static globals are lowered to SSA values and mirrored into a synthetic
DILocalVariable named global.<name>. That variable is scoped to a function
subprogram and carries no reference to the declaring namespace or class, and no
link back to the DIGlobalVariable that does have the correct scope.

Repro 1: namespace

dxc -T cs_6_0 -Zi -Qembed_debug -Od -Fc namespace_static.ll namespace_static.hlsl
namespace A { static int MyNum = 67; }      // line 11
namespace B { static int MyNum = 68; }      // line 15

[numthreads(1, 1, 1)]
void main()
{
    A::MyNum = input[0];
    B::MyNum = input[1];
    output[0] = A::MyNum + B::MyNum;
}
Actual
!42 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.MyNum", arg: 0, scope: !4, file: !1, line: 15, type: !12)
!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.MyNum", arg: 0, scope: !4, file: !1, line: 11, type: !12)

!4 is the main subprogram for both, so A::MyNum and B::MyNum are
indistinguishable apart from line:.

The namespace is present elsewhere in the module, just not reachable from the
local:

!14 = !DIGlobalVariable(name: "MyNum", linkageName: "\01?MyNum@A@@3HA", scope: !15, file: !1, line: 11, ...)
!15 = !DINamespace(name: "A", scope: null, file: !1, line: 10)
!16 = !DIGlobalVariable(name: "MyNum", linkageName: "\01?MyNum@B@@3HA", scope: !17, file: !1, line: 15, ...)
!17 = !DINamespace(name: "B", scope: null, file: !1, line: 14)

Repro 2: class static member

dxc -T cs_6_0 -Zi -Qembed_debug -Od -Fc class_static_member.ll class_static_member.hlsl
class Counter
{
    static int count;
    int localValue;
    void Initialize(int value) { localValue = value; count += value; }
};

int Counter::count = 0;         // line 23
Actual

One global.count is emitted per function that touches the static, each scoped
to that function's subprogram:

!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.count", arg: 0, scope: !7, file: !1, line: 23, type: !11)
!51 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.count", arg: 0, scope: !4, file: !1, line: 23, type: !11)

!4 = !DISubprogram(name: "main", ...)
!7 = !DISubprogram(name: "Initialize", linkageName: "\01?Initialize@Counter@@QAAXH@Z", scope: !8, ...)

call void @llvm.dbg.value(metadata i32 0,  i64 0, metadata !48, metadata !49), !dbg !50   ; var:"global.count" !DIExpression() func:"Initialize"
call void @llvm.dbg.value(metadata i32 0,  i64 0, metadata !51, metadata !49), !dbg !52   ; var:"global.count" !DIExpression() func:"main"
call void @llvm.dbg.value(metadata i32 %6, i64 0, metadata !48, metadata !49), !dbg !50   ; var:"global.count" !DIExpression() func:"Initialize"
call void @llvm.dbg.value(metadata i32 %6, i64 0, metadata !51, metadata !49), !dbg !52   ; var:"global.count" !DIExpression() func:"main"

Expected

There should be a way to link a global lowered to local back to the original global, something like:

!dx.dbg.local_globals = {!100, !101}

!100 = !{ !48, !23 }
!101 = !{ !51, !23 }
!8  = !DICompositeType(tag: DW_TAG_class_type, name: "Counter", file: !1, line: 11, size: 32, align: 32, elements: !9)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "count", scope: !8, file: !1, line: 13, baseType: !11, flags: DIFlagPublic | DIFlagStaticMember)
!23 = !DIGlobalVariable(name: "count", linkageName: "\01?count@Counter@@2HA", scope: !0, file: !1, line: 23, type: !11, isLocal: true, isDefinition: true, declaration: !10)
!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.count", arg: 0, scope: !7, file: !1, line: 23, type: !11)
!51 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "global.count", arg: 0, scope: !4, file: !1, line: 23, type: !11)

So the backend can reconstruct the correct scope information if appropriate.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the namespace and class-static cases with the supplied dxc commands, then inspect the generated namespace_static.ll and class_static_member.ll debug metadata. Trace how lowered global values become global. DILocalVariable entries and how the corresponding DIGlobalVariable and declaring scope are represented. Done means the emitted metadata lets the backend recover the namespace or class scope for each lowered local.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.