https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #9 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Apparently we are missing range implementation of casts between different
floating point types as well.

Trying now:
--- gcc/range-op-mixed.h.jj     2025-05-20 08:14:06.520404648 +0200
+++ gcc/range-op-mixed.h        2025-06-02 14:30:37.304673412 +0200
@@ -473,14 +473,15 @@ public:
   bool fold_range (prange &r, tree type,
                   const irange &op1, const prange &op2,
                   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (frange &r, tree type,
+                  const frange &op1, const frange &op2,
+                  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
-                  const frange &lh,
-                  const irange &rh,
-                  relation_trio = TRIO_VARYING) const;
+                  const frange &op1, const irange &op2,
+                  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type,
-                  const irange &lh,
-                  const frange &rh,
-                  relation_trio = TRIO_VARYING) const;
+                  const irange &op1, const frange &op2,
+                  relation_trio = TRIO_VARYING) const final override;

   bool op1_range (irange &r, tree type,
                  const irange &lhs, const irange &op2,
@@ -495,13 +496,14 @@ public:
                  const irange &lhs, const prange &op2,
                  relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
-                 const irange &lhs,
-                 const irange &op2,
-                 relation_trio = TRIO_VARYING) const;
+                 const frange &lhs, const frange &op2,
+                 relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (frange &r, tree type,
+                 const irange &lhs, const irange &op2,
+                 relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
-                 const frange &lhs,
-                 const frange &op2,
-                 relation_trio = TRIO_VARYING) const;
+                 const frange &lhs, const frange &op2,
+                 relation_trio = TRIO_VARYING) const final override;

   relation_kind lhs_op1_relation (const irange &lhs,
                                  const irange &op1, const irange &op2,
--- gcc/range-op-float.cc.jj    2025-05-20 08:14:06.519404661 +0200
+++ gcc/range-op-float.cc       2025-06-02 15:23:14.171003089 +0200
@@ -2899,6 +2899,107 @@ private:
   }
 } fop_div;

+bool
+operator_cast::fold_range (frange &r, tree type, const frange &op1,
+                          const frange &, relation_trio) const
+{
+  REAL_VALUE_TYPE lb, ub;
+  enum machine_mode mode = TYPE_MODE (type);
+  bool mode_composite = MODE_COMPOSITE_P (mode);
+
+  if (empty_range_varying (r, type, op1, op1))
+    return true;
+  if (!MODE_HAS_NANS (mode) && op1.maybe_isnan ())
+    {
+      r.set_varying (type);
+      return true;
+    }
+  if (op1.known_isnan ())
+    {
+      r.set_nan (type);
+      return true;
+    }
+
+  const REAL_VALUE_TYPE &lh_lb = op1.lower_bound ();
+  const REAL_VALUE_TYPE &lh_ub = op1.upper_bound ();
+  real_convert (&lb, mode, &lh_lb);
+  real_convert (&ub, mode, &lh_ub);
+
+  if (flag_rounding_math)
+    {
+      if (real_less (&lh_lb, &lb))
+       {
+         if (mode_composite
+             && (real_isdenormal (&lb, mode) || real_iszero (&lb)))
+           {
+             // IBM extended denormals only have DFmode precision.
+             REAL_VALUE_TYPE tmp, tmp2;
+             real_convert (&tmp2, DFmode, &lh_lb);
+             real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2,
+                             &dconstninf);
+             real_convert (&lb, mode, &tmp);
+           }
+         else
+           frange_nextafter (mode, lb, dconstninf);
+       }
+      if (real_less (&ub, &lh_ub))
+       {
+         if (mode_composite
+             && (real_isdenormal (&ub, mode) || real_iszero (&ub)))
+           {
+             // IBM extended denormals only have DFmode precision.
+             REAL_VALUE_TYPE tmp, tmp2;
+             real_convert (&tmp2, DFmode, &lh_ub);
+             real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2,
+                             &dconstinf);
+             real_convert (&ub, mode, &tmp);
+           }
+         else
+           frange_nextafter (mode, ub, dconstinf);
+       }
+    }
+
+  r.set (type, lb, ub, op1.get_nan_state ());
+
+  if (flag_trapping_math
+      && MODE_HAS_INFINITIES (TYPE_MODE (type))
+      && r.known_isinf ()
+      && !op1.known_isinf ())
+    {
+      REAL_VALUE_TYPE inf = r.lower_bound ();
+      if (real_isneg (&inf))
+       {
+         REAL_VALUE_TYPE min = real_min_representable (type);
+         r.set (type, inf, min);
+       }
+      else
+       {
+         REAL_VALUE_TYPE max = real_max_representable (type);
+         r.set (type, max, inf);
+       }
+    }
+
+  r.flush_denormals_to_zero ();
+  return true;
+}
+
+// Implement fold for a cast from float to another float.
+bool
+operator_cast::op1_range (frange &r, tree type, const frange &lhs,
+                         const frange &op2, relation_trio) const
+{
+  if (lhs.undefined_p ())
+    return false;
+  tree lhs_type = lhs.type ();
+  frange wlhs = float_widen_lhs_range (lhs_type, lhs);
+  auto save_flag_rounding_math = flag_rounding_math;
+  flag_rounding_math = 1;
+  bool ret = float_binary_op_range_finish (fold_range (r, type, wlhs, op2),
+                                          r, type, wlhs);
+  flag_rounding_math = save_flag_rounding_math;
+  return ret;
+}
+
 // Implement fold for a cast from float to an int.
 bool
 operator_cast::fold_range (irange &, tree, const frange &,

Reply via email to