microsoft / microsoft/DirectXShaderCompiler

Constant register declarations have diverging behavior between FXC and DXC

Open
#7,640 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Description
Constant register declarations are legacy syntax, but still accepted by DXC and packed into the implicit $Globals constant buffer. However, the packing behavior differs to FXC.

Steps to Reproduce

uint u1 : register(b2);
uint u2 : register(c2);
uint u3 : register(i2);

If the above declarations are compiled with DXC, it interprets all three register declarations as packoffsets within the $Globals constant buffer, thus overlapping all three variables at offset 32. The reflection output is:

cbuffer $Globals
{
  struct $Globals
  {
      uint u1;                                      ; Offset:   32
      uint u2;                                      ; Offset:   32
      uint u3;                                      ; Offset:   32
  } $Globals;                                       ; Offset:    0 Size:    36
}

https://hlsl.godbolt.org/z/9fbE5svEx

FXC with shader models >= 4.0 instead ignores the first and third register declaration and only interprets the second one as a packoffset equivalent, leading to the following layout:

cbuffer $Globals
{
  uint u2;                           // Offset:   32 Size:     4
  uint u1;                           // Offset:   36 Size:     4
  uint u3;                           // Offset:   40 Size:     4
}

https://shader-playground.timjones.io/536347a8d3b1b75f6ec00229afd283cf

Interestingly enough, clang seems to agree with FXC when the errors about the syntax are downgraded to warnings (see first link, it doesn't output the struct reflection, but the actual loads/extractvalues in DXIL confirm the layout).

This is all very much legacy (and I'm not even technically using it fully correctly for SM3 or older), but still accepted syntax and maybe someone still wants to port really old shaders and will run into weird issues.
Possible courses of action include aligning the behavior and/or deprecating those declarations altogether. In any case there should be at least warnings, since it either breaks potential existing shaders using that syntax with DXC (if its behavior will be aligned to FXC) or breaks shaders being ported from FXC to DXC (if its packing behavior will not be changed). Clang made b# and i# declarations on globals errors by default, see also the HLSL Register Types and Diagnostics Proposal.

Environment

  • DXC version: 1.6+
  • Host Operating System: All

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

No source file or test is named. Start by reproducing the three HLSL declarations with DXC and compare the reflection layout against FXC and the linked examples. Done means the compiler behavior is aligned or the legacy declarations receive diagnostics, with regression coverage for the reported packing difference.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.