Skip to content

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

Description

@hbystuff

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions