builtins.c (expand_builtin_memset, [...]): Additional arguments TARGET and MODE.
* builtins.c (expand_builtin_memset, expand_builtin_memcpy, expand_builtin_strcpy): Additional arguments TARGET and MODE. (expand_builtin_bzero, expand_builtin_strcpy, expand_builtin_strncpy, expand_builtin_bzero): Pass additional TARGET and MODE parameters to the above functions. (expand_builtin_memset, expand_builtin_memcpy): Optimize the case where the LEN parameter is constant zero. (expand_builtin_memcmp): No longer conditional on HAVE_cmpstrsi. Take an additional mode parameter. Optimize the cases where len is either constant zero or one. Optimize to call to memcpy, even if the memcpy isn't inlined. (expand_builtin_strncpy): Optimize to call memcpy, even if the memcpy isn't inlined. (expand_builtin_strcmp, expand_builtin_strncmp): Always attempt to optimize to a call to memcmp. (expand_builtin): expand_builtin_memcmp can always be called, and pass the required parameters to expand_builtin_memcmp, expand_builtin_memset, expand_builtin_memcpy and expand_builtin_strcpy. * gcc.c-torture/execute/string-opt-14.c: New test case. * gcc.c-torture/execute/string-opt-15.c: New test case. From-SVN: r47960
This commit is contained in:
parent
897bb55fe3
commit
c2bd38e892
4 changed files with 294 additions and 135 deletions
|
@ -1,3 +1,25 @@
|
|||
2001-12-12 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
* builtins.c (expand_builtin_memset, expand_builtin_memcpy,
|
||||
expand_builtin_strcpy): Additional arguments TARGET and MODE.
|
||||
(expand_builtin_bzero, expand_builtin_strcpy,
|
||||
expand_builtin_strncpy, expand_builtin_bzero): Pass additional
|
||||
TARGET and MODE parameters to the above functions.
|
||||
(expand_builtin_memset, expand_builtin_memcpy): Optimize the
|
||||
case where the LEN parameter is constant zero.
|
||||
(expand_builtin_memcmp): No longer conditional on
|
||||
HAVE_cmpstrsi. Take an additional mode parameter. Optimize
|
||||
the cases where len is either constant zero or one.
|
||||
Optimize to call to memcpy, even if the memcpy isn't inlined.
|
||||
(expand_builtin_strncpy): Optimize to call memcpy, even if the
|
||||
memcpy isn't inlined.
|
||||
(expand_builtin_strcmp, expand_builtin_strncmp): Always attempt
|
||||
to optimize to a call to memcmp.
|
||||
(expand_builtin): expand_builtin_memcmp can always be called,
|
||||
and pass the required parameters to expand_builtin_memcmp,
|
||||
expand_builtin_memset, expand_builtin_memcpy and
|
||||
expand_builtin_strcpy.
|
||||
|
||||
2001-12-12 David O'Brien <obrien@FreeBSD.org>
|
||||
|
||||
* config.gcc (arm-*-freebsd*): Add target.
|
||||
|
|
321
gcc/builtins.c
321
gcc/builtins.c
|
@ -101,9 +101,8 @@ static rtx expand_builtin_next_arg PARAMS ((tree));
|
|||
static rtx expand_builtin_va_start PARAMS ((int, tree));
|
||||
static rtx expand_builtin_va_end PARAMS ((tree));
|
||||
static rtx expand_builtin_va_copy PARAMS ((tree));
|
||||
#ifdef HAVE_cmpstrsi
|
||||
static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx));
|
||||
#endif
|
||||
static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
|
||||
|
@ -118,15 +117,18 @@ static rtx expand_builtin_strspn PARAMS ((tree, rtx,
|
|||
enum machine_mode));
|
||||
static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_memcpy PARAMS ((tree));
|
||||
static rtx expand_builtin_strcpy PARAMS ((tree));
|
||||
static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_strcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_memset PARAMS ((tree));
|
||||
static rtx expand_builtin_memset PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_bzero PARAMS ((tree));
|
||||
static rtx expand_builtin_strlen PARAMS ((tree, rtx));
|
||||
static rtx expand_builtin_strstr PARAMS ((tree, rtx,
|
||||
|
@ -1910,11 +1912,16 @@ builtin_memcpy_read_str (data, offset, mode)
|
|||
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.
|
||||
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). */
|
||||
|
||||
static rtx
|
||||
expand_builtin_memcpy (arglist)
|
||||
expand_builtin_memcpy (arglist, target, mode)
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
|
@ -1931,10 +1938,22 @@ expand_builtin_memcpy (arglist)
|
|||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
rtx dest_mem, src_mem, dest_addr, len_rtx;
|
||||
|
||||
/* If either SRC or DEST is not a pointer type, don't do
|
||||
this operation in-line. */
|
||||
if (src_align == 0 || dest_align == 0)
|
||||
return 0;
|
||||
/* If DEST is not a pointer type, call the normal function. */
|
||||
if (dest_align == 0)
|
||||
return 0;
|
||||
|
||||
/* If the LEN parameter is zero, return DEST. */
|
||||
if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* If either SRC is not a pointer type, don't do this
|
||||
operation in-line. */
|
||||
if (src_align == 0)
|
||||
return 0;
|
||||
|
||||
dest_mem = get_memory_rtx (dest);
|
||||
set_mem_align (dest_mem, dest_align);
|
||||
|
@ -1970,33 +1989,34 @@ expand_builtin_memcpy (arglist)
|
|||
}
|
||||
|
||||
/* Expand expression EXP, which is a call to the strcpy builtin. Return 0
|
||||
if we failed the caller should emit a normal call. */
|
||||
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). */
|
||||
|
||||
static rtx
|
||||
expand_builtin_strcpy (exp)
|
||||
expand_builtin_strcpy (exp, target, mode)
|
||||
tree exp;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
rtx result;
|
||||
tree fn, len;
|
||||
|
||||
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
fn = built_in_decls[BUILT_IN_MEMCPY];
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
len = size_binop (PLUS_EXPR, len, ssize_int (1));
|
||||
chainon (arglist, build_tree_list (NULL_TREE, len));
|
||||
}
|
||||
len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
result = expand_builtin_memcpy (arglist);
|
||||
|
||||
if (! result)
|
||||
TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
|
||||
return result;
|
||||
len = size_binop (PLUS_EXPR, len, ssize_int (1));
|
||||
chainon (arglist, build_tree_list (NULL_TREE, len));
|
||||
return expand_expr (build_function_call_expr (fn, arglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
|
||||
|
@ -2033,6 +2053,7 @@ expand_builtin_strncpy (arglist, target, mode)
|
|||
{
|
||||
tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
tree fn;
|
||||
|
||||
/* We must be passed a constant len parameter. */
|
||||
if (TREE_CODE (len) != INTEGER_CST)
|
||||
|
@ -2081,7 +2102,11 @@ expand_builtin_strncpy (arglist, target, mode)
|
|||
}
|
||||
|
||||
/* OK transform into builtin memcpy. */
|
||||
return expand_builtin_memcpy (arglist);
|
||||
fn = built_in_decls[BUILT_IN_MEMCPY];
|
||||
if (!fn)
|
||||
return 0;
|
||||
return expand_expr (build_function_call_expr (fn, arglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2104,11 +2129,15 @@ builtin_memset_read_str (data, offset, mode)
|
|||
}
|
||||
|
||||
/* Expand expression EXP, which is a call to the memset builtin. Return 0
|
||||
if we failed the caller should emit a normal call. */
|
||||
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). */
|
||||
|
||||
static rtx
|
||||
expand_builtin_memset (exp)
|
||||
expand_builtin_memset (exp, target, mode)
|
||||
tree exp;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
|
||||
|
@ -2131,6 +2160,14 @@ expand_builtin_memset (exp)
|
|||
if (dest_align == 0)
|
||||
return 0;
|
||||
|
||||
/* If the LEN parameter is zero, return DEST. */
|
||||
if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
|
||||
{
|
||||
/* Evaluate and ignore VAL in case it has side-effects. */
|
||||
expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
return expand_expr (dest, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
if (TREE_CODE (val) != INTEGER_CST)
|
||||
return 0;
|
||||
|
||||
|
@ -2184,14 +2221,16 @@ expand_builtin_bzero (exp)
|
|||
size = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
|
||||
/* New argument list transforming bzero(ptr x, int y) to
|
||||
memset(ptr x, int 0, size_t y). */
|
||||
memset(ptr x, int 0, size_t y). This is done this way
|
||||
so that if it isn't expanded inline, we fallback to
|
||||
calling bzero instead of memset. */
|
||||
|
||||
newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
|
||||
newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
|
||||
newarglist = tree_cons (NULL_TREE, dest, newarglist);
|
||||
|
||||
TREE_OPERAND (exp, 1) = newarglist;
|
||||
result = expand_builtin_memset(exp);
|
||||
result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
|
||||
|
||||
/* Always restore the original arguments. */
|
||||
TREE_OPERAND (exp, 1) = arglist;
|
||||
|
@ -2199,28 +2238,58 @@ expand_builtin_bzero (exp)
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef HAVE_cmpstrsi
|
||||
|
||||
/* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
|
||||
ARGLIST is the argument list for this call. Return 0 if we failed and the
|
||||
caller should emit a normal call, otherwise try to get the result in
|
||||
TARGET, if convenient. */
|
||||
TARGET, if convenient (and in mode MODE, if that's convenient). */
|
||||
|
||||
static rtx
|
||||
expand_builtin_memcmp (exp, arglist, target)
|
||||
expand_builtin_memcmp (exp, arglist, target, mode)
|
||||
tree exp;
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
tree arg1, arg2, len;
|
||||
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
|
||||
arg1 = TREE_VALUE (arglist);
|
||||
arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
|
||||
/* If the len parameter is zero, return zero. */
|
||||
if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
|
||||
{
|
||||
/* Evaluate and ignore arg1 and arg2 in case they have
|
||||
side-effects. */
|
||||
expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
/* If len parameter is one, return an expression corresponding to
|
||||
(*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
|
||||
if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
|
||||
{
|
||||
tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
|
||||
tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
|
||||
tree ind1 =
|
||||
fold (build1 (CONVERT_EXPR, integer_type_node,
|
||||
build1 (INDIRECT_REF, cst_uchar_node,
|
||||
build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
|
||||
tree ind2 =
|
||||
fold (build1 (CONVERT_EXPR, integer_type_node,
|
||||
build1 (INDIRECT_REF, cst_uchar_node,
|
||||
build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
|
||||
tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_cmpstrsi
|
||||
{
|
||||
enum machine_mode mode;
|
||||
tree arg1 = TREE_VALUE (arglist);
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
rtx arg1_rtx, arg2_rtx, arg3_rtx;
|
||||
rtx result;
|
||||
rtx insn;
|
||||
|
@ -2275,9 +2344,11 @@ expand_builtin_memcmp (exp, arglist, target)
|
|||
else
|
||||
return convert_to_mode (mode, result, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand expression EXP, which is a call to the strcmp builtin. Return 0
|
||||
if we failed the caller should emit a normal call, otherwise try to get
|
||||
the result in TARGET, if convenient. */
|
||||
|
@ -2289,7 +2360,7 @@ expand_builtin_strcmp (exp, target, mode)
|
|||
enum machine_mode mode;
|
||||
{
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
tree arg1, arg2;
|
||||
tree arg1, arg2, len, len2, fn;
|
||||
const char *p1, *p2;
|
||||
|
||||
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
|
||||
|
@ -2325,58 +2396,49 @@ expand_builtin_strcmp (exp, target, mode)
|
|||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_cmpstrsi
|
||||
if (! HAVE_cmpstrsi)
|
||||
len = c_strlen (arg1);
|
||||
len2 = c_strlen (arg2);
|
||||
|
||||
if (len)
|
||||
len = size_binop (PLUS_EXPR, ssize_int (1), len);
|
||||
|
||||
if (len2)
|
||||
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
|
||||
|
||||
/* 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
|
||||
this case; some cost analysis could be done if both are available
|
||||
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
|
||||
could arise if optimization results in strcpy being called with
|
||||
two fixed strings, or if the code was machine-generated. We should
|
||||
add some code to the `memcmp' handler below to deal with such
|
||||
situations, someday. */
|
||||
|
||||
if (!len || TREE_CODE (len) != INTEGER_CST)
|
||||
{
|
||||
if (len2 && !TREE_SIDE_EFFECTS (len2))
|
||||
len = len2;
|
||||
else if (len == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (len2 && TREE_CODE (len2) == INTEGER_CST
|
||||
&& tree_int_cst_lt (len2, len))
|
||||
len = len2;
|
||||
|
||||
/* If both arguments have side effects, we cannot optimize. */
|
||||
if (TREE_SIDE_EFFECTS (len))
|
||||
return 0;
|
||||
|
||||
{
|
||||
tree len = c_strlen (arg1);
|
||||
tree len2 = c_strlen (arg2);
|
||||
rtx result;
|
||||
fn = built_in_decls[BUILT_IN_MEMCMP];
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
if (len)
|
||||
len = size_binop (PLUS_EXPR, ssize_int (1), len);
|
||||
|
||||
if (len2)
|
||||
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
|
||||
|
||||
/* 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
|
||||
this case; some cost analysis could be done if both are available
|
||||
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
|
||||
could arise if optimization results in strcpy being called with
|
||||
two fixed strings, or if the code was machine-generated. We should
|
||||
add some code to the `memcmp' handler below to deal with such
|
||||
situations, someday. */
|
||||
|
||||
if (!len || TREE_CODE (len) != INTEGER_CST)
|
||||
{
|
||||
if (len2 && !TREE_SIDE_EFFECTS (len2))
|
||||
len = len2;
|
||||
else if (len == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (len2 && TREE_CODE (len2) == INTEGER_CST
|
||||
&& tree_int_cst_lt (len2, len))
|
||||
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));
|
||||
result = expand_builtin_memcmp (exp, arglist, target);
|
||||
if (! result)
|
||||
TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
chainon (arglist, build_tree_list (NULL_TREE, len));
|
||||
return expand_expr (build_function_call_expr (fn, arglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* Expand expression EXP, which is a call to the strncmp builtin. Return 0
|
||||
|
@ -2390,6 +2452,7 @@ expand_builtin_strncmp (exp, target, mode)
|
|||
enum machine_mode mode;
|
||||
{
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
tree fn, newarglist, len = 0;
|
||||
tree arg1, arg2, arg3;
|
||||
const char *p1, *p2;
|
||||
|
||||
|
@ -2442,45 +2505,42 @@ expand_builtin_strncmp (exp, target, mode)
|
|||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_cmpstrsi
|
||||
/* If c_strlen can determine an expression for one of the string
|
||||
lengths, and it doesn't have side effects, then call
|
||||
expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */
|
||||
if (HAVE_cmpstrsi)
|
||||
{
|
||||
tree newarglist, len = 0;
|
||||
|
||||
/* Perhaps one of the strings is really constant, if so prefer
|
||||
that constant length over the other string's length. */
|
||||
if (p1)
|
||||
len = c_strlen (arg1);
|
||||
else if (p2)
|
||||
len = c_strlen (arg2);
|
||||
/* Perhaps one of the strings is really constant, if so prefer
|
||||
that constant length over the other string's length. */
|
||||
if (p1)
|
||||
len = c_strlen (arg1);
|
||||
else if (p2)
|
||||
len = c_strlen (arg2);
|
||||
|
||||
/* If we still don't have a len, try either string arg as long
|
||||
as they don't have side effects. */
|
||||
if (!len && !TREE_SIDE_EFFECTS (arg1))
|
||||
len = c_strlen (arg1);
|
||||
if (!len && !TREE_SIDE_EFFECTS (arg2))
|
||||
len = c_strlen (arg2);
|
||||
/* If we still don't have a length, punt. */
|
||||
if (!len)
|
||||
return 0;
|
||||
/* If we still don't have a len, try either string arg as long
|
||||
as they don't have side effects. */
|
||||
if (!len && !TREE_SIDE_EFFECTS (arg1))
|
||||
len = c_strlen (arg1);
|
||||
if (!len && !TREE_SIDE_EFFECTS (arg2))
|
||||
len = c_strlen (arg2);
|
||||
/* If we still don't have a length, punt. */
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
/* Add one to the string length. */
|
||||
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
|
||||
fn = built_in_decls[BUILT_IN_MEMCMP];
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
/* The actual new length parameter is MIN(len,arg3). */
|
||||
len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
|
||||
/* Add one to the string length. */
|
||||
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
|
||||
|
||||
newarglist = build_tree_list (NULL_TREE, len);
|
||||
newarglist = tree_cons (NULL_TREE, arg2, newarglist);
|
||||
newarglist = tree_cons (NULL_TREE, arg1, newarglist);
|
||||
return expand_builtin_memcmp (exp, newarglist, target);
|
||||
}
|
||||
#endif
|
||||
/* The actual new length parameter is MIN(len,arg3). */
|
||||
len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
|
||||
|
||||
return 0;
|
||||
newarglist = build_tree_list (NULL_TREE, len);
|
||||
newarglist = tree_cons (NULL_TREE, arg2, newarglist);
|
||||
newarglist = tree_cons (NULL_TREE, arg1, newarglist);
|
||||
return expand_expr (build_function_call_expr (fn, newarglist),
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* Expand expression EXP, which is a call to the strcat builtin.
|
||||
|
@ -3661,7 +3721,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
|||
break;
|
||||
|
||||
case BUILT_IN_STRCPY:
|
||||
target = expand_builtin_strcpy (exp);
|
||||
target = expand_builtin_strcpy (exp, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
@ -3723,13 +3783,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
|||
break;
|
||||
|
||||
case BUILT_IN_MEMCPY:
|
||||
target = expand_builtin_memcpy (arglist);
|
||||
target = expand_builtin_memcpy (arglist, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMSET:
|
||||
target = expand_builtin_memset (exp);
|
||||
target = expand_builtin_memset (exp, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
@ -3752,21 +3812,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
|||
return target;
|
||||
break;
|
||||
|
||||
/* These comparison functions need an instruction that returns an actual
|
||||
index. An ordinary compare that just sets the condition codes
|
||||
is not enough. */
|
||||
#ifdef HAVE_cmpstrsi
|
||||
case BUILT_IN_BCMP:
|
||||
case BUILT_IN_MEMCMP:
|
||||
target = expand_builtin_memcmp (exp, arglist, target);
|
||||
target = expand_builtin_memcmp (exp, arglist, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
#else
|
||||
case BUILT_IN_BCMP:
|
||||
case BUILT_IN_MEMCMP:
|
||||
break;
|
||||
#endif
|
||||
|
||||
case BUILT_IN_SETJMP:
|
||||
target = expand_builtin_setjmp (arglist, target);
|
||||
|
|
40
gcc/testsuite/gcc.c-torture/execute/string-opt-14.c
Normal file
40
gcc/testsuite/gcc.c-torture/execute/string-opt-14.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* Copyright (C) 2001 Free Software Foundation.
|
||||
|
||||
Ensure builtin memset and memcpy are optimized away correctly.
|
||||
|
||||
Written by Roger Sayle, 11/23/2001. */
|
||||
|
||||
extern void abort (void);
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void *memset (void *s, int c, size_t n);
|
||||
extern void *memcpy (void *dest, const void *src, size_t n);
|
||||
|
||||
char dst[32];
|
||||
char src[32];
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
memset (src, 0, 0);
|
||||
memcpy (dst, src, 0);
|
||||
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 void *
|
||||
memset (void *s, int c, size_t n)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
static void *
|
||||
memcpy (void *dest, const void *src, size_t n)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
#endif
|
||||
|
46
gcc/testsuite/gcc.c-torture/execute/string-opt-15.c
Normal file
46
gcc/testsuite/gcc.c-torture/execute/string-opt-15.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (C) 2001 Free Software Foundation.
|
||||
|
||||
Ensure that short builtin memcmp are optimized and perform correctly.
|
||||
On architectures with a cmpstrsi instruction, this test doesn't determine
|
||||
which optimization is being performed, but it does check for correctness.
|
||||
|
||||
Written by Roger Sayle, 12/02/2001. */
|
||||
|
||||
extern void abort (void);
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern int memcmp (const void *, const void *, size_t);
|
||||
extern char *strcpy (char *, const char *);
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char str[8];
|
||||
|
||||
strcpy (str, "3141");
|
||||
|
||||
if ( memcmp (str, str+2, 0) != 0 )
|
||||
abort ();
|
||||
if ( memcmp (str+1, str+3, 0) != 0 )
|
||||
abort ();
|
||||
|
||||
if ( memcmp (str+1, str+3, 1) != 0 )
|
||||
abort ();
|
||||
if ( memcmp (str, str+2, 1) >= 0 )
|
||||
abort ();
|
||||
if ( memcmp (str+2, str, 1) <= 0 )
|
||||
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 int
|
||||
memcmp (const char *p1, const char *p2, size_t len)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Add table
Reference in a new issue