This patch allows the operator_plus::op1_op2_relation_effect to record
the known least significant bit (which is zero) for both full and partial
equivalences of PLUS_EXPR operands.
The normal update_bitmask hook, which computes a bitmask from operand ranges,
previously replaced the refined bitmask from the relation effect if run
afterward,
losing the known-zero bit. This patch adjusts the order to run normal bitmask
propagation first and apply the relation effect last, ensuring the constraint
from the relation intersects with the complete result.
Existing range-op tests have been expanded to include selftests for VREL_EQ
and partial equivalences. Additionally, an EVRP regression test with DOM
disabled
and a -ftrapv test (to verify the retention of potentially trapping additions)
have been added.
Bootstrapped and regression tested on x86_64-pc-linux-gnu.
PR tree-optimization/126877
gcc/ChangeLog:
* range-op-mixed.h (class operator_plus): Expose and override
op1_op2_relation_effect.
* range-op.cc (range_operator::fold_range): Apply relation effects
after normal bitmask propagation.
(operator_plus::op1_op2_relation_effect): New.
(range_op_plus_relation_tests): New.
(range_op_tests): Call it.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr126877.c: New test.
* gcc.dg/tree-ssa/pr126877-2.c: New test.
Signed-off-by: Jian Li <[email protected]>
---
gcc/range-op-mixed.h | 6 +++
gcc/range-op.cc | 51 ++++++++++++++++++++--
gcc/testsuite/gcc.dg/tree-ssa/pr126877-2.c | 15 +++++++
gcc/testsuite/gcc.dg/tree-ssa/pr126877.c | 18 ++++++++
4 files changed, 86 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126877-2.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126877.c
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 0e97fb11688..bb0034ebf19 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -576,6 +576,7 @@ public:
using range_operator::lhs_op1_relation;
using range_operator::lhs_op2_relation;
using range_operator::update_bitmask;
+ using range_operator::op1_op2_relation_effect;
bool op1_range (irange &r, tree type,
const irange &lhs, const irange &op2,
relation_trio) const final override;
@@ -599,6 +600,11 @@ public:
void update_bitmask (irange &r, const irange &lh,
const irange &rh) const final override;
+ bool op1_op2_relation_effect (irange &lhs_range, tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const final override;
+
bool overflow_free_p (const irange &lh, const irange &rh,
relation_trio = TRIO_VARYING) const final override;
// Check compatibility of all operands.
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 4199300f4c8..906bad196b1 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -735,8 +735,8 @@ range_operator::fold_range (irange &r, tree type,
if (r.varying_p ())
break;
}
- op1_op2_relation_effect (r, type, lh, rh, rel);
update_bitmask (r, lh, rh);
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -747,8 +747,8 @@ range_operator::fold_range (irange &r, tree type,
{
wi_fold_in_parts (r, type, lh.lower_bound (), lh.upper_bound (),
rh.lower_bound (), rh.upper_bound ());
- op1_op2_relation_effect (r, type, lh, rh, rel);
update_bitmask (r, lh, rh);
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -765,13 +765,13 @@ range_operator::fold_range (irange &r, tree type,
r.union_ (tmp);
if (r.varying_p ())
{
- op1_op2_relation_effect (r, type, lh, rh, rel);
update_bitmask (r, lh, rh);
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
}
- op1_op2_relation_effect (r, type, lh, rh, rel);
update_bitmask (r, lh, rh);
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -1716,6 +1716,28 @@ operator_plus::update_bitmask (irange &r, const irange
&lh,
update_known_bitmask (r, PLUS_EXPR, lh, rh);
}
+// If both operands are equivalent, their low bit is the same, so the low
+// bit of their sum is known to be zero.
+
+bool
+operator_plus::op1_op2_relation_effect (irange &lhs_range, tree type,
+ const irange &,
+ const irange &,
+ relation_kind rel) const
+{
+ if (!relation_equiv_p (rel)
+ || TYPE_OVERFLOW_TRAPS (type))
+ return false;
+
+ unsigned prec = TYPE_PRECISION (type);
+ int_range<2> rel_range;
+ rel_range.set_varying (type);
+ rel_range.update_bitmask
+ (irange_bitmask (wi::zero (prec), wi::minus_one (prec) << 1));
+ lhs_range.intersect (rel_range);
+ return true;
+}
+
// Check to see if the range of OP2 indicates anything about the relation
// between LHS and OP1.
@@ -5436,6 +5458,26 @@ range_relational_tests ()
ASSERT_TRUE (code == VREL_LT);
}
+static void
+range_op_plus_relation_tests ()
+{
+ int_range_max result;
+ int_range<1> op1 (integer_type_node);
+ int_range<1> op2 (integer_type_node);
+
+ relation_kind relations[] = {
+ VREL_EQ, VREL_PE8, VREL_PE16, VREL_PE32, VREL_PE64
+ };
+ for (relation_kind rel : relations)
+ {
+ op_plus.fold_range (result, integer_type_node, op1, op2,
+ relation_trio::op1_op2 (rel));
+ irange_bitmask bm = result.get_bitmask ();
+ ASSERT_FALSE (bm.member_p (INT (1)));
+ ASSERT_TRUE (bm.member_p (INT (2)));
+ }
+}
+
void
range_op_tests ()
{
@@ -5444,6 +5486,7 @@ range_op_tests ()
range_op_bitwise_and_tests ();
range_op_cast_tests ();
range_relational_tests ();
+ range_op_plus_relation_tests ();
extern void range_op_float_tests ();
range_op_float_tests ();
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126877-2.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr126877-2.c
new file mode 100644
index 00000000000..62b31bab82a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126877-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftrapv -fdump-tree-evrp" } */
+
+int
+f (int a, int b)
+{
+ if (a == b)
+ {
+ int c = a + b;
+ return c & 1;
+ }
+ return 1;
+}
+
+/* { dg-final { scan-tree-dump-times " \\+ " 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126877.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr126877.c
new file mode 100644
index 00000000000..5ae06d75d6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126877.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdisable-tree-dom1 -fdisable-tree-dom2
-fdisable-tree-dom3 -fdump-tree-evrp" } */
+
+int
+f (int a, int b)
+{
+ if (a == b)
+ {
+ int c = a + b;
+ return c & 1;
+ }
+ return 1;
+}
+
+/* The relation between distinct SSA names must be sufficient to make the
+ addition's low bit known zero. */
+/* { dg-final { scan-tree-dump-not " \\+ " "evrp" } } */
+/* { dg-final { scan-tree-dump-not " & 1" "evrp" } } */
--
2.43.0