Commit 57814e5e by Jakub Jelinek Committed by Jakub Jelinek

expr.h (store_by_pieces): Add prototype.

	* expr.h (store_by_pieces): Add prototype.
	(can_store_by_pieces): Likewise.
	* expr.c (struct store_by_pieces): Renamed from clear_by_pieces.
	(can_store_by_pieces): New.
	(store_by_pieces): New.
	(clear_by_pieces): New.
	(clear_by_pieces_1): New.
	(store_by_pieces_1): Renamed from clear_by_pieces, handle storing
	arbitrary compiler generated constants into memory block.
	(store_by_pieces_2): Renamed from clear_by_pieces_1, likewise.
	* builtins.c (c_readstr): New.
	(builtin_memcpy_read_str): New.
	(expand_builtin_memcpy): If src is string constant and
	emit_block_move would move it by pieces, compute integer constants
	from the string and store it into memory block instead.
	(builtin_strncpy_read_str): New.
	(expand_builtin_strncpy): If N is not constant zero and c_strlen does
	not return INTEGER_CST, don't optimize.
	If N is larger than strlen(src) + 1, try to copy the string
	including padding with store_by_pieces.
	(expand_builtin_strcmp): If both arguments have side effects, don't
	optimize.
	(expand_builtin_fputs): If STR has side effects, don't optimize.

	* gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy
	tests.
	* gcc.c-torture/execute/string-opt-6.c: New test.

