For `(a - b)`, if a and b are signed types are non negative and there
was no overflow, you can infer a relationship if you know the result
of the minus is non-negative (`a >= b`) or is non-positive (`a <= b`).
You can also remove the `==` part if you know the range does not contain
0.
This allows us to optimize stuff like this:
```
int f(int a, int b)
{
a&=0xff;
b&=0xff;
int t = a - b;
if (t < 0)
{
return a < b;
}
return 0;
}
```
without needing to optimize `(a - b) < 0` into `a < b`.
The main thing that needed to be changed to support is passing
the ranges to op1_op2_relation inside register_outgoing_edges.
Bootstrapped and tested on x86_64-linux-gnu.
gcc/ChangeLog:
* gimple-range-fold.cc (fur_source::register_outgoing_edges): Use
the range of the rhs1/rsh2 on that edge rather than varry.
* range-op.cc (operator_minus::op1_op2_relation): Add
case for signed types with non-negative rhs sides.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/vrp-cmp-sub-4.c: New test.
Signed-off-by: Andrea Pinski <[email protected]>
---
gcc/gimple-range-fold.cc | 12 +++++++
gcc/range-op.cc | 21 +++++++++--
gcc/testsuite/gcc.dg/tree-ssa/vrp-cmp-sub-4.c | 36 +++++++++++++++++++
3 files changed, 66 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-cmp-sub-4.c
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a66993a0ab0..2f2a92edb36 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1869,6 +1869,12 @@ fur_source::register_outgoing_edges (gcond *s, irange
&lhs_range,
&& !r.undefined_p ()
&& !r.varying_p ())
{
+ if (!gori ()->edge_range_p (r1, e0, ssa1, *m_query)
+ || r1.undefined_p ())
+ r1.set_varying (TREE_TYPE (ssa1));
+ if (!gori ()->edge_range_p (r2, e0, ssa2, *m_query)
+ || r2.undefined_p ())
+ r2.set_varying (TREE_TYPE (ssa2));
relation_kind relation = handler.op1_op2_relation (r, r1, r2);
if (relation != VREL_VARYING)
register_relation (e0, relation, ssa1, ssa2);
@@ -1877,6 +1883,12 @@ fur_source::register_outgoing_edges (gcond *s, irange
&lhs_range,
&& !r.undefined_p ()
&& !r.varying_p ())
{
+ if (!gori ()->edge_range_p (r1, e1, ssa1, *m_query)
+ || r1.undefined_p ())
+ r1.set_varying (TREE_TYPE (ssa1));
+ if (!gori ()->edge_range_p (r2, e1, ssa2, *m_query)
+ || r2.undefined_p ())
+ r2.set_varying (TREE_TYPE (ssa2));
relation_kind relation = handler.op1_op2_relation (r, r1, r2);
if (relation != VREL_VARYING)
register_relation (e1, relation, ssa1, ssa2);
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index da788182899..289488b9502 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2104,10 +2104,12 @@ minus_op1_op2_relation_effect (irange &lhs_range, tree
type,
// Check if the LHS range indicates a relation between OP1 and OP2.
// OP1 - OP2 == 0 implies OP1 == OP2 even with wrapping arithmetic.
+// For signed types, when both OP1 and OP2 are both positive, infer
+// a relationship if there were it is overflow free.
relation_kind
-operator_minus::op1_op2_relation (const irange &lhs, const irange &,
- const irange &) const
+operator_minus::op1_op2_relation (const irange &lhs, const irange &rhs1,
+ const irange &rhs2) const
{
if (lhs.undefined_p ())
return VREL_UNDEFINED;
@@ -2115,7 +2117,20 @@ operator_minus::op1_op2_relation (const irange &lhs,
const irange &,
if (lhs.zero_p ())
return VREL_EQ;
- if (!lhs.contains_zero_p ())
+ bool contains_z = lhs.contains_zero_p ();
+ // When a and b are both positive (or zero), then infer the
+ // relationship between a and b.
+ if (!TYPE_UNSIGNED (lhs.type ())
+ && rhs1.nonnegative_p () && rhs2.nonnegative_p ()
+ && overflow_free_p (rhs1, rhs2))
+ {
+ if (lhs.nonnegative_p ())
+ return contains_z ? VREL_GE : VREL_GT;
+ if (lhs.nonpositive_p ())
+ return contains_z ? VREL_LE : VREL_LT;
+ }
+
+ if (!contains_z)
return VREL_NE;
return VREL_VARYING;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-cmp-sub-4.c
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-cmp-sub-4.c
new file mode 100644
index 00000000000..775a7f79de3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-cmp-sub-4.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f(int a, int b)
+{
+ a&=0xff;
+ b&=0xff;
+ int t = a - b;
+ if (t < 0)
+ return a < b;
+ return 0;
+}
+
+int g();
+
+int f1(int a, int b)
+{
+ a&=0xff;
+ b&=0xff;
+ int t = a - b;
+ if (t < 0)
+ {
+ if (a < b)
+ return g();
+ }
+ return 0;
+}
+
+
+/* { dg-final { scan-tree-dump-times " < " 2 "optimized" } } */
+/* Only 1 if left for f1 */
+/* { dg-final { scan-tree-dump-times "if " 1 "optimized" } } */
+/* 4 &, 2 `& 255` for each functions. */
+/* { dg-final { scan-tree-dump-times " & " 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " != " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " == " "optimized" } } */
--
2.43.0