The following teaches phiprop to handle the case of aggregate copies
where the aggregate has non-BLKmode which means it is very likely
expanded as reg-reg moves (any better test for that apart from
checking for non-BLKmode?).  This improves code for the testcase
from

_Z14struct_ternary1SS_b:
.LFB2:
        .cfi_startproc
        leaq    -40(%rsp), %rcx
        leaq    -24(%rsp), %rax
        testb   %dl, %dl
        movl    %edi, -24(%rsp)
        movl    %esi, -40(%rsp)
        cmove   %rcx, %rax
        movl    (%rax), %eax
        ret

to

_Z14struct_ternary1SS_b:
.LFB2:
        .cfi_startproc
        testb   %dl, %dl
        movl    %edi, %eax
        cmove   %esi, %eax
        ret

Bootstrapped and tested on x86_64-unknown-linux-gnu, queued for stage1.

Richard.

2016-03-11  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/70171
        * tree-ssa-phiprop.c: Include stor-layout.h.
        (phiprop_insert_phi): Handle the aggregate copy case.
        (propagate_with_phi): Likewise.

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

Index: gcc/tree-ssa-phiprop.c
===================================================================
*** gcc/tree-ssa-phiprop.c      (revision 234134)
--- gcc/tree-ssa-phiprop.c      (working copy)
*************** along with GCC; see the file COPYING3.
*** 31,36 ****
--- 31,37 ----
  #include "tree-eh.h"
  #include "gimplify.h"
  #include "gimple-iterator.h"
+ #include "stor-layout.h"
  
  /* This pass propagates indirect loads through the PHI node for its
     address to make the load source possibly non-addressable and to
*************** phiprop_insert_phi (basic_block bb, gphi
*** 132,138 ****
                    struct phiprop_d *phivn, size_t n)
  {
    tree res;
!   gphi *new_phi;
    edge_iterator ei;
    edge e;
  
--- 133,139 ----
                    struct phiprop_d *phivn, size_t n)
  {
    tree res;
!   gphi *new_phi = NULL;
    edge_iterator ei;
    edge e;
  
*************** phiprop_insert_phi (basic_block bb, gphi
*** 142,148 ****
    /* Build a new PHI node to replace the definition of
       the indirect reference lhs.  */
    res = gimple_assign_lhs (use_stmt);
!   new_phi = create_phi_node (res, bb);
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
--- 143,150 ----
    /* Build a new PHI node to replace the definition of
       the indirect reference lhs.  */
    res = gimple_assign_lhs (use_stmt);
!   if (TREE_CODE (res) == SSA_NAME)
!     new_phi = create_phi_node (res, bb);
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
*************** phiprop_insert_phi (basic_block bb, gphi
*** 187,193 ****
        {
          tree rhs = gimple_assign_rhs1 (use_stmt);
          gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
!         new_var = make_ssa_name (TREE_TYPE (rhs));
          if (!is_gimple_min_invariant (old_arg))
            old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
          else
--- 189,198 ----
        {
          tree rhs = gimple_assign_rhs1 (use_stmt);
          gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
!         if (TREE_CODE (res) == SSA_NAME)
!           new_var = make_ssa_name (TREE_TYPE (rhs));
!         else
!           new_var = unshare_expr (res);
          if (!is_gimple_min_invariant (old_arg))
            old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
          else
*************** phiprop_insert_phi (basic_block bb, gphi
*** 210,222 ****
            }
        }
  
!       add_phi_arg (new_phi, new_var, e, locus);
      }
  
!   update_stmt (new_phi);
  
!   if (dump_file && (dump_flags & TDF_DETAILS))
!     print_gimple_stmt (dump_file, new_phi, 0, 0);
  
    return res;
  }
--- 215,231 ----
            }
        }
  
!       if (new_phi)
!       add_phi_arg (new_phi, new_var, e, locus);
      }
  
!   if (new_phi)
!     {
!       update_stmt (new_phi);
  
!       if (dump_file && (dump_flags & TDF_DETAILS))
!       print_gimple_stmt (dump_file, new_phi, 0, 0);
!     }
  
    return res;
  }
*************** propagate_with_phi (basic_block bb, gphi
*** 250,256 ****
    tree type = NULL_TREE;
  
    if (!POINTER_TYPE_P (TREE_TYPE (ptr))
!       || !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
      return false;
  
    /* Check if we can "cheaply" dereference all phi arguments.  */
--- 259,266 ----
    tree type = NULL_TREE;
  
    if (!POINTER_TYPE_P (TREE_TYPE (ptr))
!       || (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))
!         && TYPE_MODE (TREE_TYPE (TREE_TYPE (ptr))) == BLKmode))
      return false;
  
    /* Check if we can "cheaply" dereference all phi arguments.  */
*************** propagate_with_phi (basic_block bb, gphi
*** 306,312 ****
           
        /* Check whether this is a load of *ptr.  */
        if (!(is_gimple_assign (use_stmt)
-           && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
            && gimple_assign_rhs_code (use_stmt) == MEM_REF
            && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
            && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
--- 316,321 ----
*************** propagate_with_phi (basic_block bb, gphi
*** 327,335 ****
                                  bb, gimple_bb (def_stmt))))
        goto next;
  
        /* Found a proper dereference.  Insert a phi node if this
         is the first load transformation.  */
!       if (!phi_inserted)
        {
          res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
          type = TREE_TYPE (res);
--- 336,366 ----
                                  bb, gimple_bb (def_stmt))))
        goto next;
  
+       /* Found a proper dereference with an aggregate copy.  Just
+          insert aggregate copies on the edges instead.  */
+       if (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
+       {
+         phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
+ 
+         /* Remove old stmt.  The phi is taken care of by DCE.  */
+         gsi = gsi_for_stmt (use_stmt);
+         /* Unlinking the VDEF here is fine as we are sure that we process
+            stmts in execution order due to aggregate copies having VDEFs
+            and we emit loads on the edges in the very same order.
+            We get multiple copies (or intermediate register loads) handled
+            only by walking PHIs or immediate uses in a lucky order though,
+            so we could signal the caller to re-start iterating over PHIs
+            when we come here which would make it quadratic in the number
+            of PHIs.  */
+         unlink_stmt_vdef (use_stmt);
+         gsi_remove (&gsi, true);
+ 
+         phi_inserted = true;
+       }
+ 
        /* Found a proper dereference.  Insert a phi node if this
         is the first load transformation.  */
!       else if (!phi_inserted)
        {
          res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
          type = TREE_TYPE (res);
Index: gcc/testsuite/g++.dg/tree-ssa/pr70171.C
===================================================================
*** gcc/testsuite/g++.dg/tree-ssa/pr70171.C     (revision 0)
--- gcc/testsuite/g++.dg/tree-ssa/pr70171.C     (working copy)
***************
*** 0 ****
--- 1,8 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ 
+ struct S { int i; };
+ S struct_ternary (S a, S b, bool select) { return select ? a : b; }
+ 
+ /* { dg-final { scan-tree-dump-not "&\[ab\]" "optimized" } } */
+ /* { dg-final { scan-assembler-not "\[er\]sp" { target { { i?86-*-* 
x86_64-*-* } && { ! ia32 } } } } } */

Reply via email to