https://gcc.gnu.org/g:081959973e38fde06077cbfa70e036e4f018489c

commit r17-2324-g081959973e38fde06077cbfa70e036e4f018489c
Author: Roger Sayle <[email protected]>
Date:   Fri Jul 10 23:09:04 2026 +0100

    PR tree-optimization/57371: Improved comparison of integers to FP constants.
    
    This patch improves the tree-level optimization of (fptype)ivar != CST
    in match.pd (historically tracked under PR 57371).  Joseph Myers'
    description in comment #1 provides an excellent overview of the issues,
    that historically it's the trapping behaviour of (fptype)ivar conversion
    that is the primary concern, which is why the current code in match.pd
    checks fmt.can_represent_integral_type_p (itype).  The first of the
    improvements with this patch is to check flag_trapping_math to control
    whether FP_OVERFLOW/FP_INEXACT needs to be preserved.
    
    The main optimization concerns checking whether the comparison
    against CST is unambiguous allowing it to be replaced with a integer
    comparison.  For reference, consider the table below which shows the
    default conversion of integers to IEEE 32-bit float.
    
    (float)16777211 => 16777211.0f;
    (float)16777212 => 16777212.0f;
    (float)16777213 => 16777213.0f;
    (float)16777214 => 16777214.0f;
    (float)16777215 => 16777215.0f;
    (float)16777216 => 16777216.0f;
    (float)16777217 => 16777216.0f;  // rounded
    (float)16777218 => 16777218.0f;
    (float)16777219 => 16777220.0f;  // rounded
    (float)16777220 => 16777220.0f;
    (float)16777221 => 16777220.0f;  // rounded
    (float)16777222 => 16777222.0f;
    (float)16777223 => 16777224.0f;  // rounded
    (float)16777224 => 16777224.0f;
    (float)16777225 => 16777224.0f;  // rounded
    (float)16777226 => 16777226.0f;
    
    Observe that it's safe to optimize (float)i == 16777212.0f to the
    equivalent i == 16777212 (as this is the only integer that can
    convert to that floating point constant), but that it's unsafe to
    optimize (float)i == 16777220.0f, as with default rounding there
    are three possible integer values that FLOAT_EXPR to 16777220.0f.
    The pragmatic check used in this patch is to confirm that (float)(i-1)
    and (float)(i+1) are both distinct from (float)i before simplifying
    the comparison to an integer-typed comparison.
    
    Finally, this patch also handles non-default rounding modes.
    In the table above, it's safe to optimize (float)i == 16777222.0f
    in IEEE's default rounding mode, but not in all FP rounding modes.
    This eventuality is handled by testing whether the (float)i, the
    (float)(i-1) and the (float)(i+1) are all exactly rounded when
    -frounding-math is specified.
    
    The original motivation for this patch was Claudiu's issue/analysis at
    https://github.com/foss-for-synopsys-dwc-arc-processors/gcc/issues/118
    which predicted a dramatic +26% performance improvement on EEMBC's
    iirflt01 benchmark.
    
    2026-07-10  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            PR tree-optimization/57371
            * fold-const.cc (fold_cmp_float_cst_p): New helper function.
            * fold-const.h (fold_cmp_float_cst_p): Prototype here.
            * match.pd ((FTYPE) N CMP CST): Use the new helper
            fold_cmp_float_cst_p to check that transformation to an integer
            comparison is safe.
    
    gcc/testsuite/ChangeLog
            PR tree-optimization/57371
            * c-c++-common/pr57371-6.c: New test case.
            * c-c++-common/pr57371-7.c: Likewise.
            * c-c++-common/pr57371-8.c: Likewise.
            * c-c++-common/pr57371-9.c: Likewise.
            * c-c++-common/pr57371-10.c: Likewise.

Diff:
---
 gcc/fold-const.cc                       |  86 +++++++++++++
 gcc/fold-const.h                        |   6 +
 gcc/match.pd                            |  35 ++---
 gcc/testsuite/c-c++-common/pr57371-10.c |  20 +++
 gcc/testsuite/c-c++-common/pr57371-6.c  | 200 +++++++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr57371-7.c  | 218 ++++++++++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr57371-8.c  |  20 +++
 gcc/testsuite/c-c++-common/pr57371-9.c  |  24 ++++
 8 files changed, 594 insertions(+), 15 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 1d0ed62a82fe..b4e3a56aeb55 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -7020,6 +7020,92 @@ fold_real_zero_addition_p (const_tree type, const_tree 
arg,
   return negate || (arg && !tree_expr_maybe_real_minus_zero_p (arg));
 }
 
