[PATCH][mem-ref2] Fix PR42834

Richard Guenther rguenther@suse.de
Mon Jun 21 11:57:00 GMT 2010


This fixes PR42834 - one reason I started working on mem-ref again.

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

Richard.

2010-06-21  Richard Guenther  <rguenther@suse.de>

	PR middle-end/42834
	* builtins.c (fold_builtin_memory_op): Use ref-all types
	for all memcpy foldings.
	* expr.c (store_expr): Handle MEM_REFs from STRING_CSTs.

	* c-c++-common/torture/pr42834.c: New testcase.
	* gcc.dg/tree-prof/stringop-1.c: Adjust.
	* gfortran.dg/array_memcpy_3.f90: Likewise.
	* gfortran.dg/array_memcpy_4.f90: Likewise.

Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c	(revision 161051)
--- gcc/builtins.c	(working copy)
*************** fold_builtin_memory_op (location_t loc,
*** 8349,8354 ****
--- 8349,8355 ----
      {
        tree srctype, desttype;
        int src_align, dest_align;
+       tree off0;
  
        if (endp == 3)
  	{
*************** fold_builtin_memory_op (location_t loc,
*** 8476,8487 ****
  	  dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
  	}
        if (!srctype || !desttype
  	  || !TYPE_SIZE_UNIT (srctype)
  	  || !TYPE_SIZE_UNIT (desttype)
  	  || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
! 	  || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
! 	  || TYPE_VOLATILE (srctype)
! 	  || TYPE_VOLATILE (desttype))
  	return NULL_TREE;
  
        src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
--- 8477,8488 ----
  	  dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
  	}
        if (!srctype || !desttype
+ 	  || TREE_ADDRESSABLE (srctype)
+ 	  || TREE_ADDRESSABLE (desttype)
  	  || !TYPE_SIZE_UNIT (srctype)
  	  || !TYPE_SIZE_UNIT (desttype)
  	  || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
! 	  || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST)
  	return NULL_TREE;
  
        src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
*************** fold_builtin_memory_op (location_t loc,
*** 8493,8589 ****
        if (!ignore)
          dest = builtin_save_expr (dest);
  
!       srcvar = NULL_TREE;
!       if (tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
! 	{
! 	  srcvar = build_fold_indirect_ref_loc (loc, src);
! 	  if (TREE_THIS_VOLATILE (srcvar))
! 	    return NULL_TREE;
! 	  else if (!tree_int_cst_equal (tree_expr_size (srcvar), len))
! 	    srcvar = NULL_TREE;
! 	  /* With memcpy, it is possible to bypass aliasing rules, so without
! 	     this check i.e. execute/20060930-2.c would be misoptimized,
! 	     because it use conflicting alias set to hold argument for the
! 	     memcpy call.  This check is probably unnecessary with
! 	     -fno-strict-aliasing.  Similarly for destvar.  See also
! 	     PR29286.  */
! 	  else if (!var_decl_component_p (srcvar))
! 	    srcvar = NULL_TREE;
! 	}
  
!       destvar = NULL_TREE;
!       if (tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
! 	{
! 	  destvar = build_fold_indirect_ref_loc (loc, dest);
! 	  if (TREE_THIS_VOLATILE (destvar))
! 	    return NULL_TREE;
! 	  else if (!tree_int_cst_equal (tree_expr_size (destvar), len))
! 	    destvar = NULL_TREE;
! 	  else if (!var_decl_component_p (destvar))
! 	    destvar = NULL_TREE;
! 	}
  
        if (srcvar == NULL_TREE && destvar == NULL_TREE)
  	return NULL_TREE;
  
        if (srcvar == NULL_TREE)
  	{
! 	  tree srcptype;
! 	  if (TREE_ADDRESSABLE (TREE_TYPE (destvar)))
! 	    return NULL_TREE;
! 
! 	  srctype = build_qualified_type (desttype, 0);
! 	  if (src_align < (int) TYPE_ALIGN (srctype))
! 	    {
! 	      if (AGGREGATE_TYPE_P (srctype)
! 		  || SLOW_UNALIGNED_ACCESS (TYPE_MODE (srctype), src_align))
! 		return NULL_TREE;
! 
! 	      srctype = build_variant_type_copy (srctype);
! 	      TYPE_ALIGN (srctype) = src_align;
! 	      TYPE_USER_ALIGN (srctype) = 1;
! 	      TYPE_PACKED (srctype) = 1;
! 	    }
! 	  srcptype = build_pointer_type_for_mode (srctype, ptr_mode, true);
! 	  src = fold_convert_loc (loc, srcptype, src);
! 	  srcvar = build_fold_indirect_ref_loc (loc, src);
  	}
        else if (destvar == NULL_TREE)
  	{
! 	  tree destptype;
! 	  if (TREE_ADDRESSABLE (TREE_TYPE (srcvar)))
! 	    return NULL_TREE;
! 
! 	  desttype = build_qualified_type (srctype, 0);
! 	  if (dest_align < (int) TYPE_ALIGN (desttype))
! 	    {
! 	      if (AGGREGATE_TYPE_P (desttype)
! 		  || SLOW_UNALIGNED_ACCESS (TYPE_MODE (desttype), dest_align))
! 		return NULL_TREE;
! 
! 	      desttype = build_variant_type_copy (desttype);
! 	      TYPE_ALIGN (desttype) = dest_align;
! 	      TYPE_USER_ALIGN (desttype) = 1;
! 	      TYPE_PACKED (desttype) = 1;
! 	    }
! 	  destptype = build_pointer_type_for_mode (desttype, ptr_mode, true);
! 	  dest = fold_convert_loc (loc, destptype, dest);
! 	  destvar = build_fold_indirect_ref_loc (loc, dest);
  	}
  
!       if (srctype == desttype
! 	  || (gimple_in_ssa_p (cfun)
! 	      && useless_type_conversion_p (desttype, srctype)))
! 	expr = srcvar;
!       else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
! 	   || POINTER_TYPE_P (TREE_TYPE (srcvar)))
! 	  && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
! 	      || POINTER_TYPE_P (TREE_TYPE (destvar))))
! 	expr = fold_convert_loc (loc, TREE_TYPE (destvar), srcvar);
!       else
! 	expr = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
! 			    TREE_TYPE (destvar), srcvar);
!       expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
      }
  
    if (ignore)
