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