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
- Writes through a non-constant index should still describe the output array.
DW_OP_bit_piece offsets must be computed against the layout the
DILocalVariable's type describes.
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:
(a) Dynamic index: no debug info at all
The only local variables in the whole module are
gtidandt:verts,primsandtrishave noDILocalVariableand nodbg.value, despitethe
dx.op.storeVertexOutput,dx.op.storePrimitiveOutputanddx.op.emitIndicescalls in the function.(b) Constant index: fragment offsets use the wrong layout
Now all three arrays get a
DILocalVariable, each typed as a plainarray-of-struct:
verts: wrongverts[0].positionverts[0].normalverts[1].positionverts[1].normalprims: wrongThe constant stores pin the mapping exactly:
prims[0].primIDprims[0].shadeprims[1].primIDprims[1].shadeprims[0].shadeandprims[1].primIDare swapped: readingprims[0].shadeyields the bits of
9, and readingprims[1].primIDyields the bits of0.25.tris: correctCorrect for
uint3[2]. The index triple is a single signature row, so thestruct-of-arrays and array-of-struct layouts coincide and there is nothing to
transpose.
trisis 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:Expected
DW_OP_bit_pieceoffsets must be computed against the layout theDILocalVariable's type describes.