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
>

Reply via email to