On Thu, Jun 25, 2026 at 10:41 PM Eikansh Gupta
<[email protected]> wrote:
>
> 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.

Ok. Pushed as https://gcc.gnu.org/pipermail/gcc-cvs/2026-June/456401.html .

Thanks,
Andrea


>
> 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