[PATCH] [frange] Convert the int to float cast to sub-ranges.

Aldy Hernandez <[email protected]> Fri, 7 Aug 2026 09:00:19 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
operator_cast::fold_range for an integer operand converted only the
[lower, upper] hull of the integer range.  Convert  sub-ranges.

Tested on ppc64le Linux: regstrap and LAPACK.

Pushed.

gcc/ChangeLog:

	* range-op-float.cc (operator_cast::fold_range): Convert each
	integer sub-range and union the results.
	(range_op_float_tests): New test.
---
 gcc/range-op-float.cc | 48 ++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index c3a287fbf50..b03f1e97449 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -3128,25 +3128,31 @@ operator_cast::fold_range (frange &r, tree type, const irange &op1,
 {
   if (empty_range_varying (r, type, op1, op1))
     return true;
-  REAL_VALUE_TYPE lb, ub;
-  wide_int op1_lb = op1.lower_bound ();
-  wide_int op1_ub = op1.upper_bound ();
   tree op1_type = op1.type ();
-  enum machine_mode mode = flag_rounding_math ? VOIDmode : TYPE_MODE (type);
-  real_from_integer (&lb, mode, op1_lb, TYPE_SIGN (op1_type));
-  real_from_integer (&ub, mode, op1_ub, TYPE_SIGN (op1_type));
-  if (flag_rounding_math)
+  r.set_undefined ();
+  for (unsigned i = 0; i < op1.num_pairs (); ++i)
     {
-      REAL_VALUE_TYPE lbo = lb, ubo = ub;
-      mode = TYPE_MODE (type);
-      real_convert (&lb, mode, &lb);
-      real_convert (&ub, mode, &ub);
-      if (real_less (&lbo, &lb))
-	frange_nextafter (mode, lb, dconstninf);
-      if (real_less (&ub, &ubo))
-	frange_nextafter (mode, ub, dconstinf);
+      REAL_VALUE_TYPE lb, ub;
+      wide_int op1_lb = op1.lower_bound (i);
+      wide_int op1_ub = op1.upper_bound (i);
+      enum machine_mode mode = flag_rounding_math ? VOIDmode : TYPE_MODE (type);
+      real_from_integer (&lb, mode, op1_lb, TYPE_SIGN (op1_type));
+      real_from_integer (&ub, mode, op1_ub, TYPE_SIGN (op1_type));
+      if (flag_rounding_math)
+	{
+	  REAL_VALUE_TYPE lbo = lb, ubo = ub;
+	  mode = TYPE_MODE (type);
+	  real_convert (&lb, mode, &lb);
+	  real_convert (&ub, mode, &ub);
+	  if (real_less (&lbo, &lb))
+	    frange_nextafter (mode, lb, dconstninf);
+	  if (real_less (&ub, &ubo))
+	    frange_nextafter (mode, ub, dconstinf);
+	}
+      frange tmp;
+      tmp.set (type, lb, ub, nan_state (false));
+      r.union_ (tmp);
     }
-  r.set (type, lb, ub, nan_state (false));
   if (r.undefined_p ())
     r.set_varying (type);
   return true;
@@ -3308,6 +3314,16 @@ range_op_float_tests ()
   r0.clear_nan ();
   range_op_handler (ABS_EXPR).fold_range (r, float_type_node, r0, trange);
   ASSERT_EQ (r.num_pairs (), 2);
+
+  // (float)([1, 4] U [6, 10]) keeps the gap.
+  unsigned iprec = TYPE_PRECISION (integer_type_node);
+  int_range<2> i0 (integer_type_node,
+		   wi::shwi (1, iprec), wi::shwi (4, iprec));
+  int_range<2> i1 (integer_type_node,
+		   wi::shwi (6, iprec), wi::shwi (10, iprec));
+  i0.union_ (i1);
+  range_op_handler (FLOAT_EXPR).fold_range (r, float_type_node, i0, trange);
+  ASSERT_EQ (r.num_pairs (), 2);
 }
 
 } // namespace selftest
-- 
2.47.3