This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][4.7] Fix the issue in PR13954


This fixes PR13954, not by doing SRA as requested but instead by
looking through memcpy during value-numbering (similar to what
we do for aggregate copies).  On its own it isn't that useful
as we still do not optimize the memcpy away itself (PR16427),
but that issue can be fixed in DCE with the returns-have-VOPs
prerequesite.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Richard.

2011-03-09  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/13954
	* tree-ssa-sccvn.c (vn_reference_lookup_3): Look through memcpy
	and friends.

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

Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig	2011-03-08 16:50:33.000000000 +0100
--- gcc/tree-ssa-sccvn.c	2011-03-09 15:45:44.000000000 +0100
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1288,1294 ****
  {
    vn_reference_t vr = (vn_reference_t)vr_;
    gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
-   tree fndecl;
    tree base;
    HOST_WIDE_INT offset, maxsize;
    static VEC (vn_reference_op_s, heap) *lhs_ops = NULL;
--- 1288,1293 ----
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1326,1335 ****
       from that defintion.
       1) Memset.  */
    if (is_gimple_reg_type (vr->type)
!       && is_gimple_call (def_stmt)
!       && (fndecl = gimple_call_fndecl (def_stmt))
!       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
!       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET
        && integer_zerop (gimple_call_arg (def_stmt, 1))
        && host_integerp (gimple_call_arg (def_stmt, 2), 1)
        && TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR)
--- 1325,1331 ----
       from that defintion.
       1) Memset.  */
    if (is_gimple_reg_type (vr->type)
!       && gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
        && integer_zerop (gimple_call_arg (def_stmt, 1))
        && host_integerp (gimple_call_arg (def_stmt, 2), 1)
        && TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR)
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1379,1385 ****
  	}
      }
  
!   /* 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)
--- 1375,1381 ----
  	}
      }
  
!   /* 3) 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
*** 1450,1455 ****
--- 1446,1592 ----
        vr->hashcode = vn_reference_compute_hash (vr);
  
        /* Adjust *ref from the new operands.  */
