Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Float literals treated as double in ternary operator #6147

Closed
simco50 opened this issue Jan 11, 2024 · 1 comment
Closed

Float literals treated as double in ternary operator #6147

simco50 opened this issue Jan 11, 2024 · 1 comment
Labels
bug Bug, regression, crash needs-triage Awaiting triage

Comments

@simco50
Copy link

simco50 commented Jan 11, 2024

Description
Float literals seems to be used as doubles in intermediate operations when using ternary operators.
This makes the shaders require double operations which is usually unexpected.
I'm unsure if this behavior is intentional?

Steps to Reproduce
Below a simplified example:

RWStructuredBuffer<float> Output;

[numthreads(1,1,1)]
void CSMain(uint x : SV_DispatchThreadID)
{
    Output[x] = x ? (x ? 1.0 : 2.0) : 2.0 * (x ? 1.0 : 2.0);
}

dxc.exe -T cs_6_6 -E CSMain

Godbolt link: https://godbolt.org/z/YdojbWcE3

Moving forward, we have added a bit of code on our end to check the shader feature flags to see if D3D_SHADER_REQUIRES_DOUBLES is set, and if so consider compilation failed.

Environment
Using either DXC C++ API or CLI

  • DXC version: dxcompiler.dll: 1.7 - 1.7.2308.7 (69e54e2); dxil.dll: 1.7(101.7.2308.12)
  • Host Operating System: W10 22H2
@simco50 simco50 added bug Bug, regression, crash needs-triage Awaiting triage labels Jan 11, 2024
@llvm-beanz
Copy link
Collaborator

Hi @simco, this is the expected behavior. Today HLSL gets to this result through a bit of a roundabout way because of the HLSL literal type rules (we have an issue tracking removing literal types: microsoft/hlsl-specs#73).

literal types default to "the biggest type available" (in this case double), unless an implicit or explicit cast is contained within the expression. In your example the rule applies in a rather pedantic sense. Your ternary operator results are all literal float, so there is no implicit or explicit cast within the expressions... but the expression result is implicitly casted to float. This results in the worst of all worlds behavior where the type for each of the subexpressions becomes double even though it just gets casted to float in the final result. Then it becomes up to the optimizer whether or not it is smart enough to optimize it away (spoiler alert: it isn't).

A really silly illustration of how this plays out in practice can be seen in this silly modification of your example:

RWStructuredBuffer<float> Output;

[numthreads(1,1,1)]
void CSMain(uint x : SV_DispatchThreadID)
{
    Output[x] = x ? (x ? 1.0f : 2.0) : 2.0 * (x ? 1.0 : 2.0);
}

Godbolt link

You'll notice I made just one of your arguments an explicitly-sized float. this results in the first sub-ternary operator being float typed, which forces all the literal float values to resolve as float instead of double.

Regardless of the literal types the resolution here would be unchanged, because under C/C++ rules, non-suffixed floating point literals are double. For this reason, the best advice I can give is: always explicitly suffix literals.

@llvm-beanz llvm-beanz closed this as not planned Won't fix, can't repro, duplicate, stale Jan 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug, regression, crash needs-triage Awaiting triage
Projects
Archived in project
Development

No branches or pull requests

2 participants