diff options
author | Ian Romanick <ian.d.romanick@intel.com> | 2019-08-08 15:40:29 -0700 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2020-02-19 17:43:16 -0800 |
commit | ae9a8633f08b6f49fd151f9d18909f2ac980fb03 (patch) | |
tree | bae22c3c95f4bf2daabf1e1ce8465f7069113863 | |
parent | fde152ac76cde4688fa5b967770cce458905f044 (diff) |
glsl: Verify floating point underflow compared with zero
Recent optimizations added to Mesa's GLSL compiler detected that (x*y)
must be greater than zero if both x and y are greater than zero. It
would then use this information to eliminate comparisons with zero like
(x*y) > 0 because the result "must" be true.
If x and y are sufficiently small, the multiplication can underflow
and flush to zero. These tests exercise this for multiplication, pow,
exp2, and fma.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111308
Part-of: <https://gitlab.freedesktop.org/mesa/piglit/merge_requests/110>
4 files changed, 230 insertions, 0 deletions
diff --git a/tests/spec/arb_gpu_shader5/execution/fs-underflow-fma-compare-zero.shader_test b/tests/spec/arb_gpu_shader5/execution/fs-underflow-fma-compare-zero.shader_test new file mode 100644 index 000000000..1f81a4f6d --- /dev/null +++ b/tests/spec/arb_gpu_shader5/execution/fs-underflow-fma-compare-zero.shader_test @@ -0,0 +1,64 @@ +# Some compilers may try to optimize comparisons based on the expected +# range of the sources. Check that pessimal cases are handled correctly. +# +# See also https://bugs.freedesktop.org/show_bug.cgi?id=111308 + +[require] +GLSL >= 1.50 +GL_ARB_gpu_shader5 + +[vertex shader passthrough] + +[fragment shader] +#version 150 +#extension GL_ARB_gpu_shader5: require + +uniform float a; +uniform float b; +uniform float c; +uniform float zero = 0.0; +uniform bool expect_non_zero; + +const float epsilon = 0.000000000000000000433681; + +out vec4 piglit_fragcolor; + +void main(void) +{ + /* The worrysome optimization only occurs if the compiler believes that + * the mathematical result of the multiply is > 0. + */ + float ab = (abs(a) + epsilon) * (abs(b) + epsilon); + float result = fma(ab, epsilon, abs(zero)); + + piglit_fragcolor = expect_non_zero == (0 < result) + ? vec4(0.0, 1.0, 0.0, 1.0) + : vec4(1.0, 0.0, 0.0, 1.0); +} + +[test] +# 2**(-61) * 2**(61) * 2**(-61) = 2**(-61) +uniform float a 0.000000000000000000433681 +uniform float b 2305843009213693952 +uniform int expect_non_zero 1 +draw rect -1 -1 1 1 + +# 2**(-61) * 2**(-28) * 2**(-61) = 2**(-150) +uniform float a 0.000000000000000000433681 +uniform float b 0.0000000037252902984619140625 +uniform int expect_non_zero 0 +draw rect 0 -1 1 1 + +# 2**(-45) * 2**(-44) * 2**(-61) = 2**(-150) +uniform float a 0.000000000000028421709430404007434844970703125 +uniform float b 0.00000000000005684341886080801486968994140625 +uniform int expect_non_zero 0 +draw rect -1 0 1 1 + +# 2**(-61) * 2**(-61) * 2**(-61) = 2**(-183) +uniform float a 0.000000000000000000433681 +uniform float b 0.000000000000000000433681 +uniform int expect_non_zero 0 +draw rect 0 0 1 1 + +probe all rgba 0.0 1.0 0.0 1.0 diff --git a/tests/spec/glsl-1.20/execution/fs-underflow-exp2-compare-zero.shader_test b/tests/spec/glsl-1.20/execution/fs-underflow-exp2-compare-zero.shader_test new file mode 100644 index 000000000..433b4bd05 --- /dev/null +++ b/tests/spec/glsl-1.20/execution/fs-underflow-exp2-compare-zero.shader_test @@ -0,0 +1,45 @@ +# Some compilers may try to optimize comparisons based on the expected +# range of the sources. Check that pessimal cases are handled correctly. +# +# See also https://bugs.freedesktop.org/show_bug.cgi?id=111308 + +[require] +GLSL >= 1.20 + +[vertex shader passthrough] + +[fragment shader] +#version 120 + +uniform float power; +uniform bool expect_non_zero; + +void main(void) +{ + float result = exp2(power); + + gl_FragColor = expect_non_zero == (0 < result) + ? vec4(0.0, 1.0, 0.0, 1.0) + : vec4(1.0, 0.0, 0.0, 1.0); +} + +[test] +uniform float power 0 +uniform int expect_non_zero 1 +draw rect -1 -1 1 1 + +uniform float power -6 +uniform int expect_non_zero 1 +draw rect 0 -1 1 1 + +# Smallest possible subnormal number is 2**-149. If someone has a +# representation that has more exponent, this case may incorrectly fail. +uniform float power -150 +uniform int expect_non_zero 0 +draw rect -1 0 1 1 + +uniform float power -1000000 +uniform int expect_non_zero 0 +draw rect 0 0 1 1 + +probe all rgba 0.0 1.0 0.0 1.0 diff --git a/tests/spec/glsl-1.20/execution/fs-underflow-mul-compare-zero.shader_test b/tests/spec/glsl-1.20/execution/fs-underflow-mul-compare-zero.shader_test new file mode 100644 index 000000000..7591b01a1 --- /dev/null +++ b/tests/spec/glsl-1.20/execution/fs-underflow-mul-compare-zero.shader_test @@ -0,0 +1,59 @@ +# Some compilers may try to optimize comparisons based on the expected +# range of the sources. Check that pessimal cases are handled correctly. +# +# See also https://bugs.freedesktop.org/show_bug.cgi?id=111308 + +[require] +GLSL >= 1.20 + +[vertex shader passthrough] + +[fragment shader] +#version 120 + +uniform float a; +uniform float b; +uniform float c; +uniform bool expect_non_zero; + +const float epsilon = 0.000000000000000000433681; + +void main(void) +{ + /* The worrysome optimization only occurs if the compiler believes that + * the mathematical result of the multiply is > 0. + */ + float result = (abs(a) + epsilon) * + (abs(b) + epsilon) * + epsilon; + gl_FragColor = expect_non_zero == (0 < result) + ? vec4(0.0, 1.0, 0.0, 1.0) + : vec4(1.0, 0.0, 0.0, 1.0); +} + +[test] +# 2**(-61) * 2**(61) * 2**(-61) = 2**(-61) +uniform float a 0.000000000000000000433681 +uniform float b 2305843009213693952 +uniform int expect_non_zero 1 +draw rect -1 -1 1 1 + +# 2**(-61) * 2**(-28) * 2**(-61) = 2**(-150) +uniform float a 0.000000000000000000433681 +uniform float b 0.0000000037252902984619140625 +uniform int expect_non_zero 0 +draw rect 0 -1 1 1 + +# 2**(-45) * 2**(-44) * 2**(-61) = 2**(-150) +uniform float a 0.000000000000028421709430404007434844970703125 +uniform float b 0.00000000000005684341886080801486968994140625 +uniform int expect_non_zero 0 +draw rect -1 0 1 1 + +# 2**(-61) * 2**(-61) * 2**(-61) = 2**(-183) +uniform float a 0.000000000000000000433681 +uniform float b 0.000000000000000000433681 +uniform int expect_non_zero 0 +draw rect 0 0 1 1 + +probe all rgba 0.0 1.0 0.0 1.0 diff --git a/tests/spec/glsl-1.20/execution/fs-underflow-pow-compare-zero.shader_test b/tests/spec/glsl-1.20/execution/fs-underflow-pow-compare-zero.shader_test new file mode 100644 index 000000000..01222affa --- /dev/null +++ b/tests/spec/glsl-1.20/execution/fs-underflow-pow-compare-zero.shader_test @@ -0,0 +1,62 @@ +# Some compilers may try to optimize comparisons based on the expected +# range of the sources. Check that pessimal cases are handled correctly. +# +# See also https://bugs.freedesktop.org/show_bug.cgi?id=111308 + +[require] +GLSL >= 1.20 + +[vertex shader passthrough] + +[fragment shader] +#version 120 + +uniform float base; +uniform float power; +uniform bool expect_non_zero; + +void main(void) +{ + float result = pow(base, power); + + gl_FragColor = expect_non_zero == (0 < result) + ? vec4(0.0, 1.0, 0.0, 1.0) + : vec4(1.0, 0.0, 0.0, 1.0); +} + +[test] +uniform float base 2 +uniform float power 0 +uniform int expect_non_zero 1 +draw rect -1 -1 1 1 + +# Smallest possible subnormal number is 2**-149. If someone has a +# representation that has more exponent, this case may incorrectly fail. +uniform float base 2 +uniform float power -150 +uniform int expect_non_zero 0 +draw rect 0 -1 1 1 + +# Be very careful here... GLSL 1.20 has very low requirements for +# precision of calculations. GLSL ES 1.00, for example, only requires +# 2**-61. Specify a number slightly larger than that to ensure the +# hardware doesn't flush to zero. Smallest possible subnormal number +# is 2**-149. If someone has a representation that has more exponent, +# this case may incorrectly fail. +# +# Note: 2**(-150) = (2**(-61))**2.459 +uniform float base 0.000000000000000000433681 +uniform float power 2.459 +uniform int expect_non_zero 0 +draw rect -1 0 1 1 + +# Like the previous case, but use 2**61 and a much larger negative +# exponent. +# +# Note: 2**(-150) = (2**(-61))**2.459 +uniform float base 2305843009213693952 +uniform float power -2.459 +uniform int expect_non_zero 0 +draw rect 0 0 1 1 + +probe all rgba 0.0 1.0 0.0 1.0 |