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


Reply via email to