aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2008-11-20 22:35:03 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2008-11-20 22:35:03 +0100
commit81f5094da422fbdf4f76e80f6dbc52df91582a46 (patch)
tree0cc48991865f78326414c0d9ce7c0db3f4e962e0 /gcc/builtins.c
parent1fd8faf0599d4054a7a6118c35fc0ef6c2db5e4a (diff)
downloadgcc-81f5094da422fbdf4f76e80f6dbc52df91582a46.zip
gcc-81f5094da422fbdf4f76e80f6dbc52df91582a46.tar.gz
gcc-81f5094da422fbdf4f76e80f6dbc52df91582a46.tar.bz2
re PR middle-end/29215 (extra store for memcpy)
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. * trans-array.c (trans_array_constructor_value, gfc_build_constant_array_constructor): Fill in TREE_PURPOSE. * gfortran.dg/array_memcpy_3.f90: Adjust pattern to match even memcpy optimized into ref-all store. * gcc.dg/pr29215.c: New test. From-SVN: r142061
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c119
1 files changed, 88 insertions, 31 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index fd6d0b8..0e5b834 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)