When integer operands are converted to a floating-point type before a
comparison, the existing fold only checks whether the whole integer type
is exactly representable.  Use SSA range information as a fallback so
range-limited values, such as those masked to [0, 255], can be compared
directly as integers.  Apply the same range-aware exactness check to
integer-to-float comparisons against real constants.

        PR tree-optimization/125385

gcc/ChangeLog:

        * match.pd ((FTYPE) N CMP (FTYPE) M): Use range information
        to decide whether integer operands are exactly representable.
        ((FTYPE) N CMP CST): Likewise.
        * real.cc: Include backend.h and vr-values.h.
        (format_helper::can_represent_range_value_p): New function.
        * real.h (format_helper::can_represent_range_value_p): Declare.
        * tree-core.h (class irange): Forward declare.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/pr125385.c: New test.

Signed-off-by: Eikansh Gupta <[email protected]>
---
 gcc/match.pd                             | 41 ++++++++++--
 gcc/real.cc                              | 24 +++++++
 gcc/real.h                               |  1 +
 gcc/testsuite/gcc.dg/tree-ssa/pr125385.c | 82 ++++++++++++++++++++++++
 gcc/tree-core.h                          |  1 +
 5 files changed, 142 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr125385.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 8c410c2f3b3..5e1659896ae 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7610,7 +7610,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for cmp  (lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
      icmp (lt le eq ne ge gt unordered ordered lt   le   gt   ge   eq   ne)
  (simplify
-  (cmp (float@0 @1) (float @2))
+  (cmp (float@0 @1) (float@3 @2))
    (if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@0))
        && ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0)))
     (with
@@ -7618,11 +7618,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0))));
        tree type1 = TREE_TYPE (@1);
        bool type1_signed_p = TYPE_SIGN (type1) == SIGNED;
+       bool type1_ok = fmt.can_represent_integral_type_p (type1);
        tree type2 = TREE_TYPE (@2);
        bool type2_signed_p = TYPE_SIGN (type2) == SIGNED;
+       bool type2_ok = fmt.can_represent_integral_type_p (type2);
+#if GIMPLE
+       int_range_max vr1, vr2;
+       if (!type1_ok
+          && gimple_match_range_of_expr (vr1, @1, @0))
+        type1_ok = fmt.can_represent_range_value_p (&vr1);
+       if (!type2_ok
+          && gimple_match_range_of_expr (vr2, @2, @3))
+        type2_ok = fmt.can_represent_range_value_p (&vr2);
+#endif
      }
