This handles the case of CSEing part of an SSA name that is stored
to memory and defined with a composition like COMPLEX_EXPR or
CONSTRUCTOR.  This fixes the remaining pieces of PR38884 and
PR38885.

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

Richard.

2011-10-06  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/38884
        * tree-ssa-sccvn.c (vn_reference_lookup_3): Handle partial
        reads from aggregate SSA names.

        * gcc.dg/tree-ssa/ssa-fre-34.c: New testcase.
        * gcc.dg/tree-ssa/ssa-fre-35.c: Likewise.

Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c        (revision 179556)
--- gcc/tree-ssa-sccvn.c        (working copy)
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1489,1495 ****
        }
      }
  
!   /* 4) For aggregate copies translate the reference through them if
       the copy kills ref.  */
    else if (vn_walk_kind == VN_WALKREWRITE
           && gimple_assign_single_p (def_stmt)
--- 1489,1554 ----
        }
      }
  
!   /* 4) Assignment from an SSA name which definition we may be able
!      to access pieces from.  */
!   else if (ref->size == maxsize
!          && is_gimple_reg_type (vr->type)
!          && gimple_assign_single_p (def_stmt)
!          && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
!     {
!       tree rhs1 = gimple_assign_rhs1 (def_stmt);
!       gimple def_stmt2 = SSA_NAME_DEF_STMT (rhs1);
!       if (is_gimple_assign (def_stmt2)
!         && (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR
!             || gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR)
!         && types_compatible_p (vr->type, TREE_TYPE (TREE_TYPE (rhs1))))
!       {
!         tree base2;
!         HOST_WIDE_INT offset2, size2, maxsize2, off;
!         base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
!                                          &offset2, &size2, &maxsize2);
!         off = offset - offset2;
!         if (maxsize2 != -1
!             && maxsize2 == size2
!             && operand_equal_p (base, base2, 0)
!             && offset2 <= offset
!             && offset2 + size2 >= offset + maxsize)
!           {
!             tree val = NULL_TREE;
!             HOST_WIDE_INT elsz
!               = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (TREE_TYPE (rhs1))));
!             if (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR)
!               {
!                 if (off == 0)
!                   val = gimple_assign_rhs1 (def_stmt2);
!                 else if (off == elsz)
!                   val = gimple_assign_rhs2 (def_stmt2);
!               }
!             else if (gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR
!                      && off % elsz == 0)
!               {
!                 tree ctor = gimple_assign_rhs1 (def_stmt2);
!                 unsigned i = off / elsz;
!                 if (i < CONSTRUCTOR_NELTS (ctor))
!                   {
!                     constructor_elt *elt = CONSTRUCTOR_ELT (ctor, i);
!                     if (compare_tree_int (elt->index, i) == 0)
!                       val = elt->value;
!                   }
!               }
!             if (val)
!               {
!                 unsigned int value_id = get_or_alloc_constant_value_id (val);
!                 return vn_reference_insert_pieces
!                          (vuse, vr->set, vr->type,
!                           VEC_copy (vn_reference_op_s, heap, vr->operands),
!                           val, value_id);
!               }
!           }
!       }
!     }
! 
!   /* 5) For aggregate copies translate the reference through them if
       the copy kills ref.  */
    else if (vn_walk_kind == VN_WALKREWRITE
           && gimple_assign_single_p (def_stmt)
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1587,1593 ****
        return NULL;
      }
  
!   /* 5) For memcpy copies translate the reference through them if
       the copy kills ref.  */
    else if (vn_walk_kind == VN_WALKREWRITE
           && is_gimple_reg_type (vr->type)
--- 1646,1652 ----
        return NULL;
      }
  
!   /* 6) For memcpy copies translate the reference through them if
       the copy kills ref.  */
    else if (vn_walk_kind == VN_WALKREWRITE
           && is_gimple_reg_type (vr->type)
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-34.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-34.c  (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-34.c  (revision 0)
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-fre1-details" } */
+ 
+ #define vector __attribute__((vector_size(16) ))
+ 
+ struct {
+     float i;
+     vector float global_res;
+ } s;
+ float foo(float f)
+ {
+   vector float res = (vector float){0.0f,f,0.0f,1.0f};
+   s.global_res = res;
+   return *((float*)&s.global_res + 1);
+ }
+ 
+ /* { dg-final { scan-tree-dump "Replaced BIT_FIELD_REF.*with f" "fre1" } } */
+ /* { dg-final { cleanup-tree-dump "fre1" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-35.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-35.c  (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-35.c  (revision 0)
***************
*** 0 ****
--- 1,17 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-fre1-details" } */
+ 
+ struct s { _Complex float i; };
+ void g(struct s *);
+ 
+ float a1 (float dd)
+ {
+   struct s sv;
+   sv.i = dd;
+   float d = __real__ sv.i;
+   g(&sv);
+   return d;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Replaced REALPART_EXPR.*with dd" "fre1" } } */
+ /* { dg-final { cleanup-tree-dump "fre1" } } */

Reply via email to