[RFC] [frange] Convert range_operator::fold_range to sub-ranges.
Aldy Hernandez <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
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.
I'm not sure about this, and made a lot of comments to wrap my head
around this, that I'll strip before the final commit.
I'm trying to follow irange's convention, without doing all the fancy
things we do there (fold in parts, etc), but keeping relations sane.
I've tested this, but I'd appreciate another set of eyes before
cleaning this up and contributing.
How does this look everyone?
Tested on ppc64le Linux, LAPACK 103/103. Shrinks 6 of 3631 BLAS/LAPACK
asm TUs, none larger: drotmg and srotmg by 2 insns each, cunbdb by 8,
zunbdb by 14.
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.
---
gcc/range-op-float.cc | 75 ++++++++++++++++++-
.../gcc.dg/tree-ssa/vrp-float-subrange-1.c | 17 +++++
2 files changed, 89 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-subrange-1.c
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 3a19f58cdc8..88e9a02b9f9 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;
@@ -3302,6 +3342,35 @@ range_op_float_tests ()
int_range<2> ir, ir_op2;
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 00000000000..d7740e2868a
--- /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" } }
--
2.47.3