[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