[gcc r13-10448] range-op-float: Fix up inf handling in other reverse ops [PR126464]
Jakub Jelinek via Gcc-cvs <[email protected]> Sat, 1 Aug 2026 10:58:42 +0000 (GMT)
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:1fa3bf850f885b863e268987441be5e402406a4c commit r13-10448-g1fa3bf850f885b863e268987441be5e402406a4c Author: Jakub Jelinek <[email protected]> Date: Fri Jul 31 08:56:03 2026 +0200 range-op-float: Fix up inf handling in other reverse ops [PR126464] On Thu, Jul 30, 2026 at 09:31:17AM +0200, Richard Biener wrote: > > The following testcase is miscompiled since my r16-1108 change. > > The problem is if we handle a reverse of a narrowing float to float cast > > (in the example there are double -> float and long double -> double > > cast) and the lhs range is [-inf, -inf] or [+inf, +inf] (note, regardless > > of whether some NaNs are allowed or not, so not necessarily > > lhs.known_isinf ()), then handling that range in the wider type also > > as [-inf, -inf] or [+inf, +inf] is wrong, e.g. for the double -> float > > conversion, [-inf, -0x0.ffffff8p+128] double range could map to just > > that [-inf, -inf]. We have already float_widen_lhs_range function > > but that just extends the range by +/-1ulp or 0.5ulp if the bounds > > are finite. If the range isn't singleton (except for optional NaN), > > then the minimum (or maximum) finite is already in the range, so this just > > extends the case where they are singleton. > > I don't know how to portably figure out that 0x0.ffffff8p+128 for > > double -> float (especially when in float_widen_lhs_range we don't know > > yet the wider type), so the patch just uses the +/-1ulp extension (i.e. > > [-inf, min_finite] or [+inf, max_finite] case. On a second thought, this actually isn't specific to just reverse of narrowing float to float casts, it is a problem for any other reverse binary ops too. E.g. the following testcase is miscompiled at -O2 since r13-3926-gd4c2f1d376da (but works with -O0). The lhs of the addition is [-inf, -inf], one of its operand is [-1e304, -1e300] and we think the other operand has to be [-inf, -inf]. That is obviously wrong, even much larger operands can result in -inf, anything below -DBL_MAX + -1e300 where x + -1e300 doesn't round to -DBL_MAX or higher but to -inf. So, the following patch just widens lb of +inf and ub of -inf by 1ulp for all callers (and thus doesn't need the also_inf argument. 2026-07-31 Jakub Jelinek <[email protected]> PR tree-optimization/126464 * range-op-float.cc (float_widen_lhs_range): Remove also_inf argument, replace its uses as if it was always true. * gcc.dg/torture/pr126464.c: New test. Reviewed-by: Richard Biener <[email protected]> (cherry picked from commit 6f32166346de2d1c0f6253e4fe37e8a6edac655d) Diff: --- gcc/range-op-float.cc | 10 +++++----- gcc/testsuite/gcc.dg/torture/pr126464.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 3535b04071f2..0584eebf0e59 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -2334,14 +2334,14 @@ zero_to_inf_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) in each direction. See PR109008 for more details. */ static frange -float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) +float_widen_lhs_range (tree type, const frange &lhs) { frange ret = lhs; if (lhs.known_isnan ()) return ret; REAL_VALUE_TYPE lb = lhs.lower_bound (); REAL_VALUE_TYPE ub = lhs.upper_bound (); - if (real_isfinite (&lb) || (also_inf && !real_isneg (&lb))) + if (real_isfinite (&lb) || !real_isneg (&lb)) { frange_nextafter (TYPE_MODE (type), lb, dconstninf); if (real_isinf (&lb)) @@ -2357,7 +2357,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) } if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type)) - && (!also_inf || real_isfinite (&lhs.lower_bound ()))) + && real_isfinite (&lhs.lower_bound ())) { /* If not -frounding-math nor IBM double double, actually widen just by 0.5ulp rather than 1ulp. */ @@ -2366,7 +2366,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2); } } - if (real_isfinite (&ub) || (also_inf && real_isneg (&ub))) + if (real_isfinite (&ub) || real_isneg (&ub)) { frange_nextafter (TYPE_MODE (type), ub, dconstinf); if (real_isinf (&ub)) @@ -2377,7 +2377,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) } if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type)) - && (!also_inf || real_isfinite (&lhs.upper_bound ()))) + && real_isfinite (&lhs.upper_bound ())) { /* If not -frounding-math nor IBM double double, actually widen just by 0.5ulp rather than 1ulp. */ diff --git a/gcc/testsuite/gcc.dg/torture/pr126464.c b/gcc/testsuite/gcc.dg/torture/pr126464.c new file mode 100644 index 000000000000..c0dced1eedc0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr126464.c @@ -0,0 +1,28 @@ +/* PR tree-optimization/126464 */ +/* { dg-do run } */ + +#if __DBL_MANT_DIG__ == 53 && __DBL_MAX_10_EXP__ == 308 \ + && __DBL_HAS_INFINITY__ && __FLT_EVAL_METHOD__ == 0 +[[gnu::noipa]] double +foo (double x, double y) +{ + if (y >= -1e304 && y <= -1e300) + { + if (x + y == -__builtin_inf ()) + return x * 0.5; + } + return x; +} +#endif + +int +main () +{ +#if __DBL_MANT_DIG__ == 53 && __DBL_MAX_10_EXP__ == 308 \ + && __DBL_HAS_INFINITY__ && __FLT_EVAL_METHOD__ == 0 + if (foo (-__builtin_inf (), -1e303) != -__builtin_inf ()) + __builtin_abort (); + if (foo (-1.797693134862e308, -1e303) != -1.797693134862e308 / 2.0) + __builtin_abort (); +#endif +}