On Thu, Jul 30, 2026 at 11:42 AM Jakub Jelinek <[email protected]> wrote: > > 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. > > Ok for trunk/16.2 if it passes bootstrap/regtest?
LGTM as well. > 2026-07-30 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. > (operator_cast::op1_range): Don't pass third argument to > float_widen_lhs_range. > > * gcc.dg/torture/pr126464.c: New test. > > --- gcc/range-op-float.cc.jj 2026-07-30 09:56:33.399864195 +0200 > +++ gcc/range-op-float.cc 2026-07-30 11:24:54.504217764 +0200 > @@ -2374,14 +2374,14 @@ zero_to_inf_range (REAL_VALUE_TYPE &lb, > 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)) > @@ -2397,7 +2397,7 @@ float_widen_lhs_range (tree type, const > } > 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. */ > @@ -2406,7 +2406,7 @@ float_widen_lhs_range (tree type, const > 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)) > @@ -2417,7 +2417,7 @@ float_widen_lhs_range (tree type, const > } > 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. */ > @@ -3026,7 +3026,7 @@ operator_cast::op1_range (frange &r, tre > else > { > rm = true; > - wlhs = float_widen_lhs_range (lhs_type, lhs, true); > + wlhs = float_widen_lhs_range (lhs_type, lhs); > } > auto save_flag_rounding_math = flag_rounding_math; > flag_rounding_math = rm; > --- gcc/testsuite/gcc.dg/torture/pr126464.c.jj 2026-07-30 11:23:07.024598145 > +0200 > +++ gcc/testsuite/gcc.dg/torture/pr126464.c 2026-07-30 11:22:55.461746647 > +0200 > @@ -0,0 +1,26 @@ > +/* PR tree-optimization/126464 */ > +/* { dg-do run } */ > + > +#if __DBL_MANT_DIG__ == 53 && __DBL_MAX_10_EXP__ == 308 && > __DBL_HAS_INFINITY__ > +[[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__ > + if (foo (-__builtin_inf (), -1e303) != -__builtin_inf ()) > + __builtin_abort (); > + if (foo (-1.797693134862e308, -1e303) != -1.797693134862e308 / 2.0) > + __builtin_abort (); > +#endif > +} > > > Jakub >