+/* Subroutine of match.pd that determines if it is safe to optimize
+   a floating point comparison of an integer value, known to be between
+   LO and HI, using comparison operator CMP, against the real constant
+   R in floating point type FMT, as the same integer comparison against
+   the integer constant I, with sign ISIGN.
+
+   For example, with IEEE-754, (float)x == 2.0f may replaced with x == 2
+   because the floating point representations of the neighboring integers
+   (float)1 and (float)3 are distinct from 2.0f, having values 1.0f and
+   3.0f respectively.  On the other hand (float)x == 16777220.0f can't
+   be replaced by x == 16777220 as (float)16777221 is also 1677220.0f
+   due to truncation/rounding.
+*/
+bool
+fold_cmp_float_cst_p (wide_int lo, wide_int hi, enum tree_code cmp,
+                     const REAL_VALUE_TYPE *r, format_helper fmt,
+                     wide_int i, signop isign)
+{
+  REAL_VALUE_TYPE raw;
+  REAL_VALUE_TYPE rnd;
+  bool check_im1 = true;
+  bool check_ip1 = true;
+
+  switch (cmp)
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* Check both i-1 and i+1.  */
+      break;
+
+    case LT_EXPR:
+    case GE_EXPR:
+      /* Only check i-1.  */
+      check_ip1 = false;
+      break;
+
+    case LE_EXPR:
+    case GT_EXPR:
+      /* Only check i+1.  */
+      check_im1 = false;
+      break;
+
+    default:
+      return false;
+    }
+
+    if (flag_rounding_math && i != 0)
+      {
+       real_from_integer (&raw, VOIDmode, i, isign);
+       if (!real_identical (r, &raw))
+         return false;
+      }
+
+    if (check_im1 && wi::gt_p (i, lo, isign))
+      {
+       if (flag_rounding_math)
+         {
+           real_from_integer (&raw, VOIDmode, i - 1, isign);
+           real_convert (&rnd, fmt, &raw);
+           if (!real_identical (&raw, &rnd))
+             return false;
+         }
+       else
+         real_from_integer (&rnd, fmt, i - 1, isign);
+       if (real_identical (r, &rnd))
+         return false;
+      }
+
+    if (check_ip1 && wi::lt_p (i, hi, isign))
+      {
+       if (flag_rounding_math)
+         {
+           real_from_integer (&raw, VOIDmode, i + 1, isign);
+           real_convert (&rnd, fmt, &raw);
+           if (!real_identical (&raw, &rnd))
+             return false;
+         }
+       else
+         real_from_integer (&rnd, fmt, i + 1, isign);
+       if (real_identical (r, &rnd))
+         return false;
+      }
+
+  return true;
+}
+
 /* Subroutine of match.pd that optimizes comparisons of a division by
    a nonzero integer constant against an integer constant, i.e.
    X/C1 op C2.
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 8c0c3edba178..25e1cbf911f5 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -173,6 +173,12 @@ extern bool integer_valued_real_p (tree, int = 0);
 
 extern bool fold_real_zero_addition_p (const_tree, const_tree, const_tree,
                                       int);
+extern bool fold_cmp_float_cst_p (wide_int lo, wide_int hi,
+                                 enum tree_code cmp,
+                                 const REAL_VALUE_TYPE *r,
+                                 format_helper fmt,
+                                 wide_int i, signop isign);
+
 extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
                                 enum tree_code, tree, tree, tree);
 extern tree_code combine_comparisons (enum tree_code, enum tree_code,
diff --git a/gcc/match.pd b/gcc/match.pd
index 891f15fb69b7..89ed2aaaa527 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7800,6 +7800,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        tree itype = TREE_TYPE (@0);
+       signop isign = TYPE_SIGN (itype);
        format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@1))));
        bool itype_ok = fmt.can_represent_integral_type_p (itype);
        bool value_ok = itype_ok;
@@ -7817,10 +7818,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
           && gimple_match_range_of_expr (vr, @0, @2))
         value_ok = fmt.can_represent_range_value_p (&vr);
 #endif
+       /* Conversion may raise FPE_INEXACT with -ftrapping-math.  */
+       if (flag_trapping_math && !value_ok)
+        exception_p = true;
      }
