re PR middle-end/27567 (__builtin_memcpy generates redundant stores/moves.)
PR middle-end/27567 * builtins.c (fold_builtin_memcpy, fold_builtin_memmove): Remove. (fold_builtin_mempcpy): Rename to... (fold_builtin_memory_op): ... this. Optimize one element copy into an assignment. (fold_builtin_memset, fold_builtin_bzero, fold_builtin_bcopy): New functions. (expand_builtin_strcpy, expand_builtin_strncpy): Handle COMPOUND_EXPR. (expand_builtin_memcpy, expand_builtin_mempcpy, expand_builtin_memmove): Likewise. Use fold_builtin_memory_op. (fold_builtin_1): Handle BUILT_IN_MEMSET, BUILT_IN_BZERO and BUILT_IN_BCOPY. Use fold_builtin_memory_op for BUILT_IN_MEM{CPY,PCPY,MOVE}. From-SVN: r116656
This commit is contained in:
parent
07515729e9
commit
bc038ad518
|
@ -1,3 +1,19 @@
|
|||
2006-09-02 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/27567
|
||||
* builtins.c (fold_builtin_memcpy, fold_builtin_memmove): Remove.
|
||||
(fold_builtin_mempcpy): Rename to...
|
||||
(fold_builtin_memory_op): ... this. Optimize one element copy
|
||||
into an assignment.
|
||||
(fold_builtin_memset, fold_builtin_bzero, fold_builtin_bcopy): New
|
||||
functions.
|
||||
(expand_builtin_strcpy, expand_builtin_strncpy): Handle COMPOUND_EXPR.
|
||||
(expand_builtin_memcpy, expand_builtin_mempcpy,
|
||||
expand_builtin_memmove): Likewise. Use fold_builtin_memory_op.
|
||||
(fold_builtin_1): Handle BUILT_IN_MEMSET, BUILT_IN_BZERO and
|
||||
BUILT_IN_BCOPY. Use fold_builtin_memory_op for
|
||||
BUILT_IN_MEM{CPY,PCPY,MOVE}.
|
||||
|
||||
2006-09-01 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* config/m32c/cond.md (cbranch<mode>4): Defer splitting until after reload.
|
||||
|
|
319
gcc/builtins.c
319
gcc/builtins.c
|
@ -160,9 +160,7 @@ static tree fold_builtin_ceil (tree, tree);
|
|||
static tree fold_builtin_round (tree, tree);
|
||||
static tree fold_builtin_int_roundingfn (tree, tree);
|
||||
static tree fold_builtin_bitop (tree, tree);
|
||||
static tree fold_builtin_memcpy (tree, tree);
|
||||
static tree fold_builtin_mempcpy (tree, tree, int);
|
||||
static tree fold_builtin_memmove (tree, tree);
|
||||
static tree fold_builtin_memory_op (tree, tree, bool, int);
|
||||
static tree fold_builtin_strchr (tree, tree);
|
||||
static tree fold_builtin_memcmp (tree);
|
||||
static tree fold_builtin_strcmp (tree);
|
||||
|
@ -2888,10 +2886,19 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
|
|||
unsigned int dest_align
|
||||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
rtx dest_mem, src_mem, dest_addr, len_rtx;
|
||||
tree result = fold_builtin_memcpy (fndecl, arglist);
|
||||
tree result = fold_builtin_memory_op (arglist, TREE_TYPE (TREE_TYPE (fndecl)),
|
||||
false, /*endp=*/0);
|
||||
|
||||
if (result)
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
{
|
||||
while (TREE_CODE (result) == COMPOUND_EXPR)
|
||||
{
|
||||
expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
|
||||
EXPAND_NORMAL);
|
||||
result = TREE_OPERAND (result, 1);
|
||||
}
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* If DEST is not a pointer type, call the normal function. */
|
||||
if (dest_align == 0)
|
||||
|
@ -2977,10 +2984,18 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
|
|||
unsigned int dest_align
|
||||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
rtx dest_mem, src_mem, len_rtx;
|
||||
tree result = fold_builtin_mempcpy (arglist, type, endp);
|
||||
tree result = fold_builtin_memory_op (arglist, type, false, endp);
|
||||
|
||||
if (result)
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
{
|
||||
while (TREE_CODE (result) == COMPOUND_EXPR)
|
||||
{
|
||||
expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
|
||||
EXPAND_NORMAL);
|
||||
result = TREE_OPERAND (result, 1);
|
||||
}
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* If either SRC or DEST is not a pointer type, don't do this
|
||||
operation in-line. */
|
||||
|
@ -3051,10 +3066,18 @@ expand_builtin_memmove (tree arglist, tree type, rtx target,
|
|||
unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
|
||||
unsigned int dest_align
|
||||
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
|
||||
tree result = fold_builtin_memmove (arglist, type);
|
||||
tree result = fold_builtin_memory_op (arglist, type, false, /*endp=*/3);
|
||||
|
||||
if (result)
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
{
|
||||
while (TREE_CODE (result) == COMPOUND_EXPR)
|
||||
{
|
||||
expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
|
||||
EXPAND_NORMAL);
|
||||
result = TREE_OPERAND (result, 1);
|
||||
}
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* If DEST is not a pointer type, call the normal function. */
|
||||
if (dest_align == 0)
|
||||
|
@ -3202,7 +3225,15 @@ expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode
|
|||
{
|
||||
tree result = fold_builtin_strcpy (fndecl, arglist, 0);
|
||||
if (result)
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
{
|
||||
while (TREE_CODE (result) == COMPOUND_EXPR)
|
||||
{
|
||||
expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
|
||||
EXPAND_NORMAL);
|
||||
result = TREE_OPERAND (result, 1);
|
||||
}
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
return expand_movstr (TREE_VALUE (arglist),
|
||||
TREE_VALUE (TREE_CHAIN (arglist)),
|
||||
|
@ -3328,7 +3359,15 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
|
|||
tree result = fold_builtin_strncpy (fndecl, arglist, slen);
|
||||
|
||||
if (result)
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
{
|
||||
while (TREE_CODE (result) == COMPOUND_EXPR)
|
||||
{
|
||||
expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
|
||||
EXPAND_NORMAL);
|
||||
result = TREE_OPERAND (result, 1);
|
||||
}
|
||||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* We must be passed a constant len and src parameter. */
|
||||
if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
|
||||
|
@ -7849,78 +7888,121 @@ fold_builtin_exponent (tree fndecl, tree arglist,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Fold function call to builtin memcpy. Return
|
||||
/* Fold function call to builtin memset. Return
|
||||
NULL_TREE if no simplification can be made. */
|
||||
|
||||
static tree
|
||||
fold_builtin_memcpy (tree fndecl, tree arglist)
|
||||
fold_builtin_memset (tree arglist, tree type, bool ignore)
|
||||
{
|
||||
tree dest, src, len;
|
||||
tree dest, c, len, var, ret;
|
||||
unsigned HOST_WIDE_INT length, cval;
|
||||
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
|
||||
dest = TREE_VALUE (arglist);
|
||||
src = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
c = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
|
||||
if (! host_integerp (len, 1))
|
||||
return 0;
|
||||
|
||||
/* If the LEN parameter is zero, return DEST. */
|
||||
if (integer_zerop (len))
|
||||
return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
|
||||
return omit_one_operand (type, dest, c);
|
||||
|
||||
/* If SRC and DEST are the same (and not volatile), return DEST. */
|
||||
if (operand_equal_p (src, dest, 0))
|
||||
return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
|
||||
if (! host_integerp (c, 1) || TREE_SIDE_EFFECTS (dest))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
var = dest;
|
||||
STRIP_NOPS (var);
|
||||
if (TREE_CODE (var) != ADDR_EXPR)
|
||||
return 0;
|
||||
|
||||
/* Fold function call to builtin mempcpy. Return
|
||||
NULL_TREE if no simplification can be made. */
|
||||
var = TREE_OPERAND (var, 0);
|
||||
if (TREE_THIS_VOLATILE (var))
|
||||
return 0;
|
||||
|
||||
static tree
|
||||
fold_builtin_mempcpy (tree arglist, tree type, int endp)
|
||||
{
|
||||
if (validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (var))
|
||||
&& !POINTER_TYPE_P (TREE_TYPE (var)))
|
||||
return 0;
|
||||
|
||||
length = tree_low_cst (len, 1);
|
||||
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (var))) != length
|
||||
|| get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
|
||||
< (int) length)
|
||||
return 0;
|
||||
|
||||
if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
|
||||
return 0;
|
||||
|
||||
if (integer_zerop (c))
|
||||
cval = 0;
|
||||
else
|
||||
{
|
||||
tree dest = TREE_VALUE (arglist);
|
||||
tree src = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
|
||||
return 0;
|
||||
|
||||
/* If the LEN parameter is zero, return DEST. */
|
||||
if (integer_zerop (len))
|
||||
return omit_one_operand (type, dest, src);
|
||||
|
||||
/* If SRC and DEST are the same (and not volatile), return DEST+LEN. */
|
||||
if (operand_equal_p (src, dest, 0))
|
||||
{
|
||||
if (endp == 0)
|
||||
return omit_one_operand (type, dest, len);
|
||||
|
||||
if (endp == 2)
|
||||
len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
|
||||
ssize_int (1));
|
||||
|
||||
len = fold_convert (TREE_TYPE (dest), len);
|
||||
len = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
|
||||
return fold_convert (type, len);
|
||||
}
|
||||
cval = tree_low_cst (c, 1);
|
||||
cval &= 0xff;
|
||||
cval |= cval << 8;
|
||||
cval |= cval << 16;
|
||||
cval |= (cval << 31) << 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
ret = build_int_cst_type (TREE_TYPE (var), cval);
|
||||
ret = build2 (MODIFY_EXPR, TREE_TYPE (var), var, ret);
|
||||
if (ignore)
|
||||
return ret;
|
||||
|
||||
return omit_one_operand (type, dest, ret);
|
||||
}
|
||||
|
||||
/* Fold function call to builtin memmove. Return
|
||||
/* Fold function call to builtin memset. Return
|
||||
NULL_TREE if no simplification can be made. */
|
||||
|
||||
static tree
|
||||
fold_builtin_memmove (tree arglist, tree type)
|
||||
fold_builtin_bzero (tree arglist, bool ignore)
|
||||
{
|
||||
tree dest, src, len;
|
||||
tree dest, size, newarglist;
|
||||
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
|
||||
if (!ignore)
|
||||
return 0;
|
||||
|
||||
dest = TREE_VALUE (arglist);
|
||||
size = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
|
||||
/* New argument list transforming bzero(ptr x, int y) to
|
||||
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, fold_convert (sizetype, size));
|
||||
newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
|
||||
newarglist = tree_cons (NULL_TREE, dest, newarglist);
|
||||
return fold_builtin_memset (newarglist, void_type_node, ignore);
|
||||
}
|
||||
|
||||
/* Fold function call to builtin mem{{,p}cpy,move}. Return
|
||||
NULL_TREE if no simplification can be made.
|
||||
If ENDP is 0, return DEST (like memcpy).
|
||||
If ENDP is 1, return DEST+LEN (like mempcpy).
|
||||
If ENDP is 2, return DEST+LEN-1 (like stpcpy).
|
||||
If ENDP is 3, return DEST, additionally *SRC and *DEST may overlap
|
||||
(memmove). */
|
||||
|
||||
static tree
|
||||
fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
|
||||
{
|
||||
tree dest, src, len, destvar, srcvar, expr;
|
||||
unsigned HOST_WIDE_INT length;
|
||||
|
||||
if (! validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
|
||||
dest = TREE_VALUE (arglist);
|
||||
|
@ -7931,11 +8013,115 @@ fold_builtin_memmove (tree arglist, tree type)
|
|||
if (integer_zerop (len))
|
||||
return omit_one_operand (type, dest, src);
|
||||
|
||||
/* If SRC and DEST are the same (and not volatile), return DEST. */
|
||||
/* If SRC and DEST are the same (and not volatile), return
|
||||
DEST{,+LEN,+LEN-1}. */
|
||||
if (operand_equal_p (src, dest, 0))
|
||||
return omit_one_operand (type, dest, len);
|
||||
expr = len;
|
||||
else
|
||||
{
|
||||
if (! host_integerp (len, 1))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
|
||||
return 0;
|
||||
|
||||
destvar = dest;
|
||||
STRIP_NOPS (destvar);
|
||||
if (TREE_CODE (destvar) != ADDR_EXPR)
|
||||
return 0;
|
||||
|
||||
destvar = TREE_OPERAND (destvar, 0);
|
||||
if (TREE_THIS_VOLATILE (destvar))
|
||||
return 0;
|
||||
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
|
||||
&& !POINTER_TYPE_P (TREE_TYPE (destvar))
|
||||
&& !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
|
||||
return 0;
|
||||
|
||||
srcvar = src;
|
||||
STRIP_NOPS (srcvar);
|
||||
if (TREE_CODE (srcvar) != ADDR_EXPR)
|
||||
return 0;
|
||||
|
||||
srcvar = TREE_OPERAND (srcvar, 0);
|
||||
if (TREE_THIS_VOLATILE (srcvar))
|
||||
return 0;
|
||||
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
|
||||
&& !POINTER_TYPE_P (TREE_TYPE (srcvar))
|
||||
&& !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
|
||||
return 0;
|
||||
|
||||
length = tree_low_cst (len, 1);
|
||||
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
|
||||
|| get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
|
||||
< (int) length
|
||||
|| GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length
|
||||
|| get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
|
||||
< (int) length)
|
||||
return 0;
|
||||
|
||||
if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
|
||||
|| POINTER_TYPE_P (TREE_TYPE (srcvar)))
|
||||
&& (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
|
||||
|| POINTER_TYPE_P (TREE_TYPE (destvar))))
|
||||
expr = fold_convert (TREE_TYPE (destvar), srcvar);
|
||||
else
|
||||
expr = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (destvar), srcvar);
|
||||
expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
|
||||
}
|
||||
|
||||
if (ignore)
|
||||
return expr;
|
||||
|
||||
if (endp == 0 || endp == 3)
|
||||
return omit_one_operand (type, dest, expr);
|
||||
|
||||
if (expr == len)
|
||||
expr = 0;
|
||||
|
||||
if (endp == 2)
|
||||
len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
|
||||
ssize_int (1));
|
||||
|
||||
len = fold_convert (TREE_TYPE (dest), len);
|
||||
dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
|
||||
dest = fold_convert (type, dest);
|
||||
if (expr)
|
||||
dest = omit_one_operand (type, dest, expr);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Fold function call to builtin bcopy. Return NULL_TREE if no
|
||||
simplification can be made. */
|
||||
|
||||
static tree
|
||||
fold_builtin_bcopy (tree arglist, bool ignore)
|
||||
{
|
||||
tree src, dest, size, newarglist;
|
||||
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
|
||||
if (! ignore)
|
||||
return 0;
|
||||
|
||||
src = TREE_VALUE (arglist);
|
||||
dest = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
|
||||
|
||||
/* New argument list transforming bcopy(ptr x, ptr y, int z) to
|
||||
memmove(ptr y, ptr x, size_t z). This is done this way
|
||||
so that if it isn't expanded inline, we fallback to
|
||||
calling bcopy instead of memmove. */
|
||||
|
||||
newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
|
||||
newarglist = tree_cons (NULL_TREE, src, newarglist);
|
||||
newarglist = tree_cons (NULL_TREE, dest, newarglist);
|
||||
|
||||
return fold_builtin_memory_op (newarglist, void_type_node, true, /*endp=*/3);
|
||||
}
|
||||
|
||||
/* Fold function call to builtin strcpy. If LEN is not NULL, it represents
|
||||
|
@ -8826,14 +9012,23 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
|
|||
CASE_INT_FN (BUILT_IN_PARITY):
|
||||
return fold_builtin_bitop (fndecl, arglist);
|
||||
|
||||
case BUILT_IN_MEMSET:
|
||||
return fold_builtin_memset (arglist, type, ignore);
|
||||
|
||||
case BUILT_IN_MEMCPY:
|
||||
return fold_builtin_memcpy (fndecl, arglist);
|
||||
return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/0);
|
||||
|
||||
case BUILT_IN_MEMPCPY:
|
||||
return fold_builtin_mempcpy (arglist, type, /*endp=*/1);
|
||||
return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/1);
|
||||
|
||||
case BUILT_IN_MEMMOVE:
|
||||
return fold_builtin_memmove (arglist, type);
|
||||
return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/3);
|
||||
|
||||
case BUILT_IN_BZERO:
|
||||
return fold_builtin_bzero (arglist, ignore);
|
||||
|
||||
case BUILT_IN_BCOPY:
|
||||
return fold_builtin_bcopy (arglist, ignore);
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_SIGNBIT):
|
||||
return fold_builtin_signbit (fndecl, arglist);
|
||||
|
|
Loading…
Reference in New Issue