From 854db99ff1371995e015a65dfd88556c5af01027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjimihe=E2=80=9D?= Date: Fri, 17 Nov 2023 17:02:10 +0800 Subject: [PATCH] Out-of-range floats should overflow/underflow to infinity/0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit glslang representing literal constants with double precision, so 1.0e40 and 1.0e-50 are normal values. Shader1: precision highp float; out vec4 my_FragColor; void main() { // Out-of-range floats should overflow to infinity // GLSL ES 3.00.6 section 4.1.4 Floats: // "If the value of the floating point number is too large (small) to be stored as a single precision value, it is converted to positive (negative) infinity" float correct = isinf(1.0e40) ? 1.0 : 0.0; my_FragColor = vec4(0.0, correct, 0.0, 1.0); } The expected ouput result of this test is vec4(0.0, 1.0, 0.0, 1.0), but it's vec4(0.0,0.0,0.0,1.0).Because the return value of isInf is false. precision highp float; out vec4 my_FragColor; void main() { // GLSL ES 3.00.6 section 4.1.4 Floats: // "A value with a magnitude too small to be represented as a mantissa and exponent is converted to zero." // 1.0e-50 is small enough that it can't even be stored as subnormal. float correct = (1.0e-50 == 0.0) ? 1.0 : 0.0; my_FragColor = vec4(0.0, correct, 0.0, 1.0); } The expected ouput result of this test is vec4(0.0, 1.0, 0.0, 1.0), but it's vec4(0.0,0.0,0.0,1.0). For f32 and f16 type, when the literal constant out of range of the f32 and f16 number, the value should overflow or underflow to inf or zero. glcts test item KHR-GLES3.number_parsing.float_out_of_range_as_infinity --- .../overflow_underflow_toinf_0.out | 28 +++++++++++++++++++ Test/overflow_underflow_toinf_0.frag | 12 ++++++++ Test/runtests | 2 ++ glslang/MachineIndependent/Intermediate.cpp | 12 ++++++++ 4 files changed, 54 insertions(+) create mode 100644 Test/baseResults/overflow_underflow_toinf_0.out create mode 100644 Test/overflow_underflow_toinf_0.frag diff --git a/Test/baseResults/overflow_underflow_toinf_0.out b/Test/baseResults/overflow_underflow_toinf_0.out new file mode 100644 index 00000000..3e017b8c --- /dev/null +++ b/Test/baseResults/overflow_underflow_toinf_0.out @@ -0,0 +1,28 @@ +overflow_underflow_toinf_0.frag +Shader version: 320 +0:? Sequence +0:4 Function Definition: main( ( global void) +0:4 Function Parameters: +0:9 Sequence +0:9 Sequence +0:9 move second child to first child ( temp highp float) +0:9 'correct' ( temp highp float) +0:9 Constant: +0:9 1.000000 +0:10 Sequence +0:10 move second child to first child ( temp highp float) +0:10 'correct1' ( temp highp float) +0:10 Constant: +0:10 1.000000 +0:11 move second child to first child ( temp highp 4-component vector of float) +0:11 'my_FragColor' ( out highp 4-component vector of float) +0:11 Construct vec4 ( temp highp 4-component vector of float) +0:11 Constant: +0:11 0.000000 +0:11 'correct' ( temp highp float) +0:11 'correct1' ( temp highp float) +0:11 Constant: +0:11 1.000000 +0:? Linker Objects +0:? 'my_FragColor' ( out highp 4-component vector of float) + diff --git a/Test/overflow_underflow_toinf_0.frag b/Test/overflow_underflow_toinf_0.frag new file mode 100644 index 00000000..2e557577 --- /dev/null +++ b/Test/overflow_underflow_toinf_0.frag @@ -0,0 +1,12 @@ + #version 320 es + precision highp float; + out vec4 my_FragColor; + void main() + { + // GLSL ES 3.00.6 section 4.1.4 Floats: + // "A value with a magnitude too small to be represented as a mantissa and exponent is converted to zero." + // 1.0e-50 is small enough that it can't even be stored as subnormal. + float correct = (1.0e-50 == 0.0) ? 1.0 : 0.0; + float correct1 = isinf(1.0e40) ? 1.0 : 0.0; + my_FragColor = vec4(0.0, correct, correct1, 1.0); + } \ No newline at end of file diff --git a/Test/runtests b/Test/runtests index e7e1d33f..197f7fcd 100755 --- a/Test/runtests +++ b/Test/runtests @@ -343,6 +343,8 @@ run --enhanced-msgs -V --target-env vulkan1.2 --amb --aml enhanced.7.vert enhanc diff -b $BASEDIR/enhanced.7.link.out $TARGETDIR/enhanced.7.link.out || HASERROR=1 run --enhanced-msgs -V --target-env vulkan1.2 --amb --aml spv.textureError.frag > $TARGETDIR/spv.textureError.frag.out diff -b $BASEDIR/spv.textureError.frag.out $TARGETDIR/spv.textureError.frag.out || HASERROR=1 +run -i overflow_underflow_toinf_0.frag > $TARGETDIR/overflow_underflow_toinf_0.out +diff -b $BASEDIR/overflow_underflow_toinf_0.out $TARGETDIR/overflow_underflow_toinf_0.out || HASERROR=1 # # Final checking diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 30450b36..5d3fc8af 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -2590,6 +2590,18 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT { assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16); + if (isEsProfile() && (baseType == EbtFloat || baseType == EbtFloat16)) { + int exponent = 0; + frexp(d, &exponent); + int minExp = baseType == EbtFloat ? -126 : -14; + int maxExp = baseType == EbtFloat ? 127 : 15; + if (exponent > maxExp) { //overflow, d = inf + d = std::numeric_limits::infinity(); + } else if (exponent < minExp) { //underflow, d = 0.0; + d = 0.0; + } + } + TConstUnionArray unionArray(1); unionArray[0].setDConst(d);