aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2006-12-31 17:27:35 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2006-12-31 17:27:35 +0000
commite015f578884bce00d4fe8d7b8d14b94b11879ba3 (patch)
tree37fae3dae27d12d89d0e81b7873ac69ef8dd0b39
parent870aa1ebe0d3e05912f763ece1ed4491282d34e2 (diff)
downloadgcc-e015f578884bce00d4fe8d7b8d14b94b11879ba3.zip
gcc-e015f578884bce00d4fe8d7b8d14b94b11879ba3.tar.gz
gcc-e015f578884bce00d4fe8d7b8d14b94b11879ba3.tar.bz2
re PR tree-optimization/30137 (Missed folding of pointer comparison)
2006-12-31 Richard Guenther <rguenther@suse.de> PR middle-end/30137 * fold-const.c (fold_comparison): Fold comparison of addresses of components. * testsuite/gcc.dg/pr30137-1.c: New testcase. * testsuite/gcc.dg/pr30137-2.c: Likewise. From-SVN: r120301
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/fold-const.c104
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/pr30137-1.c23
-rw-r--r--gcc/testsuite/gcc.dg/pr30137-2.c20
5 files changed, 159 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index be1f4fb..168c195 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2006-12-31 Richard Guenther <rguenther@suse.de>
+
+ PR middle-end/30137
+ * fold-const.c (fold_comparison): Fold comparison of addresses
+ of components.
+
2006-12-31 Roger Sayle <roger@eyesopen.com>
PR middle-end/30322
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index da9579e..071ddcd 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -7988,6 +7988,110 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (code, type, variable, lhs);
}
+ /* For comparisons of pointers we can decompose it to a compile time
+ comparison of the base objects and the offsets into the object.
+ This requires at least one operand being an ADDR_EXPR to do more
+ than the operand_equal_p test below. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0))
+ && (TREE_CODE (arg0) == ADDR_EXPR
+ || TREE_CODE (arg1) == ADDR_EXPR))
+ {
+ tree base0, base1, offset0 = NULL_TREE, offset1 = NULL_TREE;
+ HOST_WIDE_INT bitsize, bitpos0 = 0, bitpos1 = 0;
+ enum machine_mode mode;
+ int volatilep, unsignedp;
+ bool indirect_base0 = false;
+
+ /* Get base and offset for the access. Strip ADDR_EXPR for
+ get_inner_reference, but put it back by stripping INDIRECT_REF
+ off the base object if possible. */
+ base0 = arg0;
+ if (TREE_CODE (arg0) == ADDR_EXPR)
+ {
+ base0 = get_inner_reference (TREE_OPERAND (arg0, 0),
+ &bitsize, &bitpos0, &offset0, &mode,
+ &unsignedp, &volatilep, false);
+ if (TREE_CODE (base0) == INDIRECT_REF)
+ base0 = TREE_OPERAND (base0, 0);
+ else
+ indirect_base0 = true;
+ }
+
+ base1 = arg1;
+ if (TREE_CODE (arg1) == ADDR_EXPR)
+ {
+ base1 = get_inner_reference (TREE_OPERAND (arg1, 0),
+ &bitsize, &bitpos1, &offset1, &mode,
+ &unsignedp, &volatilep, false);
+ /* We have to make sure to have an indirect/non-indirect base1
+ just the same as we did for base0. */
+ if (TREE_CODE (base1) == INDIRECT_REF
+ && !indirect_base0)
+ base1 = TREE_OPERAND (base1, 0);
+ else if (!indirect_base0)
+ base1 = NULL_TREE;
+ }
+ else if (indirect_base0)
+ base1 = NULL_TREE;
+
+ /* If we have equivalent bases we might be able to simplify. */
+ if (base0 && base1
+ && operand_equal_p (base0, base1, 0))
+ {
+ /* We can fold this expression to a constant if the non-constant
+ offset parts are equal. */
+ if (offset0 == offset1
+ || (offset0 && offset1
+ && operand_equal_p (offset0, offset1, 0)))
+ {
+ switch (code)
+ {
+ case EQ_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 == bitpos1);
+ case NE_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 != bitpos1);
+ case LT_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 < bitpos1);
+ case LE_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 <= bitpos1);
+ case GE_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 >= bitpos1);
+ case GT_EXPR:
+ return build_int_cst (boolean_type_node, bitpos0 > bitpos1);
+ default:;
+ }
+ }
+ /* We can simplify the comparison to a comparison of the variable
+ offset parts if the constant offset parts are equal.
+ Be careful to use signed size type here because otherwise we
+ mess with array offsets in the wrong way. This is possible
+ because pointer arithmetic is restricted to retain within an
+ object and overflow on pointer differences is undefined as of
+ 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */
+ else if (bitpos0 == bitpos1)
+ {
+ tree signed_size_type_node;
+ signed_size_type_node = signed_type_for (size_type_node);
+
+ /* By converting to signed size type we cover middle-end pointer
+ arithmetic which operates on unsigned pointer types of size
+ type size and ARRAY_REF offsets which are properly sign or
+ zero extended from their type in case it is narrower than
+ size type. */
+ if (offset0 == NULL_TREE)
+ offset0 = build_int_cst (signed_size_type_node, 0);
+ else
+ offset0 = fold_convert (signed_size_type_node, offset0);
+ if (offset1 == NULL_TREE)
+ offset1 = build_int_cst (signed_size_type_node, 0);
+ else
+ offset1 = fold_convert (signed_size_type_node, offset1);
+
+ return fold_build2 (code, type, offset0, offset1);
+ }
+ }
+ }
+
/* If this is a comparison of two exprs that look like an ARRAY_REF of the
same object, then we can fold this to a comparison of the two offsets in
signed size type. This is possible because pointer arithmetic is
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 30d25ea..7b2dbcd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2006-12-31 Richard Guenther <rguenther@suse.de>
+
+ PR middle-end/30137
+ * testsuite/gcc.dg/pr30137-1.c: New testcase.
+ * testsuite/gcc.dg/pr30137-2.c: Likewise.
+
2006-12-31 Roger Sayle <roger@eyesopen.com>
PR middle-end/30322
diff --git a/gcc/testsuite/gcc.dg/pr30137-1.c b/gcc/testsuite/gcc.dg/pr30137-1.c
new file mode 100644
index 0000000..cf1b406
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30137-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-w -fdump-tree-gimple" } */
+
+/* Things that should not be folded. */
+
+struct { long base; int tail; void * volatile ptr; } *s;
+int foo3 (void) { return s == &s; }
+int foo5 (void) { return s->ptr == s->ptr; }
+
+struct { union { int i; short s } u; } x;
+int foo6 (void) { return x.u.i == x.u.s; }
+
+void **p;
+int foo8 (void) { return p == &p; }
+int foo9 (void) { return *p == p; }
+int foo10 (void) { return *p == &p; }
+int foo11 (void) { return p != &p; }
+int foo12 (void) { return *p != p; }
+int foo13 (void) { return *p != &p; }
+
+/* { dg-final { scan-tree-dump-not "= 0;" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "= 1;" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr30137-2.c b/gcc/testsuite/gcc.dg/pr30137-2.c
new file mode 100644
index 0000000..53be163
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30137-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-w -fdump-tree-gimple" } */
+
+/* Things that should be folded. */
+
+struct { long base; int tail; void * volatile ptr; } *s;
+int foo1a (void) { return (s == &s->base); }
+int foo1b (void) { return (&s->base == s); }
+int foo2 (void) { return ((void *)s == (void *) &s->base); }
+int foo4 (void) { return s->base == s->base; }
+int foo5 (void) { return &s->ptr == &s->ptr; }
+int foo6 (void) { return &s->ptr != &s->ptr; }
+int foo7 (void) { return &s->base != &s->ptr; }
+
+struct { union { int i; short s } u; } x;
+int foo8 (void) { return &x.u.i == &x.u.s; }
+
+/* { dg-final { scan-tree-dump-times "= 0" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "= 1" 7 "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */