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