microsoft / microsoft/DirectXShaderCompiler

Initializing a const-qualified var of type 'struct/array of (struct/array of) more than one type' with initializer 'init' will ignore any dynamic writes made to 'init' beforehand

Open
#5,883 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug correctness matrix-bug
Dominant language
C++
Stars
3.7k
Forks
900
Avg merge
2d 11h
Merged PRs (30d)
44

Description

See the following HLSL compute shader:

01: struct S {
02:   float2x3 m;
03: };
04: 
05: RWByteAddressBuffer buffer : register(u0);
06: 
07: [numthreads(1, 1, 1)]
08: void main() {
09:   float2x3 m = float2x3(42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f);
10:   m[0] = float3(1, 2, 3);
11:   m[1] = float3(4, 5, 6);
12: 
13:   S a = {m}; // valid, S contains values written to m after init
14:   // const S a = {m}; // invalid, S contains init m values
15: 
16:   buffer.Store3(0u, int3(a.m[0]));
17:   buffer.Store3(16u, int3(a.m[1]));
18: }

When line 13 is uncommented, that is, we create a non-const instance of S, the compiled DXIL shows that it correctly initializes the buffer with the values that were written to the matrix on lines 10 and 11:

  call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %1, i32 0, i32 undef, i32 1, i32 2, i32 3, i32 undef, i8 7, i32 4)  ; RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)
  call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %1, i32 16, i32 undef, i32 4, i32 5, i32 6, i32 undef, i8 7, i32 4)  ; RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)

However, if we comment out line 13 and uncomment line 14 so that we create a const instance of S instead, now the compiled DXIL shows that the buffer is initialized with the initial values that were in the matrix from line 9:

  call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %1, i32 0, i32 undef, i32 42, i32 43, i32 44, i32 undef, i8 7, i32 4)  ; RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)
  call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %1, i32 16, i32 undef, i32 45, i32 46, i32 47, i32 undef, i8 7, i32 4)  ; RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)

This seems to only happen with matrices inside a struct. So to summarize: it looks like initializing a const-qualified var of type 'struct of matrix' with m ignores dynamic writes made to m before said initialization.

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

Start by compiling the HLSL compute shader shown in the issue, comparing the generated DXIL for non-const and const S a = {m} initialization. Trace the compiler entry points handling aggregate initialization and matrix values. Done means the const-qualified case preserves the dynamic writes from lines 10 and 11 rather than the initial values from line 9.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.