builtins.c (expand_builtin_memcpy): Remove endp argument and endp != 0 handling.
* builtins.c (expand_builtin_memcpy): Remove endp argument and endp != 0 handling. Pass 0 to store_by_pieces. (expand_builtin_mempcpy): Add endp argument. Don't call expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces directly. If ignoring result, only do expand_call. (expand_builtin_stpcpy): Likewise. Call expand_builtin_mempcpy otherwise. (expand_builtin_strncpy, expand_builtin_memset): Adjust store_by_pices callers. (expand_builtin): Adjust expand_builtin_memcpy and expand_builtin_mempcpy callers. * expr.c (can_move_by_pieces): New function. (move_by_pieces): Add endp argument, return to resp. memory at end or one byte earlier depending on endp. (store_by_pieces): Likewise. (emit_block_move): Adjust call to move_by_pieces. (emit_push_insn): Adjust move_by_pieces caller. * expr.h (can_move_by_pieces): New prototype. (store_by_pieces): Adjust prototypes. * rtl.h (move_by_pieces): Adjust prototype. * config/mips/mips.c (expand_block_move): Adjust move_by_pieces caller. * gcc.c-torture/execute/builtins/string-4.c (main_test): Remove mempcpy test with post-increments. * gcc.c-torture/execute/string-opt-3.c: New test. * gcc.dg/string-opt-1.c: New test. From-SVN: r67358
This commit is contained in:
parent
cc6a602b27
commit
8fd3cf4e17
@ -1,3 +1,28 @@
|
||||
2003-06-03 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* builtins.c (expand_builtin_memcpy): Remove endp argument and endp
|
||||
!= 0 handling. Pass 0 to store_by_pieces.
|
||||
(expand_builtin_mempcpy): Add endp argument. Don't call
|
||||
expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces
|
||||
directly. If ignoring result, only do expand_call.
|
||||
(expand_builtin_stpcpy): Likewise. Call expand_builtin_mempcpy
|
||||
otherwise.
|
||||
(expand_builtin_strncpy, expand_builtin_memset): Adjust
|
||||
store_by_pices callers.
|
||||
(expand_builtin): Adjust expand_builtin_memcpy and
|
||||
expand_builtin_mempcpy callers.
|
||||
* expr.c (can_move_by_pieces): New function.
|
||||
(move_by_pieces): Add endp argument, return to resp. memory at end
|
||||
or one byte earlier depending on endp.
|
||||
(store_by_pieces): Likewise.
|
||||
(emit_block_move): Adjust call to move_by_pieces.
|
||||
(emit_push_insn): Adjust move_by_pieces caller.
|
||||
* expr.h (can_move_by_pieces): New prototype.
|
||||
(store_by_pieces): Adjust prototypes.
|
||||
* rtl.h (move_by_pieces): Adjust prototype.
|
||||
* config/mips/mips.c (expand_block_move): Adjust move_by_pieces
|
||||
caller.
|
||||
|
||||
2003-06-03 Ben Elliston <bje@wasabisystems.com>
|
||||
|
||||
* doc/md.texi (Processor pipeline description): Improve wording.
|
||||
|
177
gcc/builtins.c
177
gcc/builtins.c
@ -125,9 +125,9 @@ static rtx expand_builtin_strspn PARAMS ((tree, rtx,
|
||||
static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode, int));
|
||||
static rtx expand_builtin_mempcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_mempcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode, int));
|
||||
static rtx expand_builtin_memmove PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_bcopy PARAMS ((tree));
|
||||
@ -2274,16 +2274,12 @@ builtin_memcpy_read_str (data, offset, mode)
|
||||
/* Expand a call to the memcpy builtin, with arguments in ARGLIST.
|
||||
Return 0 if we failed, the caller should emit a normal call,
|
||||
otherwise try to get the result in TARGET, if convenient (and in
|
||||
mode MODE if that's convenient). If ENDP is 0 return the
|
||||
destination pointer, if ENDP is 1 return the end pointer ala
|
||||
mempcpy, and if ENDP is 2 return the end pointer minus one ala
|
||||
stpcpy. */
|
||||
mode MODE if that's convenient). */
|
||||
static rtx
|
||||
expand_builtin_memcpy (arglist, target, mode, endp)
|
||||
expand_builtin_memcpy (arglist, target, mode)
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
int endp;
|
||||
{
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
@ -2294,7 +2290,6 @@ expand_builtin_memcpy (arglist, target, mode, endp)
|
||||
tree src = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
const char *src_str;
|
||||
|
||||
unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
|
||||
unsigned int dest_align
|
||||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
@ -2331,28 +2326,15 @@ expand_builtin_memcpy (arglist, target, mode, endp)
|
||||
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
|
||||
(PTR) src_str, dest_align))
|
||||
{
|
||||
store_by_pieces (dest_mem, INTVAL (len_rtx),
|
||||
builtin_memcpy_read_str,
|
||||
(PTR) src_str, dest_align);
|
||||
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
|
||||
builtin_memcpy_read_str,
|
||||
(PTR) src_str, dest_align, 0);
|
||||
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
dest_mem = convert_memory_address (ptr_mode, dest_mem);
|
||||
#endif
|
||||
if (endp)
|
||||
{
|
||||
rtx result;
|
||||
rtx delta = len_rtx;
|
||||
|
||||
if (endp == 2)
|
||||
delta = GEN_INT (INTVAL (delta) - 1);
|
||||
|
||||
result = simplify_gen_binary (PLUS, GET_MODE (dest_mem),
|
||||
dest_mem, delta);
|
||||
return force_operand (result, NULL_RTX);
|
||||
}
|
||||
else
|
||||
return dest_mem;
|
||||
return dest_mem;
|
||||
}
|
||||
|
||||
src_mem = get_memory_rtx (src);
|
||||
@ -2370,61 +2352,112 @@ expand_builtin_memcpy (arglist, target, mode, endp)
|
||||
dest_addr = convert_memory_address (ptr_mode, dest_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (endp)
|
||||
{
|
||||
rtx result = force_operand (len_rtx, NULL_RTX);
|
||||
|
||||
if (endp == 2)
|
||||
{
|
||||
result = simplify_gen_binary (MINUS, GET_MODE (dest_addr),
|
||||
result, const1_rtx);
|
||||
result = force_operand (result, NULL_RTX);
|
||||
}
|
||||
|
||||
result = simplify_gen_binary (PLUS, GET_MODE (dest_addr),
|
||||
dest_addr, result);
|
||||
return force_operand (result, NULL_RTX);
|
||||
}
|
||||
else
|
||||
return dest_addr;
|
||||
return dest_addr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
|
||||
Return 0 if we failed the caller should emit a normal call,
|
||||
otherwise try to get the result in TARGET, if convenient (and in
|
||||
mode MODE if that's convenient). */
|
||||
mode MODE if that's convenient). If ENDP is 0 return the
|
||||
destination pointer, if ENDP is 1 return the end pointer ala
|
||||
mempcpy, and if ENDP is 2 return the end pointer minus one ala
|
||||
stpcpy. */
|
||||
|
||||
static rtx
|
||||
expand_builtin_mempcpy (arglist, target, mode)
|
||||
expand_builtin_mempcpy (arglist, target, mode, endp)
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
int endp;
|
||||
{
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
/* If return value is ignored, transform mempcpy into memcpy. */
|
||||
else if (target == const0_rtx)
|
||||
{
|
||||
tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
|
||||
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
return expand_expr (build_function_call_expr (fn, arglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If return value is ignored, transform mempcpy into memcpy. */
|
||||
if (target == const0_rtx)
|
||||
tree dest = TREE_VALUE (arglist);
|
||||
tree src = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
const char *src_str;
|
||||
unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
|
||||
unsigned int dest_align
|
||||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
rtx dest_mem, src_mem, len_rtx;
|
||||
|
||||
/* If DEST is not a pointer type or LEN is not constant,
|
||||
call the normal function. */
|
||||
if (dest_align == 0 || !host_integerp (len, 1))
|
||||
return 0;
|
||||
|
||||
/* If the LEN parameter is zero, return DEST. */
|
||||
if (tree_low_cst (len, 1) == 0)
|
||||
{
|
||||
tree fn;
|
||||
rtx ret = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
return expand_expr (build_function_call_expr (fn, arglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
/* Evaluate and ignore SRC in case it has side-effects. */
|
||||
expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
return expand_expr (dest, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
return expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
|
||||
/* If either SRC is not a pointer type, don't do this
|
||||
operation in-line. */
|
||||
if (src_align == 0)
|
||||
return 0;
|
||||
|
||||
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
|
||||
src_str = c_getstr (src);
|
||||
|
||||
/* If SRC is a string constant and block move would be done
|
||||
by pieces, we can avoid loading the string from memory
|
||||
and only stored the computed constants. */
|
||||
if (src_str
|
||||
&& GET_CODE (len_rtx) == CONST_INT
|
||||
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
|
||||
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
|
||||
(PTR) src_str, dest_align))
|
||||
{
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
set_mem_align (dest_mem, dest_align);
|
||||
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
|
||||
builtin_memcpy_read_str,
|
||||
(PTR) src_str, dest_align, endp);
|
||||
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
dest_mem = convert_memory_address (ptr_mode, dest_mem);
|
||||
#endif
|
||||
return dest_mem;
|
||||
}
|
||||
|
||||
if (GET_CODE (len_rtx) == CONST_INT
|
||||
&& can_move_by_pieces (INTVAL (len_rtx),
|
||||
MIN (dest_align, src_align)))
|
||||
{
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
set_mem_align (dest_mem, dest_align);
|
||||
src_mem = get_memory_rtx (src);
|
||||
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);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
dest_mem = convert_memory_address (ptr_mode, dest_mem);
|
||||
#endif
|
||||
return dest_mem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2563,13 +2596,7 @@ expand_builtin_stpcpy (arglist, target, mode)
|
||||
/* If return value is ignored, transform stpcpy into strcpy. */
|
||||
if (target == const0_rtx)
|
||||
{
|
||||
tree fn;
|
||||
rtx ret = expand_builtin_strcpy (arglist, target, mode);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fn = implicit_built_in_decls[BUILT_IN_STRCPY];
|
||||
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
@ -2577,7 +2604,7 @@ expand_builtin_stpcpy (arglist, target, mode)
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* Ensure we get an actual string who length can be evaluated at
|
||||
/* Ensure we get an actual string whose length can be evaluated at
|
||||
compile-time, not an expression containing a string. This is
|
||||
because the latter will potentially produce pessimized code
|
||||
when used to produce the return value. */
|
||||
@ -2588,7 +2615,7 @@ expand_builtin_stpcpy (arglist, target, mode)
|
||||
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
|
||||
newarglist = copy_list (arglist);
|
||||
chainon (newarglist, build_tree_list (NULL_TREE, len));
|
||||
return expand_builtin_memcpy (newarglist, target, mode, /*endp=*/2);
|
||||
return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2670,7 +2697,7 @@ expand_builtin_strncpy (arglist, target, mode)
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
store_by_pieces (dest_mem, tree_low_cst (len, 1),
|
||||
builtin_strncpy_read_str,
|
||||
(PTR) p, dest_align);
|
||||
(PTR) p, dest_align, 0);
|
||||
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
@ -2798,7 +2825,7 @@ expand_builtin_memset (arglist, target, mode)
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
store_by_pieces (dest_mem, tree_low_cst (len, 1),
|
||||
builtin_memset_gen_str,
|
||||
(PTR) val_rtx, dest_align);
|
||||
(PTR) val_rtx, dest_align, 0);
|
||||
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
@ -2822,7 +2849,7 @@ expand_builtin_memset (arglist, target, mode)
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
store_by_pieces (dest_mem, tree_low_cst (len, 1),
|
||||
builtin_memset_read_str,
|
||||
(PTR) &c, dest_align);
|
||||
(PTR) &c, dest_align, 0);
|
||||
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
@ -4698,13 +4725,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMCPY:
|
||||
target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
|
||||
target = expand_builtin_memcpy (arglist, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMPCPY:
|
||||
target = expand_builtin_mempcpy (arglist, target, mode);
|
||||
target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
@ -3821,7 +3821,7 @@ expand_block_move (operands)
|
||||
|
||||
else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES
|
||||
&& align == (unsigned) UNITS_PER_WORD)
|
||||
move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD);
|
||||
move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD, 0);
|
||||
|
||||
else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES)
|
||||
emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
|
||||
|
98
gcc/expr.c
98
gcc/expr.c
@ -1456,6 +1456,18 @@ convert_modes (mode, oldmode, x, unsignedp)
|
||||
|
||||
#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. */
|
||||
|
||||
int
|
||||
can_move_by_pieces (len, align)
|
||||
unsigned HOST_WIDE_INT len;
|
||||
unsigned int align;
|
||||
{
|
||||
return MOVE_BY_PIECES_P (len, align);
|
||||
}
|
||||
|
||||
/* Generate several move instructions to copy LEN bytes from block FROM to
|
||||
block TO. (These are MEM rtx's with BLKmode). The caller must pass FROM
|
||||
and TO through protect_from_queue before calling.
|
||||
@ -1463,13 +1475,18 @@ convert_modes (mode, oldmode, x, unsignedp)
|
||||
If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
|
||||
used to push FROM to the stack.
|
||||
|
||||
ALIGN is maximum stack alignment we can assume. */
|
||||
ALIGN is maximum stack alignment we can assume.
|
||||
|
||||
void
|
||||
move_by_pieces (to, from, len, align)
|
||||
If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
|
||||
mempcpy, and if ENDP is 2 return memory the end minus one byte ala
|
||||
stpcpy. */
|
||||
|
||||
rtx
|
||||
move_by_pieces (to, from, len, align, endp)
|
||||
rtx to, from;
|
||||
unsigned HOST_WIDE_INT len;
|
||||
unsigned int align;
|
||||
int endp;
|
||||
{
|
||||
struct move_by_pieces data;
|
||||
rtx to_addr, from_addr = XEXP (from, 0);
|
||||
@ -1583,6 +1600,36 @@ move_by_pieces (to, from, len, align)
|
||||
/* The code above should have handled everything. */
|
||||
if (data.len > 0)
|
||||
abort ();
|
||||
|
||||
if (endp)
|
||||
{
|
||||
rtx to1;
|
||||
|
||||
if (data.reverse)
|
||||
abort ();
|
||||
if (data.autinc_to)
|
||||
{
|
||||
if (endp == 2)
|
||||
{
|
||||
if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
|
||||
emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
|
||||
else
|
||||
data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
|
||||
-1));
|
||||
}
|
||||
to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
|
||||
data.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endp == 2)
|
||||
--data.offset;
|
||||
to1 = adjust_address (data.to, QImode, data.offset);
|
||||
}
|
||||
return to1;
|
||||
}
|
||||
else
|
||||
return data.to;
|
||||
}
|
||||
|
||||
/* Return number of insns required to move L bytes by pieces.
|
||||
@ -1760,7 +1807,7 @@ emit_block_move (x, y, size, method)
|
||||
}
|
||||
|
||||
if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
|
||||
move_by_pieces (x, y, INTVAL (size), align);
|
||||
move_by_pieces (x, y, INTVAL (size), align, 0);
|
||||
else if (emit_block_move_via_movstr (x, y, size, align))
|
||||
;
|
||||
else if (may_use_call)
|
||||
@ -2014,7 +2061,7 @@ init_block_move_fn (asmspec)
|
||||
{
|
||||
if (!block_move_fn)
|
||||
{
|
||||
tree fn, args;
|
||||
tree args, fn;
|
||||
|
||||
if (TARGET_MEM_FUNCTIONS)
|
||||
{
|
||||
@ -2738,15 +2785,19 @@ can_store_by_pieces (len, constfun, constfundata, align)
|
||||
/* Generate several move instructions to store LEN bytes generated by
|
||||
CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a
|
||||
pointer which will be passed as argument in every CONSTFUN call.
|
||||
ALIGN is maximum alignment we can assume. */
|
||||
ALIGN is maximum alignment we can assume.
|
||||
If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
|
||||
mempcpy, and if ENDP is 2 return memory the end minus one byte ala
|
||||
stpcpy. */
|
||||
|
||||
void
|
||||
store_by_pieces (to, len, constfun, constfundata, align)
|
||||
rtx
|
||||
store_by_pieces (to, len, constfun, constfundata, align, endp)
|
||||
rtx to;
|
||||
unsigned HOST_WIDE_INT len;
|
||||
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
|
||||
PTR constfundata;
|
||||
unsigned int align;
|
||||
int endp;
|
||||
{
|
||||
struct store_by_pieces data;
|
||||
|
||||
@ -2758,6 +2809,35 @@ store_by_pieces (to, len, constfun, constfundata, align)
|
||||
data.len = len;
|
||||
data.to = to;
|
||||
store_by_pieces_1 (&data, align);
|
||||
if (endp)
|
||||
{
|
||||
rtx to1;
|
||||
|
||||
if (data.reverse)
|
||||
abort ();
|
||||
if (data.autinc_to)
|
||||
{
|
||||
if (endp == 2)
|
||||
{
|
||||
if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
|
||||
emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
|
||||
else
|
||||
data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
|
||||
-1));
|
||||
}
|
||||
to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
|
||||
data.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endp == 2)
|
||||
--data.offset;
|
||||
to1 = adjust_address (data.to, QImode, data.offset);
|
||||
}
|
||||
return to1;
|
||||
}
|
||||
else
|
||||
return data.to;
|
||||
}
|
||||
|
||||
/* Generate several move instructions to clear LEN bytes of block TO. (A MEM
|
||||
@ -3872,7 +3952,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
|
||||
&& where_pad != none && where_pad != stack_direction)
|
||||
anti_adjust_stack (GEN_INT (extra));
|
||||
|
||||
move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
|
||||
move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0);
|
||||
}
|
||||
else
|
||||
#endif /* PUSH_ROUNDING */
|
||||
|
16
gcc/expr.h
16
gcc/expr.h
@ -450,6 +450,11 @@ extern void use_group_regs PARAMS ((rtx *, rtx));
|
||||
If OBJECT has BLKmode, SIZE is its length in bytes. */
|
||||
extern rtx clear_storage PARAMS ((rtx, 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 PARAMS ((unsigned HOST_WIDE_INT, unsigned int));
|
||||
|
||||
/* Return nonzero if it is desirable to store LEN bytes generated by
|
||||
CONSTFUN with several move instructions by store_by_pieces
|
||||
function. CONSTFUNDATA is a pointer which will be passed as argument
|
||||
@ -463,11 +468,12 @@ extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT,
|
||||
/* Generate several move instructions to store LEN bytes generated by
|
||||
CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a
|
||||
pointer which will be passed as argument in every CONSTFUN call.
|
||||
ALIGN is maximum alignment we can assume. */
|
||||
extern void store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
|
||||
rtx (*) (PTR, HOST_WIDE_INT,
|
||||
enum machine_mode),
|
||||
PTR, unsigned int));
|
||||
ALIGN is maximum alignment we can assume.
|
||||
Returns TO + LEN. */
|
||||
extern rtx store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
|
||||
rtx (*) (PTR, HOST_WIDE_INT,
|
||||
enum machine_mode),
|
||||
PTR, unsigned int, int));
|
||||
|
||||
/* Emit insns to set X from Y. */
|
||||
extern rtx emit_move_insn PARAMS ((rtx, rtx));
|
||||
|
@ -2141,9 +2141,9 @@ extern void emit_jump PARAMS ((rtx));
|
||||
extern int preserve_subexpressions_p PARAMS ((void));
|
||||
|
||||
/* In expr.c */
|
||||
extern void move_by_pieces PARAMS ((rtx, rtx,
|
||||
extern rtx move_by_pieces PARAMS ((rtx, rtx,
|
||||
unsigned HOST_WIDE_INT,
|
||||
unsigned int));
|
||||
unsigned int, int));
|
||||
|
||||
/* In flow.c */
|
||||
extern void recompute_reg_usage PARAMS ((rtx, int));
|
||||
|
@ -1,3 +1,10 @@
|
||||
2003-06-03 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.c-torture/execute/builtins/string-4.c (main_test): Remove
|
||||
mempcpy test with post-increments.
|
||||
* gcc.c-torture/execute/string-opt-3.c: New test.
|
||||
* gcc.dg/string-opt-1.c: New test.
|
||||
|
||||
2003-06-03 David Billinghurst (David.Billinghurst@riotinto.com)
|
||||
|
||||
PR fortran/10965
|
||||
|
@ -23,7 +23,6 @@ void
|
||||
main_test (void)
|
||||
{
|
||||
int i;
|
||||
const char *s;
|
||||
|
||||
if (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6))
|
||||
abort ();
|
||||
@ -47,9 +46,8 @@ main_test (void)
|
||||
if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) || i != 9 || memcmp (p + 20, "q23\0u", 6))
|
||||
abort ();
|
||||
|
||||
s = s1; i = 3;
|
||||
memcpy (p + 25, "QRSTU", 6);
|
||||
if (mempcpy (p + 25 + 1, s++, i++) != (p + 25 + 1 + 3) || i != 4 || s != s1 + 1 || memcmp (p + 25, "Q123U", 6))
|
||||
if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) || memcmp (p + 25, "Q123U", 6))
|
||||
abort ();
|
||||
|
||||
if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8))
|
||||
|
166
gcc/testsuite/gcc.c-torture/execute/string-opt-3.c
Normal file
166
gcc/testsuite/gcc.c-torture/execute/string-opt-3.c
Normal file
@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2003 Free Software Foundation.
|
||||
|
||||
Ensure that builtin mempcpy and stpcpy perform correctly.
|
||||
|
||||
Written by Jakub Jelinek, 21/05/2003. */
|
||||
|
||||
extern void abort (void);
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void *mempcpy (void *, const void *, size_t);
|
||||
extern int memcmp (const void *, const void *, size_t);
|
||||
extern char *stpcpy (char *, const char *);
|
||||
|
||||
long buf1[64];
|
||||
char *buf2 = (char *) (buf1 + 32);
|
||||
long buf5[20];
|
||||
char buf7[20];
|
||||
|
||||
int
|
||||
__attribute__((noinline))
|
||||
test (long *buf3, char *buf4, char *buf6, int n)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* These should probably be handled by store_by_pieces on most arches. */
|
||||
if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9
|
||||
|| memcmp (buf1, "ABCDEFGHI\0", 11))
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17
|
||||
|| memcmp (buf1, "abcdefghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6
|
||||
|| memcmp (buf1, "ABCDEFghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1
|
||||
|| memcmp (buf1, "aBCDEFghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4
|
||||
|| memcmp (buf1, "aBcdEFghijklmnopq\0", 19)
|
||||
|| i != 1)
|
||||
abort ();
|
||||
|
||||
/* These should probably be handled by move_by_pieces on most arches. */
|
||||
if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10
|
||||
|| memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1)
|
||||
!= (char *) buf1 + 11
|
||||
|| memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19)
|
||||
|| i != 2)
|
||||
abort ();
|
||||
|
||||
if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16
|
||||
|| memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8
|
||||
|| memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17
|
||||
|| memcmp (buf1, "RSTUVWXYZ01234567\0", 19))
|
||||
abort ();
|
||||
|
||||
__builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19);
|
||||
|
||||
/* These should be handled either by movstrendM or mempcpy
|
||||
call. */
|
||||
if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10
|
||||
|| memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, n + 1)
|
||||
!= (char *) buf1 + 12
|
||||
|| memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19)
|
||||
|| i != 3)
|
||||
abort ();
|
||||
|
||||
if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16
|
||||
|| memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19))
|
||||
abort ();
|
||||
|
||||
i = 1;
|
||||
|
||||
/* These might be handled by store_by_pieces. */
|
||||
if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9
|
||||
|| memcmp (buf2, "ABCDEFGHI\0", 11))
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17
|
||||
|| memcmp (buf2, "abcdefghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6
|
||||
|| memcmp (buf2, "ABCDEFghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1
|
||||
|| memcmp (buf2, "aBCDEFghijklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4
|
||||
|| memcmp (buf2, "aBcdEFghijklmnopq\0", 19)
|
||||
|| i != 2)
|
||||
abort ();
|
||||
|
||||
/* These might be handled by move_by_pieces. */
|
||||
if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10
|
||||
|| memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, 1)
|
||||
!= buf2 + 11
|
||||
|| memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19)
|
||||
|| i != 3)
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16
|
||||
|| memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19))
|
||||
abort ();
|
||||
|
||||
__builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19);
|
||||
|
||||
/* These should be handled either by movstrendM or mempcpy
|
||||
call. */
|
||||
if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10
|
||||
|| memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
|
||||
abort ();
|
||||
|
||||
if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, n + 1)
|
||||
!= buf2 + 12
|
||||
|| memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19)
|
||||
|| i != 4)
|
||||
abort ();
|
||||
|
||||
if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16
|
||||
|| memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19))
|
||||
abort ();
|
||||
|
||||
/* Now stpcpy tests. */
|
||||
if (stpcpy ((char *) buf3, "abcdefghijklmnop") != (char *) buf1 + 16
|
||||
|| memcmp (buf1, "abcdefghijklmnop", 17))
|
||||
abort ();
|
||||
|
||||
if (__builtin_stpcpy ((char *) buf3, "ABCDEFG") != (char *) buf1 + 7
|
||||
|| memcmp (buf1, "ABCDEFG\0ijklmnop", 17))
|
||||
abort ();
|
||||
|
||||
if (stpcpy ((char *) buf3 + i++, "x") != (char *) buf1 + 5
|
||||
|| memcmp (buf1, "ABCDx\0G\0ijklmnop", 17))
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
__builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20);
|
||||
__builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20);
|
||||
return test (buf1, buf2, "rstuvwxyz", 0);
|
||||
}
|
11
gcc/testsuite/gcc.dg/string-opt-1.c
Normal file
11
gcc/testsuite/gcc.dg/string-opt-1.c
Normal file
@ -0,0 +1,11 @@
|
||||
/* Ensure mempcpy is not "optimized" into memcpy followed by addition. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
void *
|
||||
fn (char *x, char *y, int z)
|
||||
{
|
||||
return __builtin_mempcpy (x, y, z);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "memcpy" } } */
|
Loading…
Reference in New Issue
Block a user