OSDN Git Service

2008-08-13 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Aug 2008 14:22:19 +0000 (14:22 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Aug 2008 14:22:19 +0000 (14:22 +0000)
* tree.h (maybe_fold_offset_to_address): Declare.
* tree-ssa-ccp.c (surely_varying_stmt_p): Fix typo in last commit.
(ccp_fold): Handle pointer conversions the same as fold_stmt.
Likewise for POINTER_PLUS_EXPR.
(maybe_fold_offset_to_reference): Enable disabled code.
(maybe_fold_offset_to_address): New function.
(fold_stmt_r): Use it.
(fold_gimple_assign): Likewise.
* gimplify.c (gimplify_conversion): Use maybe_fold_offset_to_address.
(gimplify_expr): Likewise.

* gcc.dg/tree-ssa/ssa-ccp-21.c: New testcase.
* gcc.dg/tree-ssa/ssa-ccp-22.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139061 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c [new file with mode: 0644]
gcc/tree-ssa-ccp.c
gcc/tree.h

index f07113a..fa88d55 100644 (file)
@@ -1,3 +1,16 @@
+2008-08-13  Richard Guenther  <rguenther@suse.de>
+
+       * tree.h (maybe_fold_offset_to_address): Declare.
+       * tree-ssa-ccp.c (surely_varying_stmt_p): Fix typo in last commit.
+       (ccp_fold): Handle pointer conversions the same as fold_stmt.
+       Likewise for POINTER_PLUS_EXPR.
+       (maybe_fold_offset_to_reference): Enable disabled code.
+       (maybe_fold_offset_to_address): New function.
+       (fold_stmt_r): Use it.
+       (fold_gimple_assign): Likewise.
+       * gimplify.c (gimplify_conversion): Use maybe_fold_offset_to_address.
+       (gimplify_expr): Likewise.
+
 2008-08-13  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
 
        * toplev.h (pedwarn_at): Fix declaration.
 2008-08-13  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
 
        * toplev.h (pedwarn_at): Fix declaration.
index 753aa59..43c8df9 100644 (file)
@@ -1842,17 +1842,13 @@ gimplify_conversion (tree *expr_p)
   /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
      For example this fold (subclass *)&A into &A->subclass avoiding
      a need for statement.  */
   /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
      For example this fold (subclass *)&A into &A->subclass avoiding
      a need for statement.  */
-  if (TREE_CODE (*expr_p) == NOP_EXPR
+  if (CONVERT_EXPR_P (*expr_p)
       && POINTER_TYPE_P (TREE_TYPE (*expr_p))
       && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
       && POINTER_TYPE_P (TREE_TYPE (*expr_p))
       && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
-      && (tem = maybe_fold_offset_to_reference
+      && (tem = maybe_fold_offset_to_address
                  (TREE_OPERAND (*expr_p, 0),
                  (TREE_OPERAND (*expr_p, 0),
-                  integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p)))))
-    {
-      tree ptr_type = build_pointer_type (TREE_TYPE (tem));
-      if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
-        *expr_p = build_fold_addr_expr_with_type (tem, ptr_type);
-    }
+                  integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE)
+    *expr_p = tem;
 
   /* If we still have a conversion at the toplevel,
      then canonicalize some constructs.  */
 
   /* If we still have a conversion at the toplevel,
      then canonicalize some constructs.  */
@@ -6735,30 +6731,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
             The second is gimple immediate saving a need for extra statement.
           */
          if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
             The second is gimple immediate saving a need for extra statement.
           */
          if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
-             && (tmp = maybe_fold_offset_to_reference
+             && (tmp = maybe_fold_offset_to_address
                         (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
                         (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
-                         TREE_TYPE (TREE_TYPE (*expr_p)))))
-            {
-              tree ptr_type = build_pointer_type (TREE_TYPE (tmp));
-              if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
-                {
-                   *expr_p = build_fold_addr_expr_with_type (tmp, ptr_type);
-                  break;
-                }
-            }
+                         TREE_TYPE (*expr_p))))
+           {
+             *expr_p = tmp;
+             break;
+           }
          /* Convert (void *)&a + 4 into (void *)&a[1].  */
          if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
              && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
              && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
                                                                        0),0)))
          /* Convert (void *)&a + 4 into (void *)&a[1].  */
          if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
              && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
              && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
                                                                        0),0)))
