]> gcc.gnu.org Git - gcc.git/commit
range-op-float: Fix up frange_arithmetic [PR107967]
authorJakub Jelinek <jakub@redhat.com>
Thu, 8 Dec 2022 09:34:26 +0000 (10:34 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 8 Dec 2022 09:34:26 +0000 (10:34 +0100)
commit2f187e9893916796992b60b278e743ec865f7418
tree0dd320e996a20faed7d1fe5001f218b40acbd29a
parentab9fc70149d217a4631822d3db956f45b7c43ecb
range-op-float: Fix up frange_arithmetic [PR107967]

The addition of PLUS/MINUS/MULT/RDIV_EXPR frange handlers causes
miscompilation of some of the libm routines, resulting in lots of
glibc test failures.  A part of them is purely PR107608 fold-overflow-1.c
etc. issues, say when the code does
  return -0.5 / 0.0;
and expects division by zero to be emitted, but we propagate -Inf
and avoid the operation.
But there are also various tests where we end up with different computed
value from the expected ones.  All those cases are like:
 is:          inf   inf
 should be:   1.18973149535723176502e+4932   0xf.fffffffffffffff0p+16380
 is:          inf   inf
 should be:   1.18973149535723176508575932662800701e+4932   0x1.ffffffffffffffffffffffffffffp+16383
 is:          inf   inf
 should be:   1.7976931348623157e+308   0x1.fffffffffffffp+1023
 is:          inf   inf
 should be:   3.40282346e+38   0x1.fffffep+127
and the corresponding source looks like:
static const double huge = 1.0e+300;
double whatever (...) {
...
  return huge * huge;
...
}
which for rounding to nearest or +inf should and does return +inf, but
for rounding to -inf or 0 should instead return nextafter (inf, -inf);
The rules IEEE754 has are that operations on +-Inf operands are exact
and produce +-Inf (except for the invalid ones that produce NaN) regardless
of rounding mode, while overflows:
"a) roundTiesToEven and roundTiesToAway carry all overflows to ∞ with the
sign of the intermediate result.
b) roundTowardZero carries all overflows to the format’s largest finite
number with the sign of the intermediate result.
c) roundTowardNegative carries positive overflows to the format’s largest
finite number, and carries negative overflows to −∞.
d) roundTowardPositive carries negative overflows to the format’s most
negative finite number, and carries positive overflows to +∞."

The behavior around overflows to -Inf or nextafter (-inf, inf) was actually
handled correctly, we'd construct [-INF, -MAX] ranges in those cases
because !real_less (&value, &result) in that case - value is finite
but larger in magnitude than what the format can represent (but GCC
internal's format can), while result is -INF in that case.
But for the overflows to +Inf or nextafter (inf, -inf) was handled
incorrectly, it tested real_less (&result, &value) rather than
!real_less (&result, &value), the former test is true when already the
rounding value -> result rounded down and in that case we shouldn't
round again, we should round down when it didn't.

So, in theory this could be fixed just by adding one ! character,
-  if ((mode_composite || (real_isneg (&inf) ? real_less (&result, &value)
+  if ((mode_composite || (real_isneg (&inf) ? !real_less (&result, &value)
                          : !real_less (&value, &result)))
but the following patch goes further.  The distance between
nextafter (inf, -inf) and inf is large (infinite) and expressions like
1.0e+300 * 1.0e+300 always produce +inf in round to nearest mode by far,
so I think having low bound of nextafter (inf, -inf) in that case is
unnecessary.  But if it isn't multiplication but say addition and we are
inexact and very close to the boundary between rounding to nearest
maximum representable vs. rounding to nearest +inf, still using [MAX, +INF]
etc. ranges seems safer because we don't know exactly what we lost in the
inexact computation.

The following patch implements that.

2022-12-08  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/107967
* range-op-float.cc (frange_arithmetic): Fix a thinko - if
inf is negative, use nextafter if !real_less (&result, &value)
rather than if real_less (&result, &value).  If result is +-INF
while value is finite and -fno-rounding-math, don't do rounding
if !inexact or if result is significantly above max representable
value or below min representable value.

* gcc.dg/pr107967-1.c: New test.
* gcc.dg/pr107967-2.c: New test.
* gcc.dg/pr107967-3.c: New test.
gcc/range-op-float.cc
gcc/testsuite/gcc.dg/pr107967-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr107967-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr107967-3.c [new file with mode: 0644]
This page took 0.071337 seconds and 5 git commands to generate.