2008-06-09 J"orn Rennecke PR39350: * doc/tm.texi (CAN_MOVE_BY_PIECES): Document. * expr.c (emit_block_move_via_movmem): No longer static. (can_move_by_pieces): New argument consider_movmem. Changed all callers. (expand_constructor): Use can_move_by_pieces. * expr.h (emit_block_move_via_movmem): Declare. (can_move_by_pieces): Adjust declaration. * builtins.c (expand_builtin_mempcpy): Use target. Use emit_block_move_via_movmem. Index: gcc/gcc/doc/tm.texi =================================================================== --- gcc/gcc/doc/tm.texi (revision 144476) +++ gcc/gcc/doc/tm.texi (working copy) @@ -5969,6 +5969,13 @@ will be used. Defaults to 1 if @code{mo than @code{MOVE_RATIO}. @end defmac +@defmac CAN_MOVE_BY_PIECES (@var{size}, @var{alignment}) +A C expression used to determine whether a chunk of memory is to be copied +in pieces either by @code{move_by_pieces}, or by a movmem expander. This +is used by other optimizers that want to anticipate how a block copy is +going to be done. If not defined, MOVE_BY_PIECES_P is used instead. +@end defmac + @defmac MOVE_MAX_PIECES A C expression used by @code{move_by_pieces} to determine the largest unit a load or store used to copy memory is. Defaults to @code{MOVE_MAX}. Index: gcc/gcc/value-prof.c =================================================================== --- gcc/gcc/value-prof.c (revision 144476) +++ gcc/gcc/value-prof.c (working copy) @@ -1412,7 +1412,7 @@ gimple_stringops_transform (gimple_stmt_ case BUILT_IN_MEMPCPY: src = gimple_call_arg (stmt, 1); src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); - if (!can_move_by_pieces (val, MIN (dest_align, src_align))) + if (!can_move_by_pieces (val, MIN (dest_align, src_align), 1)) return false; break; case BUILT_IN_MEMSET: Index: gcc/gcc/builtins.c =================================================================== --- gcc/gcc/builtins.c (revision 144476) +++ gcc/gcc/builtins.c (working copy) @@ -3525,7 +3525,8 @@ expand_builtin_mempcpy_args (tree dest, if (GET_CODE (len_rtx) == CONST_INT && can_move_by_pieces (INTVAL (len_rtx), - MIN (dest_align, src_align))) + MIN (dest_align, src_align), + 0)) { dest_mem = get_memory_rtx (dest, len); set_mem_align (dest_mem, dest_align); @@ -3533,12 +3534,30 @@ expand_builtin_mempcpy_args (tree dest, set_mem_align (src_mem, src_align); dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx), MIN (dest_align, src_align), endp); - dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); + dest_mem = force_operand (XEXP (dest_mem, 0), target); dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } + else + { + unsigned int align = MIN (dest_align, src_align); - return NULL_RTX; + dest_mem = get_memory_rtx (dest, len); + set_mem_align (dest_mem, dest_align); + src_mem = get_memory_rtx (src, len); + set_mem_align (src_mem, src_align); + if (!emit_block_move_via_movmem (dest_mem, src_mem, len_rtx, align, + 0, -1)) + return NULL_RTX; + dest_mem = XEXP (dest_mem, 0); + if (endp) + dest_mem = gen_rtx_PLUS (GET_MODE (dest_mem), dest_mem, + (endp == 2 + ? plus_constant (len_rtx, -1) : len_rtx)); + dest_mem = convert_memory_address (ptr_mode, + force_operand (dest_mem, target)); + return dest_mem; + } } } Index: gcc/gcc/expr.c =================================================================== --- gcc/gcc/expr.c (revision 144476) +++ gcc/gcc/expr.c (working copy) @@ -127,7 +127,6 @@ static unsigned HOST_WIDE_INT move_by_pi static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode, struct move_by_pieces *); static bool block_move_libcall_safe_for_call_parm (void); -static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT); static tree emit_block_move_libcall_fn (int); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode); @@ -868,13 +867,20 @@ convert_modes (enum machine_mode mode, e #define STORE_MAX_PIECES MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT)) /* Determine whether the LEN bytes can be moved by using several move - instructions. Return nonzero if a call to move_by_pieces should - succeed. */ + instructions. If consider_movmem is false: Return nonzero if a call + to move_by_pieces should should be done for this move. + If consider_movmem is true: Return nonzero if we want to do this move + in pieces, either via move_by_pieces, or via movmem. */ int can_move_by_pieces (unsigned HOST_WIDE_INT len, - unsigned int align ATTRIBUTE_UNUSED) + unsigned int align ATTRIBUTE_UNUSED, + bool consider_movmem ATTRIBUTE_UNUSED) { +#ifdef CAN_MOVE_BY_PIECES + if (consider_movmem) + return CAN_MOVE_BY_PIECES (len, align); +#endif return MOVE_BY_PIECES_P (len, align); } @@ -1302,7 +1308,7 @@ block_move_libcall_safe_for_call_parm (v /* A subroutine of emit_block_move. Expand a movmem pattern; return true if successful. */ -static bool +bool emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, unsigned int expected_align, HOST_WIDE_INT expected_size) { @@ -6988,9 +6994,9 @@ expand_constructor (tree exp, rtx target && ! (target != 0 && safe_from_p (target, exp, 1))) || TREE_ADDRESSABLE (exp) || (host_integerp (TYPE_SIZE_UNIT (type), 1) - && (! MOVE_BY_PIECES_P + && (! can_move_by_pieces (tree_low_cst (TYPE_SIZE_UNIT (type), 1), - TYPE_ALIGN (type))) + TYPE_ALIGN (type), 1)) && ! mostly_zeros_p (exp)))) || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS) && TREE_CONSTANT (exp))) Index: gcc/gcc/expr.h =================================================================== --- gcc/gcc/expr.h (revision 144476) +++ gcc/gcc/expr.h (working copy) @@ -412,6 +412,8 @@ extern rtx emit_block_move (rtx, rtx, rt extern rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool); extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods, unsigned int, HOST_WIDE_INT); +extern bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, + unsigned, HOST_WIDE_INT); /* Copy all or part of a value X into registers starting at REGNO. The number of registers to be filled is NREGS. */ @@ -470,7 +472,7 @@ extern bool set_storage_via_setmem (rtx, /* Determine whether the LEN bytes can be moved by using several move instructions. Return nonzero if a call to move_by_pieces should succeed. */ -extern int can_move_by_pieces (unsigned HOST_WIDE_INT, unsigned int); +extern int can_move_by_pieces (unsigned HOST_WIDE_INT, unsigned int, bool); /* Return nonzero if it is desirable to store LEN bytes generated by CONSTFUN with several move instructions by store_by_pieces Index: gcc/gcc/gimplify.c =================================================================== --- gcc/gcc/gimplify.c (revision 144476) +++ gcc/gcc/gimplify.c (working copy) @@ -3616,7 +3616,7 @@ gimplify_init_constructor (tree *expr_p, if (size > 0 && num_nonzero_elements > 1 - && !can_move_by_pieces (size, align)) + && !can_move_by_pieces (size, align, 1)) { tree new_tree;