/* Expand builtin functions.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "machmode.h"
+#include "real.h"
#include "rtl.h"
#include "tree.h"
#include "obstack.h"
#include "predict.h"
#include "tm_p.h"
#include "target.h"
+#include "langhooks.h"
#define CALLED_AS_BUILT_IN(NODE) \
(!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
initialized to NULL_TREE. */
tree built_in_decls[(int) END_BUILTINS];
-tree (*lang_type_promotes_to) PARAMS ((tree));
-
static int get_pointer_alignment PARAMS ((tree, unsigned int));
static tree c_strlen PARAMS ((tree));
static const char *c_getstr PARAMS ((tree));
static rtx c_readstr PARAMS ((const char *,
enum machine_mode));
-static int target_char_cast PARAMS ((tree, char *));
+static int target_char_cast PARAMS ((tree, char *));
static rtx get_memory_rtx PARAMS ((tree));
static int apply_args_size PARAMS ((void));
static int apply_result_size PARAMS ((void));
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,
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 builtin_memset_gen_str PARAMS ((PTR, HOST_WIDE_INT,
+ enum machine_mode));
+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,
static rtx expand_builtin_alloca PARAMS ((tree, rtx));
static rtx expand_builtin_ffs PARAMS ((tree, rtx, rtx));
static rtx expand_builtin_frame_address PARAMS ((tree));
-static rtx expand_builtin_fputs PARAMS ((tree, int));
+static rtx expand_builtin_fputs PARAMS ((tree, int, int));
static tree stabilize_va_list PARAMS ((tree, int));
static rtx expand_builtin_expect PARAMS ((tree, rtx));
static tree fold_builtin_constant_p PARAMS ((tree));
void
expand_builtin_setjmp_receiver (receiver_label)
- rtx receiver_label ATTRIBUTE_UNUSED;
+ rtx receiver_label ATTRIBUTE_UNUSED;
{
/* Clobber the FP when we get here, so we have to make sure it's
marked as used by this function. */
expand_builtin_longjmp (buf_addr, value)
rtx buf_addr, value;
{
- rtx fp, lab, stack, insn;
+ rtx fp, lab, stack, insn, last;
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
if (setjmp_alias_set == -1)
current_function_calls_longjmp = 1;
+ last = get_last_insn ();
#ifdef HAVE_builtin_longjmp
if (HAVE_builtin_longjmp)
emit_insn (gen_builtin_longjmp (buf_addr));
internal exception handling use only. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
+ if (insn == last)
+ abort ();
if (GET_CODE (insn) == JUMP_INSN)
{
REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
break;
}
else if (GET_CODE (insn) == CALL_INSN)
- break;
+ break;
}
}
tree arg0, arg1, arg2;
rtx op0, op1, op2;
+ if (!validate_arglist (arglist, POINTER_TYPE, 0))
+ return;
+
arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
+ zero (read) and argument 2 (locality) defaults to 3 (high degree of
+ locality). */
+ if (TREE_CHAIN (arglist))
+ {
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ if (TREE_CHAIN (TREE_CHAIN (arglist)))
+ arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ else
+ arg2 = build_int_2 (3, 0);
+ }
+ else
+ {
+ arg1 = integer_zero_node;
+ arg2 = build_int_2 (3, 0);
+ }
/* Argument 0 is an address. */
op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
/* Argument 1 (read/write flag) must be a compile-time constant int. */
if (TREE_CODE (arg1) != INTEGER_CST)
{
- error ("second arg to `__builtin_prefetch' must be a constant");
- arg1 = integer_zero_node;
+ error ("second arg to `__builtin_prefetch' must be a constant");
+ arg1 = integer_zero_node;
}
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
/* Argument 1 must be either zero or one. */
if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
{
error ("third arg to `__builtin_prefetch' must be a constant");
arg2 = integer_zero_node;
}
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
/* Argument 2 must be 0, 1, 2, or 3. */
if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
{
#ifdef HAVE_prefetch
if (HAVE_prefetch)
{
- if (! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
- (op0, Pmode))
- op0 = force_reg (Pmode, op0);
+ if ((! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
+ (op0,
+ insn_data[(int)CODE_FOR_prefetch].operand[0].mode)) ||
+ (GET_MODE(op0) != Pmode))
+ {
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE(op0) != Pmode)
+ op0 = convert_memory_address (Pmode, op0);
+#endif
+ op0 = force_reg (Pmode, op0);
+ }
emit_insn (gen_prefetch (op0, op1, op2));
}
else
used for calling a function. */
static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
-/* Return the offset of register REGNO into the block returned by
+/* Return the offset of register REGNO into the block returned by
__builtin_apply_args. This is not declared static, since it is
needed in objc-act.c. */
-int
+int
apply_args_register_offset (regno)
int regno;
{
apply_args_size ()
{
static int size = -1;
- int align, regno;
+ int align;
+ unsigned int regno;
enum machine_mode mode;
/* The values computed by this function never change. */
enum machine_mode mode;
rtx reg, mem;
rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
-
+
size = nelts = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
default: return no_type_class;
}
}
-
+
/* Expand a call to __builtin_classify_type with arguments found in
ARGLIST. */
tree exp;
rtx target, subtarget;
{
- optab builtin_optab;
+ optab builtin_optab;
rtx op0, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
+ enum machine_mode argmode;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return 0;
case BUILT_IN_COSF:
case BUILT_IN_COSL:
builtin_optab = cos_optab; break;
- case BUILT_IN_FSQRT:
+ case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL:
builtin_optab = sqrt_optab; break;
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
- target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
- builtin_optab, op0, target, 0);
+ argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
+ target = expand_unop (argmode, builtin_optab, op0, target, 0);
/* If we were unable to expand via the builtin, stop the
sequence (without outputting the insns) and return 0, causing
return 0;
}
- /* If errno must be maintained and if we are not allowing unsafe
- math optimizations, check the result. */
+ /* If errno must be maintained, we must set it to EDOM for NaN results. */
- if (flag_errno_math && ! flag_unsafe_math_optimizations)
+ if (flag_errno_math && HONOR_NANS (argmode))
{
rtx lab1;
- /* Don't define the builtin FP instructions
- if your machine is not IEEE. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- abort ();
-
lab1 = gen_label_rtx ();
/* Test the result; if it is NaN, set errno=EDOM because
0, lab1);
#ifdef TARGET_EDOM
- {
+ {
#ifdef GEN_ERRNO_RTX
- rtx errno_rtx = GEN_ERRNO_RTX;
+ rtx errno_rtx = GEN_ERRNO_RTX;
#else
- rtx errno_rtx
- = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
+ rtx errno_rtx
+ = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
#endif
- emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
- }
+ emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
+ }
#else
/* We can't set errno=EDOM directly; let the library call do it.
Pop the arguments right away in case the call gets deleted. */
insns = get_insns ();
end_sequence ();
emit_insns (insns);
-
+
return target;
}
/* Now that we are assured of success, expand the source. */
start_sequence ();
- pat = memory_address (BLKmode,
+ pat = memory_address (BLKmode,
expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
if (pat != src_reg)
emit_move_insn (src_reg, pat);
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))
= 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)
+ /* 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);
}
/* 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;
- len = size_binop (PLUS_EXPR, len, ssize_int (1));
- chainon (arglist, build_tree_list (NULL_TREE, len));
- }
+ fn = built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
- result = expand_builtin_memcpy (arglist);
+ len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+ if (len == 0)
+ return 0;
- 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)
{
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)
return 0;
/* If the len parameter is zero, return the dst parameter. */
- if (compare_tree_int (len, 0) == 0)
- {
- /* Evaluate and ignore the src argument in case it has
- side-effects. */
+ 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 the dst parameter. */
return expand_expr (TREE_VALUE (arglist), target, mode,
EXPAND_NORMAL);
}
(PTR) p, dest_align);
return force_operand (XEXP (dest_mem, 0), NULL_RTX);
}
-
+
/* 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);
}
}
return c_readstr (p, mode);
}
+/* Callback routine for store_by_pieces. Return the RTL of a register
+ containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
+ char value given in the RTL register data. For example, if mode is
+ 4 bytes wide, return the RTL for 0x01010101*data. */
+
+static rtx
+builtin_memset_gen_str (data, offset, mode)
+ PTR data;
+ HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+{
+ rtx target, coeff;
+ size_t size;
+ char *p;
+
+ size = GET_MODE_SIZE (mode);
+ if (size==1)
+ return (rtx)data;
+
+ p = alloca (size);
+ memset (p, 1, size);
+ coeff = c_readstr (p, mode);
+
+ target = convert_to_mode (mode, (rtx)data, 1);
+ target = expand_mult (mode, target, coeff, NULL_RTX, 1);
+ return force_reg (mode, target);
+}
+
/* 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);
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
rtx dest_mem, dest_addr, len_rtx;
- /* If DEST is not a pointer type, don't do this
+ /* If DEST is not a pointer type, don't do this
operation in-line. */
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;
+ {
+ rtx val_rtx;
+
+ if (!host_integerp (len, 1))
+ return 0;
+
+ if (optimize_size && tree_low_cst (len, 1) > 1)
+ return 0;
+
+ /* Assume that we can memset by pieces if we can store the
+ * the coefficients by pieces (in the required modes).
+ * We can't pass builtin_memset_gen_str as that emits RTL. */
+ c = 1;
+ if (!can_store_by_pieces (tree_low_cst (len, 1),
+ builtin_memset_read_str,
+ (PTR) &c, dest_align))
+ return 0;
+
+ val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
+ val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+ val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
+ val_rtx);
+ dest_mem = get_memory_rtx (dest);
+ store_by_pieces (dest_mem, tree_low_cst (len, 1),
+ builtin_memset_gen_str,
+ (PTR)val_rtx, dest_align);
+ return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+ }
if (target_char_cast (val, &c))
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). */
-
+ 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;
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)
- tree exp;
+expand_builtin_memcmp (exp, arglist, target, mode)
+ tree exp ATTRIBUTE_UNUSED;
tree arglist;
rtx target;
+ enum machine_mode mode;
{
+ tree arg1, arg2, len;
+ const char *p1, *p2;
+
if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ 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;
+ }
+
+ p1 = c_getstr (arg1);
+ p2 = c_getstr (arg2);
+
+ /* If all arguments are constant, and the value of len is not greater
+ than the lengths of arg1 and arg2, evaluate at compile-time. */
+ if (host_integerp (len, 1) && p1 && p2
+ && compare_tree_int (len, strlen (p1) + 1) <= 0
+ && compare_tree_int (len, strlen (p2) + 1) <= 0)
+ {
+ const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+
+ return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : 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;
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. */
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))
tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
-
-#ifdef HAVE_cmpstrsi
- if (! HAVE_cmpstrsi)
- return 0;
- {
- tree len = c_strlen (arg1);
- tree len2 = c_strlen (arg2);
- rtx result;
+ len = c_strlen (arg1);
+ len2 = c_strlen (arg2);
- if (len)
- len = size_binop (PLUS_EXPR, ssize_int (1), len);
+ if (len)
+ len = size_binop (PLUS_EXPR, ssize_int (1), len);
- if (len2)
- len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+ 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 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 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 (!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;
+ /* 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;
+ fn = built_in_decls[BUILT_IN_MEMCMP];
+ if (!fn)
+ return 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
enum machine_mode mode;
{
tree arglist = TREE_OPERAND (exp, 1);
+ tree fn, newarglist, len = 0;
tree arg1, arg2, arg3;
const char *p1, *p2;
/* If the len parameter is zero, return zero. */
if (host_integerp (arg3, 1) && tree_low_cst (arg3, 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;
- }
+ {
+ /* 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;
+ }
p1 = c_getstr (arg1);
p2 = c_getstr (arg2);
/* If all arguments are constant, evaluate at compile-time. */
if (host_integerp (arg3, 1) && p1 && p2)
- {
- const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
- return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
- }
+ {
+ const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
+ return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
+ }
/* If len == 1 or (either string parameter is "" and (len >= 1)),
return (*(const u_char*)arg1 - *(const u_char*)arg2). */
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);
-
- /* 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)));
-
- /* The actual new length parameter is MIN(len,arg3). */
- len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
-
- 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
-
- return 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);
+
+ /* 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;
+
+ fn = built_in_decls[BUILT_IN_MEMCMP];
+ if (!fn)
+ return 0;
+
+ /* Add one to the string length. */
+ len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
+
+ /* The actual new length parameter is MIN(len,arg3). */
+ len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
+
+ 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.
/* If the requested length is zero, or the src parameter string
length is zero, return the dst parameter. */
- if ((TREE_CODE (len) == INTEGER_CST && compare_tree_int (len, 0) == 0)
- || (p && *p == '\0'))
- {
+ if (integer_zerop (len) || (p && *p == '\0'))
+ {
/* Evaluate and ignore the src and len parameters in case
they have side-effects. */
expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
length, call strcat. */
if (TREE_CODE (len) == INTEGER_CST && p
&& compare_tree_int (len, strlen (p)) >= 0)
- {
- tree newarglist =
- tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)),
- fn = built_in_decls[BUILT_IN_STRCAT];
-
+ {
+ tree newarglist
+ = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
+ tree fn = built_in_decls[BUILT_IN_STRCAT];
+
/* If the replacement _DECL isn't initialized, don't do the
transformation. */
if (!fn)
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
-
+
/* If both arguments are constants, evaluate at compile-time. */
if (p1 && p2)
- {
+ {
const size_t r = strspn (p1, p2);
return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
}
-
+
/* If either argument is "", return 0. */
if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
- {
+ {
/* Evaluate and ignore both arguments in case either one has
side-effects. */
expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
-
+
/* If both arguments are constants, evaluate at compile-time. */
if (p1 && p2)
- {
+ {
const size_t r = strcspn (p1, p2);
return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
}
-
+
/* If the first argument is "", return 0. */
if (p1 && *p1 == '\0')
- {
+ {
/* Evaluate and ignore argument s2 in case it has
side-effects. */
expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* If the second argument is "", return __builtin_strlen(s1). */
if (p2 && *p2 == '\0')
- {
+ {
tree newarglist = build_tree_list (NULL_TREE, s1),
fn = built_in_decls[BUILT_IN_STRLEN];
-
+
/* If the replacement _DECL isn't initialized, don't do the
transformation. */
if (!fn)
tree arglist = TREE_OPERAND (exp, 1);
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
int *word_ptr = (int *) ¤t_function_args_info;
-#if 0
+#if 0
/* These are used by the code below that is if 0'ed away */
int i;
tree type, elts, result;
tree arg = TREE_VALUE (arglist);
/* Strip off all nops for the sake of the comparison. This
- is not quite the same as STRIP_NOPS. It does more.
+ is not quite the same as STRIP_NOPS. It does more.
We must also strip off INDIRECT_EXPR for C++ reference
parameters. */
while (TREE_CODE (arg) == NOP_EXPR
So fix it. */
if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
{
- tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
- tree p2 = build_pointer_type (va_list_type_node);
+ tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+ tree p2 = build_pointer_type (va_list_type_node);
- valist = build1 (ADDR_EXPR, p2, valist);
+ valist = build1 (ADDR_EXPR, p2, valist);
valist = fold (build1 (NOP_EXPR, p1, valist));
}
}
{
if (! TREE_SIDE_EFFECTS (valist))
return valist;
-
+
pt = build_pointer_type (va_list_type_node);
valist = fold (build1 (ADDR_EXPR, pt, valist));
TREE_SIDE_EFFECTS (valist) = 1;
std_expand_builtin_va_arg (valist, type)
tree valist, type;
{
- tree addr_tree, t;
- HOST_WIDE_INT align;
- HOST_WIDE_INT rounded_size;
+ tree addr_tree, t, type_size = NULL;
+ tree align, alignm1;
+ tree rounded_size;
rtx addr;
/* Compute the rounded size of the type. */
- align = PARM_BOUNDARY / BITS_PER_UNIT;
- rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
+ align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
+ alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
+ if (type == error_mark_node
+ || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+ || TREE_OVERFLOW (type_size))
+ rounded_size = size_zero_node;
+ else
+ rounded_size = fold (build (MULT_EXPR, sizetype,
+ fold (build (TRUNC_DIV_EXPR, sizetype,
+ fold (build (PLUS_EXPR, sizetype,
+ type_size, alignm1)),
+ align)),
+ align));
/* Get AP. */
addr_tree = valist;
- if (PAD_VARARGS_DOWN)
+ if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
{
/* Small args are padded downward. */
-
- HOST_WIDE_INT adj
- = rounded_size > align ? rounded_size : int_size_in_bytes (type);
-
- addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
- build_int_2 (rounded_size - adj, 0));
+ addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
+ fold (build (COND_EXPR, sizetype,
+ fold (build (GT_EXPR, sizetype,
+ rounded_size,
+ align)),
+ size_zero_node,
+ fold (build (MINUS_EXPR, sizetype,
+ rounded_size,
+ type_size))))));
}
addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
addr = copy_to_reg (addr);
/* Compute new value for AP. */
- t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build (PLUS_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (rounded_size, 0)));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ if (! integer_zerop (rounded_size))
+ {
+ t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ build (PLUS_EXPR, TREE_TYPE (valist), valist,
+ rounded_size));
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
return addr;
}
have_va_type = TREE_TYPE (valist);
if (TREE_CODE (want_va_type) == ARRAY_TYPE)
{
- /* If va_list is an array type, the argument may have decayed
+ /* If va_list is an array type, the argument may have decayed
to a pointer type, e.g. by being passed to another function.
In that case, unwrap both types so that we can compare the
underlying records. */
/* Generate a diagnostic for requesting data of a type that cannot
be passed through `...' due to type promotion at the call site. */
- else if ((promoted_type = (*lang_type_promotes_to) (type)) != NULL_TREE)
+ else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
+ != type)
{
const char *name = "<anonymous type>", *pname = 0;
- static int gave_help;
+ static bool gave_help;
if (TYPE_NAME (type))
{
pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
}
- error ("`%s' is promoted to `%s' when passed through `...'", name, pname);
+ /* 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 ("`%s' is promoted to `%s' when passed through `...'",
+ name, pname);
if (! gave_help)
{
- gave_help = 1;
- error ("(so you should pass `%s' not `%s' to `va_arg')", pname, name);
+ gave_help = true;
+ warning ("(so you should pass `%s' not `%s' to `va_arg')",
+ pname, name);
}
+ /* We can, however, treat "undefined" any way we please.
+ Call abort to encourage the user to fix the program. */
+ expand_builtin_trap ();
+
+ /* This is dead code, but go ahead and finish so that the
+ mode of the result comes out right. */
addr = const0_rtx;
}
else
return const0_rtx;
}
-/* Expand ARGLIST, from a call to __builtin_va_copy. We do this as a
+/* Expand ARGLIST, from a call to __builtin_va_copy. We do this as a
builtin rather than just as an assignment in stdarg.h because of the
nastiness of array-type va_list types. */
long, we attempt to transform this call into __builtin_fputc(). */
static rtx
-expand_builtin_fputs (arglist, ignore)
+expand_builtin_fputs (arglist, ignore, unlocked)
tree arglist;
int ignore;
+ int unlocked;
{
- tree len, fn, fn_fputc = built_in_decls[BUILT_IN_FPUTC],
- fn_fwrite = built_in_decls[BUILT_IN_FWRITE];
+ tree len, fn;
+ tree fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+ : built_in_decls[BUILT_IN_FPUTC];
+ tree fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
+ : built_in_decls[BUILT_IN_FWRITE];
/* If the return value is used, or the replacement _DECL isn't
initialized, don't do the transformation. */
const char *p = c_getstr (TREE_VALUE (arglist));
if (p != NULL)
- {
+ {
/* New argument list transforming fputs(string, stream) to
fputc(string[0], stream). */
arglist =
case 1: /* length is greater than 1, call fwrite. */
{
tree string_arg = TREE_VALUE (arglist);
-
+
/* New argument list transforming fputs(string, stream) to
fwrite(string, 1, len, stream). */
arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
break;
}
default:
- abort();
+ abort ();
}
-
+
return expand_expr (build_function_call_expr (fn, arglist),
(ignore ? const0_rtx : NULL_RTX),
VOIDmode, EXPAND_NORMAL);
moderately sure to be able to correctly interpret the branch
condition later. */
target = force_reg (GET_MODE (target), target);
-
+
rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
return ret;
}
+
+void
+expand_builtin_trap ()
+{
+#ifdef HAVE_trap
+ if (HAVE_trap)
+ emit_insn (gen_trap ());
+ else
+#endif
+ emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
+ emit_barrier ();
+}
\f
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore);
-
+
/* When not optimizing, generate calls to library functions for a certain
set of builtins. */
- if (! optimize && ! CALLED_AS_BUILT_IN (fndecl)
- && (fcode == BUILT_IN_SIN || fcode == BUILT_IN_COS
- || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_SQRTF
- || fcode == BUILT_IN_SQRTL || fcode == BUILT_IN_MEMSET
- || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
- || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO
- || fcode == BUILT_IN_INDEX || fcode == BUILT_IN_RINDEX
- || fcode == BUILT_IN_STRCHR || fcode == BUILT_IN_STRRCHR
- || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
- || fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP
- || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
- || fcode == BUILT_IN_STRCAT || fcode == BUILT_IN_STRNCAT
- || fcode == BUILT_IN_STRSPN || fcode == BUILT_IN_STRCSPN
- || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
- || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
- || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC
- || fcode == BUILT_IN_FPUTS || fcode == BUILT_IN_FWRITE))
- return expand_call (exp, target, ignore);
+ if (!optimize && !CALLED_AS_BUILT_IN (fndecl))
+ switch (fcode)
+ {
+ case BUILT_IN_SIN:
+ case BUILT_IN_COS:
+ case BUILT_IN_SQRT:
+ case BUILT_IN_SQRTF:
+ case BUILT_IN_SQRTL:
+ case BUILT_IN_MEMSET:
+ case BUILT_IN_MEMCPY:
+ case BUILT_IN_MEMCMP:
+ case BUILT_IN_BCMP:
+ case BUILT_IN_BZERO:
+ case BUILT_IN_INDEX:
+ case BUILT_IN_RINDEX:
+ case BUILT_IN_STRCHR:
+ case BUILT_IN_STRRCHR:
+ case BUILT_IN_STRLEN:
+ case BUILT_IN_STRCPY:
+ case BUILT_IN_STRNCPY:
+ case BUILT_IN_STRNCMP:
+ case BUILT_IN_STRSTR:
+ case BUILT_IN_STRPBRK:
+ case BUILT_IN_STRCAT:
+ case BUILT_IN_STRNCAT:
+ case BUILT_IN_STRSPN:
+ case BUILT_IN_STRCSPN:
+ case BUILT_IN_STRCMP:
+ case BUILT_IN_FFS:
+ case BUILT_IN_PUTCHAR:
+ case BUILT_IN_PUTS:
+ case BUILT_IN_PRINTF:
+ case BUILT_IN_FPUTC:
+ case BUILT_IN_FPUTS:
+ case BUILT_IN_FWRITE:
+ case BUILT_IN_PUTCHAR_UNLOCKED:
+ case BUILT_IN_PUTS_UNLOCKED:
+ case BUILT_IN_PRINTF_UNLOCKED:
+ case BUILT_IN_FPUTC_UNLOCKED:
+ case BUILT_IN_FPUTS_UNLOCKED:
+ case BUILT_IN_FWRITE_UNLOCKED:
+ return expand_call (exp, target, ignore);
+
+ default:
+ break;
+ }
switch (fcode)
{
because of possible accuracy problems. */
if (! flag_unsafe_math_optimizations)
break;
- case BUILT_IN_FSQRT:
+ case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL:
target = expand_builtin_mathfn (exp, target, subtarget);
0 otherwise. */
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
if (arglist != 0
- || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
- || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
- return const0_rtx;
+ || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+ || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
+ return const0_rtx;
else
- return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+ return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
case BUILT_IN_ALLOCA:
target = expand_builtin_alloca (arglist, target);
break;
case BUILT_IN_STRCPY:
- target = expand_builtin_strcpy (exp);
+ target = expand_builtin_strcpy (exp, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRNCPY:
target = expand_builtin_strncpy (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRCAT:
target = expand_builtin_strcat (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRNCAT:
target = expand_builtin_strncat (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRSPN:
target = expand_builtin_strspn (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRCSPN:
target = expand_builtin_strcspn (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRSTR:
target = expand_builtin_strstr (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_STRPBRK:
target = expand_builtin_strpbrk (arglist, target, mode);
if (target)
return target;
break;
-
+
case BUILT_IN_INDEX:
case BUILT_IN_STRCHR:
target = expand_builtin_strchr (arglist, target, mode);
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;
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);
}
case BUILT_IN_TRAP:
-#ifdef HAVE_trap
- if (HAVE_trap)
- emit_insn (gen_trap ());
- else
-#endif
- error ("__builtin_trap not supported by this target");
- emit_barrier ();
+ expand_builtin_trap ();
return const0_rtx;
case BUILT_IN_PUTCHAR:
case BUILT_IN_PUTS:
case BUILT_IN_FPUTC:
case BUILT_IN_FWRITE:
+ case BUILT_IN_PUTCHAR_UNLOCKED:
+ case BUILT_IN_PUTS_UNLOCKED:
+ case BUILT_IN_FPUTC_UNLOCKED:
+ case BUILT_IN_FWRITE_UNLOCKED:
break;
case BUILT_IN_FPUTS:
- target = expand_builtin_fputs (arglist, ignore);
+ target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
if (target)
return target;
break;
-
+ case BUILT_IN_FPUTS_UNLOCKED:
+ target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1);
+ if (target)
+ return target;
+ break;
+
/* Various hooks for the DWARF 2 __throw routine. */
case BUILT_IN_UNWIND_INIT:
expand_builtin_unwind_init ();