aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2021-10-01 13:05:36 +0200
committerAldy Hernandez <aldyh@redhat.com>2021-10-02 00:03:23 +0200
commit5f9ccf17de7f7581412c6bffd4a37beca9a79836 (patch)
treee10e84c7a9062a57145cea3cbd6229b47a350446 /gcc
parent257d2890a769a8aa564d079170377e637e07acb1 (diff)
downloadgcc-5f9ccf17de7f7581412c6bffd4a37beca9a79836.zip
gcc-5f9ccf17de7f7581412c6bffd4a37beca9a79836.tar.gz
gcc-5f9ccf17de7f7581412c6bffd4a37beca9a79836.tar.bz2
[PR102546] X << Y being non-zero implies X is also non-zero.
This patch teaches this to range-ops. Tested on x86-64 Linux. gcc/ChangeLog: PR tree-optimization/102546 * range-op.cc (operator_lshift::op1_range): Teach range-ops that X << Y is non-zero implies X is also non-zero.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/range-op.cc18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr102546.c23
2 files changed, 37 insertions, 4 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 5e37133..2baca4a 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2078,6 +2078,12 @@ operator_lshift::op1_range (irange &r,
relation_kind rel ATTRIBUTE_UNUSED) const
{
tree shift_amount;
+
+ if (!lhs.contains_p (build_zero_cst (type)))
+ r.set_nonzero (type);
+ else
+ r.set_varying (type);
+
if (op2.singleton_p (&shift_amount))
{
wide_int shift = wi::to_wide (shift_amount);
@@ -2089,21 +2095,24 @@ operator_lshift::op1_range (irange &r,
return false;
if (shift == 0)
{
- r = lhs;
+ r.intersect (lhs);
return true;
}
// Work completely in unsigned mode to start.
tree utype = type;
+ int_range_max tmp_range;
if (TYPE_SIGN (type) == SIGNED)
{
int_range_max tmp = lhs;
utype = unsigned_type_for (type);
range_cast (tmp, utype);
- op_rshift.fold_range (r, utype, tmp, op2);
+ op_rshift.fold_range (tmp_range, utype, tmp, op2);
}
else
- op_rshift.fold_range (r, utype, lhs, op2);
+ op_rshift.fold_range (tmp_range, utype, lhs, op2);
+
+ r.intersect (tmp_range);
// Start with ranges which can produce the LHS by right shifting the
// result by the shift amount.
@@ -2128,7 +2137,8 @@ operator_lshift::op1_range (irange &r,
range_cast (r, type);
return true;
}
- return false;
+
+ return !r.varying_p ();
}
bool
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr102546.c b/gcc/testsuite/gcc.dg/tree-ssa/pr102546.c
new file mode 100644
index 0000000..4bd9874
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr102546.c
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-options "-O3 -fdump-tree-optimized" }
+
+static int a;
+static char b, c, d;
+void bar(void);
+void foo(void);
+
+int main() {
+ int f = 0;
+ for (; f <= 5; f++) {
+ bar();
+ b = b && f;
+ d = f << f;
+ if (!(a >= d || f))
+ foo();
+ c = 1;
+ for (; c; c = 0)
+ ;
+ }
+}
+
+// { dg-final { scan-tree-dump-not "foo" "optimized" } }