Jakub noticed that we don't forward &a[i] into a dereference of said
pointer when the resulting struct is partially accessed.  I suppose
I just didn't implement that initially because I was lazy.  It turns
out to be comparatively easy to do though.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2013-09-12  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/58404
        * tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Also
        propagate non-invariant addresses into dereferences wrapped
        in component references.

        * g++.dg/tree-ssa/pr58404.C: New testcase.

Index: gcc/tree-ssa-forwprop.c
===================================================================
*** gcc/tree-ssa-forwprop.c     (revision 202515)
--- gcc/tree-ssa-forwprop.c     (working copy)
*************** forward_propagate_addr_expr_1 (tree name
*** 786,794 ****
  
    /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
       ADDR_EXPR will not appear on the LHS.  */
!   lhs = gimple_assign_lhs (use_stmt);
!   while (handled_component_p (lhs))
!     lhs = TREE_OPERAND (lhs, 0);
  
    /* Now see if the LHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
--- 786,795 ----
  
    /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
       ADDR_EXPR will not appear on the LHS.  */
!   tree *lhsp = gimple_assign_lhs_ptr (use_stmt);
!   while (handled_component_p (*lhsp))
!     lhsp = &TREE_OPERAND (*lhsp, 0);
!   lhs = *lhsp;
  
    /* Now see if the LHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
*************** forward_propagate_addr_expr_1 (tree name
*** 822,832 ****
        /* If the LHS is a plain dereference and the value type is the same as
           that of the pointed-to type of the address we can put the
         dereferenced address on the LHS preserving the original alias-type.  */
!       else if (gimple_assign_lhs (use_stmt) == lhs
!              && integer_zerop (TREE_OPERAND (lhs, 1))
!              && useless_type_conversion_p
!                   (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
!                    TREE_TYPE (gimple_assign_rhs1 (use_stmt)))
               /* Don't forward anything into clobber stmts if it would result
                  in the lhs no longer being a MEM_REF.  */
               && (!gimple_clobber_p (use_stmt)
--- 823,835 ----
        /* If the LHS is a plain dereference and the value type is the same as
           that of the pointed-to type of the address we can put the
         dereferenced address on the LHS preserving the original alias-type.  */
!       else if (integer_zerop (TREE_OPERAND (lhs, 1))
!              && ((gimple_assign_lhs (use_stmt) == lhs
!                   && useless_type_conversion_p
!                        (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
!                         TREE_TYPE (gimple_assign_rhs1 (use_stmt))))
!                  || types_compatible_p (TREE_TYPE (lhs),
!                                         TREE_TYPE (TREE_OPERAND (def_rhs, 
0))))
               /* Don't forward anything into clobber stmts if it would result
                  in the lhs no longer being a MEM_REF.  */
               && (!gimple_clobber_p (use_stmt)
*************** forward_propagate_addr_expr_1 (tree name
*** 854,860 ****
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (lhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (lhs);
          new_lhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
!         gimple_assign_set_lhs (use_stmt, new_lhs);
          TREE_THIS_VOLATILE (new_lhs) = TREE_THIS_VOLATILE (lhs);
          TREE_SIDE_EFFECTS (new_lhs) = TREE_SIDE_EFFECTS (lhs);
          *def_rhs_basep = saved;
--- 857,863 ----
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (lhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (lhs);
          new_lhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
!         *lhsp = new_lhs;
          TREE_THIS_VOLATILE (new_lhs) = TREE_THIS_VOLATILE (lhs);
          TREE_SIDE_EFFECTS (new_lhs) = TREE_SIDE_EFFECTS (lhs);
          *def_rhs_basep = saved;
*************** forward_propagate_addr_expr_1 (tree name
*** 873,883 ****
  
    /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
       nodes from the RHS.  */
!   rhs = gimple_assign_rhs1 (use_stmt);
!   if (TREE_CODE (rhs) == ADDR_EXPR)
!     rhs = TREE_OPERAND (rhs, 0);
!   while (handled_component_p (rhs))
!     rhs = TREE_OPERAND (rhs, 0);
  
    /* Now see if the RHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
--- 876,887 ----
  
    /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
       nodes from the RHS.  */
!   tree *rhsp = gimple_assign_rhs1_ptr (use_stmt);
!   if (TREE_CODE (*rhsp) == ADDR_EXPR)
!     rhsp = &TREE_OPERAND (*rhsp, 0);
!   while (handled_component_p (*rhsp))
!     rhsp = &TREE_OPERAND (*rhsp, 0);
!   rhs = *rhsp;
  
    /* Now see if the RHS node is a MEM_REF using NAME.  If so,
       propagate the ADDR_EXPR into the use of NAME and fold the result.  */
*************** forward_propagate_addr_expr_1 (tree name
*** 909,919 ****
        /* If the RHS is a plain dereference and the value type is the same as
           that of the pointed-to type of the address we can put the
         dereferenced address on the RHS preserving the original alias-type.  */
!       else if (gimple_assign_rhs1 (use_stmt) == rhs
!              && integer_zerop (TREE_OPERAND (rhs, 1))
!              && useless_type_conversion_p
!                   (TREE_TYPE (gimple_assign_lhs (use_stmt)),
!                    TREE_TYPE (TREE_OPERAND (def_rhs, 0))))
        {
          tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
          tree new_offset, new_base, saved, new_rhs;
--- 913,925 ----
        /* If the RHS is a plain dereference and the value type is the same as
           that of the pointed-to type of the address we can put the
         dereferenced address on the RHS preserving the original alias-type.  */
!       else if (integer_zerop (TREE_OPERAND (rhs, 1))
!              && ((gimple_assign_rhs1 (use_stmt) == rhs
!                   && useless_type_conversion_p
!                        (TREE_TYPE (gimple_assign_lhs (use_stmt)),
!                         TREE_TYPE (TREE_OPERAND (def_rhs, 0))))
!                  || types_compatible_p (TREE_TYPE (rhs),
!                                         TREE_TYPE (TREE_OPERAND (def_rhs, 
0)))))
        {
          tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
          tree new_offset, new_base, saved, new_rhs;
*************** forward_propagate_addr_expr_1 (tree name
*** 937,943 ****
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (rhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (rhs);
          new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
!         gimple_assign_set_rhs1 (use_stmt, new_rhs);
          TREE_THIS_VOLATILE (new_rhs) = TREE_THIS_VOLATILE (rhs);
          TREE_SIDE_EFFECTS (new_rhs) = TREE_SIDE_EFFECTS (rhs);
          *def_rhs_basep = saved;
--- 943,949 ----
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (rhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (rhs);
          new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
!         *rhsp = new_rhs;
          TREE_THIS_VOLATILE (new_rhs) = TREE_THIS_VOLATILE (rhs);
          TREE_SIDE_EFFECTS (new_rhs) = TREE_SIDE_EFFECTS (rhs);
          *def_rhs_basep = saved;
Index: gcc/testsuite/g++.dg/tree-ssa/pr58404.C
===================================================================
*** gcc/testsuite/g++.dg/tree-ssa/pr58404.C     (revision 0)
--- gcc/testsuite/g++.dg/tree-ssa/pr58404.C     (working copy)
***************
*** 0 ****
--- 1,20 ----
+ // { dg-do compile }
+ // { dg-options "-O -fdump-tree-cddce1" }
+ 
+ struct S { int s; };
+ S a[1024];
+ 
+ void
+ foo ()
+ {
+   for (int i = 0; i < 1024; i++)
+     {
+       S &r = a[i];
+       r.s++;
+     }
+ }
+ 
+ // We should propagate the reference into both memory accesses
+ // during the first forwprop pass
+ // { dg-final { scan-tree-dump-times "= &a" 0 "cddce1" } }
+ // { dg-final { cleanup-tree-dump "cddce1" } }

Reply via email to