-             && (tmp = maybe_fold_offset_to_reference
+             && (tmp = maybe_fold_offset_to_address
                         (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
                          TREE_OPERAND (*expr_p, 1),
                         (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
                          TREE_OPERAND (*expr_p, 1),
-                         TREE_TYPE (TREE_TYPE
-                                 (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
-                                                0))))))
+                         TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
+                                                  0)))))
             {
             {
-               tmp = build_fold_addr_expr (tmp);
                *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
               break;
             }
                *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
               break;
             }
index d036b78..951f82e 100644 (file)
@@ -1,3 +1,9 @@
+2008-08-13  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/ssa-ccp-21.c: New testcase.
+       * gcc.dg/tree-ssa/ssa-ccp-22.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.
+
 2008-08-13  Samuel Tardieu  <sam@rfc1149.net>
 
        PR ada/36777
 2008-08-13  Samuel Tardieu  <sam@rfc1149.net>
 
        PR ada/36777
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c
new file mode 100644 (file)
index 0000000..3b23c36
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+struct A {
+    struct B {
+       int i;
+    } b;
+} a;
+
+int foo (void)
+{
+  struct B *p = &a.b;
+  struct A *q = (struct A *) p;
+  return q->b.i;
+}
+
+int bar (void)
+{
+  struct A *p = &a;
+  struct B *q = (struct B *) p;
+  return q->i;
+}
+
+/* { dg-final { scan-tree-dump-times "a.b.i" 2 "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c
new file mode 100644 (file)
index 0000000..01d11ec
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+/* Make sure we propagate through builtins.  */
+
+int foo (unsigned b)
+{
+  unsigned t = -1;
+  int x = b <= t;
+  long l = __builtin_expect (x, 0);
+  return l;
+}
+
+/* { dg-final { scan-tree-dump "return 1;" "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c
new file mode 100644 (file)
index 0000000..ac7f068
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+/* Make sure we propagate through POINTER_PLUS_EXPRs.  */
+
+struct A {
+  int i[2];
+} a;
+
+int foo (void)
+{
+  struct A *p = &a;
+  int *q = (int *)p;
+  int *x = q + 1;
+  return *x;
+}
+
+/* { dg-final { scan-tree-dump "a.i\\\[1\\\]" "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
index af102cd..ff8af4f 100644 (file)
@@ -630,7 +630,7 @@ surely_varying_stmt_p (gimple stmt)
       tree fndecl;
       if (!gimple_call_lhs (stmt)
          || ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
       tree fndecl;
       if (!gimple_call_lhs (stmt)
          || ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
-             && DECL_BUILT_IN (fndecl)))
+             && !DECL_BUILT_IN (fndecl)))
        return true;
     }
 
        return true;
     }
 
@@ -988,18 +988,26 @@ ccp_fold (gimple stmt)
                 useless_type_conversion_p places for pointer type conversions
                 do not apply here.  Substitution later will only substitute to
                 allowed places.  */
                 useless_type_conversion_p places for pointer type conversions
                 do not apply here.  Substitution later will only substitute to
                 allowed places.  */
