aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2020-11-17 14:47:58 -0500
committerAndrew MacLeod <amacleod@redhat.com>2020-11-17 16:59:48 -0500
commit1e27e7a582a9b86bcf86f5c103cd947672746e97 (patch)
tree62dba27e63b49b12d89a0b669c93fb51be9b511a /gcc
parent0c1db9fa47b97ac4f080994e7c4b382b7353e6dd (diff)
downloadgcc-1e27e7a582a9b86bcf86f5c103cd947672746e97.zip
gcc-1e27e7a582a9b86bcf86f5c103cd947672746e97.tar.gz
gcc-1e27e7a582a9b86bcf86f5c103cd947672746e97.tar.bz2
recognize implied ranges for modulo.
implement op1_range for modulo with implied positive and negative ranges. gcc/ PR tree-optimization/91029 * range-op.cc (operator_trunc_mod::op1_range): New. gcc/testsuite/ * gcc.dg/pr91029.c: New.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/range-op.cc28
-rw-r--r--gcc/testsuite/gcc.dg/pr91029.c47
2 files changed, 75 insertions, 0 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index d0adc95..f37796c 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2634,6 +2634,9 @@ public:
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
+ virtual bool op1_range (irange &r, tree type,
+ const irange &lhs,
+ const irange &op2) const;
} op_trunc_mod;
void
@@ -2680,6 +2683,31 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
value_range_with_overflow (r, type, new_lb, new_ub);
}
+bool
+operator_trunc_mod::op1_range (irange &r, tree type,
+ const irange &lhs,
+ const irange &op2) const
+{
+ // PR 91029. Check for signed truncation with op2 >= 0.
+ if (TYPE_SIGN (type) == SIGNED && wi::ge_p (op2.lower_bound (), 0, SIGNED))
+ {
+ unsigned prec = TYPE_PRECISION (type);
+ // if a & b >=0 , then a >= 0.
+ if (wi::ge_p (lhs.lower_bound (), 0, SIGNED))
+ {
+ r = value_range (type, wi::zero (prec), wi::max_value (prec, SIGNED));
+ return true;
+ }
+ // if a & b < 0 , then a <= 0.
+ if (wi::lt_p (lhs.upper_bound (), 0, SIGNED))
+ {
+ r = value_range (type, wi::min_value (prec, SIGNED), wi::zero (prec));
+ return true;
+ }
+ }
+ return false;
+}
+
class operator_logical_not : public range_operator
{
diff --git a/gcc/testsuite/gcc.dg/pr91029.c b/gcc/testsuite/gcc.dg/pr91029.c
new file mode 100644
index 0000000..8a4134c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91029.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void kill (void);
+int xx;
+
+void f1 (int i)
+{
+ if ((i % 7) == 3)
+ {
+ xx = (i < 0);
+ if (xx)
+ kill ();
+ }
+}
+
+void f2 (int i)
+{
+ if ((i % 7) >= 0)
+ {
+ xx = (i < 0);
+ if (xx)
+ kill ();
+ }
+}
+
+void f3 (int i)
+{
+ if ((i % 7) == -3)
+ {
+ xx = (i > 0);
+ if (xx)
+ kill ();
+ }
+}
+
+void f4 (int i)
+{
+ if ((i % 7) < 0)
+ {
+ xx = (i > 0);
+ if (xx)
+ kill ();
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "kill" "evrp" } } */