microsoft / DirectXShaderCompiler

This repo hosts the source for the DirectX Shader Compiler which is based on LLVM/Clang.
Other
3.08k stars 689 forks source link

[SPIR-V] Incorrect float->int->uint conversion behavior #6975

Open thevaber opened 1 week ago

thevaber commented 1 week ago

Description The compiler generates a float->uint conversion (OpConvertFToU instruction) when trying to convert float->int->uint (which should result in OpConvertFToS followed by OpBitcast) - since OpConvertFToU is as far as I can tell not defined for negative float values (and hardware seems to convert negative floats to 0u), the two operations are not equivalent, and the behavior is different than expected for negative values.

Steps to Reproduce

struct Data {
    float4 x;
    uint4 y;
};
RWStructuredBuffer<Data> buffer;

[numthreads(1, 1, 1)]
void main()
{
    buffer[0].y = uint4(buffer[0].x); // A
    buffer[1].y = uint4(int4(buffer[1].x)); // B - Generates same code as A, but shouldn't
    buffer[2].y = int4(buffer[2].x); // C - The implicit cast here seems to generate the correct code
}

(https://godbolt.org/z/1sb68E8b1)

Environment All DXC versions currently available via godbolt.org

damyanp commented 1 week ago

@llvm-beanz - it might be interesting to see what the language spec says about this.

Keenuts commented 1 day ago

For the SPIR-V codegen side, seems like there is a slight mismatch between how we handle implicit casts (first is an IntegralCast), vs the explicit cast from float -> int -> uint.

Waiting on MS answer on what the spec says before fixing one side or the other.

s-perron commented 1 day ago

I'm not too concerned about the spec in this case. It would be unreasonable that the cast to int could be elided with the case to uint making it undefined. The AST has all of the correct casts, and the spir-v should reflect that.