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, 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_memmove (tree, tree, rtx, enum machine_mode, tree);
+static rtx expand_builtin_bcopy (tree);
static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
-static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
+static rtx expand_builtin_memset (tree, rtx, enum machine_mode, tree);
static rtx expand_builtin_bzero (tree);
static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
static rtx expand_builtin_strstr (tree, tree, rtx, enum machine_mode);
runtime. */
if (offset < 0 || offset > max)
{
- warning ("offset outside bounds of constant string");
+ warning (0, "offset outside bounds of constant string");
return 0;
}
/* Argument 1 must be either zero or one. */
if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
{
- warning ("invalid second argument to %<__builtin_prefetch%>;"
+ warning (0, "invalid second argument to %<__builtin_prefetch%>;"
" using zero");
op1 = const0_rtx;
}
/* Argument 2 must be 0, 1, 2, or 3. */
if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
{
- warning ("invalid third argument to %<__builtin_prefetch%>; using zero");
+ warning (0, "invalid third argument to %<__builtin_prefetch%>; using zero");
op2 = const0_rtx;
}
/* Copy word part most expediently. */
dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
- BLOCK_OP_NORMAL);
+ CALL_EXPR_TAILCALL (exp)
+ ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
if (dest_addr == 0)
{
static rtx
expand_builtin_memmove (tree arglist, tree type, rtx target,
- enum machine_mode mode)
+ enum machine_mode mode, tree orig_exp)
{
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
normal memcpy. */
if (readonly_data_expr (src))
{
- tree const fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ 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);
+ fn = build_function_call_expr (fn, arglist);
+ if (TREE_CODE (fn) == CALL_EXPR)
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
+ return expand_expr (fn, target, mode, EXPAND_NORMAL);
}
/* If length is 1 and we can expand memcpy call inline,
if we failed the caller should emit a normal call. */
static rtx
-expand_builtin_bcopy (tree arglist, tree type)
+expand_builtin_bcopy (tree exp)
{
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree type = TREE_TYPE (exp);
tree src, dest, size, newarglist;
if (!validate_arglist (arglist,
newarglist = tree_cons (NULL_TREE, src, newarglist);
newarglist = tree_cons (NULL_TREE, dest, newarglist);
- return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode);
+ return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp);
}
#ifndef HAVE_movstr
convenient). */
static rtx
-expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
+expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
+ tree orig_exp)
{
if (!validate_arglist (arglist,
POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
dest_mem = get_memory_rtx (dest);
set_mem_align (dest_mem, dest_align);
- dest_addr = clear_storage (dest_mem, len_rtx);
+ dest_addr = clear_storage (dest_mem, len_rtx,
+ CALL_EXPR_TAILCALL (orig_exp)
+ ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
if (dest_addr == 0)
{
if we failed the caller should emit a normal call. */
static rtx
-expand_builtin_bzero (tree arglist)
+expand_builtin_bzero (tree exp)
{
+ tree arglist = TREE_OPERAND (exp, 1);
tree dest, size, newarglist;
if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
newarglist = tree_cons (NULL_TREE, dest, newarglist);
- return expand_builtin_memset (newarglist, const0_rtx, VOIDmode);
+ return expand_builtin_memset (newarglist, const0_rtx, VOIDmode, exp);
}
/* Expand expression EXP, which is a call to the memcmp built-in function.
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
- tree fndecl;
+ tree fndecl, fn;
int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
arglist = build_tree_list (NULL_TREE, arg2);
arglist = tree_cons (NULL_TREE, arg1, arglist);
fndecl = get_callee_fndecl (exp);
- exp = build_function_call_expr (fndecl, arglist);
- return expand_call (exp, target, target == const0_rtx);
+ fn = build_function_call_expr (fndecl, arglist);
+ if (TREE_CODE (fn) == CALL_EXPR)
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_call (fn, target, target == const0_rtx);
}
#endif
return 0;
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
- tree fndecl;
+ tree fndecl, fn;
int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
arglist = tree_cons (NULL_TREE, arg2, arglist);
arglist = tree_cons (NULL_TREE, arg1, arglist);
fndecl = get_callee_fndecl (exp);
- exp = build_function_call_expr (fndecl, arglist);
- return expand_call (exp, target, target == const0_rtx);
+ fn = build_function_call_expr (fndecl, arglist);
+ if (TREE_CODE (fn) == CALL_EXPR)
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_call (fn, target, target == const0_rtx);
}
#endif
return 0;
/* Unfortunately, this is merely undefined, rather than a constraint
violation, so we cannot make this an error. If this call is never
executed, the program is still strictly conforming. */
- warning ("%qT is promoted to %qT when passed through %<...%>",
+ warning (0, "%qT is promoted to %qT when passed through %<...%>",
type, promoted_type);
if (! gave_help)
{
gave_help = true;
- warning ("(so you should pass %qT not %qT to %<va_arg%>)",
+ warning (0, "(so you should pass %qT not %qT to %<va_arg%>)",
promoted_type, type);
}
gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
if (!targetm.gimplify_va_arg_expr)
- /* Once most targets are converted this should abort. */
+ /* FIXME:Once most targets are converted we should merely
+ assert this is non-null. */
return GS_ALL_DONE;
*expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
if (tem == NULL)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
- warning ("unsupported argument to %<__builtin_frame_address%>");
+ warning (0, "unsupported argument to %<__builtin_frame_address%>");
else
- warning ("unsupported argument to %<__builtin_return_address%>");
+ warning (0, "unsupported argument to %<__builtin_return_address%>");
return const0_rtx;
}
return t;
}
-/* Expand a call to printf or printf_unlocked with argument list ARGLIST.
+/* Expand EXP, a call to printf or printf_unlocked.
Return 0 if a normal call should be emitted rather than transforming
the function inline. If convenient, the result should be placed in
TARGET with mode MODE. UNLOCKED indicates this is a printf_unlocked
call. */
static rtx
-expand_builtin_printf (tree arglist, rtx target, enum machine_mode mode,
+expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
bool unlocked)
{
+ tree arglist = TREE_OPERAND (exp, 1);
tree fn_putchar = unlocked
? implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
: implicit_built_in_decls[BUILT_IN_PUTCHAR];
if (!fn)
return 0;
- return expand_expr (build_function_call_expr (fn, arglist),
- target, mode, EXPAND_NORMAL);
+ fn = build_function_call_expr (fn, arglist);
+ if (TREE_CODE (fn) == CALL_EXPR)
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_expr (fn, target, mode, EXPAND_NORMAL);
}
-/* Expand a call to fprintf or fprintf_unlocked with argument list ARGLIST.
+/* Expand EXP, a call to fprintf or fprintf_unlocked.
Return 0 if a normal call should be emitted rather than transforming
the function inline. If convenient, the result should be placed in
TARGET with mode MODE. UNLOCKED indicates this is a fprintf_unlocked
call. */
static rtx
-expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode mode,
+expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
bool unlocked)
{
+ tree arglist = TREE_OPERAND (exp, 1);
tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
: implicit_built_in_decls[BUILT_IN_FPUTC];
tree fn_fputs = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
if (!fn)
return 0;
- return expand_expr (build_function_call_expr (fn, arglist),
- target, mode, EXPAND_NORMAL);
+ fn = build_function_call_expr (fn, arglist);
+ if (TREE_CODE (fn) == CALL_EXPR)
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_expr (fn, target, mode, EXPAND_NORMAL);
}
/* Expand a call to sprintf with argument list ARGLIST. Return 0 if
{
enum machine_mode mode;
rtx addr, val, mem;
- tree valt;
/* Expand the operands. */
addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
arglist = TREE_CHAIN (arglist);
- valt = TREE_VALUE (arglist);
- if (code == NOT && TREE_CONSTANT (valt))
- {
- valt = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (valt), valt);
- code = AND;
- }
- val = expand_expr (valt, NULL, mode, EXPAND_NORMAL);
+ val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
/* Note that we explicitly do not want any alias information for this
memory, so that we kill all other live memories. Otherwise we don't
break;
case BUILT_IN_MEMMOVE:
- target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target, mode);
+ target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
+ mode, exp);
if (target)
return target;
break;
case BUILT_IN_BCOPY:
- target = expand_builtin_bcopy (arglist, TREE_TYPE (exp));
+ target = expand_builtin_bcopy (exp);
if (target)
return target;
break;
case BUILT_IN_MEMSET:
- target = expand_builtin_memset (arglist, target, mode);
+ target = expand_builtin_memset (arglist, target, mode, exp);
if (target)
return target;
break;
case BUILT_IN_BZERO:
- target = expand_builtin_bzero (arglist);
+ target = expand_builtin_bzero (exp);
if (target)
return target;
break;
return const0_rtx;
case BUILT_IN_PRINTF:
- target = expand_builtin_printf (arglist, target, mode, false);
+ target = expand_builtin_printf (exp, target, mode, false);
if (target)
return target;
break;
case BUILT_IN_PRINTF_UNLOCKED:
- target = expand_builtin_printf (arglist, target, mode, true);
+ target = expand_builtin_printf (exp, target, mode, true);
if (target)
return target;
break;
break;
case BUILT_IN_FPRINTF:
- target = expand_builtin_fprintf (arglist, target, mode, false);
+ target = expand_builtin_fprintf (exp, target, mode, false);
if (target)
return target;
break;
case BUILT_IN_FPRINTF_UNLOCKED:
- target = expand_builtin_fprintf (arglist, target, mode, true);
+ target = expand_builtin_fprintf (exp, target, mode, true);
if (target)
return target;
break;
/* If we know this is a constant, emit the constant of one. */
if (CONSTANT_CLASS_P (arglist)
|| (TREE_CODE (arglist) == CONSTRUCTOR
- && TREE_CONSTANT (arglist))
- || (TREE_CODE (arglist) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST))
+ && TREE_CONSTANT (arglist)))
return integer_one_node;
+ if (TREE_CODE (arglist) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (arglist, 0);
+ if (TREE_CODE (op) == STRING_CST
+ || (TREE_CODE (op) == ARRAY_REF
+ && integer_zerop (TREE_OPERAND (op, 1))
+ && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST))
+ return integer_one_node;
+ }
/* If this expression has side effects, show we don't know it to be a
constant. Likewise if it's a pointer or aggregate type since in
{
/* Evidently an out of date version of <stdarg.h>; can't validate
va_start's second argument, but can still work as intended. */
- warning ("%<__builtin_next_arg%> called without an argument");
+ warning (0, "%<__builtin_next_arg%> called without an argument");
return true;
}
/* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0)
argument. We just warn and set the arg to be the last
argument so that we will get wrong-code because of
it. */
- warning ("second parameter of %<va_start%> not last named argument");
+ warning (0, "second parameter of %<va_start%> not last named argument");
}
/* We want to verify the second parameter just once before the tree
optimizers are run and then avoid keeping it in the tree,