+       if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+ 	return (void *)-1;
+       /* This can happen with bitfields.  */
+       if (ref->size != r.size)
+ 	return (void *)-1;
+       *ref = r;
+ 
+       /* Do not update last seen VUSE after translating.  */
+       last_vuse_ptr = NULL;
+ 
+       /* Keep looking for the adjusted *REF / VR pair.  */
+       return NULL;
+     }
+ 
+   /* 4) 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)
+ 	   /* ???  Handle BCOPY as well.  */
+ 	   && (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMCPY)
+ 	       || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMPCPY)
+ 	       || gimple_call_builtin_p (def_stmt, BUILT_IN_MEMMOVE))
+ 	   && (TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR
+ 	       || TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME)
+ 	   && (TREE_CODE (gimple_call_arg (def_stmt, 1)) == ADDR_EXPR
+ 	       || TREE_CODE (gimple_call_arg (def_stmt, 1)) == SSA_NAME)
+ 	   && host_integerp (gimple_call_arg (def_stmt, 2), 1))
+     {
+       tree lhs, rhs;
+       ao_ref r;
+       HOST_WIDE_INT rhs_offset, copy_size, lhs_offset;
+       vn_reference_op_s op;
+       HOST_WIDE_INT at;
+ 
+ 
+       /* Only handle non-variable, addressable refs.  */
+       if (ref->size != maxsize
+ 	  || offset % BITS_PER_UNIT != 0
+ 	  || ref->size % BITS_PER_UNIT != 0)
+ 	return (void *)-1;
+ 
+       /* Extract a pointer base and an offset for the destination.  */
+       lhs = gimple_call_arg (def_stmt, 0);
+       lhs_offset = 0;
+       if (TREE_CODE (lhs) == SSA_NAME)
+ 	lhs = SSA_VAL (lhs);
+       if (TREE_CODE (lhs) == ADDR_EXPR)
+ 	{
+ 	  tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (lhs, 0),
+ 						    &lhs_offset);
+ 	  if (!tem)
+ 	    return (void *)-1;
+ 	  if (TREE_CODE (tem) == MEM_REF
+ 	      && host_integerp (TREE_OPERAND (tem, 1), 1))
+ 	    {
+ 	      lhs = TREE_OPERAND (tem, 0);
+ 	      lhs_offset += TREE_INT_CST_LOW (TREE_OPERAND (tem, 1));
+ 	    }
+ 	  else if (DECL_P (tem))
+ 	    lhs = build_fold_addr_expr (tem);
+ 	  else
+ 	    return (void *)-1;
+ 	}
+       if (TREE_CODE (lhs) != SSA_NAME
+ 	  && TREE_CODE (lhs) != ADDR_EXPR)
+ 	return (void *)-1;
+ 
+       /* Extract a pointer base and an offset for the source.  */
+       rhs = gimple_call_arg (def_stmt, 1);
+       rhs_offset = 0;
+       if (TREE_CODE (rhs) == SSA_NAME)
+ 	rhs = SSA_VAL (rhs);
+       if (TREE_CODE (rhs) == ADDR_EXPR)
+ 	{
+ 	  tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs, 0),
+ 						    &rhs_offset);
+ 	  if (!tem)
+ 	    return (void *)-1;
+ 	  if (TREE_CODE (tem) == MEM_REF
+ 	      && host_integerp (TREE_OPERAND (tem, 1), 1))
+ 	    {
+ 	      rhs = TREE_OPERAND (tem, 0);
+ 	      rhs_offset += TREE_INT_CST_LOW (TREE_OPERAND (tem, 1));
+ 	    }
+ 	  else if (DECL_P (tem))
+ 	    rhs = build_fold_addr_expr (tem);
+ 	  else
+ 	    return (void *)-1;
+ 	}
+       if (TREE_CODE (rhs) != SSA_NAME
+ 	  && TREE_CODE (rhs) != ADDR_EXPR)
+ 	return (void *)-1;
+ 
+       copy_size = TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 2));
+ 
+       /* The bases of the destination and the references have to agree.  */
+       if ((TREE_CODE (base) != MEM_REF
+ 	   && !DECL_P (base))
+ 	  || (TREE_CODE (base) == MEM_REF
+ 	      && (TREE_OPERAND (base, 0) != lhs
+ 		  || !host_integerp (TREE_OPERAND (base, 1), 1)))
+ 	  || (DECL_P (base)
+ 	      && (TREE_CODE (lhs) != ADDR_EXPR
+ 		  || TREE_OPERAND (lhs, 0) != base)))
+ 	return (void *)-1;
+ 
+       /* And the access has to be contained within the memcpy destination.  */
+       at = offset / BITS_PER_UNIT;
+       if (TREE_CODE (base) == MEM_REF)
+ 	at += TREE_INT_CST_LOW (TREE_OPERAND (base, 1));
+       if (lhs_offset > at
+ 	  || lhs_offset + copy_size < at + maxsize / BITS_PER_UNIT)
+ 	return (void *)-1;
+ 
+       /* Make room for 2 operands in the new reference.  */
+       if (VEC_length (vn_reference_op_s, vr->operands) < 2)
+ 	{
+ 	  VEC (vn_reference_op_s, heap) *old = vr->operands;
+ 	  VEC_safe_grow (vn_reference_op_s, heap, vr->operands, 2);
+ 	  if (old == shared_lookup_references
+ 	      && vr->operands != old)
+ 	    shared_lookup_references = NULL;
+ 	}
+       else
+ 	VEC_truncate (vn_reference_op_s, vr->operands, 2);
+ 
+       /* The looked-through reference is a simple MEM_REF.  */
+       memset (&op, 0, sizeof (op));
+       op.type = vr->type;
+       op.opcode = MEM_REF;
+       op.op0 = build_int_cst (ptr_type_node, at - rhs_offset);
+       op.off = at - lhs_offset + rhs_offset;
+       VEC_replace (vn_reference_op_s, vr->operands, 0, &op);
+       op.type = TYPE_MAIN_VARIANT (TREE_TYPE (rhs));
+       op.opcode = TREE_CODE (rhs);
+       op.op0 = rhs;
+       op.off = -1;
+       VEC_replace (vn_reference_op_s, vr->operands, 1, &op);
+       vr->hashcode = vn_reference_compute_hash (vr);
+ 
+       /* Adjust *ref from the new operands.  */
        if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
  	return (void *)-1;
        /* This can happen with bitfields.  */
Index: gcc/testsuite/g++.dg/tree-ssa/pr13954.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/tree-ssa/pr13954.C	2011-03-09 15:44:37.000000000 +0100
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do compile } */ 
+ /* { dg-options "-O1 -fdump-tree-optimized" } */
+ 
+ void link_error (void);
+ 
+ class base
+ {
+ };
+ 
+ class teststruct: public base
+ {
+ public:
+   double d;
+   char f1;
+ };
+ 
+ void
+ copystruct1 (teststruct param)
+ {
+   teststruct local;
+   param.f1 = 0;
+   local = param;
+   if (local.f1 != 0)
+     link_error ();
+ }
+ 
+ /* There should be no reference to link_error. */
+ /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]