diff mbox series

PR tree-optimization/57371: Optimize (float)i == 16777222.0f sometimes.

Message ID 002e01dae0e5$e4a45b00$aded1100$@nextmovesoftware.com
State New
Headers show
Series PR tree-optimization/57371: Optimize (float)i == 16777222.0f sometimes. | expand

Commit Message

Roger Sayle July 28, 2024, 12:01 p.m. UTC
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, and to use
ranger to determine whether the bounds on ivar confirm that these
traps aren't possible.  For example, the expression (int)var & 15
can't overflow conversion to IEEE float, even though the type of a
32-bit int could potentially overflow the significant of a 32-bit
float.

The next of the optimizations concern 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.

This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures.  Ok for mainline?  If the testcases need to be
tweaked for non-IEEE targets (the transformations themselves should
be portable to VAX and IBM floating point formats) hopefully that
can be done as follow-up patches by folks with the appropriate
effective-targets?


2024-07-28  Roger Sayle  <roger@nextmovesoftware.com>

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 ranger to determine
        whether value is exactly representable by floating point type,
        and check flag_trapping_math if not.  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.


Thanks in advance,
Roger
--

Comments

Jeff Law Aug. 5, 2024, 2:29 p.m. UTC | #1
On 7/28/24 6:01 AM, Roger Sayle wrote:
> 
> 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, and to use
> ranger to determine whether the bounds on ivar confirm that these
> traps aren't possible.  For example, the expression (int)var & 15
> can't overflow conversion to IEEE float, even though the type of a
> 32-bit int could potentially overflow the significant of a 32-bit
> float.
> 
> The next of the optimizations concern 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.
> 
> This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
> and make -k check, both with and without --target_board=unix{-m32}
> with no new failures.  Ok for mainline?  If the testcases need to be
> tweaked for non-IEEE targets (the transformations themselves should
> be portable to VAX and IBM floating point formats) hopefully that
> can be done as follow-up patches by folks with the appropriate
> effective-targets?
> 
> 
> 2024-07-28  Roger Sayle  <roger@nextmovesoftware.com>
> 
> 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 ranger to determine
>          whether value is exactly representable by floating point type,
>          and check flag_trapping_math if not.  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.
Nice.  I was a bit concerned about using Ranger in match.pd as match.pd 
can be used for GENERIC as well as GIMPLE.  But it looks like you 
handled that reasonably.  Similarly for the other FP formats.

As you note, I wouldn't be terribly surprised if the other FP formats 
need testsuite adjustments.  I'd hoped we had a target selector, but we 
don't.

Does it make sense to use "add_options_for_ieee" to conditionally add 
the necessary target options in the tests?   It only affects alpha, sh & 
rx, so it's unlikely to have been needed in your testing.

Jeff
diff mbox series

Patch

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 710d697..3dd6dae 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -7531,6 +7531,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 b82ef13..e5a2c0d 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -175,6 +175,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 void debug_fold_checksum (const_tree);
diff --git a/gcc/match.pd b/gcc/match.pd
index 6818856..86114ac 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6860,6 +6860,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))));
        const REAL_VALUE_TYPE *cst = TREE_REAL_CST_PTR (@1);
        /* Be careful to preserve any potential exceptions due to NaNs.
@@ -6869,16 +6870,41 @@  DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 			  && ((cmp != EQ_EXPR && cmp != NE_EXPR)
 			      || (cst->signalling
 				  && HONOR_SNANS (TREE_TYPE (@1))));
+       /* Conversion may raise FPE_INEXACT with -ftrapping-math.  */
+       wide_int hi,lo;
+       bool exact_p;
+#if GIMPLE
+       int_range_max vr0;
+       get_range_query (cfun)->range_of_expr (vr0, @0);
+       if (!vr0.undefined_p ())
+	 {
+	   lo = vr0.lower_bound ();
+	   hi = vr0.upper_bound ();
+	   int prec = (isign == SIGNED)
+		      ? MAX (wi::min_precision (hi, SIGNED),
+			     wi::min_precision (lo, SIGNED)) - 1
+		      : wi::min_precision (hi, UNSIGNED);
+	   wide_int nz = vr0.get_nonzero_bits ();
+	   if (nz != 0)
+	     prec -= wi::ctz (nz);
+	   exact_p = prec <= significand_size (fmt);
+	 }
+       else
+#endif
+       {
+         exact_p = fmt.can_represent_integral_type_p (itype);
+         lo = wi::min_value (itype);
+         hi = wi::max_value (itype);
+       }
+       if (flag_trapping_math && !exact_p)
+	 exception_p = true;
      }
-     /* TODO: allow non-fitting itype and SNaNs when
-	-fno-trapping-math.  */
-     (if (fmt.can_represent_integral_type_p (itype) && ! exception_p)
+     (if (! exception_p)
       (with
        {
-	 signop isign = TYPE_SIGN (itype);
 	 REAL_VALUE_TYPE imin, imax;
-	 real_from_integer (&imin, fmt, wi::min_value (itype), isign);
-	 real_from_integer (&imax, fmt, wi::max_value (itype), isign);
+	 real_from_integer (&imin, fmt, lo, isign);
+	 real_from_integer (&imax, fmt, hi, isign);
 
 	 REAL_VALUE_TYPE icst;
 	 if (cmp == GT_EXPR || cmp == GE_EXPR)
@@ -6888,7 +6914,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
@@ -6902,21 +6928,22 @@  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.  */
+	(if (cst_int_p
+	     && fold_cmp_float_cst_p (lo, hi, 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 (lo, hi, 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 0000000..9617276
--- /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 0000000..3486b94
--- /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 " > 100;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_2;
+    in_range_2 = (float) x < 200.0f;
+    /* { dg-final { scan-tree-dump " <= 199;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_3;
+    in_range_3 = (float) x > 300.5f;
+    /* { dg-final { scan-tree-dump " > 300;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_4;
+    in_range_4 = (float) x < 400.5f;
+    /* { dg-final { scan-tree-dump " <= 400;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_5;
+    in_range_5 = (float) x == 500.0f;
+    /* { dg-final { scan-tree-dump " == 500;" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_6;
+    in_range_6 = (float) x != 600.0f;
+    /* { dg-final { scan-tree-dump " != 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 0000000..b976eb9
--- /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 " > 100" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_2;
+    x &= 4095;
+    in_range_2 = (float) x < 200.0f;
+    /* { dg-final { scan-tree-dump " <= 199" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_3;
+    x &= 4095;
+    in_range_3 = (float) x > 300.5f;
+    /* { dg-final { scan-tree-dump " > 300" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_4;
+    x &= 4095;
+    in_range_4 = (float) x < 400.5f;
+    /* { dg-final { scan-tree-dump " <= 400" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_5;
+    x &= 4095;
+    in_range_5 = (float) x == 500.0f;
+    /* { dg-final { scan-tree-dump " == 500" "optimized" } } */
+  }
+
+  {
+    volatile int in_range_6;
+    x &= 4095;
+    in_range_6 = (float) x != 600.0f;
+    /* { dg-final { scan-tree-dump " != 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 0000000..d0d7eec
--- /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 0000000..32b8cba
--- /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" } } */