-     (if (fmt.can_represent_integral_type_p (type1)
-         && fmt.can_represent_integral_type_p (type2))
+     (if (type1_ok && type2_ok)
       (if (cmp == ORDERED_EXPR || cmp == UNORDERED_EXPR)
        { constant_boolean_node (cmp == ORDERED_EXPR, type); }
        (if (TYPE_PRECISION (type1) > TYPE_PRECISION (type2)
@@ -7639,13 +7649,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for cmp  (lt le eq ne ge gt)
      icmp (le le eq ne ge ge)
  (simplify
-  (cmp (float @0) REAL_CST@1)
+  (cmp (float@2 @0) REAL_CST@1)
    (if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@1))
        && ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@1)))
     (with
      {
        tree itype = TREE_TYPE (@0);
        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;
        const REAL_VALUE_TYPE *cst = TREE_REAL_CST_PTR (@1);
        /* Be careful to preserve any potential exceptions due to NaNs.
          qNaNs are ok in == or != context.  */
@@ -7654,16 +7666,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                          && ((cmp != EQ_EXPR && cmp != NE_EXPR)
                              || (cst->signalling
                                  && HONOR_SNANS (TREE_TYPE (@1))));
+#if GIMPLE
+       int_range_max vr;
+       if (!value_ok
+          && gimple_match_range_of_expr (vr, @0, @2))
+        value_ok = fmt.can_represent_range_value_p (&vr);
+#endif
      }
      /* TODO: allow non-fitting itype and SNaNs when
        -fno-trapping-math.  */
-     (if (fmt.can_represent_integral_type_p (itype) && ! exception_p)
+     (if (value_ok && ! exception_p)
       (with
        {
         signop isign = TYPE_SIGN (itype);
+        wide_int imin_val = wi::min_value (itype);
+        wide_int imax_val = wi::max_value (itype);
+#if GIMPLE
+        if (!itype_ok)
+          {
+            imin_val = vr.lower_bound ();
+            imax_val = vr.upper_bound ();
+          }
+#endif
         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, imin_val, isign);
+        real_from_integer (&imax, fmt, imax_val, isign);
 
         REAL_VALUE_TYPE icst;
         if (cmp == GT_EXPR || cmp == GE_EXPR)
diff --git a/gcc/real.cc b/gcc/real.cc
index 4c017cb878d..29cb6a1edd2 100644
--- a/gcc/real.cc
+++ b/gcc/real.cc
@@ -22,9 +22,13 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "bitmap.h"
+#include "function.h"
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "value-range.h"
+#include "vr-values.h"
 #include "realmpfr.h"
 #include "dfp.h"
 
@@ -5512,6 +5516,26 @@ bool format_helper::can_represent_integral_type_p (tree 
type) const
   return TYPE_PRECISION (type) - signed_p <= significand_size (*this);
 }
 
+/* True if all values in integer range *VR can be represented by this
+   floating-point type exactly.  */
+
+bool
+format_helper::can_represent_range_value_p (const irange *vr) const
+{
+  gcc_assert (!decimal_p ());
+
+  if (vr->undefined_p () || vr->varying_p ())
+    return false;
+
+  tree type = vr->type ();
+  unsigned precision = significand_size (*this);
+
+  if (TYPE_SIGN (type) == SIGNED)
+    precision++;
+
+  return range_fits_type_p (vr, precision, TYPE_SIGN (type));
+}
+
 /* True if mode M has a NaN representation and
    the treatment of NaN operands is important.  */
 
diff --git a/gcc/real.h b/gcc/real.h
index dc39c32d85f..e9ddcf5e171 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -223,6 +223,7 @@ public:
 
   bool decimal_p () const { return m_format && m_format->b == 10; }
   bool can_represent_integral_type_p (tree type) const;
+  bool can_represent_range_value_p (const class irange *) const;
 
 private:
   const real_format *m_format;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr125385.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr125385.c
new file mode 100644
index 00000000000..630fa58d23e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr125385.c
@@ -0,0 +1,82 @@
+/* PR tree-optimization/125385 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+f_lt (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a < (float) b;
+}
+
+int
+f_le (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a <= (float) b;
+}
+
+int
+f_eq (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a == (float) b;
+}
+
+int
+f_ne (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a != (float) b;
+}
+
+int
+f_ge (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a >= (float) b;
+}
+
+int
+f_gt (int a, int b)
+{
+  a &= 0xff;
+  b &= 0xff;
+  return (float) a > (float) b;
+}
+
+int
+f_signed_range (int a, int b)
+{
+  a = (a & 0xff) - 128;
+  b = (b & 0xff) - 128;
+  return (float) a < (float) b;
+}
+
+int
+f_cst (int a)
+{
+  a &= 0xff;
+  return (float) a < 42.0f;
+}
+
+int
+f_cst_fractional (int a)
+{
+  a &= 0xff;
+  return (float) a < 42.5f;
+}
+
+int
+f_cst_outside_type (int a)
+{
+  a &= 0xff;
+  return (float) a < 2147483648.0f;
+}
+
+/* { dg-final { scan-tree-dump-not "\\(float\\)" "optimized" } } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 09c07c5c129..c9232c16fec 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -34,6 +34,7 @@ struct real_value;
 struct fixed_value;
 struct ptr_info_def;
 struct die_struct;
+class irange;
 
 
 /*---------------------------------------------------------------------------
-- 
2.34.1

Reply via email to