[PATCH] range-op.cc: add VREL_EQ relation effect for div and mod [PR126745]
Daniel Barboza <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
For res = a / b and a == b, set 'res' to one.
For res = a % b and a == b, set 'res' to zero.
Both are done by dom2/dom3 already. With this change we're now
doing it earlier (with -O2) in evrp.
Bootstrapped and regtested in x86_64.
PR tree-optimization/126745
gcc/ChangeLog:
* range-op.cc (operator_div::op1_op2_relation_effect): add
VREL_EQ range equal one for op1/op2 and op1%op2 if op1 == op2.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr126745.c: New test.
---
gcc/range-op.cc | 36 ++++++++++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr126745.c | 16 +++++++++++
2 files changed, 52 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126745.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index bb055623872..0311cef7d47 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2641,6 +2641,7 @@ operator_div::op1_op2_relation_effect (irange &lhs_range,
return false;
int_range<2> rel_range;
+ wide_int one;
switch (rel)
{
@@ -2652,6 +2653,10 @@ operator_div::op1_op2_relation_effect (irange &lhs_range,
&& wi::ge_p (op2_range.lower_bound (), 0, SIGNED)))
rel_range.set_zero (type);
break;
+ case VREL_EQ:
+ one = wi::one (TYPE_PRECISION (type));
+ rel_range.set (type, one, one);
+ break;
default:
return false;
}
@@ -4380,6 +4385,7 @@ class operator_trunc_mod : public range_operator
using range_operator::op1_range;
using range_operator::op2_range;
using range_operator::update_bitmask;
+ using range_operator::op1_op2_relation_effect;
public:
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
@@ -4396,6 +4402,11 @@ public:
relation_trio) const;
void update_bitmask (irange &r, const irange &lh, const irange &rh) const
{ update_known_bitmask (r, TRUNC_MOD_EXPR, lh, rh); }
+ bool op1_op2_relation_effect (irange &lhs_range,
+ tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const final override;
} op_trunc_mod;
void
@@ -4536,6 +4547,31 @@ operator_trunc_mod::op2_range (irange &r, tree type,
return false;
}
+bool
+operator_trunc_mod::op1_op2_relation_effect (irange &lhs_range,
+ tree type,
+ const irange &,
+ const irange &,
+ relation_kind rel) const
+{
+ if (rel == VREL_VARYING)
+ return false;
+
+ int_range<2> rel_range;
+
+ switch (rel)
+ {
+ case VREL_EQ:
+ rel_range.set_zero (type);
+ break;
+ default:
+ return false;
+ }
+
+ lhs_range.intersect (rel_range);
+ return true;
+}
+
class operator_logical_not : public range_operator
{
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126745.c b/gcc/testsuite/gcc.dg/tree-ssa/pr126745.c
new file mode 100644
index 00000000000..77405653ba2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126745.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int f (int a, int b)
+{
+ if (a != b) __builtin_unreachable ();
+ return a / b;
+}
+/* { dg-final { scan-tree-dump-times "return 1;" 1 "evrp" } } */
+
+int f2 (int a, int b)
+{
+ if (a != b) __builtin_unreachable ();
+ return a % b;
+}
+/* { dg-final { scan-tree-dump-times "return 0;" 1 "evrp" } } */
--
2.43.0