-     /* TODO: allow non-fitting itype and SNaNs when
-       -fno-trapping-math.  */
-     (if (value_ok && ! exception_p)
+
+     (if (! exception_p)
       (with
        {
         signop isign = TYPE_SIGN (itype);
@@ -7845,7 +7848,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
         else
           real_trunc (&icst, fmt, cst);
 
-        bool cst_int_p = !real_isnan (cst) && real_identical (&icst, cst);
+        bool cst_int_p = real_isfinite (cst) && real_identical (&icst, cst);
 
         bool overflow_p = false;
         wide_int icst_val
@@ -7859,21 +7862,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        (if (real_compare (GT_EXPR, cst, &imax))
         { constant_boolean_node (cmp == LT_EXPR || cmp == LE_EXPR || cmp == 
NE_EXPR,
                                  type); })
-       /* Remove cast if CST is an integer representable by ITYPE.  */
-       (if (cst_int_p)
-        (cmp @0 { gcc_assert (!overflow_p);
-                  wide_int_to_tree (itype, icst_val); })
-       )
-       /* When CST is fractional, optimize
+       /* When CST is fractional, infinity or NaN, then optimize
            (FTYPE) N == CST -> 0
            (FTYPE) N != CST -> 1.  */
-       (if (cmp == EQ_EXPR || cmp == NE_EXPR)
+       (if (!cst_int_p
+            && (cmp == EQ_EXPR || cmp == NE_EXPR))
         { constant_boolean_node (cmp == NE_EXPR, type); })
+       /* Remove cast if CST is an integer representable by ITYPE,
+          and it is safe to do so.  */
+       (if (cst_int_p
+            && fold_cmp_float_cst_p (imin_val, imax_val, cmp, &icst, fmt,
+                                     icst_val, isign))
+        (cmp @0 { wide_int_to_tree (itype, icst_val); })
+       )
        /* Otherwise replace with sensible integer constant.  */
-       (with
-        {
-          gcc_checking_assert (!overflow_p);
-        }
+       (if (!cst_int_p
+            && fold_cmp_float_cst_p (imin_val, imax_val, icmp, &icst, fmt,
+                                     icst_val, isign))
         (icmp @0 { wide_int_to_tree (itype, icst_val); })))))))))
 
 /* Fold A /[ex] B CMP C to A CMP B * C.  */
