Skip to content

[Debug info] Mesh shader vertices[] / primitives[] / indices[]: missing or wrongly-offset debug info #8754

Description

@hbystuff

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

Repro files: mesh_shader_repro.zip

Both repros share this signature:

struct Vertex    { float4 position : SV_Position;    float3 normal : NORMAL; };
struct Primitive { uint   primID   : SV_PrimitiveID; float  shade  : COLOR0; };

[numthreads(4, 1, 1)]
[outputtopology("triangle")]
void main(
    uint gtid : SV_GroupThreadID,
    out vertices   Vertex    verts[3],
    out primitives Primitive prims[2],
    out indices    uint3     tris[2])

(a) Dynamic index: no debug info at all

dxc -T ms_6_5 -Zi -Qembed_debug -Od -Fc dynamic_index.ll dynamic_index.hlsl
    if (gtid < 3)
    {
        verts[gtid].position = float4(t, t, t, 1.0);
        verts[gtid].normal   = float3(0, 0, 1);
    }
    if (gtid < 2)
    {
        prims[gtid].primID = gtid;
        prims[gtid].shade  = t;
        tris[gtid]         = uint3(0, 1, 2);
    }

The only local variables in the whole module are gtid and t:

!DILocalVariable(tag: DW_TAG_arg_variable, name: "gtid", arg: 1, scope: !34, ...)
!DILocalVariable(tag: DW_TAG_auto_variable, name: "t",   scope: !34, ...)

verts, prims and tris have no DILocalVariable and no dbg.value, despite
the dx.op.storeVertexOutput, dx.op.storePrimitiveOutput and
dx.op.emitIndices calls in the function.

(b) Constant index: fragment offsets use the wrong layout

dxc -T ms_6_5 -Zi -Qembed_debug -Od -Fc constant_index.ll constant_index.hlsl

Now all three arrays get a DILocalVariable, each typed as a plain
array-of-struct:

!92  = !DILocalVariable(tag: DW_TAG_arg_variable, name: "verts", arg: 2, scope: !34, file: !1, line: 27, type: !39)
!104 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "prims", arg: 3, scope: !34, file: !1, line: 28, type: !47)
!109 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "tris",  arg: 4, scope: !34, file: !1, line: 29, type: !55)

!39 = !DICompositeType(tag: DW_TAG_array_type, baseType: !40, size: 672, align: 32, elements: !44)   ; Vertex[3]
!40 = !DICompositeType(tag: DW_TAG_structure_type, name: "Vertex", ..., size: 224, align: 32, elements: !41)
!42 = !DIDerivedType(tag: DW_TAG_member, name: "position", scope: !40, ..., size: 128, align: 32)
!43 = !DIDerivedType(tag: DW_TAG_member, name: "normal",   scope: !40, ..., size:  96, align: 32, offset: 128)

!47 = !DICompositeType(tag: DW_TAG_array_type, baseType: !48, size: 128, align: 32, elements: !52)   ; Primitive[2]
!48 = !DICompositeType(tag: DW_TAG_structure_type, name: "Primitive", ..., size: 64, align: 32, elements: !49)
!50 = !DIDerivedType(tag: DW_TAG_member, name: "primID", scope: !48, ..., size: 32, align: 32)
!51 = !DIDerivedType(tag: DW_TAG_member, name: "shade",  scope: !48, ..., size: 32, align: 32, offset: 32)

!55 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 192, align: 32, elements: !52)   ; uint3[2]

verts: wrong

    verts[0].position = float4(t, t, t, 1.0);
    verts[0].normal   = float3(0, 0, 1);
    verts[1].position = float4(1, 1, 1, 1);
    verts[1].normal   = float3(0, 1, 0);
var:"verts" !DIExpression(DW_OP_bit_piece,   0,  32)   ; verts[0].position.x
var:"verts" !DIExpression(DW_OP_bit_piece,  32,  32)   ; verts[0].position.y
var:"verts" !DIExpression(DW_OP_bit_piece,  64,  32)   ; verts[0].position.z
var:"verts" !DIExpression(DW_OP_bit_piece,  96,  32)   ; verts[0].position.w
var:"verts" !DIExpression(DW_OP_bit_piece, 384,  96)   ; verts[0].normal
var:"verts" !DIExpression(DW_OP_bit_piece, 128, 128)   ; verts[1].position
var:"verts" !DIExpression(DW_OP_bit_piece, 480,  96)   ; verts[1].normal
field expected emitted
verts[0].position 0, 128 0, 128
verts[0].normal 128, 96 384, 96
verts[1].position 224, 128 128, 128
verts[1].normal 352, 96 480, 96

prims: wrong

The constant stores pin the mapping exactly:

call void @llvm.dbg.value(metadata i32 7,              ...)  ; var:"prims" !DIExpression(DW_OP_bit_piece,  0, 32)
call void @dx.op.storePrimitiveOutput.i32(i32 172, i32 0, i32 0, i8 0, i32 7,              i32 0)  ; prims[0].primID = 7

call void @llvm.dbg.value(metadata float 2.500000e-01, ...)  ; var:"prims" !DIExpression(DW_OP_bit_piece, 64, 32)
call void @dx.op.storePrimitiveOutput.f32(i32 172, i32 1, i32 0, i8 0, float 2.500000e-01, i32 0)  ; prims[0].shade = 0.25

call void @llvm.dbg.value(metadata i32 9,              ...)  ; var:"prims" !DIExpression(DW_OP_bit_piece, 32, 32)
call void @dx.op.storePrimitiveOutput.i32(i32 172, i32 0, i32 0, i8 0, i32 9,              i32 1)  ; prims[1].primID = 9

call void @llvm.dbg.value(metadata float 7.500000e-01, ...)  ; var:"prims" !DIExpression(DW_OP_bit_piece, 96, 32)
call void @dx.op.storePrimitiveOutput.f32(i32 172, i32 1, i32 0, i8 0, float 7.500000e-01, i32 1)  ; prims[1].shade = 0.75
field expected emitted
prims[0].primID 0, 32 0, 32
prims[0].shade 32, 32 64, 32
prims[1].primID 64, 32 32, 32
prims[1].shade 96, 32 96, 32

prims[0].shade and prims[1].primID are swapped: reading prims[0].shade
yields the bits of 9, and reading prims[1].primID yields the bits of 0.25.

tris: correct

var:"tris" !DIExpression(DW_OP_bit_piece,  0, 96)   ; tris[0]
var:"tris" !DIExpression(DW_OP_bit_piece, 96, 96)   ; tris[1]

Correct for uint3[2]. The index triple is a single signature row, so the
struct-of-arrays and array-of-struct layouts coincide and there is nothing to
transpose. tris is only affected by (a).

Root cause

The emitted offsets follow the struct-of-arrays layout of the lowered output
signature, one contiguous run per signature row indexed by element, while
the DILocalVariable's type is array-of-struct:

verts, 2 rows (position, normal):    position[3] @ 0..383    normal[3] @ 384..671
prims, 2 rows (primID, shade):       primID[2]   @ 0..63     shade[2]  @  64..127

Expected

  1. Writes through a non-constant index should still describe the output array.
  2. DW_OP_bit_piece offsets must be computed against the layout the
    DILocalVariable's type describes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug, regression, crashneeds-triageAwaiting triage

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions