[PATCH] [frange] Convert operator_abs::fold_range to sub-ranges.
Aldy Hernandez <[email protected]> Thu, 6 Aug 2026 23:07:36 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
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.
Pushed.
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.
---
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 3e0258c4cc0..c3a287fbf50 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
--
2.47.3