static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
-static rtx expand_builtin_strcat (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
-static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode, int);
+static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode);
static rtx expand_builtin_bcopy (tree, tree);
static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
static tree fold_builtin_round (tree);
static tree fold_builtin_bitop (tree);
static tree fold_builtin_memcpy (tree);
-static tree fold_builtin_mempcpy (tree);
+static tree fold_builtin_mempcpy (tree, tree, int);
static tree fold_builtin_memmove (tree, tree);
static tree fold_builtin_strchr (tree);
static tree fold_builtin_memcmp (tree);
stpcpy. */
static rtx
-expand_builtin_mempcpy (tree arglist, rtx target, enum machine_mode mode,
+expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode mode,
int endp)
{
if (!validate_arglist (arglist,
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);
- /* If DEST is not a pointer type, call the normal function. */
- if (dest_align == 0)
+ if (result)
+ 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. */
+ if (dest_align == 0 || src_align == 0)
return 0;
- /* If SRC and DEST are the same (and not volatile), do nothing. */
- if (operand_equal_p (src, dest, 0))
- {
- tree expr;
-
- if (endp == 0)
- {
- /* Evaluate and ignore LEN in case it has side-effects. */
- expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
- return expand_expr (dest, target, mode, EXPAND_NORMAL);
- }
-
- if (endp == 2)
- len = fold (build2 (MINUS_EXPR, TREE_TYPE (len), len,
- integer_one_node));
- len = fold_convert (TREE_TYPE (dest), len);
- expr = fold (build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len));
- return expand_expr (expr, target, mode, EXPAND_NORMAL);
- }
-
/* If LEN is not constant, call the normal function. */
if (! host_integerp (len, 1))
return 0;
- /* If the LEN parameter is zero, return DEST. */
- if (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;
-
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
src_str = c_getstr (src);
tree result = fold_builtin_memmove (arglist, type);
if (result)
- expand_expr (result, target, mode, EXPAND_NORMAL);
+ return expand_expr (result, target, mode, EXPAND_NORMAL);
/* If DEST is not a pointer type, call the normal function. */
if (dest_align == 0)
it is ok to use memcpy as well. */
if (integer_onep (len))
{
- rtx ret = expand_builtin_mempcpy (arglist, target, mode,
+ rtx ret = expand_builtin_mempcpy (arglist, type, target, mode,
/*endp=*/0);
if (ret)
return ret;
narglist = build_tree_list (NULL_TREE, lenp1);
narglist = tree_cons (NULL_TREE, src, narglist);
narglist = tree_cons (NULL_TREE, dst, narglist);
- ret = expand_builtin_mempcpy (narglist, target, mode, /*endp=*/2);
+ ret = expand_builtin_mempcpy (narglist, TREE_TYPE (exp),
+ target, mode, /*endp=*/2);
if (ret)
return ret;
if we failed the caller should emit a normal call. */
static rtx
-expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode)
+expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
{
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
- return 0;
- else
+ tree arglist = TREE_OPERAND (exp, 1);
+ if (validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
{
tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
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)
- return 0;
-
- /* If the len parameter is zero, return the dst parameter. */
- if (integer_zerop (len))
- {
- /* Evaluate and ignore the src argument in case it has
- side-effects. */
- expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
- VOIDmode, EXPAND_NORMAL);
- /* Return the dst parameter. */
- return expand_expr (TREE_VALUE (arglist), target, mode,
- EXPAND_NORMAL);
- }
+ tree result = fold_builtin_strncpy (exp, slen);
+
+ if (result)
+ return expand_expr (result, target, mode, EXPAND_NORMAL);
- /* Now, we must be passed a constant src ptr parameter. */
- if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
+ /* We must be passed a constant len and src parameter. */
+ if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
return 0;
slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
}
-
- /* OK transform into builtin memcpy. */
- 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);
}
+ return 0;
}
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode)
+expand_builtin_strcat (tree arglist, tree type, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
pass in a target of zero, it should never actually be
used. If this was successful return the original
dst, not the result of mempcpy. */
- if (expand_builtin_mempcpy (arglist, /*target=*/0, mode, /*endp=*/0))
+ if (expand_builtin_mempcpy (arglist, type, /*target=*/0, mode, /*endp=*/0))
return expand_expr (dst, target, mode, EXPAND_NORMAL);
else
return 0;
chain = TREE_CHAIN (arglist);
+ if (!chain)
+ {
+ error ("too few arguments to function %<va_start%>");
+ return const0_rtx;
+ }
if (TREE_CHAIN (chain))
error ("too many arguments to function %<va_start%>");
break;
case BUILT_IN_STRNCPY:
- target = expand_builtin_strncpy (arglist, target, mode);
+ target = expand_builtin_strncpy (exp, target, mode);
if (target)
return target;
break;
break;
case BUILT_IN_STRCAT:
- target = expand_builtin_strcat (arglist, target, mode);
+ target = expand_builtin_strcat (arglist, TREE_TYPE (exp), target, mode);
if (target)
return target;
break;
break;
case BUILT_IN_MEMPCPY:
- target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1);
+ target = expand_builtin_mempcpy (arglist, TREE_TYPE (exp), target, mode, /*endp=*/ 1);
if (target)
return target;
break;
{
REAL_VALUE_TYPE real;
+ /* __builtin_inff is intended to be usable to define INFINITY on all
+ targets. If an infinity is not available, INFINITY expands "to a
+ positive constant of type float that overflows at translation
+ time", footnote "In this case, using INFINITY will violate the
+ constraint in 6.4.4 and thus require a diagnostic." (C99 7.12#4).
+ Thus we pedwarn to ensure this constraint violation is
+ diagnosed. */
if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
- warning ("target format does not support infinity");
+ pedwarn ("target format does not support infinity");
real_inf (&real);
return build_real (type, real);
NULL_TREE if no simplification can be made. */
static tree
-fold_builtin_mempcpy (tree exp)
+fold_builtin_mempcpy (tree arglist, tree type, int endp)
{
- tree arglist = TREE_OPERAND (exp, 1);
- tree dest, src, len;
-
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
- return 0;
+ if (validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ {
+ tree dest = TREE_VALUE (arglist);
+ tree src = TREE_VALUE (TREE_CHAIN (arglist));
+ tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- dest = TREE_VALUE (arglist);
- src = TREE_VALUE (TREE_CHAIN (arglist));
- len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ /* If the LEN parameter is zero, return DEST. */
+ if (integer_zerop (len))
+ return omit_one_operand (type, dest, src);
- /* If the LEN parameter is zero, return DEST. */
- if (integer_zerop (len))
- return omit_one_operand (TREE_TYPE (exp), 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 SRC and DEST are the same (and not volatile), return DEST+LEN. */
- if (operand_equal_p (src, dest, 0))
- {
- tree temp = fold_convert (TREE_TYPE (dest), len);
- temp = fold (build2 (PLUS_EXPR, TREE_TYPE (dest), dest, temp));
- return fold_convert (TREE_TYPE (exp), temp);
+ 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);
+ }
}
-
return 0;
}
tree type = TREE_TYPE (TREE_TYPE (fndecl));
enum tree_code code;
tree arg0, arg1;
+ tree type0, type1;
+ enum tree_code code0, code1;
+ tree cmp_type = NULL_TREE;
if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
{
- enum tree_code code0, code1;
- tree type0, type1;
- tree cmp_type = 0;
-
/* Check that we have exactly two arguments. */
if (arglist == 0 || TREE_CHAIN (arglist) == 0)
{
IDENTIFIER_POINTER (DECL_NAME (fndecl)));
return error_mark_node;
}
-
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-
- type0 = TREE_TYPE (arg0);
- type1 = TREE_TYPE (arg1);
-
- code0 = TREE_CODE (type0);
- code1 = TREE_CODE (type1);
-
- if (code0 == REAL_TYPE && code1 == REAL_TYPE)
- /* Choose the wider of two real types. */
- cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
- ? type0 : type1;
- else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
- cmp_type = type0;
- else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
- cmp_type = type1;
- else
- {
- error ("non-floating-point argument to function %qs",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- return error_mark_node;
- }
-
- arg0 = fold_convert (cmp_type, arg0);
- arg1 = fold_convert (cmp_type, arg1);
}
+
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ type0 = TREE_TYPE (arg0);
+ type1 = TREE_TYPE (arg1);
+
+ code0 = TREE_CODE (type0);
+ code1 = TREE_CODE (type1);
+
+ if (code0 == REAL_TYPE && code1 == REAL_TYPE)
+ /* Choose the wider of two real types. */
+ cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
+ ? type0 : type1;
+ else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
+ cmp_type = type0;
+ else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
+ cmp_type = type1;
else
{
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ error ("non-floating-point argument to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
}
+
+ arg0 = fold_convert (cmp_type, arg0);
+ arg1 = fold_convert (cmp_type, arg1);
if (unordered_code == UNORDERED_EXPR)
{
return fold_builtin_memcpy (exp);
case BUILT_IN_MEMPCPY:
- return fold_builtin_mempcpy (exp);
+ return fold_builtin_mempcpy (arglist, type, /*endp=*/1);
case BUILT_IN_MEMMOVE:
return fold_builtin_memmove (arglist, type);