--- 8494,8537 ----
        if (!ignore)
          dest = builtin_save_expr (dest);
  
!       /* Build accesses at offset zero with a ref-all character type.  */
!       off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
! 							 ptr_mode, true), 0);
! 
!       destvar = dest;
!       STRIP_NOPS (destvar);
!       if (TREE_CODE (destvar) == ADDR_EXPR
! 	  && var_decl_component_p (TREE_OPERAND (destvar, 0))
! 	  && tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
! 	destvar = fold_build2 (MEM_REF, desttype, destvar, off0);
!       else
! 	destvar = NULL_TREE;
  
!       srcvar = src;
!       STRIP_NOPS (srcvar);
!       if (TREE_CODE (srcvar) == ADDR_EXPR
! 	  && var_decl_component_p (TREE_OPERAND (srcvar, 0))
! 	  && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
! 	srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
! 			      srcvar, off0);
!       else
! 	srcvar = NULL_TREE;
  
        if (srcvar == NULL_TREE && destvar == NULL_TREE)
  	return NULL_TREE;
  
        if (srcvar == NULL_TREE)
  	{
! 	  STRIP_NOPS (src);
! 	  srcvar = fold_build2 (MEM_REF, desttype, src, off0);
  	}
        else if (destvar == NULL_TREE)
  	{
! 	  STRIP_NOPS (dest);
! 	  destvar = fold_build2 (MEM_REF, srctype, dest, off0);
  	}
  
!       expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
      }
  
    if (ignore)
Index: gcc/expr.c
===================================================================
*** gcc/expr.c	(revision 161051)
--- gcc/expr.c	(working copy)
*************** store_expr (tree exp, rtx target, int ca
*** 4681,4686 ****
--- 4681,4731 ----
  		       BLOCK_OP_NORMAL);
        return NULL_RTX;
      }
