[gcc r17-3239] [frange] Convert range_operator::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:7f4f4b9fe867c07b597412629c7b33636db4a066 commit r17-3239-g7f4f4b9fe867c07b597412629c7b33636db4a066 Author: Aldy Hernandez <[email protected]> Date: Tue Aug 4 10:03:39 2026 +0000 [frange] Convert range_operator::fold_range to sub-ranges. Fold each pair of operand sub-ranges through rv_fold and union the results, which keeps the gaps between sub-ranges instead of folding the [lower, upper] hull. When the operands are known equal (x op x) fold the diagonal instead, folding each sub-range against itself. This follows irange's fold_range. Tested on ppc64le Linux: regstrap, LAPACK. Shrinks 6 of 3631 LAPACK asm TUs, none larger. gcc/ChangeLog: * range-op-float.cc (range_operator::fold_range): Fold each pair of sub-ranges, or the diagonal when the operands are equal. (range_op_float_tests): New test. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/vrp-float-subrange-1.c: New test. Diff: --- gcc/range-op-float.cc | 75 +++++++++++++++++++++- .../gcc.dg/tree-ssa/vrp-float-subrange-1.c | 17 +++++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 60c522ee2a0e..49dd705db323 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -62,9 +62,49 @@ range_operator::fold_range (frange &r, tree type, return true; } - rv_fold (r, type, - op1.lower_bound (), op1.upper_bound (), - op2.lower_bound (), op2.upper_bound (), trio.op1_op2 ()); + relation_kind rel = trio.op1_op2 (); + r.set_undefined (); + frange tmp; + if (relation_equiv_p (rel) && op1 == op2) + { + // The operands are known equal (x op x). Fold each sub-range against + // itself, the diagonal of the cross product, so a relation-aware rv_fold + // like operator_mult's is_square stays valid. + // + // For x * x with x in [-3, -2] U [2, 3] the diagonal is + // + // [-3, -2] * [-3, -2] = [4, 9] + // [ 2, 3] * [ 2, 3] = [4, 9] + // + // giving the exact [4, 9]. The full cross product would form: + // + // [-3, -2] * [-3, -2] = [4, 9] + // [-3, -2] * [ 2, 3] = [-9, -4] + // [ 2, 3] * [-3, -2] = [-9, -4] + // [ 2, 3] * [ 2, 3] = [4, 9] + // + // whose union [-9, -4] U [4, 9] contains negative products that x * x + // can never produce: the off-diagonal terms pair a value from one + // sub-range with a value from the other, which x (a single value) can + // never do. + for (unsigned i = 0; i < op1.num_pairs (); ++i) + { + rv_fold (tmp, type, + op1.lower_bound (i), op1.upper_bound (i), + op1.lower_bound (i), op1.upper_bound (i), rel); + r.union_ (tmp); + } + } + else + // Otherwise do the straight cross product. + for (unsigned i = 0; i < op1.num_pairs (); ++i) + for (unsigned j = 0; j < op2.num_pairs (); ++j) + { + rv_fold (tmp, type, + op1.lower_bound (i), op1.upper_bound (i), + op2.lower_bound (j), op2.upper_bound (j), rel); + r.union_ (tmp); + } if (r.known_isnan ()) return true; @@ -3296,6 +3336,35 @@ range_op_float_tests () range_op_handler (FIX_TRUNC_EXPR).fold_range (ir, integer_type_node, r0, ir_op2); ASSERT_EQ (ir.num_pairs (), 2); + + // ([1, 2] U [10, 11]) + 0 stays two pieces. + r0 = frange_float ("1.0", "2.0"); + r1 = frange_float ("10.0", "11.0"); + r0.union_ (r1); + r0.clear_nan (); + r1 = frange_float ("0.0", "0.0"); + r1.clear_nan (); + range_op_handler (PLUS_EXPR).fold_range (r, float_type_node, r0, r1); + ASSERT_EQ (r.num_pairs (), 2); + + // x * x (VREL_EQ) with a two-piece x: the diagonal fold gives the exact + // [4, 9], not the full cross product's [-9, -4] U [4, 9], nor the hull's + // looser [0, 9]. + r0 = frange_float ("-3.0", "-2.0"); + r1 = frange_float ("2.0", "3.0"); + r0.union_ (r1); + r0.clear_nan (); + range_op_handler (MULT_EXPR).fold_range (r, float_type_node, r0, r0, + relation_trio (VREL_VARYING, + VREL_VARYING, + VREL_EQ)); + REAL_VALUE_TYPE val; + real_from_string (&val, "5.0"); + ASSERT_TRUE (r.contains_p (val)); // the result is [4, 9] + real_from_string (&val, "-5.0"); + ASSERT_FALSE (r.contains_p (val)); // not the cross product's negatives + real_from_string (&val, "3.0"); + ASSERT_FALSE (r.contains_p (val)); // tighter than the hull [0, 9] } } // namespace selftest diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-subrange-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-subrange-1.c new file mode 100644 index 000000000000..d7740e2868a3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-subrange-1.c @@ -0,0 +1,17 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-optimized" } + +extern void link_error (); + +void +test (double x) +{ + if (x != 3.0) + { + double z = x + 0.0; + if (z == 3.0) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "optimized" } }