Skip to content

[Debug info] TraceRay payload: no dbg.declare on the payload alloca, stale field values after the call #8753

Description

@hbystuff

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

Repro files: payload_traceray.zip

dxc -T lib_6_5 -Zi -Qembed_debug -Od -Fc payload_traceray.ll payload_traceray.hlsl
struct MyPayload
{
    float4 color;
    float  hitT;
    uint   bounces;
};

[shader("raygeneration")]
void RayGen()
{
    MyPayload payload;
    payload.color   = float4(0, 0, 0, 0);
    payload.hitT    = -1.0f;
    payload.bounces = 0;
    ...
    TraceRay(Scene, RAY_FLAG_NONE, 0xff, 0, 1, 0, ray, payload);

    Result[0] = payload.color;      // only .color is read afterwards
}

[shader("closesthit")]
void ClosestHit(inout MyPayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
    float4 incoming = payload.color;
    payload.bounces = payload.bounces + 1;      // writes .bounces
    payload.hitT    = RayTCurrent();            // writes .hitT
    payload.color   = incoming + float4(attr.barycentrics, 0, 1);
}

Actual

RayGen has a %struct.MyPayload alloca that is the payload's canonical
location. It is what is handed to dx.op.traceRay and what the hit shaders
write through. It never gets a llvm.dbg.declare:

  %3 = alloca %struct.MyPayload
  ; no llvm.dbg.declare for %3 anywhere in RayGen

  ; payload is described purely by per-field dbg.values of the initialisers
  call void @llvm.dbg.value(metadata <4 x float> zeroinitializer, ...)  ; var:"payload" !DIExpression(DW_OP_bit_piece,   0, 128)
  call void @llvm.dbg.value(metadata float -1.000000e+00,         ...)  ; var:"payload" !DIExpression(DW_OP_bit_piece, 128,  32)
  call void @llvm.dbg.value(metadata i32 0,                       ...)  ; var:"payload" !DIExpression(DW_OP_bit_piece, 160,  32)

  ; the struct is initialized into the alloca and TraceRay is called
  %12 = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %3, i32 0, i32 0
  store <4 x float> zeroinitializer, <4 x float>* %12
  %13 = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %3, i32 0, i32 1
  store float -1.000000e+00, float* %13
  %14 = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %3, i32 0, i32 2
  store i32 0, i32* %14
  call void @dx.op.traceRay.struct.MyPayload(i32 157, ..., %struct.MyPayload* %3)

  ; after TraceRay only .color is re-described, because only .color is read
  %15 = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %3, i32 0, i32 0
  %16 = load <4 x float>, <4 x float>* %15
  call void @llvm.dbg.value(metadata <4 x float> %16, ...)              ; var:"payload" !DIExpression(DW_OP_bit_piece,   0, 128)

After TraceRay returns, the debug info still claims payload.hitT == -1.0 and
payload.bounces == 0, even though it could have been rewritten.

For contrast, the hit shader's payload parameter does get a declare, because it
stays a pointer:

define void @"\01?ClosestHit@@..."(%struct.MyPayload* noalias %payload, ...) {
  call void @llvm.dbg.declare(metadata %struct.MyPayload* %payload, metadata !130, metadata !128)   ; var:"payload" !DIExpression()

Expected

payload in RayGen should be described by a llvm.dbg.declare on the alloca
for its whole live range.

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