Re: [PATCH] range-op-float: Fix up inf handling in reverse narrowing float to float cast [PR126464]

Torbjorn SVENSSON <[email protected]> Tue, 4 Aug 2026 14:13:19 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Hello,

This causes regression on most (all?) arm-none-eabi targets.

Testing gcc.dg/pr126464.c
doing compile
Executing on host: /build/r16-9480-g967a69a03886ebd6/bin/arm-none-eabi-gcc  /build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c  -mthumb -march=armv6s-m -mcpu=cortex-m0 -mfloat-abi=soft -mfpu=auto   -dumpbase "" -fdiagnostics-plain-output   -O2      --specs=rdimon.specs -Wl,--start-group -lc -lm -Wl,--end-group --specs=nosys.specs -Wl,--allow-multiple-definition -Wl,-u,_isatty,-u,_fstat  -Wl,-wrap,exit -Wl,-wrap,_exit -Wl,-wrap,main -Wl,-wrap,abort -Wl,gcc_tg.o -lm -T qemu.ld -o ./pr126464.exe    (timeout = 800)
...
  status 0
FAIL: gcc.dg/pr126464.c (test for excess errors)
Excess errors:
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:56:3: warning: floating constant exceeds range of 'long double' [-Woverflow]
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:57:7: warning: floating constant exceeds range of 'long double' [-Woverflow]
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:58:7: warning: floating constant exceeds range of 'long double' [-Woverflow]
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:58:7: warning: floating constant exceeds range of 'long double' [-Woverflow]
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:59:11: warning: floating constant exceeds range of 'long double' [-Woverflow]
/build/gcc_src/gcc/testsuite/gcc.dg/pr126464.c:59:11: warning: floating constant exceeds range of 'long double' [-Woverflow]

I've seen this in both r16-9480-g967a69a03886ebd6 and r17-2833-g32657f29f91871.

Kind regards,
Torbjörn

On 2026-07-30 09:31, Richard Biener wrote:
> 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
>>