diff --git a/gcc/testsuite/c-c++-common/pr57371-10.c 
b/gcc/testsuite/c-c++-common/pr57371-10.c
new file mode 100644
index 000000000000..96172767c781
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-10.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math -frounding-math" 
} */
+
+int foo1 (int a) {
+  return (float) a != 16777222.0f;
+}
+
+int foo2 (unsigned int b) {
+  return (float) b != 16777222.0f;
+}
+
+int foo3 (unsigned long long c) {
+  return (float) c != 16777222.0f;
+}
+
+int foo4 (long long d) {
+  return (float) d != 16777222.0f;
+}
+
+/* { dg-final { scan-tree-dump-times "\\(float\\)" 4 "optimized" } } */
diff --git a/gcc/testsuite/c-c++-common/pr57371-6.c 
b/gcc/testsuite/c-c++-common/pr57371-6.c
new file mode 100644
index 000000000000..d3a9d8ecf7d4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-6.c
@@ -0,0 +1,200 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */
+
+int foo1 (int p) {
+  return (float) p != 0;
+  /* { dg-final { scan-tree-dump "p_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+int foo2 (unsigned int q) {
+  return (float) q != 0;
+  /* { dg-final { scan-tree-dump "q_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+int foo3 (long long r) {
+  return (float) r != 0;
+  /* { dg-final { scan-tree-dump "r_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+int foo4 (unsigned long long s) {
+  return (float) s != 0;
+  /* { dg-final { scan-tree-dump "s_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+int foo5 (long long t) {
+  return (double) t != 0;
+  /* { dg-final { scan-tree-dump "t_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+int foo6 (unsigned long long u) {
+  return (double) u != 0;
+  /* { dg-final { scan-tree-dump "u_\[0-9]+\\(D\\) != 0;" "optimized" } } */
+}
+
+/* Tests when RHS is within range of integer type.  */
+
+void in_range (unsigned int x)
+{
+  {
+    volatile int in_range_1;
+    in_range_1 = (float) x > 100.0f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+\\(D\\) > 100;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_2;
+    in_range_2 = (float) x < 200.0f;
+    /* { dg-final { scan-tree-dump "\[0-9]+\\(D\\) <= 199;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_3;
+    in_range_3 = (float) x > 300.5f;
+    /* { dg-final { scan-tree-dump "\[0-9]+\\(D\\) > 300;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_4;
+    in_range_4 = (float) x < 400.5f;
+    /* { dg-final { scan-tree-dump "\[0-9]+\\(D\\) <= 400;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_5;
+    in_range_5 = (float) x == 500.0f;
+    /* { dg-final { scan-tree-dump "\[0-9]+\\(D\\) == 500;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_6;
+    in_range_6 = (float) x != 600.0f;
+    /* { dg-final { scan-tree-dump "\[0-9]+\\(D\\) != 600;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_7;
+    in_range_7 = (float) x == 700.5f;
+    /* { dg-final { scan-tree-dump "in_range_7 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_8;
+    in_range_8 = (float) x != 800.5f;
+    /* { dg-final { scan-tree-dump "in_range_8 ={v} 1" "optimized" } } */
+  }
+}
+
+/* Tests for cases where RHS is out of range of integer type.  */
+
+void out_range (unsigned int x)
+{
+  {
+    volatile int out_range_1;
+    out_range_1 = (float) x > -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_1 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_2;
+    out_range_2 = (float) x >= -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_2 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_3;
+    out_range_3 = (float) x < -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_3 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_4;
+    out_range_4 = (float) x <= -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_4 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_5;
+    out_range_5 = (float) x == -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_5 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_6;
+    out_range_6 = (float) x != -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_6 ={v} 1" "optimized" } } */
+  }
+}
+
+/* Tests with non-finite float consts.  */
+
+void nonfinite (unsigned int x)
+{
+#define INFINITY __builtin_inff ()
+
+  {
+    volatile int nonfinite_1;
+    nonfinite_1 = (float) x > INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_1 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_2;
+    nonfinite_2 = (float) x >= INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_2 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_3;
+    nonfinite_3 = (float) x < INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_3 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_4;
+    nonfinite_4 = (float) x <= INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_4 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_5;
+    nonfinite_5 = (float) x > -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_5 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_6;
+    nonfinite_6 = (float) x >= -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_6 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_7;
+    nonfinite_7 = (float) x < -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_7 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_8;
+    nonfinite_8 = (float) x <= -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_8 ={v} 0" "optimized" } } */
+  }
+
+#define QNAN __builtin_nanf ("0")
+
+  /* Even for qNaNs, only == and != are quiet.  */
+
+  {
+    volatile int nonfinite_9;
+    nonfinite_9 = (float) x == QNAN;
+    /* { dg-final { scan-tree-dump "nonfinite_9 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_10;
+    nonfinite_10 = (float) x != QNAN;
+    /* { dg-final { scan-tree-dump "nonfinite_10 ={v} 1" "optimized" } } */
+  }
+}
+
+/* { dg-final { scan-tree-dump-not "\\(float\\)" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "\\(double\\)" "optimized" } } */
diff --git a/gcc/testsuite/c-c++-common/pr57371-7.c 
b/gcc/testsuite/c-c++-common/pr57371-7.c
new file mode 100644
index 000000000000..bde1911e64f4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-7.c
@@ -0,0 +1,218 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int foo1 (int a) {
+  a &= 4095;
+  return (float) a != 0.0f;
+  /* { dg-final { scan-tree-dump "a_\[0-9]+ != 0;" "optimized" } } */
+}
+
+int foo2 (unsigned int b) {
+  b &= 4095;
+  return (float) b != 0.0f;
+  /* { dg-final { scan-tree-dump "b_\[0-9]+ != 0;" "optimized" } } */
+}
+
+int foo3 (unsigned long long c) {
+  c &= 4095;
+  return (float) c != 0.0f;
+  /* { dg-final { scan-tree-dump "c_\[0-9]+ != 0;" "optimized" } } */
+}
+
+int foo4 (long long d) {
+  d &= 4095;
+  return (float) d != 0.0f;
+  /* { dg-final { scan-tree-dump "d_\[0-9]+ != 0;" "optimized" } } */
+}
+
+/* Tests when RHS is within range of integer type.  */
+
+void in_range (unsigned int x)
+{
+  {
+    volatile int in_range_1;
+    x &= 4095;
+    in_range_1 = (float) x > 100.0f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ > 100" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_2;
+    x &= 4095;
+    in_range_2 = (float) x < 200.0f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ <= 199" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_3;
+    x &= 4095;
+    in_range_3 = (float) x > 300.5f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ > 300" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_4;
+    x &= 4095;
+    in_range_4 = (float) x < 400.5f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ <= 400" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_5;
+    x &= 4095;
+    in_range_5 = (float) x == 500.0f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ == 500" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_6;
+    x &= 4095;
+    in_range_6 = (float) x != 600.0f;
+    /* { dg-final { scan-tree-dump "x_\[0-9]+ != 600" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_7;
+    x &= 4095;
+    in_range_7 = (float) x == 700.5f;
+    /* { dg-final { scan-tree-dump "in_range_7 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_8;
+    x &= 4095;
+    in_range_8 = (float) x != 800.5f;
+    /* { dg-final { scan-tree-dump "in_range_8 ={v} 1" "optimized" } } */
+  }
+}
+
+/* Tests for cases where RHS is out of range of integer type.  */
+
+void out_range (unsigned int x)
+{
+  {
+    volatile int out_range_1;
+    x &= 4095;
+    out_range_1 = (float) x > -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_1 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_2;
+    x &= 4095;
+    out_range_2 = (float) x >= -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_2 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_3;
+    x &= 4095;
+    out_range_3 = (float) x < -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_3 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_4;
+    x &= 4095;
+    out_range_4 = (float) x <= -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_4 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_5;
+    x &= 4095;
+    out_range_5 = (float) x == -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_5 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int out_range_6;
+    x &= 4095;
+    out_range_6 = (float) x != -100.5f;
+    /* { dg-final { scan-tree-dump "out_range_6 ={v} 1" "optimized" } } */
+  }
+}
+
+/* Tests with non-finite float consts.  */
+
+void nonfinite (unsigned int x)
+{
+#define INFINITY __builtin_inff ()
+
+  {
+    volatile int nonfinite_1;
+    x &= 4095;
+    nonfinite_1 = (float) x > INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_1 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_2;
+    x &= 4095;
+    nonfinite_2 = (float) x >= INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_2 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_3;
+    x &= 4095;
+    nonfinite_3 = (float) x < INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_3 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_4;
+    x &= 4095;
+    nonfinite_4 = (float) x <= INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_4 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_5;
+    x &= 4095;
+    nonfinite_5 = (float) x > -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_5 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_6;
+    x &= 4095;
+    nonfinite_6 = (float) x >= -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_6 ={v} 1" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_7;
+    x &= 4095;
+    nonfinite_7 = (float) x < -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_7 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_8;
+    x &= 4095;
+    nonfinite_8 = (float) x <= -INFINITY;
+    /* { dg-final { scan-tree-dump "nonfinite_8 ={v} 0" "optimized" } } */
+  }
+
+#define QNAN __builtin_nanf ("0")
+
+  /* Even for qNaNs, only == and != are quiet.  */
+
+  {
+    volatile int nonfinite_9;
+    x &= 4095;
+    nonfinite_9 = (float) x == QNAN;
+    /* { dg-final { scan-tree-dump "nonfinite_9 ={v} 0" "optimized" } } */
+  }
+
+  {
+    volatile int nonfinite_10;
+    x &= 4095;
+    nonfinite_10 = (float) x != QNAN;
+    /* { dg-final { scan-tree-dump "nonfinite_10 ={v} 1" "optimized" } } */
+  }
+}
+
+/* { dg-final { scan-tree-dump-not "\\(float\\)" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "\\(double\\)" "optimized" } } */
diff --git a/gcc/testsuite/c-c++-common/pr57371-8.c 
b/gcc/testsuite/c-c++-common/pr57371-8.c
new file mode 100644
index 000000000000..d0d7eecc9a10
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-8.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */
+
+int foo1 (int a) {
+  return (float) a != 16777220.0f;
+}
+
+int foo2 (unsigned int b) {
+  return (float) b != 16777220.0f;
+}
+
+int foo3 (unsigned long long c) {
+  return (float) c != 16777220.0f;
+}
+
+int foo4 (long long d) {
+  return (float) d != 16777220.0f;
+}
+
+/* { dg-final { scan-tree-dump-times "\\(float\\)" 4 "optimized" } } */
diff --git a/gcc/testsuite/c-c++-common/pr57371-9.c 
b/gcc/testsuite/c-c++-common/pr57371-9.c
new file mode 100644
index 000000000000..1cb7adc82922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-9.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */
+
+int foo1 (int a) {
+  return (float) a != 16777222.0f;
+  /* { dg-final { scan-tree-dump "a_\[0-9]+\\(D\\) != 16777222;" "optimized" } 
} */
+}
+
+int foo2 (unsigned int b) {
+  return (float) b != 16777222.0f;
+  /* { dg-final { scan-tree-dump "b_\[0-9]+\\(D\\) != 16777222;" "optimized" } 
} */
+}
+
+int foo3 (unsigned long long c) {
+  return (float) c != 16777222.0f;
+  /* { dg-final { scan-tree-dump "c_\[0-9]+\\(D\\) != 16777222;" "optimized" } 
} */
+}
+
+int foo4 (long long d) {
+  return (float) d != 16777222.0f;
+  /* { dg-final { scan-tree-dump "d_\[0-9]+\\(D\\) != 16777222;" "optimized" } 
} */
+}
+
+/* { dg-final { scan-tree-dump-not "\\(float\\)" "optimized" } } */

Reply via email to