]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/30137 (Missed folding of pointer comparison)
authorRichard Guenther <rguenther@suse.de>
Sun, 31 Dec 2006 17:27:35 +0000 (17:27 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sun, 31 Dec 2006 17:27:35 +0000 (17:27 +0000)
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

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr30137-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr30137-2.c [new file with mode: 0644]

index be1f4fba56284136b9b9fba4e09c50a76ca12f08..168c1959976341c9930f2d1d51afc80fcc7e7360 100644 (file)
@@ -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
index da9579e6b4e5e558f3af3d01e8f11ead74c86cfe..071ddcd6e7df42c2ad7414286235db19fac11fe1 100644 (file)
@@ -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
index 30d25ea11dd4c78da2cab0a5f51d9ccd1b974114..7b2dbcdc626312918a9d8652f84b54374a73b065 100644 (file)
@@ -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 (file)
index 0000000..cf1b406
--- /dev/null
@@ -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 (file)
index 0000000..53be163
--- /dev/null
@@ -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" } } */