KhronosGroup / SPIRV-Tools

Apache License 2.0
1.09k stars 559 forks source link

Incorrect optimization on negation of unsigned integer #5822

Closed mitdemverkaufer closed 1 month ago

mitdemverkaufer commented 2 months ago

The spirv-opt misoptimizes a negation operator on the unsigned integer. In the following GLSL code, the fragment shader should render a white square. However, the square is rendered as black due to the incorrect optimization.

#version 310 es

precision highp float;
precision highp int;

layout(location = 0) out vec4 color;

layout(binding = 0) uniform Uniform {
    int input1; // input1 = 5
};

void main() {
  uint c;
  uint t = 4u < uint(input1) ? 4u : uint(input1); // t = 4
  // uint t = 4u < uint(5) ? 4u : uint(5);           // t = 4
  c = -(t / 4u);      // c = uint(-(4u / 4u)) = 4294967295
  float e = float(c); // e = 4.2949673e+09
  color = vec4(e, e, e, 1.0);
}

The runtime input value of input1 is 5. The variable t thus receives the value of 4 since 4 is less than input1. The unsigned integer c should be -(4u / 4u), which is 4294967295. However, the spirv-opt optimizes -(t / 4u) to be t / 4294967292, which evaluates to 0.

%32 = OpUDiv %uint %46 %uint_4294967292

Note that if replacing the input1 with a constant value, the fragment shader renders the white square as expected:

uint t = 4u < 5u ? 4u : 5u; // t = 4

Steps to reproduce

Simply follow the README.md in this package. The dissembly of the optimized SPIR-V binary is also provided in the package.