From-SVN: r37851
parent 3632e1ea
2000-11-29 Jakub Jelinek <jakub@redhat.com>
* expr.h (store_by_pieces): Add prototype.
(can_store_by_pieces): Likewise.
* expr.c (struct store_by_pieces): Renamed from clear_by_pieces.
(can_store_by_pieces): New.
(store_by_pieces): New.
(clear_by_pieces): New.
(clear_by_pieces_1): New.
(store_by_pieces_1): Renamed from clear_by_pieces, handle storing
arbitrary compiler generated constants into memory block.
(store_by_pieces_2): Renamed from clear_by_pieces_1, likewise.
* builtins.c (c_readstr): New.
(builtin_memcpy_read_str): New.
(expand_builtin_memcpy): If src is string constant and
emit_block_move would move it by pieces, compute integer constants
from the string and store it into memory block instead.
(builtin_strncpy_read_str): New.
(expand_builtin_strncpy): If N is not constant zero and c_strlen does
not return INTEGER_CST, don't optimize.
If N is larger than strlen(src) + 1, try to copy the string
including padding with store_by_pieces.
(expand_builtin_strcmp): If both arguments have side effects, don't
optimize.
(expand_builtin_fputs): If STR has side effects, don't optimize.
2000-11-29 Richard Earnshaw <rearnsha@arm.com> 2000-11-29 Richard Earnshaw <rearnsha@arm.com>
* arm.md (sibcall, sibcall_value, sibcall_insn, sibcall_value_insn): * arm.md (sibcall, sibcall_value, sibcall_insn, sibcall_value_insn):
......
...@@ -81,6 +81,8 @@ tree (*lang_type_promotes_to) PARAMS ((tree)); ...@@ -81,6 +81,8 @@ tree (*lang_type_promotes_to) PARAMS ((tree));
static int get_pointer_alignment PARAMS ((tree, unsigned)); static int get_pointer_alignment PARAMS ((tree, unsigned));
static tree c_strlen PARAMS ((tree)); static tree c_strlen PARAMS ((tree));
static const char *c_getstr PARAMS ((tree)); static const char *c_getstr PARAMS ((tree));
static rtx c_readstr PARAMS ((const char *,
enum machine_mode));
static rtx get_memory_rtx PARAMS ((tree)); static rtx get_memory_rtx PARAMS ((tree));
static int apply_args_size PARAMS ((void)); static int apply_args_size PARAMS ((void));
static int apply_result_size PARAMS ((void)); static int apply_result_size PARAMS ((void));
...@@ -106,8 +108,12 @@ static rtx expand_builtin_strcmp PARAMS ((tree, rtx, ...@@ -106,8 +108,12 @@ static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
enum machine_mode)); enum machine_mode));
static rtx expand_builtin_strncmp PARAMS ((tree, rtx, static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
enum machine_mode)); enum machine_mode));
static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static rtx expand_builtin_memcpy PARAMS ((tree)); static rtx expand_builtin_memcpy PARAMS ((tree));
static rtx expand_builtin_strcpy PARAMS ((tree)); static rtx expand_builtin_strcpy PARAMS ((tree));
static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static rtx expand_builtin_strncpy PARAMS ((tree, rtx, static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
enum machine_mode)); enum machine_mode));
static rtx expand_builtin_memset PARAMS ((tree)); static rtx expand_builtin_memset PARAMS ((tree));
...@@ -308,6 +314,41 @@ c_getstr (src) ...@@ -308,6 +314,41 @@ c_getstr (src)
return ptr + offset; return ptr + offset;
} }
/* Return a CONST_INT or CONST_DOUBLE corresponding to target
reading GET_MODE_BITSIZE (MODE) bits from string constant
STR. */
static rtx
c_readstr (str, mode)
const char *str;
enum machine_mode mode;
{
HOST_WIDE_INT c[2];
HOST_WIDE_INT ch;
unsigned int i, j;
if (GET_MODE_CLASS (mode) != MODE_INT)
abort ();
c[0] = 0;
c[1] = 0;
ch = 1;
for (i = 0; i < GET_MODE_SIZE (mode); i++)
{
j = i;
if (WORDS_BIG_ENDIAN)
j = GET_MODE_SIZE (mode) - i - 1;
if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
&& GET_MODE_SIZE (mode) > UNITS_PER_WORD)
j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
j *= BITS_PER_UNIT;
if (j > 2 * HOST_BITS_PER_WIDE_INT)
abort ();
if (ch)
ch = (unsigned char) str[i];
c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
}
return immed_double_const (c[0], c[1], mode);
}
/* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
times to get the address of either a higher stack frame, or a return times to get the address of either a higher stack frame, or a return
address located within it (depending on FNDECL_CODE). */ address located within it (depending on FNDECL_CODE). */
...@@ -1685,6 +1726,24 @@ expand_builtin_strpbrk (arglist, target, mode) ...@@ -1685,6 +1726,24 @@ expand_builtin_strpbrk (arglist, target, mode)
} }
} }
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
bytes from constant string DATA + OFFSET and return it as target
constant. */
static rtx
builtin_memcpy_read_str (data, offset, mode)
PTR data;
HOST_WIDE_INT offset;
enum machine_mode mode;
{
const char *str = (const char *) data;
if (offset + GET_MODE_SIZE (mode) > strlen (str) + 1)
abort (); /* Attempt to read past the end of constant string. */
return c_readstr (str + offset, mode);
}
/* Expand a call to the memcpy builtin, with arguments in ARGLIST. */ /* Expand a call to the memcpy builtin, with arguments in ARGLIST. */
static rtx static rtx
expand_builtin_memcpy (arglist) expand_builtin_memcpy (arglist)
...@@ -1706,6 +1765,7 @@ expand_builtin_memcpy (arglist) ...@@ -1706,6 +1765,7 @@ expand_builtin_memcpy (arglist)
tree dest = TREE_VALUE (arglist); tree dest = TREE_VALUE (arglist);
tree src = TREE_VALUE (TREE_CHAIN (arglist)); tree src = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
const char *src_str;
int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
...@@ -1717,8 +1777,26 @@ expand_builtin_memcpy (arglist) ...@@ -1717,8 +1777,26 @@ expand_builtin_memcpy (arglist)
return 0; return 0;
dest_mem = get_memory_rtx (dest); dest_mem = get_memory_rtx (dest);
src_mem = get_memory_rtx (src);
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 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
&& !current_function_check_memory_usage
&& 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))
{
store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
(PTR) src_str, dest_align);
return force_operand (XEXP (dest_mem, 0), NULL_RTX);
}
src_mem = get_memory_rtx (src);
/* Just copy the rights of SRC to the rights of DEST. */ /* Just copy the rights of SRC to the rights of DEST. */
if (current_function_check_memory_usage) if (current_function_check_memory_usage)
...@@ -1774,6 +1852,24 @@ expand_builtin_strcpy (exp) ...@@ -1774,6 +1852,24 @@ expand_builtin_strcpy (exp)
return result; return result;
} }
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
bytes from constant string DATA + OFFSET and return it as target
constant. */
static rtx
builtin_strncpy_read_str (data, offset, mode)
PTR data;
HOST_WIDE_INT offset;
enum machine_mode mode;
{
const char *str = (const char *) data;
if ((unsigned HOST_WIDE_INT) offset > strlen (str))
return const0_rtx;
return c_readstr (str + offset, mode);
}
/* Expand expression EXP, which is a call to the strncpy builtin. Return 0 /* Expand expression EXP, which is a call to the strncpy builtin. Return 0
if we failed the caller should emit a normal call. */ if we failed the caller should emit a normal call. */
...@@ -1814,17 +1910,35 @@ expand_builtin_strncpy (arglist, target, mode) ...@@ -1814,17 +1910,35 @@ expand_builtin_strncpy (arglist, target, mode)
return expand_expr (TREE_VALUE (arglist), target, mode, return expand_expr (TREE_VALUE (arglist), target, mode,
EXPAND_NORMAL); EXPAND_NORMAL);
} }
/* Now, we must be passed a constant src ptr parameter. */ /* Now, we must be passed a constant src ptr parameter. */
if (slen == 0) if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
return 0; return 0;
slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
/* We're required to pad with trailing zeros if the requested /* We're required to pad with trailing zeros if the requested
len is greater than strlen(s2)+1, so in that case punt. */ len is greater than strlen(s2)+1. In that case try to
use store_by_pieces, if it fails, punt. */
if (tree_int_cst_lt (slen, len)) if (tree_int_cst_lt (slen, len))
return 0; {
tree dest = TREE_VALUE (arglist);
int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
rtx dest_mem;
if (!p || !dest_align || TREE_INT_CST_HIGH (len)
|| !can_store_by_pieces (TREE_INT_CST_LOW (len),
builtin_strncpy_read_str,
(PTR) p, dest_align))
return 0;
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, TREE_INT_CST_LOW (len),
builtin_strncpy_read_str,
(PTR) p, dest_align);
return force_operand (XEXP (dest_mem, 0), NULL_RTX);
}
/* OK transform into builtin memcpy. */ /* OK transform into builtin memcpy. */
return expand_builtin_memcpy (arglist); return expand_builtin_memcpy (arglist);
...@@ -2081,7 +2195,8 @@ expand_builtin_strcmp (exp, target, mode) ...@@ -2081,7 +2195,8 @@ expand_builtin_strcmp (exp, target, mode)
/* If we don't have a constant length for the first, use the length /* If we don't have a constant length for the first, use the length
of the second, if we know it. We don't require a constant for of the second, if we know it. We don't require a constant for
this case; some cost analysis could be done if both are available this case; some cost analysis could be done if both are available
but neither is constant. For now, assume they're equally cheap. but neither is constant. For now, assume they're equally cheap
unless one has side effects.
If both strings have constant lengths, use the smaller. This If both strings have constant lengths, use the smaller. This
could arise if optimization results in strcpy being called with could arise if optimization results in strcpy being called with
...@@ -2091,7 +2206,7 @@ expand_builtin_strcmp (exp, target, mode) ...@@ -2091,7 +2206,7 @@ expand_builtin_strcmp (exp, target, mode)
if (!len || TREE_CODE (len) != INTEGER_CST) if (!len || TREE_CODE (len) != INTEGER_CST)
{ {
if (len2) if (len2 && !TREE_SIDE_EFFECTS (len2))
len = len2; len = len2;
else if (len == 0) else if (len == 0)
return 0; return 0;
...@@ -2100,6 +2215,10 @@ expand_builtin_strcmp (exp, target, mode) ...@@ -2100,6 +2215,10 @@ expand_builtin_strcmp (exp, target, mode)
&& tree_int_cst_lt (len2, len)) && tree_int_cst_lt (len2, len))
len = len2; len = len2;
/* If both arguments have side effects, we cannot optimize. */
if (TREE_SIDE_EFFECTS (len))
return 0;
chainon (arglist, build_tree_list (NULL_TREE, len)); chainon (arglist, build_tree_list (NULL_TREE, len));
result = expand_builtin_memcmp (exp, arglist, target); result = expand_builtin_memcmp (exp, arglist, target);
if (! result) if (! result)
...@@ -2760,7 +2879,8 @@ expand_builtin_fputs (arglist, ignore) ...@@ -2760,7 +2879,8 @@ expand_builtin_fputs (arglist, ignore)
/* Get the length of the string passed to fputs. If the length /* Get the length of the string passed to fputs. If the length
can't be determined, punt. */ can't be determined, punt. */
if (!(len = c_strlen (TREE_VALUE (arglist)))) if (!(len = c_strlen (TREE_VALUE (arglist)))
|| TREE_CODE (len) != INTEGER_CST)
return 0; return 0;
switch (compare_tree_int (len, 1)) switch (compare_tree_int (len, 1))
......
...@@ -127,10 +127,10 @@ struct move_by_pieces ...@@ -127,10 +127,10 @@ struct move_by_pieces
int reverse; int reverse;
}; };
/* This structure is used by clear_by_pieces to describe the clear to /* This structure is used by store_by_pieces to describe the clear to
be performed. */ be performed. */
struct clear_by_pieces struct store_by_pieces
{ {
rtx to; rtx to;
rtx to_addr; rtx to_addr;
...@@ -138,6 +138,8 @@ struct clear_by_pieces ...@@ -138,6 +138,8 @@ struct clear_by_pieces
int explicit_inc_to; int explicit_inc_to;
unsigned HOST_WIDE_INT len; unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
int reverse; int reverse;
}; };
...@@ -151,11 +153,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns ...@@ -151,11 +153,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns
unsigned int)); unsigned int));
static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode, static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *)); struct move_by_pieces *));
static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT, static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned int)); unsigned int));
static void clear_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), static void store_by_pieces_1 PARAMS ((struct store_by_pieces *,
unsigned int));
static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...),
enum machine_mode, enum machine_mode,
struct clear_by_pieces *)); struct store_by_pieces *));
static rtx get_subtarget PARAMS ((rtx)); static rtx get_subtarget PARAMS ((rtx));
static int is_zeros_p PARAMS ((tree)); static int is_zeros_p PARAMS ((tree));
static int mostly_zeros_p PARAMS ((tree)); static int mostly_zeros_p PARAMS ((tree));
...@@ -2249,6 +2255,105 @@ use_group_regs (call_fusage, regs) ...@@ -2249,6 +2255,105 @@ use_group_regs (call_fusage, regs)
} }
} }
int
can_store_by_pieces (len, constfun, constfundata, align)
unsigned HOST_WIDE_INT len;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
unsigned int align;
{
unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1, l;
HOST_WIDE_INT offset = 0;
enum machine_mode mode, tmode;
enum insn_code icode;
int reverse;
rtx cst;
if (! MOVE_BY_PIECES_P (len, align))
return 0;
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
/* We would first store what we can in the largest integer mode, then go to
successively smaller modes. */
for (reverse = 0;
reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
reverse++)
{
l = len;
mode = VOIDmode;
while (max_size > 1)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (mode == VOIDmode)
break;
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing
&& align >= GET_MODE_ALIGNMENT (mode))
{
unsigned int size = GET_MODE_SIZE (mode);
while (l >= size)
{
if (reverse)
offset -= size;
cst = (*constfun) (constfundata, offset, mode);
if (!LEGITIMATE_CONSTANT_P (cst))
return 0;
if (!reverse)
offset += size;
l -= size;
}
}
max_size = GET_MODE_SIZE (mode);
}
/* The code above should have handled everything. */
if (l != 0)
abort ();
}
return 1;
}
/* 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. */
void
store_by_pieces (to, len, constfun, constfundata, align)
rtx to;
unsigned HOST_WIDE_INT len;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
unsigned int align;
{
struct store_by_pieces data;
if (! MOVE_BY_PIECES_P (len, align))
abort ();
to = protect_from_queue (to, 1);
data.constfun = constfun;
data.constfundata = constfundata;
data.len = len;
data.to = to;
store_by_pieces_1 (&data, align);
}
/* Generate several move instructions to clear LEN bytes of block TO. (A MEM /* Generate several move instructions to clear LEN bytes of block TO. (A MEM
rtx with BLKmode). The caller must pass TO through protect_from_queue rtx with BLKmode). The caller must pass TO through protect_from_queue
before calling. ALIGN is maximum alignment we can assume. */ before calling. ALIGN is maximum alignment we can assume. */
...@@ -2259,31 +2364,59 @@ clear_by_pieces (to, len, align) ...@@ -2259,31 +2364,59 @@ clear_by_pieces (to, len, align)
unsigned HOST_WIDE_INT len; unsigned HOST_WIDE_INT len;
unsigned int align; unsigned int align;
{ {
struct clear_by_pieces data; struct store_by_pieces data;
rtx to_addr = XEXP (to, 0);
data.constfun = clear_by_pieces_1;
data.constfundata = NULL_PTR;
data.len = len;
data.to = to;
store_by_pieces_1 (&data, align);
}
/* Callback routine for clear_by_pieces.
Return const0_rtx unconditionally. */
static rtx
clear_by_pieces_1 (data, offset, mode)
PTR data ATTRIBUTE_UNUSED;
HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return const0_rtx;
}
/* Subroutine of clear_by_pieces and store_by_pieces.
Generate several move instructions to store LEN bytes of block TO. (A MEM
rtx with BLKmode). The caller must pass TO through protect_from_queue
before calling. ALIGN is maximum alignment we can assume. */
static void
store_by_pieces_1 (data, align)
struct store_by_pieces *data;
unsigned int align;
{
rtx to_addr = XEXP (data->to, 0);
unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1; unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode; enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode; enum insn_code icode;
data.offset = 0; data->offset = 0;
data.to_addr = to_addr; data->to_addr = to_addr;
data.to = to; data->autinc_to
data.autinc_to
= (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
|| GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC); || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
data.explicit_inc_to = 0; data->explicit_inc_to = 0;
data.reverse data->reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC); = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
if (data.reverse) if (data->reverse)
data.offset = len; data->offset = data->len;
data.len = len;
/* If copying requires more than two move insns, /* If storing requires more than two move insns,
copy addresses to registers (to make displacements shorter) copy addresses to registers (to make displacements shorter)
and use post-increment if available. */ and use post-increment if available. */
if (!data.autinc_to if (!data->autinc_to
&& move_by_pieces_ninsns (len, align) > 2) && move_by_pieces_ninsns (data->len, align) > 2)
{ {
/* Determine the main mode we'll be using. */ /* Determine the main mode we'll be using. */
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT); for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
...@@ -2291,30 +2424,30 @@ clear_by_pieces (to, len, align) ...@@ -2291,30 +2424,30 @@ clear_by_pieces (to, len, align)
if (GET_MODE_SIZE (tmode) < max_size) if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode; mode = tmode;
if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to) if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{ {
data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
data.autinc_to = 1; data->autinc_to = 1;
data.explicit_inc_to = -1; data->explicit_inc_to = -1;
} }
if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
&& ! data.autinc_to) && ! data->autinc_to)
{ {
data.to_addr = copy_addr_to_reg (to_addr); data->to_addr = copy_addr_to_reg (to_addr);
data.autinc_to = 1; data->autinc_to = 1;
data.explicit_inc_to = 1; data->explicit_inc_to = 1;
} }
if ( !data.autinc_to && CONSTANT_P (to_addr)) if ( !data->autinc_to && CONSTANT_P (to_addr))
data.to_addr = copy_addr_to_reg (to_addr); data->to_addr = copy_addr_to_reg (to_addr);
} }
if (! SLOW_UNALIGNED_ACCESS (word_mode, align) if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT) || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT; align = MOVE_MAX * BITS_PER_UNIT;
/* First move what we can in the largest integer mode, then go to /* First store what we can in the largest integer mode, then go to
successively smaller modes. */ successively smaller modes. */
while (max_size > 1) while (max_size > 1)
...@@ -2329,28 +2462,28 @@ clear_by_pieces (to, len, align) ...@@ -2329,28 +2462,28 @@ clear_by_pieces (to, len, align)
icode = mov_optab->handlers[(int) mode].insn_code; icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
clear_by_pieces_1 (GEN_FCN (icode), mode, &data); store_by_pieces_2 (GEN_FCN (icode), mode, data);
max_size = GET_MODE_SIZE (mode); max_size = GET_MODE_SIZE (mode);
} }
/* The code above should have handled everything. */ /* The code above should have handled everything. */
if (data.len != 0) if (data->len != 0)
abort (); abort ();
} }
/* Subroutine of clear_by_pieces. Clear as many bytes as appropriate /* Subroutine of store_by_pieces_1. Store as many bytes as appropriate
with move instructions for mode MODE. GENFUN is the gen_... function with move instructions for mode MODE. GENFUN is the gen_... function
to make a move insn for that mode. DATA has all the other info. */ to make a move insn for that mode. DATA has all the other info. */
static void static void
clear_by_pieces_1 (genfun, mode, data) store_by_pieces_2 (genfun, mode, data)
rtx (*genfun) PARAMS ((rtx, ...)); rtx (*genfun) PARAMS ((rtx, ...));
enum machine_mode mode; enum machine_mode mode;
struct clear_by_pieces *data; struct store_by_pieces *data;
{ {
unsigned int size = GET_MODE_SIZE (mode); unsigned int size = GET_MODE_SIZE (mode);
rtx to1; rtx to1, cst;
while (data->len >= size) while (data->len >= size)
{ {
...@@ -2367,9 +2500,11 @@ clear_by_pieces_1 (genfun, mode, data) ...@@ -2367,9 +2500,11 @@ clear_by_pieces_1 (genfun, mode, data)
plus_constant (data->to_addr, data->offset)); plus_constant (data->to_addr, data->offset));
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); emit_insn (gen_add2_insn (data->to_addr,
GEN_INT (-(HOST_WIDE_INT) size)));
emit_insn ((*genfun) (to1, const0_rtx)); cst = (*data->constfun) (data->constfundata, data->offset, mode);
emit_insn ((*genfun) (to1, cst));
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0) if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size))); emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
......
...@@ -1010,6 +1010,25 @@ extern void use_group_regs PARAMS ((rtx *, rtx)); ...@@ -1010,6 +1010,25 @@ extern void use_group_regs PARAMS ((rtx *, rtx));
alignment. */ alignment. */
extern rtx clear_storage PARAMS ((rtx, rtx, unsigned int)); extern rtx clear_storage PARAMS ((rtx, rtx, unsigned int));
/* Return non-zero 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
in every CONSTFUN call.
ALIGN is maximum alignment we can assume. */
extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT,
rtx (*) (PTR, HOST_WIDE_INT,
enum machine_mode),
PTR, unsigned 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));
/* Emit insns to set X from Y. */ /* Emit insns to set X from Y. */
extern rtx emit_move_insn PARAMS ((rtx, rtx)); extern rtx emit_move_insn PARAMS ((rtx, rtx));
......
2000-11-29 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy
tests.
* gcc.c-torture/execute/string-opt-6.c: New test.
2000-11-28 Geoffrey Keating <geoffk@redhat.com> 2000-11-28 Geoffrey Keating <geoffk@redhat.com>
* gcc.dg/noncompile/940510-1.c: Update to test c89 functionality. * gcc.dg/noncompile/940510-1.c: Update to test c89 functionality.
......
/* Copyright (C) 2000 Free Software Foundation. /* Copyright (C) 2000 Free Software Foundation.
Ensure builtin strlen, strcmp, strchr and strrchr perform correctly. Ensure builtin strlen, strcmp, strchr, strrchr and strncpy
perform correctly.
Written by Jakub Jelinek, 11/7/2000. */ Written by Jakub Jelinek, 11/7/2000. */
...@@ -9,13 +10,18 @@ extern __SIZE_TYPE__ strlen (const char *); ...@@ -9,13 +10,18 @@ extern __SIZE_TYPE__ strlen (const char *);
extern int strcmp (const char *, const char *); extern int strcmp (const char *, const char *);
extern char *strchr (const char *, int); extern char *strchr (const char *, int);
extern char *strrchr (const char *, int); extern char *strrchr (const char *, int);
extern char *strncpy (char *, const char *, __SIZE_TYPE__);
extern void *memset (void *, int, __SIZE_TYPE__);
extern int memcmp (const void *, const void *, __SIZE_TYPE__);
int x = 6; int x = 6;
int y = 1;
char *bar = "hi world"; char *bar = "hi world";
int main() int main()
{ {
const char *const foo = "hello world"; const char *const foo = "hello world";
char dst [64];
if (strlen (bar) != 8) if (strlen (bar) != 8)
abort (); abort ();
...@@ -53,6 +59,27 @@ int main() ...@@ -53,6 +59,27 @@ int main()
abort (); abort ();
if (strrchr (bar, 'o') != bar + 4) if (strrchr (bar, 'o') != bar + 4)
abort (); abort ();
if (strcmp (foo + (x++ & 1), "ello world" + (--y & 1)))
abort ();
if (x != 6 || y != 0)
abort ();
dst[5] = ' ';
dst[6] = '\0';
x = 5;
y = 1;
if (strncpy (dst + 1, foo + (x++ & 3), 4) != dst + 1
|| x != 6
|| strcmp (dst + 1, "ello "))
abort ();
memset (dst, ' ', sizeof dst);
if (strncpy (dst + (++x & 1), (y++ & 3) + "foo", 10) != dst + 1
|| x != 7
|| y != 2
|| memcmp (dst, " oo\0\0\0\0\0\0\0\0 ", 12))
abort ();
memset (dst, ' ', sizeof dst);
if (strncpy (dst, "hello", 8) != dst || memcmp (dst, "hello\0\0\0 ", 9))
abort();
return 0; return 0;
} }
/* Copyright (C) 2000 Free Software Foundation.
Ensure builtin memcpy and strcpy perform correctly.
Written by Jakub Jelinek, 11/24/2000. */
extern void abort (void);
extern char *strcpy (char *, const char *);
typedef __SIZE_TYPE__ size_t;
extern void *memcpy (void *, const void *, size_t);
extern int memcmp (const void *, const void *, size_t);
char p[32] = "";
int main()
{
if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
abort ();
if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5))
abort ();
if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6))
abort ();
if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9))
abort ();
if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
abort ();
if (memcpy (p + 16, "VWX" + 1, 2) != p + 16 || memcmp (p + 16, "WXyz", 5))
abort ();
if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6))
abort ();
if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHIj", 9))
abort ();
return 0;
}
#ifdef __OPTIMIZE__
/* When optimizing, all the above cases should be transformed into
something else. So any remaining calls to the original function
should abort. */
static char *
strcpy (char *d, const char *s)
{
abort ();
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment