diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4b61173e2934..5ef81903a9f6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2008-11-20 Jakub Jelinek + PR middle-end/29215 + * builtins.c (SLOW_UNALIGNED_ACCESS): Define if not defined. + (fold_builtin_memory_op): Handle even the case where just one + of src and dest is an address of a var decl component, using + TYPE_REF_CAN_ALIAS_ALL pointers. Remove is_gimple_min_invariant + and readonly_data_expr src check. + * tree-ssa-sccvn.c (DFS): Use clear_and_done_ssa_iter to shut + up warnings. + PR rtl-optimization/36998 * dwarf2out.c (stack_adjust_offset): Add cur_args_size and cur_offset arguments. Handle sp = reg and (set (foo) (mem (pre_inc (reg sp)))). diff --git a/gcc/builtins.c b/gcc/builtins.c index fd6d0b859e00..0e5b834fde45 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -51,6 +51,10 @@ along with GCC; see the file COPYING3. If not see #include "value-prof.h" #include "diagnostic.h" +#ifndef SLOW_UNALIGNED_ACCESS +#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT +#endif + #ifndef PAD_VARARGS_DOWN #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN #endif @@ -8824,10 +8828,12 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i else { tree srctype, desttype; + int src_align, dest_align; + if (endp == 3) { - int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); - int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); + dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); /* Both DEST and SRC must be pointer types. ??? This is what old code did. Is the testing for pointer types @@ -8862,44 +8868,95 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i || !TYPE_SIZE_UNIT (srctype) || !TYPE_SIZE_UNIT (desttype) || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST - || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST - || !tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len) - || !tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len)) + || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST) return NULL_TREE; - if (get_pointer_alignment (dest, BIGGEST_ALIGNMENT) - < (int) TYPE_ALIGN (desttype) - || (get_pointer_alignment (src, BIGGEST_ALIGNMENT) - < (int) TYPE_ALIGN (srctype))) + src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); + dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + if (dest_align < (int) TYPE_ALIGN (desttype) + || src_align < (int) TYPE_ALIGN (srctype)) return NULL_TREE; if (!ignore) dest = builtin_save_expr (dest); - srcvar = build_fold_indirect_ref (src); - if (TREE_THIS_VOLATILE (srcvar)) - return NULL_TREE; - if (!tree_int_cst_equal (lang_hooks.expr_size (srcvar), len)) - return 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. */ - if (!var_decl_component_p (srcvar) - /* Accept: memcpy (*char_var, "test", 1); that simplify - to char_var='t'; */ - || is_gimple_min_invariant (srcvar) - || readonly_data_expr (src)) + srcvar = NULL_TREE; + if (tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len)) + { + srcvar = build_fold_indirect_ref (src); + if (TREE_THIS_VOLATILE (srcvar)) + srcvar = NULL_TREE; + else if (!tree_int_cst_equal (lang_hooks.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 (dest); + if (TREE_THIS_VOLATILE (destvar)) + destvar = NULL_TREE; + else if (!tree_int_cst_equal (lang_hooks.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; - destvar = build_fold_indirect_ref (dest); - if (TREE_THIS_VOLATILE (destvar)) - return NULL_TREE; - if (!tree_int_cst_equal (lang_hooks.expr_size (destvar), len)) - return NULL_TREE; - if (!var_decl_component_p (destvar)) - return NULL_TREE; + if (srcvar == NULL_TREE) + { + tree srcptype; + if (TREE_ADDRESSABLE (TREE_TYPE (destvar))) + return NULL_TREE; + + srctype = desttype; + 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 (srcptype, src); + srcvar = build_fold_indirect_ref (src); + } + else if (destvar == NULL_TREE) + { + tree destptype; + if (TREE_ADDRESSABLE (TREE_TYPE (srcvar))) + return NULL_TREE; + + desttype = srctype; + 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 (destptype, dest); + destvar = build_fold_indirect_ref (dest); + } if (srctype == desttype || (gimple_in_ssa_p (cfun) diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 1316eb679b93..941186fcbd57 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,9 @@ 2008-11-20 Jakub Jelinek + PR middle-end/29215 + * trans-array.c (trans_array_constructor_value, + gfc_build_constant_array_constructor): Fill in TREE_PURPOSE. + * trans-intrinsic.c (gfc_conv_intrinsic_minmaxloc): Use gfc_index_one_node. (gfc_conv_intrinsic_size): Use gfc_index_{zero,one}_node. diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 9c48c421465f..1385409808e4 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -1235,6 +1235,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type, tree init; tree bound; tree tmptype; + HOST_WIDE_INT idx = 0; p = c; list = NULL_TREE; @@ -1253,7 +1254,8 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type, (gfc_get_pchar_type (p->expr->ts.kind), se.expr); - list = tree_cons (NULL_TREE, se.expr, list); + list = tree_cons (build_int_cst (gfc_array_index_type, + idx++), se.expr, list); c = p; p = p->next; } @@ -1619,7 +1621,8 @@ gfc_build_constant_array_constructor (gfc_expr * expr, tree type) if (c->expr->ts.type == BT_CHARACTER && POINTER_TYPE_P (type)) se.expr = gfc_build_addr_expr (gfc_get_pchar_type (c->expr->ts.kind), se.expr); - list = tree_cons (NULL_TREE, se.expr, list); + list = tree_cons (build_int_cst (gfc_array_index_type, nelem), + se.expr, list); c = c->next; nelem++; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6eaad340c00d..3a767f1d0ba8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-11-20 Jakub Jelinek + + PR middle-end/29215 + * gfortran.dg/array_memcpy_3.f90: Adjust pattern to match even + memcpy optimized into ref-all store. + * gcc.dg/pr29215.c: New test. + 2008-11-19 Uros Bizjak PR target/38151 diff --git a/gcc/testsuite/gcc.dg/pr29215.c b/gcc/testsuite/gcc.dg/pr29215.c new file mode 100644 index 000000000000..aa3f82ce0e14 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr29215.c @@ -0,0 +1,33 @@ +/* PR middle-end/29215 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-gimple" } */ + +char buf[5 * sizeof (int) + 1] __attribute__((aligned (__alignof__ (int)))); + +static void +foo (int arg1, int arg2, int arg3, int arg4, int arg5) +{ + __builtin_memcpy (buf, &arg1, sizeof (int)); + __builtin_memcpy (buf + sizeof (int), &arg2, sizeof (int)); + __builtin_memcpy (buf + 2 * sizeof (int), &arg3, sizeof (int)); + __builtin_memcpy (buf + 3 * sizeof (int), &arg4, sizeof (int)); + __builtin_memcpy (buf + 4 * sizeof (int), &arg5, sizeof (int)); +} + +int +main (void) +{ + union { char buf[4]; int i; } u; + u.i = 0; + u.buf[0] = 'a'; + u.buf[1] = 'b'; + u.buf[2] = 'c'; + u.buf[3] = 'd'; + foo (u.i, u.i, u.i, u.i, u.i); + buf[5 * sizeof (int)] = '\0'; + __builtin_puts (buf); + return 0; +} + +/* { dg-final { scan-tree-dump-not "memcpy" "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/gfortran.dg/array_memcpy_3.f90 b/gcc/testsuite/gfortran.dg/array_memcpy_3.f90 index 05915877b159..df6bd49ef26e 100644 --- a/gcc/testsuite/gfortran.dg/array_memcpy_3.f90 +++ b/gcc/testsuite/gfortran.dg/array_memcpy_3.f90 @@ -11,5 +11,5 @@ subroutine bar(x) x = (/ 3, 1, 4, 1 /) end subroutine -! { dg-final { scan-tree-dump-times "memcpy" 2 "original" } } +! { dg-final { scan-tree-dump-times "memcpy|ref-all" 2 "original" } } ! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 80f7a92c3dce..e40681f93554 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -2654,7 +2654,7 @@ start_over: usep = op_iter_init_use (&iter, defstmt, SSA_OP_ALL_USES); } else - iter.done = true; + clear_and_done_ssa_iter (&iter); while (1) {