Re: [PATCH 1/2] [frange] Enable sub-ranges.
Aldy Hernandez <[email protected]> Mon, 3 Aug 2026 23:21:06 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On Mon, Aug 03, 2026 at 11:59:13AM +0200, Jakub Jelinek wrote: > I'm surprised float_widen_lhs_range hasn't been changed for this. > When we support 2 pairs, I think we need to widen each pair individually > and then combine them in case the widening would now cause overlap etc. Probably cause it didn't show up in any missing optimizations for the DOM audit I did :-P. But TBH, I didn't convert any range-ops operators to multi-range. However, float_widen_lhs_range seems simple enough. If we refactor the bounds logic out, the change seems very simple. See attached two patches. I'm flying blind here (i.e. I have no clue), so I'm *NOT* committing this. I've tested on ppc64le, but will only push if you review and approve it :). Aldy
0001-frange-Factor-float_widen_bound-out-of-float_widen_l.patch
(text/x-diff, 4.5 KB)
From 60242c0ce01041c6a5bae3a676ff4d098052a32d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez <[email protected]> Date: Mon, 3 Aug 2026 11:01:40 +0000 Subject: [PATCH] [frange] Factor float_widen_bound out of float_widen_lhs_range. Factor out the per-bound logic into a helper function. No functional change. Tested on ppc64le Linux. Regstrap plus no changes to assembly over LAPACK source files. gcc/ChangeLog: * range-op-float.cc (float_widen_bound): New, factored out of... (float_widen_lhs_range): ...here. --- gcc/range-op-float.cc | 83 +++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index a625202f531..689f9e09526 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -2364,6 +2364,40 @@ zero_to_inf_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) } } +/* Widen a single bound of a sub-range by 1ulp (or 0.5ulp) in the direction of + DIR. */ + +static REAL_VALUE_TYPE +float_widen_bound (tree type, const REAL_VALUE_TYPE &bound, + const REAL_VALUE_TYPE &dir) +{ + REAL_VALUE_TYPE res = bound; + if (!real_isfinite (&bound) && real_isneg (&bound) == real_isneg (&dir)) + return res; + frange_nextafter (TYPE_MODE (type), res, dir); + if (real_isinf (&res)) + { + /* For +-DBL_MAX, instead of +-Inf use nexttoward (+-DBL_MAX, +-LDBL_MAX) + in a hypothetical wider type with the same mantissa precision but + larger exponent range; it is outside of range of double values, but + makes it clear it is just one ulp larger rather than infinite amount + larger. */ + res = real_isneg (&dir) ? dconstm1 : dconst1; + SET_REAL_EXP (&res, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); + } + if (!flag_rounding_math + && !MODE_COMPOSITE_P (TYPE_MODE (type)) + && real_isfinite (&bound)) + { + /* If not -frounding-math nor IBM double double, actually widen + just by 0.5ulp rather than 1ulp. */ + REAL_VALUE_TYPE tem; + real_arithmetic (&tem, PLUS_EXPR, &bound, &res); + real_arithmetic (&res, RDIV_EXPR, &tem, &dconst2); + } + return res; +} + /* Extend the LHS range by 1ulp in each direction. For op1_range or op2_range of binary operations just computing the inverse operation on ranges isn't sufficient. Consider e.g. @@ -2379,53 +2413,8 @@ float_widen_lhs_range (tree type, const frange &lhs) frange ret = lhs; if (lhs.known_isnan ()) return ret; - REAL_VALUE_TYPE lb = lhs.lower_bound (); - REAL_VALUE_TYPE ub = lhs.upper_bound (); - if (real_isfinite (&lb) || !real_isneg (&lb)) - { - frange_nextafter (TYPE_MODE (type), lb, dconstninf); - if (real_isinf (&lb)) - { - /* For -DBL_MAX, instead of -Inf use - nexttoward (-DBL_MAX, -LDBL_MAX) in a hypothetical - wider type with the same mantissa precision but larger - exponent range; it is outside of range of double values, - but makes it clear it is just one ulp larger rather than - infinite amount larger. */ - lb = dconstm1; - SET_REAL_EXP (&lb, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); - } - if (!flag_rounding_math - && !MODE_COMPOSITE_P (TYPE_MODE (type)) - && real_isfinite (&lhs.lower_bound ())) - { - /* If not -frounding-math nor IBM double double, actually widen - just by 0.5ulp rather than 1ulp. */ - REAL_VALUE_TYPE tem; - real_arithmetic (&tem, PLUS_EXPR, &lhs.lower_bound (), &lb); - real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2); - } - } - if (real_isfinite (&ub) || real_isneg (&ub)) - { - frange_nextafter (TYPE_MODE (type), ub, dconstinf); - if (real_isinf (&ub)) - { - /* For DBL_MAX similarly. */ - ub = dconst1; - SET_REAL_EXP (&ub, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); - } - if (!flag_rounding_math - && !MODE_COMPOSITE_P (TYPE_MODE (type)) - && real_isfinite (&lhs.upper_bound ())) - { - /* If not -frounding-math nor IBM double double, actually widen - just by 0.5ulp rather than 1ulp. */ - REAL_VALUE_TYPE tem; - real_arithmetic (&tem, PLUS_EXPR, &lhs.upper_bound (), &ub); - real_arithmetic (&ub, RDIV_EXPR, &tem, &dconst2); - } - } + REAL_VALUE_TYPE lb = float_widen_bound (type, lhs.lower_bound (), dconstninf); + REAL_VALUE_TYPE ub = float_widen_bound (type, lhs.upper_bound (), dconstinf); /* Temporarily disable -ffinite-math-only, so that frange::set doesn't reduce the range back to real_min_representable (type) as lower bound or real_max_representable (type) as upper bound. */ -- 2.47.3
0002-frange-Convert-float_widen_lhs_range-to-sub-ranges.patch
(text/x-diff, 2.3 KB)
From 38fbe155b17012564726f594fe41bdc90ce470bf Mon Sep 17 00:00:00 2001 From: Aldy Hernandez <[email protected]> Date: Mon, 3 Aug 2026 11:02:38 +0000 Subject: [PATCH] [frange] Convert float_widen_lhs_range to sub-ranges. Tested on ppc64le Linux. gcc/ChangeLog: * range-op-float.cc (float_widen_lhs_range): Convert to sub-ranges. (range_op_float_tests): New test. --- gcc/range-op-float.cc | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 689f9e09526..07b00e03318 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -2413,14 +2413,22 @@ float_widen_lhs_range (tree type, const frange &lhs) frange ret = lhs; if (lhs.known_isnan ()) return ret; - REAL_VALUE_TYPE lb = float_widen_bound (type, lhs.lower_bound (), dconstninf); - REAL_VALUE_TYPE ub = float_widen_bound (type, lhs.upper_bound (), dconstinf); /* Temporarily disable -ffinite-math-only, so that frange::set doesn't reduce the range back to real_min_representable (type) as lower bound or real_max_representable (type) as upper bound. */ bool save_flag_finite_math_only = flag_finite_math_only; flag_finite_math_only = false; - ret.set (type, lb, ub, lhs.get_nan_state ()); + ret.set_undefined (); + for (unsigned i = 0; i < lhs.num_pairs (); ++i) + { + REAL_VALUE_TYPE lb = float_widen_bound (type, lhs.lower_bound (i), + dconstninf); + REAL_VALUE_TYPE ub = float_widen_bound (type, lhs.upper_bound (i), + dconstinf); + frange tmp; + tmp.set (type, lb, ub, lhs.get_nan_state ()); + ret.union_ (tmp); + } flag_finite_math_only = save_flag_finite_math_only; return ret; } @@ -3257,6 +3265,19 @@ range_op_float_tests () plus.fold_range (r, float_type_node, r0, r1); if (HONOR_NANS (float_type_node)) ASSERT_TRUE (r.maybe_isnan ()); + + // float_widen_lhs_range widens each sub-range and keeps the gap between + // them. + r0 = frange_float ("1.0", "2.0"); + r1 = frange_float ("10.0", "11.0"); + r0.union_ (r1); + r0.clear_nan (); + ASSERT_EQ (r0.num_pairs (), 2); + r = float_widen_lhs_range (float_type_node, r0); + ASSERT_EQ (r.num_pairs (), 2); + REAL_VALUE_TYPE five; + real_from_string (&five, "5.0"); + ASSERT_FALSE (r.contains_p (five)); } } // namespace selftest -- 2.47.3