microsoft / microsoft/DirectXShaderCompiler
Some specially crafted shaders exhibit unexpected branching behavior
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 3.7k
- Forks
- 900
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 44
Description
Description
I'm observing some odd behavior in some shaders resulting in incorrect branching. The issues occurs in debug with -Od. The behavior seems triggered by certain sequences of operations involving texture loads and subsequent dependent branches. With -Od, adding code that shouldn't have any changes or side-effects in execution can affect the result of the branches.
Steps to Reproduce
Compile the following pixel shader with -T ps_6_6 -E PSMain -Od (Compiler Explorer: https://godbolt.org/z/nKx5qj33s). I was able reproduce this using the DirectX-Graphics-Samples hello triangle example.
#define TOGGLE_BUG 1
struct PSInput
{
float4 position :SV_POSITION;
float2 uv :TEXCOORD;
};
Texture2D<uint4> g_texture : register(t0);
float3 bugtest()
{
float should_be_zerof = 0.0f;
float4 should_be_onef4 = 1;
uint test_flags = (1 << 0);
bool test_false = (test_flags & (1 << 3)) ? 1 : 0;
bool test_true = (test_flags & (1 << 0)) ? 1 : 0;
float close_to_zerof = 1e-20;
uint one_or_zero = (g_texture[uint2(0, 0)].w & 0x1);
uint uint_zero = uint(one_or_zero * close_to_zerof);
float zerof = 0.0f + close_to_zerof * (uint_zero != 0 ? 1.0f : 0.0f);
float onef = 1.0;
float4 zerof4 = 0.0f;
#if TOGGLE_BUG
if (test_false)
{
zerof4.x = 0.0f;
}
else
{
zerof4.x = 0.0f;
}
#endif
onef = saturate(1.0f + close_to_zerof * zerof);
should_be_onef4 = saturate(1.0f + close_to_zerof * zerof4);
if (test_true)
{
should_be_zerof = saturate(1.0f - onef);
}
float3 red = saturate(should_be_onef4.xyz * close_to_zerof + float3(1.0, 0.0f, 0));
float3 green = saturate(should_be_zerof * close_to_zerof + float3(0.0f, 1.0f, 0));
if (should_be_zerof < 1.0f)
{
// this should always be true
return green;
}
else
{
return red; // wat?
}
}
float4 PSMain(PSInput input) : SV_TARGET
{
float3 out_color = bugtest();
return float4(out_color, 1.0);
}
Actual Behavior
This code should always evaluate to producing a green pixel but ends up taking a wrong branch and produces red pixels. Changing the TOGGLE_BUG to 0 removes some extra code that shouldn't have side effects but changes the behavior with -Od and this results in the correct branch being taken at the end of the shader.
Environment
- DXC version 1.8.2502
- Host Operating System Windows 11 23H2
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Compile the supplied PSMain shader with DXC 1.8.2502 using -T ps_6_6 -E PSMain -Od, then compare behavior with TOGGLE_BUG set to 1 and 0. Trace the compiler's handling of the texture load, dependent branches, and optimization-disabled path; done means both variants produce the expected green pixel.
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