-              if ((subcode == NOP_EXPR || subcode == CONVERT_EXPR)
-                 && ((POINTER_TYPE_P (TREE_TYPE (lhs))
-                      && POINTER_TYPE_P (TREE_TYPE (op0))
-                      /* Do not allow differences in volatile qualification
-                         as this might get us confused as to whether a
-                         propagation destination statement is volatile
-                         or not.  See PR36988.  */
-                      && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
-                          == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
-                     || useless_type_conversion_p (TREE_TYPE (lhs),
-                                                   TREE_TYPE (op0))))
-                return op0;
+             if (IS_CONVERT_EXPR_CODE_P (subcode)
+                 && POINTER_TYPE_P (TREE_TYPE (lhs))
+                 && POINTER_TYPE_P (TREE_TYPE (op0))
+                 /* Do not allow differences in volatile qualification
+                    as this might get us confused as to whether a
+                    propagation destination statement is volatile
+                    or not.  See PR36988.  */
+                 && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
+                     == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
+               {
+                 tree tem;
+                 /* Still try to generate a constant of correct type.  */
+                 if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                                 TREE_TYPE (op0))
+                     && ((tem = maybe_fold_offset_to_address
+                                  (op0, integer_zero_node, TREE_TYPE (lhs)))
+                         != NULL_TREE))
+                   return tem;
+                 return op0;
+               }
 
               return fold_unary (subcode, gimple_expr_type (stmt), op0);
             }  
 
               return fold_unary (subcode, gimple_expr_type (stmt), op0);
             }  
@@ -1025,6 +1033,18 @@ ccp_fold (gimple stmt)
                     op1 = val->value;
                 }
 
                     op1 = val->value;
                 }
 
+             /* Fold &foo + CST into an invariant reference if possible.  */
+             if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+                 && TREE_CODE (op0) == ADDR_EXPR
+                 && TREE_CODE (op1) == INTEGER_CST)
+               {
+                 tree lhs = gimple_assign_lhs (stmt);
+                 tree tem = maybe_fold_offset_to_address (op0, op1,
+                                                          TREE_TYPE (lhs));
+                 if (tem != NULL_TREE)
+                   return tem;
+               }
+
               return fold_binary (subcode, gimple_expr_type (stmt), op0, op1);
             }
 
               return fold_binary (subcode, gimple_expr_type (stmt), op0, op1);
             }
 
@@ -1948,15 +1968,15 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
         so it needs to be removed and new COMPONENT_REF constructed.
         The wrong COMPONENT_REF are often constructed by folding the
         (type *)&object within the expression (type *)&object+offset  */
         so it needs to be removed and new COMPONENT_REF constructed.
         The wrong COMPONENT_REF are often constructed by folding the
         (type *)&object within the expression (type *)&object+offset  */
-      if (handled_component_p (base) && 0)
+      if (handled_component_p (base))
        {
           HOST_WIDE_INT sub_offset, size, maxsize;
          tree newbase;
          newbase = get_ref_base_and_extent (base, &sub_offset,
                                             &size, &maxsize);
          gcc_assert (newbase);
        {
           HOST_WIDE_INT sub_offset, size, maxsize;
          tree newbase;
          newbase = get_ref_base_and_extent (base, &sub_offset,
                                             &size, &maxsize);
          gcc_assert (newbase);
-         gcc_assert (!(sub_offset & (BITS_PER_UNIT - 1)));
-         if (size == maxsize)
+         if (size == maxsize
+             && !(sub_offset & (BITS_PER_UNIT - 1)))
            {
              base = newbase;
              if (sub_offset)
            {
              base = newbase;
              if (sub_offset)
@@ -1988,6 +2008,63 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
   return ret;
 }
 
   return ret;
 }
 
+/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type
+   or &BASE[index] or by combination of those.
+
+   Before attempting the conversion strip off existing component refs.  */
+
+tree
+maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type)
+{
+  tree t;
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
+             && POINTER_TYPE_P (orig_type));
+
+  t = maybe_fold_offset_to_reference (addr, offset, TREE_TYPE (orig_type));
+  if (t != NULL_TREE)
+    {
+      tree orig = addr;
+      tree ptr_type;
+
+      /* For __builtin_object_size to function correctly we need to
+         make sure not to fold address arithmetic so that we change
+        reference from one array to another.  This would happen for
+        example for
+
+          struct X { char s1[10]; char s2[10] } s;
+          char *foo (void) { return &s.s2[-4]; }
+
+        where we need to avoid generating &s.s1[6].  As the C and
+        C++ frontends create different initial trees
+        (char *) &s.s1 + -4  vs.  &s.s1[-4]  we have to do some
+        sophisticated comparisons here.  Note that checking for the
+        condition after the fact is easier than trying to avoid doing
+        the folding.  */
+      STRIP_NOPS (orig);
+      if (TREE_CODE (orig) == ADDR_EXPR)
+       orig = TREE_OPERAND (orig, 0);
+      if ((TREE_CODE (orig) == ARRAY_REF
+          || (TREE_CODE (orig) == COMPONENT_REF
+              && TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
+         && (TREE_CODE (t) == ARRAY_REF
+             || (TREE_CODE (t) == COMPONENT_REF
+                 && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) == ARRAY_TYPE))
+         && !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
+                              ? TREE_OPERAND (orig, 0) : orig,
+                              TREE_CODE (t) == ARRAY_REF
+                              ? TREE_OPERAND (t, 0) : t, 0))
+       return NULL_TREE;
+
+      ptr_type = build_pointer_type (TREE_TYPE (t));
+      if (!useless_type_conversion_p (orig_type, ptr_type))
+       return NULL_TREE;
+      return build_fold_addr_expr_with_type (t, ptr_type);
+    }
+
+  return NULL_TREE;
+}
+
 /* A subroutine of fold_stmt_r.  Attempt to simplify *(BASE+OFFSET).
    Return the simplified expression, or NULL if nothing could be done.  */
 
 /* A subroutine of fold_stmt_r.  Attempt to simplify *(BASE+OFFSET).
    Return the simplified expression, or NULL if nothing could be done.  */
 
