[gcc r17-3043] [frange] Convert operator_abs::fold_range to sub-ranges.

Aldy Hernandez via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:15211513ea09d13c1c13bdf1e057c6f52836ab48

commit r17-3043-g15211513ea09d13c1c13bdf1e057c6f52836ab48
Author: Aldy Hernandez <[email protected]>
Date:   Tue Aug 4 13:21:03 2026 +0000

    [frange] Convert operator_abs::fold_range to sub-ranges.
    
    Take the absolute value of each sub-range and union the results, so a
    range that mixes signs keeps its gaps instead of collapsing through
    zero to the [lower, upper] hull.  The all-positive fast path already
    preserved the sub-ranges.
    
    Tested on ppc64le: regstrap, LAPACK.
    
    gcc/ChangeLog:
    
            * range-op-float.cc (operator_abs::fold_range): Take the absolute
            value of each sub-range and union the results.
            (range_op_float_tests): New test.

Diff:
---
 gcc/range-op-float.cc | 51 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 3e0258c4cc01..c3a287fbf501 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -1536,7 +1536,6 @@ operator_abs::fold_range (frange &r, tree type,
     }
 
   const REAL_VALUE_TYPE lh_lb = op1.lower_bound ();
-  const REAL_VALUE_TYPE lh_ub = op1.upper_bound ();
   // Handle the easy case where everything is positive.
   if (real_compare (GE_EXPR, &lh_lb, &dconst0)
       && !real_iszero (&lh_lb, /*sign=*/true)
@@ -1546,25 +1545,32 @@ operator_abs::fold_range (frange &r, tree type,
       return true;
     }
 
-  REAL_VALUE_TYPE min = real_value_abs (&lh_lb);
-  REAL_VALUE_TYPE max = real_value_abs (&lh_ub);
-  // If the range contains zero then we know that the minimum value in the
-  // range will be zero.
-  if (real_compare (LE_EXPR, &lh_lb, &dconst0)
-      && real_compare (GE_EXPR, &lh_ub, &dconst0))
-    {
-      if (real_compare (GT_EXPR, &min, &max))
-	max = min;
-      min = dconst0;
-    }
-  else
+  // Take the absolute value of each sub-range and union the results.
+  r.set_undefined ();
+  for (unsigned i = 0; i < op1.num_pairs (); ++i)
     {
-      // If the range was reversed, swap MIN and MAX.
-      if (real_compare (GT_EXPR, &min, &max))
-	std::swap (min, max);
+      const REAL_VALUE_TYPE lb = op1.lower_bound (i);
+      const REAL_VALUE_TYPE ub = op1.upper_bound (i);
+      REAL_VALUE_TYPE min = real_value_abs (&lb);
+      REAL_VALUE_TYPE max = real_value_abs (&ub);
+      // If the range contains zero then we know that the minimum value in the
+      // range will be zero.
+      if (real_compare (LE_EXPR, &lb, &dconst0)
+	  && real_compare (GE_EXPR, &ub, &dconst0))
+	{
+	  if (real_compare (GT_EXPR, &min, &max))
+	    max = min;
+	  min = dconst0;
+	}
+      else
+	{
+	  // If the range was reversed, swap MIN and MAX.
+	  if (real_compare (GT_EXPR, &min, &max))
+	    std::swap (min, max);
+	}
+      frange tmp (type, min, max);
+      r.union_ (tmp);
     }
-
-  r.set (type, min, max);
   if (op1.maybe_isnan ())
     r.update_nan (/*sign=*/false);
   else
@@ -3293,6 +3299,15 @@ range_op_float_tests ()
   r0.clear_nan ();
   range_op_handler (NEGATE_EXPR).fold_range (r, float_type_node, r0, trange);
   ASSERT_EQ (r.num_pairs (), 2);
+
+  // abs([-6, -5] U [1, 2]) => [1, 2] U [5, 6], keeping the gap rather than
+  // collapsing to [0, 6].
+  r0 = frange_float ("-6.0", "-5.0");
+  r1 = frange_float ("1.0", "2.0");
+  r0.union_ (r1);
+  r0.clear_nan ();
+  range_op_handler (ABS_EXPR).fold_range (r, float_type_node, r0, trange);
+  ASSERT_EQ (r.num_pairs (), 2);
 }
 
 } // namespace selftest
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.