+   else if (TREE_CODE (exp) == MEM_REF
+ 	   && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+ 	   && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == STRING_CST
+ 	   && integer_zerop (TREE_OPERAND (exp, 1))
+ 	   && !nontemporal && !call_param_p
+ 	   && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+     {
+       /* Optimize initialization of an array with a STRING_CST.  */
+       HOST_WIDE_INT exp_len, str_copy_len;
+       rtx dest_mem;
+       tree str = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ 
+       exp_len = int_expr_size (exp);
+       if (exp_len <= 0)
+ 	goto normal_expr;
+ 
+       str_copy_len = strlen (TREE_STRING_POINTER (str));
+       if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
+ 	goto normal_expr;
+ 
+       str_copy_len = TREE_STRING_LENGTH (str);
+       if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+ 	{
+ 	  str_copy_len += STORE_MAX_PIECES - 1;
+ 	  str_copy_len &= ~(STORE_MAX_PIECES - 1);
+ 	}
+       str_copy_len = MIN (str_copy_len, exp_len);
+       if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
+ 				CONST_CAST(char *, TREE_STRING_POINTER (str)),
+ 				MEM_ALIGN (target), false))
+ 	goto normal_expr;
+ 
+       dest_mem = target;
+ 
+       dest_mem = store_by_pieces (dest_mem,
+ 				  str_copy_len, builtin_strncpy_read_str,
+ 				  CONST_CAST(char *, TREE_STRING_POINTER (str)),
+ 				  MEM_ALIGN (target), false,
+ 				  exp_len > str_copy_len ? 1 : 0);
+       if (exp_len > str_copy_len)
+ 	clear_storage (adjust_address (dest_mem, BLKmode, 0),
+ 		       GEN_INT (exp_len - str_copy_len),
+ 		       BLOCK_OP_NORMAL);
+       return NULL_RTX;
+     }
    else
      {
        rtx tmp_target;
Index: gcc/testsuite/c-c++-common/torture/pr42834.c
===================================================================
*** gcc/testsuite/c-c++-common/torture/pr42834.c	(revision 0)
--- gcc/testsuite/c-c++-common/torture/pr42834.c	(revision 0)
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do run } */
+ 
+ void __attribute__((noinline,noclone))
+ foo(int *p, float *q) { __asm__ volatile ("" : : : "memory"); }
+ 
+ int main()
+ {
+   if (sizeof (int) == sizeof (float))
+     {
+       int i;
+       float f;
+       int *p;
+       /* Prevent i and f from being rewritten into SSA form.  */
+       foo (&i, &f);
+       i = 0;
+       f = 1.0;
+       p = (int *)&f;
+       __builtin_memcpy (&i, p, 4);
+       if (*(float *)&i != 1.0)
+ 	__builtin_abort ();
+     }
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/tree-prof/stringop-1.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-prof/stringop-1.c	(revision 161051)
--- gcc/testsuite/gcc.dg/tree-prof/stringop-1.c	(working copy)
*************** main()
*** 16,22 ****
  /* { dg-final-use { scan-tree-dump "Single value 4 stringop" "tree_profile"} } */
  /* Really this ought to simplify into assignment, but we are not there yet.  */
  /* a[0] = b[0] is what we fold the resulting memcpy into.  */
! /* { dg-final-use { scan-tree-dump "a.0. = " "optimized"} } */
! /* { dg-final-use { scan-tree-dump "= b.0." "optimized"} } */
  /* { dg-final-use { cleanup-tree-dump "optimized" } } */
  /* { dg-final-use { cleanup-tree-dump "tree_profile" } } */
--- 16,22 ----
  /* { dg-final-use { scan-tree-dump "Single value 4 stringop" "tree_profile"} } */
  /* Really this ought to simplify into assignment, but we are not there yet.  */
  /* a[0] = b[0] is what we fold the resulting memcpy into.  */
! /* { dg-final-use { scan-tree-dump " = MEM.*&b" "optimized"} } */
! /* { dg-final-use { scan-tree-dump "MEM.*&a\\\] = " "optimized"} } */
  /* { dg-final-use { cleanup-tree-dump "optimized" } } */
  /* { dg-final-use { cleanup-tree-dump "tree_profile" } } */
Index: gcc/testsuite/gfortran.dg/array_memcpy_3.f90
===================================================================
*** gcc/testsuite/gfortran.dg/array_memcpy_3.f90	(revision 161051)
--- gcc/testsuite/gfortran.dg/array_memcpy_3.f90	(working copy)
*************** subroutine bar(x)
*** 11,15 ****
    x = (/ 3, 1, 4, 1 /)
  end subroutine
  
! ! { dg-final { scan-tree-dump-times "memcpy|ref-all" 2 "original" } }
  ! { dg-final { cleanup-tree-dump "original" } }
--- 11,15 ----
    x = (/ 3, 1, 4, 1 /)
  end subroutine
  
! ! { dg-final { scan-tree-dump-times "memcpy|(ref-all.*ref-all)" 2 "original" } }
  ! { dg-final { cleanup-tree-dump "original" } }
Index: gcc/testsuite/gfortran.dg/array_memcpy_4.f90
===================================================================
*** gcc/testsuite/gfortran.dg/array_memcpy_4.f90	(revision 161051)
--- gcc/testsuite/gfortran.dg/array_memcpy_4.f90	(working copy)
***************
*** 9,13 ****
  
    d = s
  end
! ! { dg-final { scan-tree-dump-times "d = " 1 "original" } }
  ! { dg-final { cleanup-tree-dump "original" } }
--- 9,13 ----
  
    d = s
  end
! ! { dg-final { scan-tree-dump-times "MEM.*d\\\] = MEM" 1 "original" } }
  ! { dg-final { cleanup-tree-dump "original" } }



More information about the Gcc-patches mailing list