@@ -2223,16 +2300,10 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
 
       if (POINTER_TYPE_P (TREE_TYPE (expr))
          && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
 
       if (POINTER_TYPE_P (TREE_TYPE (expr))
          && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
-         && (t = maybe_fold_offset_to_reference
-                     (TREE_OPERAND (expr, 0),
-                      integer_zero_node,
-                      TREE_TYPE (TREE_TYPE (expr)))))
-       {
-         tree ptr_type = build_pointer_type (TREE_TYPE (t));
-         if (!useless_type_conversion_p (TREE_TYPE (expr), ptr_type))
-           return NULL_TREE;
-          t = build_fold_addr_expr_with_type (t, ptr_type);
-       }
+         && (t = maybe_fold_offset_to_address (TREE_OPERAND (expr, 0),
+                                               integer_zero_node,
+                                               TREE_TYPE (TREE_TYPE (expr)))))
+       return t;
       break;
 
       /* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
       break;
 
       /* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
@@ -2715,15 +2786,10 @@ fold_gimple_assign (gimple_stmt_iterator *si)
               && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
        {
          tree type = gimple_expr_type (stmt);
               && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
        {
          tree type = gimple_expr_type (stmt);
-         tree t = maybe_fold_offset_to_reference (gimple_assign_rhs1 (stmt),
-                                                  integer_zero_node,
-                                                  TREE_TYPE (type));
+         tree t = maybe_fold_offset_to_address (gimple_assign_rhs1 (stmt),
+                                                integer_zero_node, type);
          if (t)
          if (t)
-           {
-             tree ptr_type = build_pointer_type (TREE_TYPE (t));
-             if (useless_type_conversion_p (type, ptr_type))
-               return build_fold_addr_expr_with_type (t, ptr_type);
-           }
+           return t;
        }
       break;
 
        }
       break;
 
index 5f5b37d..3f8065d 100644 (file)
@@ -4744,6 +4744,7 @@ extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
 extern tree maybe_fold_offset_to_reference (tree, tree, tree);
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
 extern tree maybe_fold_offset_to_reference (tree, tree, tree);
+extern tree maybe_fold_offset_to_address (tree, tree, tree);
 extern tree maybe_fold_stmt_addition (tree, tree, tree);
 
 extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,
 extern tree maybe_fold_stmt_addition (tree, tree, tree);
 
 extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,