On Wed, Jul 29, 2026 at 9:05 PM Jakub Jelinek <[email protected]> wrote: > > Hi! > > 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. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?
LGTM. Richard. > 2026-07-29 Jakub Jelinek <[email protected]> > > PR tree-optimization/126464 > * range-op-float.cc (float_widen_lhs_range): Add also_inf argument > defaulted to false, if true, extend even lb of +inf and ub of -inf. > (operator_cast::op1_range): Adjust float_widen_lhs_range caller. > > * gcc.dg/pr126464.c: New test. > > --- gcc/range-op-float.cc.jj 2026-05-06 17:43:14.667261681 +0200 > +++ gcc/range-op-float.cc 2026-07-29 14:10:58.343016627 +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) > +float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) > { > 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)) > + if (real_isfinite (&lb) || (also_inf && !real_isneg (&lb))) > { > frange_nextafter (TYPE_MODE (type), lb, dconstninf); > if (real_isinf (&lb)) > @@ -2395,7 +2395,9 @@ float_widen_lhs_range (tree type, const > lb = dconstm1; > SET_REAL_EXP (&lb, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); > } > - if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) > + if (!flag_rounding_math > + && !MODE_COMPOSITE_P (TYPE_MODE (type)) > + && (!also_inf || real_isfinite (&lhs.lower_bound ()))) > { > /* If not -frounding-math nor IBM double double, actually widen > just by 0.5ulp rather than 1ulp. */ > @@ -2404,7 +2406,7 @@ float_widen_lhs_range (tree type, const > real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2); > } > } > - if (real_isfinite (&ub)) > + if (real_isfinite (&ub) || (also_inf && real_isneg (&ub))) > { > frange_nextafter (TYPE_MODE (type), ub, dconstinf); > if (real_isinf (&ub)) > @@ -2413,7 +2415,9 @@ float_widen_lhs_range (tree type, const > ub = dconst1; > SET_REAL_EXP (&ub, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); > } > - if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) > + if (!flag_rounding_math > + && !MODE_COMPOSITE_P (TYPE_MODE (type)) > + && (!also_inf || real_isfinite (&lhs.upper_bound ()))) > { > /* If not -frounding-math nor IBM double double, actually widen > just by 0.5ulp rather than 1ulp. */ > @@ -3022,7 +3026,7 @@ operator_cast::op1_range (frange &r, tre > else > { > rm = true; > - wlhs = float_widen_lhs_range (lhs_type, lhs); > + wlhs = float_widen_lhs_range (lhs_type, lhs, true); > } > auto save_flag_rounding_math = flag_rounding_math; > flag_rounding_math = rm; > --- gcc/testsuite/gcc.dg/pr126464.c.jj 2026-07-29 14:29:17.256893972 +0200 > +++ gcc/testsuite/gcc.dg/pr126464.c 2026-07-29 14:30:04.502287539 +0200 > @@ -0,0 +1,61 @@ > +/* PR tree-optimization/126464 */ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > +/* { dg-add-options ieee } */ > +/* { dg-skip-if "not IEEE float" { "pdp11-*-*" } } */ > + > +[[gnu::noipa]] double > +foo (double x) > +{ > + float y = (float) x; > + > + if (y == -__builtin_inff ()) > + return x * 0.5; > + return y; > +} > + > +[[gnu::noipa]] long double > +bar (long double x) > +{ > + double y = (double) x; > + > + if (y == __builtin_inf ()) > + return x * 0.5L; > + return y; > +} > + > +[[gnu::noipa]] double > +baz (double x) > +{ > + float y = (float) x; > + > + if (y == __builtin_inff ()) > + return x * 0.5; > + return y; > +} > + > +[[gnu::noipa]] long double > +qux (long double x) > +{ > + double y = (double) x; > + > + if (y == -__builtin_inf ()) > + return x * 0.5L; > + return y; > +} > + > +int > +main () > +{ > + if (!__builtin_isinf ((double) 1e300) > + && __builtin_isinf ((float) 1e300) > + && (foo (-1e300) != -5e299 > + || baz (1e300) != 5e299)) > + __builtin_abort (); > + > + if (!__builtin_isinf ((long double) 1e4000L) > + && __builtin_isinf ((double) 1e4000L) > + && (bar (1e4000L) != 5e3999L > + || qux (-1e4000L) != -5e3999L)) > + __builtin_abort (); > +} > > Jakub >
