/* Expand builtin functions.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GCC.
static const char *c_getstr (tree);
static rtx c_readstr (const char *, enum machine_mode);
static int target_char_cast (tree, char *);
-static rtx get_memory_rtx (tree);
-static tree build_string_literal (int, const char *);
+static rtx get_memory_rtx (tree, tree);
static int apply_args_size (void);
static int apply_result_size (void);
#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
static rtx expand_builtin_mathfn (tree, rtx, rtx);
static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
+static rtx expand_builtin_sincos (tree);
static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
static rtx expand_builtin_args_info (tree);
static rtx expand_builtin_next_arg (void);
static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
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_strcpy (tree, 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 tree fold_builtin_sprintf_chk (tree, enum built_in_function);
static tree fold_builtin_printf (tree, tree, bool, enum built_in_function);
static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function);
+static bool init_target_chars (void);
+
+static unsigned HOST_WIDE_INT target_newline;
+static unsigned HOST_WIDE_INT target_percent;
+static unsigned HOST_WIDE_INT target_c;
+static unsigned HOST_WIDE_INT target_s;
+static char target_percent_c[3];
+static char target_percent_s[3];
+static char target_percent_s_newline[4];
/* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with
case ADDR_EXPR:
/* See what we are pointing at and look at its alignment. */
exp = TREE_OPERAND (exp, 0);
+ inner = max_align;
+ while (handled_component_p (exp))
+ {
+ /* Fields in a structure can be packed, honour DECL_ALIGN
+ of the FIELD_DECL. For all other references the conservative
+ alignment is the element type alignment. */
+ if (TREE_CODE (exp) == COMPONENT_REF)
+ inner = MIN (inner, DECL_ALIGN (TREE_OPERAND (exp, 1)));
+ else
+ inner = MIN (inner, TYPE_ALIGN (TREE_TYPE (exp)));
+ exp = TREE_OPERAND (exp, 0);
+ }
if (TREE_CODE (exp) == FUNCTION_DECL)
align = FUNCTION_BOUNDARY;
else if (DECL_P (exp))
- align = DECL_ALIGN (exp);
+ align = MIN (inner, DECL_ALIGN (exp));
#ifdef CONSTANT_ALIGNMENT
else if (CONSTANT_CLASS_P (exp))
- align = CONSTANT_ALIGNMENT (exp, align);
+ align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
#endif
+ else
+ align = MIN (align, inner);
return MIN (align, max_align);
default:
#ifdef INITIAL_FRAME_ADDRESS_RTX
rtx tem = INITIAL_FRAME_ADDRESS_RTX;
#else
- rtx tem = hard_frame_pointer_rtx;
+ rtx tem;
+
+ /* For a zero count, we don't care what frame address we return, so frame
+ pointer elimination is OK, and using the soft frame pointer is OK.
+ For a nonzero count, we require a stable offset from the current frame
+ pointer to the previous one, so we must use the hard frame pointer, and
+ we must disable frame pointer elimination. */
+ if (count == 0)
+ tem = frame_pointer_rtx;
+ else
+ {
+ tem = hard_frame_pointer_rtx;
+
+ /* Tell reload not to eliminate the frame pointer. */
+ current_function_accesses_prior_frames = 1;
+ }
#endif
/* Some machines need special handling before we can access
tem = DYNAMIC_CHAIN_ADDRESS (tem);
#endif
tem = memory_address (Pmode, tem);
- tem = gen_rtx_MEM (Pmode, tem);
- set_mem_alias_set (tem, get_frame_alias_set ());
+ tem = gen_frame_mem (Pmode, tem);
tem = copy_to_reg (tem);
}
#else
tem = memory_address (Pmode,
plus_constant (tem, GET_MODE_SIZE (Pmode)));
- tem = gen_rtx_MEM (Pmode, tem);
- set_mem_alias_set (tem, get_frame_alias_set ());
+ tem = gen_frame_mem (Pmode, tem);
#endif
return tem;
}
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (TYPE_MODE (integer_type_node));
- buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+ buf_addr = expand_normal (TREE_VALUE (arglist));
next_lab = gen_label_rtx ();
cont_lab = gen_label_rtx ();
arglist = TREE_CHAIN (arglist);
t_save_area = TREE_VALUE (arglist);
- r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0);
+ r_label = expand_normal (t_label);
r_label = convert_memory_address (Pmode, r_label);
- r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0);
+ r_save_area = expand_normal (t_save_area);
r_save_area = convert_memory_address (Pmode, r_save_area);
r_fp = gen_rtx_MEM (Pmode, r_save_area);
r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
error ("second argument to %<__builtin_prefetch%> must be a constant");
arg1 = integer_zero_node;
}
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op1 = expand_normal (arg1);
/* Argument 1 must be either zero or one. */
if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
{
error ("third argument to %<__builtin_prefetch%> must be a constant");
arg2 = integer_zero_node;
}
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op2 = expand_normal (arg2);
/* Argument 2 must be 0, 1, 2, or 3. */
if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
{
}
/* Get a MEM rtx for expression EXP which is the address of an operand
- to be used to be used in a string instruction (cmpstrsi, movmemsi, ..). */
+ to be used in a string instruction (cmpstrsi, movmemsi, ..). LEN is
+ the maximum length of the block of memory that might be accessed or
+ NULL if unknown. */
static rtx
-get_memory_rtx (tree exp)
+get_memory_rtx (tree exp, tree len)
{
rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
if (exp)
{
set_mem_attributes (mem, exp, 0);
+
+ /* Allow the string and memory builtins to overflow from one
+ field into another, see http://gcc.gnu.org/PR23561.
+ Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole
+ memory accessed by the string or memory builtin will fit
+ within the field. */
+ if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
+ {
+ tree mem_expr = MEM_EXPR (mem);
+ HOST_WIDE_INT offset = -1, length = -1;
+ tree inner = exp;
+
+ while (TREE_CODE (inner) == ARRAY_REF
+ || TREE_CODE (inner) == NOP_EXPR
+ || TREE_CODE (inner) == CONVERT_EXPR
+ || TREE_CODE (inner) == NON_LVALUE_EXPR
+ || TREE_CODE (inner) == VIEW_CONVERT_EXPR
+ || TREE_CODE (inner) == SAVE_EXPR)
+ inner = TREE_OPERAND (inner, 0);
+
+ gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
+
+ if (MEM_OFFSET (mem)
+ && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+ offset = INTVAL (MEM_OFFSET (mem));
+
+ if (offset >= 0 && len && host_integerp (len, 0))
+ length = tree_low_cst (len, 0);
+
+ while (TREE_CODE (inner) == COMPONENT_REF)
+ {
+ tree field = TREE_OPERAND (inner, 1);
+ gcc_assert (! DECL_BIT_FIELD (field));
+ gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
+ gcc_assert (field == TREE_OPERAND (mem_expr, 1));
+
+ if (length >= 0
+ && TYPE_SIZE_UNIT (TREE_TYPE (inner))
+ && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
+ {
+ HOST_WIDE_INT size
+ = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
+ /* If we can prove the memory starting at XEXP (mem, 0)
+ and ending at XEXP (mem, 0) + LENGTH will fit into
+ this field, we can keep that COMPONENT_REF in MEM_EXPR. */
+ if (offset <= size
+ && length <= size
+ && offset + length <= size)
+ break;
+ }
+
+ if (offset >= 0
+ && host_integerp (DECL_FIELD_OFFSET (field), 0))
+ offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
+ + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+ / BITS_PER_UNIT;
+ else
+ {
+ offset = -1;
+ length = -1;
+ }
+
+ mem_expr = TREE_OPERAND (mem_expr, 0);
+ inner = TREE_OPERAND (inner, 0);
+ }
+
+ if (mem_expr == NULL)
+ offset = -1;
+ if (mem_expr != MEM_EXPR (mem))
+ {
+ set_mem_expr (mem, mem_expr);
+ set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
+ }
+ }
set_mem_alias_set (mem, 0);
set_mem_size (mem, NULL_RTX);
}
{
case VOID_TYPE: return void_type_class;
case INTEGER_TYPE: return integer_type_class;
- case CHAR_TYPE: return char_type_class;
case ENUMERAL_TYPE: return enumeral_type_class;
case BOOLEAN_TYPE: return boolean_type_class;
case POINTER_TYPE: return pointer_type_class;
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_SQRT:
- case BUILT_IN_SQRTF:
- case BUILT_IN_SQRTL:
+ CASE_FLT_FN (BUILT_IN_SQRT):
errno_set = ! tree_expr_nonnegative_p (arg);
builtin_optab = sqrt_optab;
break;
- case BUILT_IN_EXP:
- case BUILT_IN_EXPF:
- case BUILT_IN_EXPL:
+ CASE_FLT_FN (BUILT_IN_EXP):
errno_set = true; builtin_optab = exp_optab; break;
- case BUILT_IN_EXP10:
- case BUILT_IN_EXP10F:
- case BUILT_IN_EXP10L:
- case BUILT_IN_POW10:
- case BUILT_IN_POW10F:
- case BUILT_IN_POW10L:
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_POW10):
errno_set = true; builtin_optab = exp10_optab; break;
- case BUILT_IN_EXP2:
- case BUILT_IN_EXP2F:
- case BUILT_IN_EXP2L:
+ CASE_FLT_FN (BUILT_IN_EXP2):
errno_set = true; builtin_optab = exp2_optab; break;
- case BUILT_IN_EXPM1:
- case BUILT_IN_EXPM1F:
- case BUILT_IN_EXPM1L:
+ CASE_FLT_FN (BUILT_IN_EXPM1):
errno_set = true; builtin_optab = expm1_optab; break;
- case BUILT_IN_LOGB:
- case BUILT_IN_LOGBF:
- case BUILT_IN_LOGBL:
+ CASE_FLT_FN (BUILT_IN_LOGB):
errno_set = true; builtin_optab = logb_optab; break;
- case BUILT_IN_ILOGB:
- case BUILT_IN_ILOGBF:
- case BUILT_IN_ILOGBL:
+ CASE_FLT_FN (BUILT_IN_ILOGB):
errno_set = true; builtin_optab = ilogb_optab; break;
- case BUILT_IN_LOG:
- case BUILT_IN_LOGF:
- case BUILT_IN_LOGL:
+ CASE_FLT_FN (BUILT_IN_LOG):
errno_set = true; builtin_optab = log_optab; break;
- case BUILT_IN_LOG10:
- case BUILT_IN_LOG10F:
- case BUILT_IN_LOG10L:
+ CASE_FLT_FN (BUILT_IN_LOG10):
errno_set = true; builtin_optab = log10_optab; break;
- case BUILT_IN_LOG2:
- case BUILT_IN_LOG2F:
- case BUILT_IN_LOG2L:
+ CASE_FLT_FN (BUILT_IN_LOG2):
errno_set = true; builtin_optab = log2_optab; break;
- case BUILT_IN_LOG1P:
- case BUILT_IN_LOG1PF:
- case BUILT_IN_LOG1PL:
+ CASE_FLT_FN (BUILT_IN_LOG1P):
errno_set = true; builtin_optab = log1p_optab; break;
- case BUILT_IN_ASIN:
- case BUILT_IN_ASINF:
- case BUILT_IN_ASINL:
+ CASE_FLT_FN (BUILT_IN_ASIN):
builtin_optab = asin_optab; break;
- case BUILT_IN_ACOS:
- case BUILT_IN_ACOSF:
- case BUILT_IN_ACOSL:
+ CASE_FLT_FN (BUILT_IN_ACOS):
builtin_optab = acos_optab; break;
- case BUILT_IN_TAN:
- case BUILT_IN_TANF:
- case BUILT_IN_TANL:
+ CASE_FLT_FN (BUILT_IN_TAN):
builtin_optab = tan_optab; break;
- case BUILT_IN_ATAN:
- case BUILT_IN_ATANF:
- case BUILT_IN_ATANL:
+ CASE_FLT_FN (BUILT_IN_ATAN):
builtin_optab = atan_optab; break;
- case BUILT_IN_FLOOR:
- case BUILT_IN_FLOORF:
- case BUILT_IN_FLOORL:
+ CASE_FLT_FN (BUILT_IN_FLOOR):
builtin_optab = floor_optab; break;
- case BUILT_IN_CEIL:
- case BUILT_IN_CEILF:
- case BUILT_IN_CEILL:
+ CASE_FLT_FN (BUILT_IN_CEIL):
builtin_optab = ceil_optab; break;
- case BUILT_IN_TRUNC:
- case BUILT_IN_TRUNCF:
- case BUILT_IN_TRUNCL:
+ CASE_FLT_FN (BUILT_IN_TRUNC):
builtin_optab = btrunc_optab; break;
- case BUILT_IN_ROUND:
- case BUILT_IN_ROUNDF:
- case BUILT_IN_ROUNDL:
+ CASE_FLT_FN (BUILT_IN_ROUND):
builtin_optab = round_optab; break;
- case BUILT_IN_NEARBYINT:
- case BUILT_IN_NEARBYINTF:
- case BUILT_IN_NEARBYINTL:
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
builtin_optab = nearbyint_optab; break;
- case BUILT_IN_RINT:
- case BUILT_IN_RINTF:
- case BUILT_IN_RINTL:
+ CASE_FLT_FN (BUILT_IN_RINT):
builtin_optab = rint_optab; break;
- case BUILT_IN_LRINT:
- case BUILT_IN_LRINTF:
- case BUILT_IN_LRINTL:
- case BUILT_IN_LLRINT:
- case BUILT_IN_LLRINTF:
- case BUILT_IN_LLRINTL:
+ CASE_FLT_FN (BUILT_IN_LRINT):
+ CASE_FLT_FN (BUILT_IN_LLRINT):
builtin_optab = lrint_optab; break;
default:
gcc_unreachable ();
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
+ CASE_FLT_FN (BUILT_IN_POW):
builtin_optab = pow_optab; break;
- case BUILT_IN_ATAN2:
- case BUILT_IN_ATAN2F:
- case BUILT_IN_ATAN2L:
+ CASE_FLT_FN (BUILT_IN_ATAN2):
builtin_optab = atan2_optab; break;
- case BUILT_IN_LDEXP:
- case BUILT_IN_LDEXPF:
- case BUILT_IN_LDEXPL:
+ CASE_FLT_FN (BUILT_IN_LDEXP):
builtin_optab = ldexp_optab; break;
- case BUILT_IN_FMOD:
- case BUILT_IN_FMODF:
- case BUILT_IN_FMODL:
+ CASE_FLT_FN (BUILT_IN_FMOD):
builtin_optab = fmod_optab; break;
- case BUILT_IN_DREM:
- case BUILT_IN_DREMF:
- case BUILT_IN_DREML:
+ CASE_FLT_FN (BUILT_IN_DREM):
builtin_optab = drem_optab; break;
default:
gcc_unreachable ();
if (! stable)
exp = build_function_call_expr (fndecl, arglist);
- op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
- op1 = expand_expr (arg1, 0, VOIDmode, 0);
+ op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_normal (arg1);
start_sequence ();
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode mode;
- bool errno_set = false;
tree arg, narg;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_SIN:
- case BUILT_IN_SINF:
- case BUILT_IN_SINL:
- case BUILT_IN_COS:
- case BUILT_IN_COSF:
- case BUILT_IN_COSL:
+ CASE_FLT_FN (BUILT_IN_SIN):
+ CASE_FLT_FN (BUILT_IN_COS):
builtin_optab = sincos_optab; break;
default:
gcc_unreachable ();
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
- if (! flag_errno_math || ! HONOR_NANS (mode))
- errno_set = false;
-
/* Check if sincos insn is available, otherwise fallback
to sin or cos insn. */
if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_SIN:
- case BUILT_IN_SINF:
- case BUILT_IN_SINL:
+ CASE_FLT_FN (BUILT_IN_SIN):
builtin_optab = sin_optab; break;
- case BUILT_IN_COS:
- case BUILT_IN_COSF:
- case BUILT_IN_COSL:
+ CASE_FLT_FN (BUILT_IN_COS):
builtin_optab = cos_optab; break;
default:
gcc_unreachable ();
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_SIN:
- case BUILT_IN_SINF:
- case BUILT_IN_SINL:
+ CASE_FLT_FN (BUILT_IN_SIN):
result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
break;
- case BUILT_IN_COS:
- case BUILT_IN_COSF:
- case BUILT_IN_COSL:
+ CASE_FLT_FN (BUILT_IN_COS):
result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
break;
default:
if (target != 0)
{
- if (errno_set)
- expand_errno_check (exp, target);
-
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
return target;
}
+/* Expand a call to the builtin sincos math function.
+ Return 0 if a normal call should be emitted rather than expanding the
+ function in-line. EXP is the expression that is a call to the builtin
+ function. */
+
+static rtx
+expand_builtin_sincos (tree exp)
+{
+ rtx op0, op1, op2, target1, target2;
+ tree arglist = TREE_OPERAND (exp, 1);
+ enum machine_mode mode;
+ tree arg, sinp, cosp;
+ int result;
+
+ if (!validate_arglist (arglist, REAL_TYPE,
+ POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ sinp = TREE_VALUE (TREE_CHAIN (arglist));
+ cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ /* Make a suitable register to place result in. */
+ mode = TYPE_MODE (TREE_TYPE (arg));
+
+ /* Check if sincos insn is available, otherwise emit the call. */
+ if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+ return NULL_RTX;
+
+ target1 = gen_reg_rtx (mode);
+ target2 = gen_reg_rtx (mode);
+
+ op0 = expand_normal (arg);
+ op1 = expand_normal (build_fold_indirect_ref (sinp));
+ op2 = expand_normal (build_fold_indirect_ref (cosp));
+
+ /* Compute into target1 and target2.
+ Set TARGET to wherever the result comes back. */
+ result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
+ gcc_assert (result);
+
+ /* Move target1 and target2 to the memory locations indicated
+ by op1 and op2. */
+ emit_move_insn (op1, target1);
+ emit_move_insn (op2, target2);
+
+ return const0_rtx;
+}
+
/* Expand a call to one of the builtin rounding functions (lfloor).
If expanding via optab fails, lower expression to (int)(floor(x)).
EXP is the expression that is a call to the builtin function;
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_LCEIL:
- case BUILT_IN_LCEILF:
- case BUILT_IN_LCEILL:
- case BUILT_IN_LLCEIL:
- case BUILT_IN_LLCEILF:
- case BUILT_IN_LLCEILL:
+ CASE_FLT_FN (BUILT_IN_LCEIL):
+ CASE_FLT_FN (BUILT_IN_LLCEIL):
builtin_optab = lceil_optab;
fallback_fn = BUILT_IN_CEIL;
break;
- case BUILT_IN_LFLOOR:
- case BUILT_IN_LFLOORF:
- case BUILT_IN_LFLOORL:
- case BUILT_IN_LLFLOOR:
- case BUILT_IN_LLFLOORF:
- case BUILT_IN_LLFLOORL:
+ CASE_FLT_FN (BUILT_IN_LFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLFLOOR):
builtin_optab = lfloor_optab;
fallback_fn = BUILT_IN_FLOOR;
break;
if (src_align == 0)
return 0;
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
- len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ len_rtx = expand_normal (len);
src_str = c_getstr (src);
/* If SRC is a string constant and block move would be done
return dest_mem;
}
- src_mem = get_memory_rtx (src);
+ src_mem = get_memory_rtx (src, len);
set_mem_align (src_mem, src_align);
/* Copy word part most expediently. */
if (! host_integerp (len, 1))
return 0;
- len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ len_rtx = expand_normal (len);
src_str = c_getstr (src);
/* If SRC is a string constant and block move would be done
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
(void *) src_str, dest_align))
{
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
&& can_move_by_pieces (INTVAL (len_rtx),
MIN (dest_align, src_align)))
{
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
- src_mem = get_memory_rtx (src);
+ src_mem = get_memory_rtx (src, len);
set_mem_align (src_mem, src_align);
dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
MIN (dest_align, src_align), endp);
if (!HAVE_movstr)
return 0;
- dest_mem = get_memory_rtx (dest);
- src_mem = get_memory_rtx (src);
+ dest_mem = get_memory_rtx (dest, NULL);
+ src_mem = get_memory_rtx (src, NULL);
if (!endp)
{
target = force_reg (Pmode, XEXP (dest_mem, 0));
convenient). */
static rtx
-expand_builtin_strcpy (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
{
- tree fndecl = get_callee_fndecl (exp);
- tree arglist = TREE_OPERAND (exp, 1);
if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
{
tree result = fold_builtin_strcpy (fndecl, arglist, 0);
if (TREE_CODE (len) == INTEGER_CST)
{
- rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ rtx len_rtx = expand_normal (len);
if (GET_CODE (len_rtx) == CONST_INT)
{
- ret = expand_builtin_strcpy (exp, target, mode);
+ ret = expand_builtin_strcpy (get_callee_fndecl (exp),
+ arglist, target, mode);
if (ret)
{
(void *) p, dest_align))
return 0;
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
(void *) p, dest_align, 0);
return expand_expr (dest, target, mode, EXPAND_NORMAL);
}
- len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
- dest_mem = get_memory_rtx (dest);
+ len_rtx = expand_normal (len);
+ dest_mem = get_memory_rtx (dest, len);
if (TREE_CODE (val) != INTEGER_CST)
{
rtx val_rtx;
val = fold_build1 (CONVERT_EXPR, unsigned_char_type_node, val);
- val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+ val_rtx = expand_normal (val);
/* Assume that we can memset by pieces if we can store the
* the coefficients by pieces (in the required modes).
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
- arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ arg1_rtx = get_memory_rtx (arg1, len);
+ arg2_rtx = get_memory_rtx (arg2, len);
+ arg3_rtx = expand_normal (len);
/* Set MEM_SIZE as appropriate. */
if (GET_CODE (arg3_rtx) == CONST_INT)
arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
+ arg1_rtx = get_memory_rtx (arg1, NULL);
+ arg2_rtx = get_memory_rtx (arg2, NULL);
#ifdef HAVE_cmpstrsi
/* Try to call cmpstrsi. */
return 0;
/* Stabilize the arguments in case gen_cmpstrnsi fails. */
- arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ arg3_rtx = expand_normal (len);
/* Make a place to write the result of the instruction. */
result = target;
arg2 = builtin_save_expr (arg2);
len = builtin_save_expr (len);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
- arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ arg1_rtx = get_memory_rtx (arg1, len);
+ arg2_rtx = get_memory_rtx (arg2, len);
+ arg3_rtx = expand_normal (len);
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
if (insn)
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcat (tree arglist, tree type, rtx target, enum machine_mode mode)
+expand_builtin_strcat (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
else
{
tree dst = TREE_VALUE (arglist),
- src = TREE_VALUE (TREE_CHAIN (arglist));
+ src = TREE_VALUE (TREE_CHAIN (arglist));
const char *p = c_getstr (src);
- if (p)
+ /* If the string length is zero, return the dst parameter. */
+ if (p && *p == '\0')
+ return expand_expr (dst, target, mode, EXPAND_NORMAL);
+
+ if (!optimize_size)
{
- /* If the string length is zero, return the dst parameter. */
- if (*p == '\0')
- return expand_expr (dst, target, mode, EXPAND_NORMAL);
- else if (!optimize_size)
+ /* See if we can store by pieces into (dst + strlen(dst)). */
+ tree newsrc, newdst,
+ strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+ rtx insns;
+
+ /* Stabilize the argument list. */
+ newsrc = builtin_save_expr (src);
+ if (newsrc != src)
+ arglist = build_tree_list (NULL_TREE, newsrc);
+ else
+ arglist = TREE_CHAIN (arglist); /* Reusing arglist if safe. */
+
+ dst = builtin_save_expr (dst);
+
+ start_sequence ();
+
+ /* Create strlen (dst). */
+ newdst =
+ build_function_call_expr (strlen_fn,
+ build_tree_list (NULL_TREE, dst));
+ /* Create (dst + (cast) strlen (dst)). */
+ newdst = fold_convert (TREE_TYPE (dst), newdst);
+ newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
+
+ newdst = builtin_save_expr (newdst);
+ arglist = tree_cons (NULL_TREE, newdst, arglist);
+
+ if (!expand_builtin_strcpy (fndecl, arglist, target, mode))
{
- /* Otherwise if !optimize_size, see if we can store by
- pieces into (dst + strlen(dst)). */
- tree newdst, arglist,
- strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
-
- /* This is the length argument. */
- arglist = build_tree_list (NULL_TREE,
- fold (size_binop (PLUS_EXPR,
- c_strlen (src, 0),
- ssize_int (1))));
- /* Prepend src argument. */
- arglist = tree_cons (NULL_TREE, src, arglist);
-
- /* We're going to use dst more than once. */
- dst = builtin_save_expr (dst);
-
- /* Create strlen (dst). */
- newdst =
- build_function_call_expr (strlen_fn,
- build_tree_list (NULL_TREE, dst));
- /* Create (dst + (cast) strlen (dst)). */
- newdst = fold_convert (TREE_TYPE (dst), newdst);
- newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
-
- /* Prepend the new dst argument. */
- arglist = tree_cons (NULL_TREE, newdst, arglist);
-
- /* We don't want to get turned into a memcpy if the
- target is const0_rtx, i.e. when the return value
- isn't used. That would produce pessimized code so
- 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, type, /*target=*/0, mode, /*endp=*/0))
- return expand_expr (dst, target, mode, EXPAND_NORMAL);
- else
- return 0;
+ end_sequence (); /* Stop sequence. */
+ return 0;
}
+
+ /* Output the entire sequence. */
+ insns = get_insns ();
+ end_sequence ();
+ emit_insn (insns);
+
+ return expand_expr (dst, target, mode, EXPAND_NORMAL);
}
return 0;
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
- if (boundary > align)
+ if (boundary > align
+ && !integer_zerop (TYPE_SIZE (type)))
{
t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
return 0;
/* Compute the argument. */
- op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (TREE_VALUE (arglist));
/* Allocate the desired space. */
result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
return ret;
}
-static void
+void
expand_builtin_trap (void)
{
#ifdef HAVE_trap
return 0;
arg = TREE_VALUE (arglist);
- op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+ op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
arg = TREE_VALUE (TREE_CHAIN (arglist));
- op1 = expand_expr (arg, NULL, VOIDmode, 0);
+ op1 = expand_normal (arg);
return expand_copysign (op0, op1, target);
}
/* Create a new constant string literal and return a char* pointer to it.
The STRING_CST value is the LEN characters at STR. */
-static tree
+tree
build_string_literal (int len, const char *str)
{
tree t, elem, index, type;
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];
- tree fn_puts = unlocked ? implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED]
- : implicit_built_in_decls[BUILT_IN_PUTS];
+ /* If we're using an unlocked function, assume the other unlocked
+ functions exist explicitly. */
+ tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_PUTCHAR];
+ tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_PUTS];
const char *fmt_str;
tree fn, fmt, arg;
if (fmt_str == NULL)
return 0;
+ if (!init_target_chars())
+ return 0;
+
/* If the format specifier was "%s\n", call __builtin_puts(arg). */
- if (strcmp (fmt_str, "%s\n") == 0)
+ if (strcmp (fmt_str, target_percent_s_newline) == 0)
{
if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
fn = fn_puts;
}
/* If the format specifier was "%c", call __builtin_putchar(arg). */
- else if (strcmp (fmt_str, "%c") == 0)
+ else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
else
{
/* We can't handle anything else with % args or %% ... yet. */
- if (strchr (fmt_str, '%'))
+ if (strchr (fmt_str, target_percent))
return 0;
if (arglist)
{
/* If the format specifier was "string\n", call puts("string"). */
size_t len = strlen (fmt_str);
- if (fmt_str[len - 1] == '\n')
+ if ((unsigned char)fmt_str[len - 1] == target_newline)
{
/* Create a NUL-terminated string that's one char shorter
than the original, stripping off the trailing '\n'. */
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]
- : implicit_built_in_decls[BUILT_IN_FPUTS];
+ /* If we're using an unlocked function, assume the other unlocked
+ functions exist explicitly. */
+ tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_FPUTC];
+ tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_FPUTS];
const char *fmt_str;
tree fn, fmt, fp, arg;
if (fmt_str == NULL)
return 0;
+ if (!init_target_chars())
+ return 0;
+
/* If the format specifier was "%s", call __builtin_fputs(arg,fp). */
- if (strcmp (fmt_str, "%s") == 0)
+ if (strcmp (fmt_str, target_percent_s) == 0)
{
if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
fn = fn_fputs;
}
/* If the format specifier was "%c", call __builtin_fputc(arg,fp). */
- else if (strcmp (fmt_str, "%c") == 0)
+ else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
else
{
/* We can't handle anything else with % args or %% ... yet. */
- if (strchr (fmt_str, '%'))
+ if (strchr (fmt_str, target_percent))
return 0;
if (arglist)
if (fmt_str == NULL)
return 0;
+ if (!init_target_chars())
+ return 0;
+
/* If the format doesn't contain % args or %%, use strcpy. */
- if (strchr (fmt_str, '%') == 0)
+ if (strchr (fmt_str, target_percent) == 0)
{
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
tree exp;
return expand_expr (exp, target, mode, EXPAND_NORMAL);
}
/* If the format is "%s", use strcpy if the result isn't used. */
- else if (strcmp (fmt_str, "%s") == 0)
+ else if (strcmp (fmt_str, target_percent_s) == 0)
{
tree fn, arg, len;
fn = implicit_built_in_decls[BUILT_IN_STRCPY];
arglist = TREE_CHAIN (arglist);
t_chain = TREE_VALUE (arglist);
- r_tramp = expand_expr (t_tramp, NULL_RTX, VOIDmode, 0);
- r_func = expand_expr (t_func, NULL_RTX, VOIDmode, 0);
- r_chain = expand_expr (t_chain, NULL_RTX, VOIDmode, 0);
+ r_tramp = expand_normal (t_tramp);
+ r_func = expand_normal (t_func);
+ r_chain = expand_normal (t_chain);
/* Generate insns to initialize the trampoline. */
r_tramp = round_trampoline_addr (r_tramp);
if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
- tramp = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+ tramp = expand_normal (TREE_VALUE (arglist));
tramp = round_trampoline_addr (tramp);
#ifdef TRAMPOLINE_ADJUST_ADDRESS
TRAMPOLINE_ADJUST_ADDRESS (tramp);
return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
}
- temp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ temp = expand_normal (arg);
if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
{
imode = int_mode_for_mode (fmode);
TREE_PUBLIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
TREE_NOTHROW (decl) = 1;
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
call = build_function_call_expr (decl, arglist);
return expand_call (call, target, ignore);
}
\f
+/* Reconstitute a mode for a __sync intrinsic operation. Since the type of
+ the pointer in these functions is void*, the tree optimizers may remove
+ casts. The mode computed in expand_builtin isn't reliable either, due
+ to __sync_bool_compare_and_swap.
+
+ FCODE_DIFF should be fcode - base, where base is the FOO_1 code for the
+ group of builtins. This gives us log2 of the mode size. */
+
+static inline enum machine_mode
+get_builtin_sync_mode (int fcode_diff)
+{
+ /* The size is not negotiable, so ask not to get BLKmode in return
+ if the target indicates that a smaller size would be better. */
+ return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
+}
+
+/* Expand the memory expression LOC and return the appropriate memory operand
+ for the builtin_sync operations. */
+
+static rtx
+get_builtin_sync_mem (tree loc, enum machine_mode mode)
+{
+ rtx addr, mem;
+
+ addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
+
+ /* 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
+ satisfy the full barrier semantics of the intrinsic. */
+ mem = validize_mem (gen_rtx_MEM (mode, addr));
+
+ set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT));
+ set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
+ MEM_VOLATILE_P (mem) = 1;
+
+ return mem;
+}
+
/* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
ARGLIST is the operands list to the function. CODE is the rtx code
that corresponds to the arithmetic or logical operation from the name;
the result of the operation at all. */
static rtx
-expand_builtin_sync_operation (tree arglist, enum rtx_code code, bool after,
+expand_builtin_sync_operation (enum machine_mode mode, tree arglist,
+ enum rtx_code code, bool after,
rtx target, bool ignore)
{
- enum machine_mode mode;
- rtx addr, val, mem;
+ rtx val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
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
- satisfy the full barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
if (ignore)
return expand_sync_operation (mem, val, code);
else
results; this is NOT optional if IS_BOOL is true. */
static rtx
-expand_builtin_compare_and_swap (tree arglist, bool is_bool, rtx target)
+expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist,
+ bool is_bool, rtx target)
{
- enum machine_mode mode;
- rtx addr, old_val, new_val, mem;
+ rtx old_val, new_val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
arglist = TREE_CHAIN (arglist);
new_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
- satisfy the full barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
if (is_bool)
return expand_bool_compare_and_swap (mem, old_val, new_val, target);
else
place for us to store the results. */
static rtx
-expand_builtin_lock_test_and_set (tree arglist, rtx target)
+expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist,
+ rtx target)
{
- enum machine_mode mode;
- rtx addr, val, mem;
+ rtx val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
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
- satisfy the barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
return expand_sync_lock_test_and_set (mem, val, target);
}
static void
expand_builtin_synchronize (void)
{
- rtx body;
+ tree x;
#ifdef HAVE_memory_barrier
if (HAVE_memory_barrier)
}
#endif
- /* If no explicit memory barrier instruction is available, create an empty
- asm stmt that will prevent compiler movement across the barrier. */
- body = gen_rtx_ASM_INPUT (VOIDmode, "");
- MEM_VOLATILE_P (body) = 1;
- emit_insn (body);
+ /* If no explicit memory barrier instruction is available, create an
+ empty asm stmt with a memory clobber. */
+ x = build4 (ASM_EXPR, void_type_node, build_string (0, ""), NULL, NULL,
+ tree_cons (NULL, build_string (6, "memory"), NULL));
+ ASM_VOLATILE_P (x) = 1;
+ expand_asm_expr (x);
}
/* Expand the __sync_lock_release intrinsic. ARGLIST is the operands list
to the function. */
static void
-expand_builtin_lock_release (tree arglist)
+expand_builtin_lock_release (enum machine_mode mode, tree arglist)
{
- enum machine_mode mode;
enum insn_code icode;
- rtx addr, val, mem, insn;
+ rtx mem, insn;
+ rtx val = const0_rtx;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
- val = const0_rtx;
-
- /* 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
- satisfy the barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
/* If there is an explicit operation in the md file, use it. */
icode = sync_lock_release[mode];
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
+ else
+ {
+ /* Try expanding the builtin via the generic target hook. */
+ rtx tmp = targetm.expand_library_builtin (exp, target, subtarget,
+ mode, ignore);
+ if (tmp != NULL_RTX)
+ return tmp;
+ }
/* When not optimizing, generate calls to library functions for a certain
set of builtins. */
switch (fcode)
{
- case BUILT_IN_FABS:
- case BUILT_IN_FABSF:
- case BUILT_IN_FABSL:
+ CASE_FLT_FN (BUILT_IN_FABS):
target = expand_builtin_fabs (arglist, target, subtarget);
if (target)
return target;
break;
- case BUILT_IN_COPYSIGN:
- case BUILT_IN_COPYSIGNF:
- case BUILT_IN_COPYSIGNL:
+ CASE_FLT_FN (BUILT_IN_COPYSIGN):
target = expand_builtin_copysign (arglist, target, subtarget);
if (target)
return target;
/* Just do a normal library call if we were unable to fold
the values. */
- case BUILT_IN_CABS:
- case BUILT_IN_CABSF:
- case BUILT_IN_CABSL:
+ CASE_FLT_FN (BUILT_IN_CABS):
break;
- case BUILT_IN_EXP:
- case BUILT_IN_EXPF:
- case BUILT_IN_EXPL:
- case BUILT_IN_EXP10:
- case BUILT_IN_EXP10F:
- case BUILT_IN_EXP10L:
- case BUILT_IN_POW10:
- case BUILT_IN_POW10F:
- case BUILT_IN_POW10L:
- case BUILT_IN_EXP2:
- case BUILT_IN_EXP2F:
- case BUILT_IN_EXP2L:
- case BUILT_IN_EXPM1:
- case BUILT_IN_EXPM1F:
- case BUILT_IN_EXPM1L:
- case BUILT_IN_LOGB:
- case BUILT_IN_LOGBF:
- case BUILT_IN_LOGBL:
- case BUILT_IN_ILOGB:
- case BUILT_IN_ILOGBF:
- case BUILT_IN_ILOGBL:
- case BUILT_IN_LOG:
- case BUILT_IN_LOGF:
- case BUILT_IN_LOGL:
- case BUILT_IN_LOG10:
- case BUILT_IN_LOG10F:
- case BUILT_IN_LOG10L:
- case BUILT_IN_LOG2:
- case BUILT_IN_LOG2F:
- case BUILT_IN_LOG2L:
- case BUILT_IN_LOG1P:
- case BUILT_IN_LOG1PF:
- case BUILT_IN_LOG1PL:
- case BUILT_IN_TAN:
- case BUILT_IN_TANF:
- case BUILT_IN_TANL:
- case BUILT_IN_ASIN:
- case BUILT_IN_ASINF:
- case BUILT_IN_ASINL:
- case BUILT_IN_ACOS:
- case BUILT_IN_ACOSF:
- case BUILT_IN_ACOSL:
- case BUILT_IN_ATAN:
- case BUILT_IN_ATANF:
- case BUILT_IN_ATANL:
+ CASE_FLT_FN (BUILT_IN_EXP):
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_POW10):
+ CASE_FLT_FN (BUILT_IN_EXP2):
+ CASE_FLT_FN (BUILT_IN_EXPM1):
+ CASE_FLT_FN (BUILT_IN_LOGB):
+ CASE_FLT_FN (BUILT_IN_ILOGB):
+ CASE_FLT_FN (BUILT_IN_LOG):
+ CASE_FLT_FN (BUILT_IN_LOG10):
+ CASE_FLT_FN (BUILT_IN_LOG2):
+ CASE_FLT_FN (BUILT_IN_LOG1P):
+ CASE_FLT_FN (BUILT_IN_TAN):
+ CASE_FLT_FN (BUILT_IN_ASIN):
+ CASE_FLT_FN (BUILT_IN_ACOS):
+ CASE_FLT_FN (BUILT_IN_ATAN):
/* Treat these like sqrt only if unsafe math optimizations are allowed,
because of possible accuracy problems. */
if (! flag_unsafe_math_optimizations)
break;
- case BUILT_IN_SQRT:
- case BUILT_IN_SQRTF:
- case BUILT_IN_SQRTL:
- case BUILT_IN_FLOOR:
- case BUILT_IN_FLOORF:
- case BUILT_IN_FLOORL:
- case BUILT_IN_CEIL:
- case BUILT_IN_CEILF:
- case BUILT_IN_CEILL:
- case BUILT_IN_TRUNC:
- case BUILT_IN_TRUNCF:
- case BUILT_IN_TRUNCL:
- case BUILT_IN_ROUND:
- case BUILT_IN_ROUNDF:
- case BUILT_IN_ROUNDL:
- case BUILT_IN_NEARBYINT:
- case BUILT_IN_NEARBYINTF:
- case BUILT_IN_NEARBYINTL:
- case BUILT_IN_RINT:
- case BUILT_IN_RINTF:
- case BUILT_IN_RINTL:
- case BUILT_IN_LRINT:
- case BUILT_IN_LRINTF:
- case BUILT_IN_LRINTL:
- case BUILT_IN_LLRINT:
- case BUILT_IN_LLRINTF:
- case BUILT_IN_LLRINTL:
+ CASE_FLT_FN (BUILT_IN_SQRT):
+ CASE_FLT_FN (BUILT_IN_FLOOR):
+ CASE_FLT_FN (BUILT_IN_CEIL):
+ CASE_FLT_FN (BUILT_IN_TRUNC):
+ CASE_FLT_FN (BUILT_IN_ROUND):
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ CASE_FLT_FN (BUILT_IN_RINT):
+ CASE_FLT_FN (BUILT_IN_LRINT):
+ CASE_FLT_FN (BUILT_IN_LLRINT):
target = expand_builtin_mathfn (exp, target, subtarget);
if (target)
return target;
break;
- case BUILT_IN_LCEIL:
- case BUILT_IN_LCEILF:
- case BUILT_IN_LCEILL:
- case BUILT_IN_LLCEIL:
- case BUILT_IN_LLCEILF:
- case BUILT_IN_LLCEILL:
- case BUILT_IN_LFLOOR:
- case BUILT_IN_LFLOORF:
- case BUILT_IN_LFLOORL:
- case BUILT_IN_LLFLOOR:
- case BUILT_IN_LLFLOORF:
- case BUILT_IN_LLFLOORL:
+ CASE_FLT_FN (BUILT_IN_LCEIL):
+ CASE_FLT_FN (BUILT_IN_LLCEIL):
+ CASE_FLT_FN (BUILT_IN_LFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLFLOOR):
target = expand_builtin_int_roundingfn (exp, target, subtarget);
if (target)
return target;
break;
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
+ CASE_FLT_FN (BUILT_IN_POW):
target = expand_builtin_pow (exp, target, subtarget);
if (target)
return target;
break;
- case BUILT_IN_POWI:
- case BUILT_IN_POWIF:
- case BUILT_IN_POWIL:
+ CASE_FLT_FN (BUILT_IN_POWI):
target = expand_builtin_powi (exp, target, subtarget);
if (target)
return target;
break;
- case BUILT_IN_ATAN2:
- case BUILT_IN_ATAN2F:
- case BUILT_IN_ATAN2L:
- case BUILT_IN_LDEXP:
- case BUILT_IN_LDEXPF:
- case BUILT_IN_LDEXPL:
- case BUILT_IN_FMOD:
- case BUILT_IN_FMODF:
- case BUILT_IN_FMODL:
- case BUILT_IN_DREM:
- case BUILT_IN_DREMF:
- case BUILT_IN_DREML:
+ CASE_FLT_FN (BUILT_IN_ATAN2):
+ CASE_FLT_FN (BUILT_IN_LDEXP):
+ CASE_FLT_FN (BUILT_IN_FMOD):
+ CASE_FLT_FN (BUILT_IN_DREM):
if (! flag_unsafe_math_optimizations)
break;
target = expand_builtin_mathfn_2 (exp, target, subtarget);
return target;
break;
- case BUILT_IN_SIN:
- case BUILT_IN_SINF:
- case BUILT_IN_SINL:
- case BUILT_IN_COS:
- case BUILT_IN_COSF:
- case BUILT_IN_COSL:
+ CASE_FLT_FN (BUILT_IN_SIN):
+ CASE_FLT_FN (BUILT_IN_COS):
if (! flag_unsafe_math_optimizations)
break;
target = expand_builtin_mathfn_3 (exp, target, subtarget);
return target;
break;
+ CASE_FLT_FN (BUILT_IN_SINCOS):
+ if (! flag_unsafe_math_optimizations)
+ break;
+ target = expand_builtin_sincos (exp);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_APPLY_ARGS:
return expand_builtin_apply_args ();
rtx ops[3];
for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
- ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
+ ops[i] = expand_normal (TREE_VALUE (t));
return expand_builtin_apply (ops[0], ops[1], ops[2]);
}
memory returned by __builtin_apply. */
case BUILT_IN_RETURN:
if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
- expand_builtin_return (expand_expr (TREE_VALUE (arglist),
- NULL_RTX, VOIDmode, 0));
+ expand_builtin_return (expand_normal (TREE_VALUE (arglist)));
return const0_rtx;
case BUILT_IN_SAVEREGS:
expand_stack_restore (TREE_VALUE (arglist));
return const0_rtx;
- case BUILT_IN_FFS:
- case BUILT_IN_FFSL:
- case BUILT_IN_FFSLL:
+ CASE_INT_FN (BUILT_IN_FFS):
case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, ffs_optab);
return target;
break;
- case BUILT_IN_CLZ:
- case BUILT_IN_CLZL:
- case BUILT_IN_CLZLL:
+ CASE_INT_FN (BUILT_IN_CLZ):
case BUILT_IN_CLZIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, clz_optab);
return target;
break;
- case BUILT_IN_CTZ:
- case BUILT_IN_CTZL:
- case BUILT_IN_CTZLL:
+ CASE_INT_FN (BUILT_IN_CTZ):
case BUILT_IN_CTZIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, ctz_optab);
return target;
break;
- case BUILT_IN_POPCOUNT:
- case BUILT_IN_POPCOUNTL:
- case BUILT_IN_POPCOUNTLL:
+ CASE_INT_FN (BUILT_IN_POPCOUNT):
case BUILT_IN_POPCOUNTIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, popcount_optab);
return target;
break;
- case BUILT_IN_PARITY:
- case BUILT_IN_PARITYL:
- case BUILT_IN_PARITYLL:
+ CASE_INT_FN (BUILT_IN_PARITY):
case BUILT_IN_PARITYIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, parity_optab);
break;
case BUILT_IN_STRCPY:
- target = expand_builtin_strcpy (exp, target, mode);
+ target = expand_builtin_strcpy (fndecl, arglist, target, mode);
if (target)
return target;
break;
break;
case BUILT_IN_STRCAT:
- target = expand_builtin_strcat (arglist, TREE_TYPE (exp), target, mode);
+ target = expand_builtin_strcat (fndecl, arglist, target, mode);
if (target)
return target;
break;
else
{
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
- VOIDmode, 0);
- rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
- NULL_RTX, VOIDmode, 0);
+ VOIDmode, EXPAND_NORMAL);
+ rtx value = expand_normal (TREE_VALUE (TREE_CHAIN (arglist)));
if (value != const1_rtx)
{
if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
{
rtx buf_addr
- = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+ = expand_normal (TREE_VALUE (arglist));
expand_builtin_update_setjmp_buf (buf_addr);
return const0_rtx;
return target;
break;
- case BUILT_IN_SIGNBIT:
- case BUILT_IN_SIGNBITF:
- case BUILT_IN_SIGNBITL:
+ CASE_FLT_FN (BUILT_IN_SIGNBIT):
target = expand_builtin_signbit (exp, target);
if (target)
return target;
case BUILT_IN_FETCH_AND_ADD_2:
case BUILT_IN_FETCH_AND_ADD_4:
case BUILT_IN_FETCH_AND_ADD_8:
- target = expand_builtin_sync_operation (arglist, PLUS,
+ case BUILT_IN_FETCH_AND_ADD_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
+ target = expand_builtin_sync_operation (mode, arglist, PLUS,
false, target, ignore);
if (target)
return target;
case BUILT_IN_FETCH_AND_SUB_2:
case BUILT_IN_FETCH_AND_SUB_4:
case BUILT_IN_FETCH_AND_SUB_8:
- target = expand_builtin_sync_operation (arglist, MINUS,
+ case BUILT_IN_FETCH_AND_SUB_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
+ target = expand_builtin_sync_operation (mode, arglist, MINUS,
false, target, ignore);
if (target)
return target;
case BUILT_IN_FETCH_AND_OR_2:
case BUILT_IN_FETCH_AND_OR_4:
case BUILT_IN_FETCH_AND_OR_8:
- target = expand_builtin_sync_operation (arglist, IOR,
+ case BUILT_IN_FETCH_AND_OR_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
+ target = expand_builtin_sync_operation (mode, arglist, IOR,
false, target, ignore);
if (target)
return target;
case BUILT_IN_FETCH_AND_AND_2:
case BUILT_IN_FETCH_AND_AND_4:
case BUILT_IN_FETCH_AND_AND_8:
- target = expand_builtin_sync_operation (arglist, AND,
+ case BUILT_IN_FETCH_AND_AND_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
+ target = expand_builtin_sync_operation (mode, arglist, AND,
false, target, ignore);
if (target)
return target;
case BUILT_IN_FETCH_AND_XOR_2:
case BUILT_IN_FETCH_AND_XOR_4:
case BUILT_IN_FETCH_AND_XOR_8:
- target = expand_builtin_sync_operation (arglist, XOR,
+ case BUILT_IN_FETCH_AND_XOR_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
+ target = expand_builtin_sync_operation (mode, arglist, XOR,
false, target, ignore);
if (target)
return target;
case BUILT_IN_FETCH_AND_NAND_2:
case BUILT_IN_FETCH_AND_NAND_4:
case BUILT_IN_FETCH_AND_NAND_8:
- target = expand_builtin_sync_operation (arglist, NOT,
+ case BUILT_IN_FETCH_AND_NAND_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
+ target = expand_builtin_sync_operation (mode, arglist, NOT,
false, target, ignore);
if (target)
return target;
case BUILT_IN_ADD_AND_FETCH_2:
case BUILT_IN_ADD_AND_FETCH_4:
case BUILT_IN_ADD_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, PLUS,
+ case BUILT_IN_ADD_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, PLUS,
true, target, ignore);
if (target)
return target;
case BUILT_IN_SUB_AND_FETCH_2:
case BUILT_IN_SUB_AND_FETCH_4:
case BUILT_IN_SUB_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, MINUS,
+ case BUILT_IN_SUB_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, MINUS,
true, target, ignore);
if (target)
return target;
case BUILT_IN_OR_AND_FETCH_2:
case BUILT_IN_OR_AND_FETCH_4:
case BUILT_IN_OR_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, IOR,
+ case BUILT_IN_OR_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, IOR,
true, target, ignore);
if (target)
return target;
case BUILT_IN_AND_AND_FETCH_2:
case BUILT_IN_AND_AND_FETCH_4:
case BUILT_IN_AND_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, AND,
+ case BUILT_IN_AND_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, AND,
true, target, ignore);
if (target)
return target;
case BUILT_IN_XOR_AND_FETCH_2:
case BUILT_IN_XOR_AND_FETCH_4:
case BUILT_IN_XOR_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, XOR,
+ case BUILT_IN_XOR_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, XOR,
true, target, ignore);
if (target)
return target;
case BUILT_IN_NAND_AND_FETCH_2:
case BUILT_IN_NAND_AND_FETCH_4:
case BUILT_IN_NAND_AND_FETCH_8:
- target = expand_builtin_sync_operation (arglist, NOT,
+ case BUILT_IN_NAND_AND_FETCH_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
+ target = expand_builtin_sync_operation (mode, arglist, NOT,
true, target, ignore);
if (target)
return target;
case BUILT_IN_BOOL_COMPARE_AND_SWAP_2:
case BUILT_IN_BOOL_COMPARE_AND_SWAP_4:
case BUILT_IN_BOOL_COMPARE_AND_SWAP_8:
+ case BUILT_IN_BOOL_COMPARE_AND_SWAP_16:
if (mode == VOIDmode)
mode = TYPE_MODE (boolean_type_node);
if (!target || !register_operand (target, mode))
target = gen_reg_rtx (mode);
- target = expand_builtin_compare_and_swap (arglist, true, target);
+
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
+ target = expand_builtin_compare_and_swap (mode, arglist, true, target);
if (target)
return target;
break;
case BUILT_IN_VAL_COMPARE_AND_SWAP_2:
case BUILT_IN_VAL_COMPARE_AND_SWAP_4:
case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
- target = expand_builtin_compare_and_swap (arglist, false, target);
+ case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
+ target = expand_builtin_compare_and_swap (mode, arglist, false, target);
if (target)
return target;
break;
case BUILT_IN_LOCK_TEST_AND_SET_2:
case BUILT_IN_LOCK_TEST_AND_SET_4:
case BUILT_IN_LOCK_TEST_AND_SET_8:
- target = expand_builtin_lock_test_and_set (arglist, target);
+ case BUILT_IN_LOCK_TEST_AND_SET_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
+ target = expand_builtin_lock_test_and_set (mode, arglist, target);
if (target)
return target;
break;
case BUILT_IN_LOCK_RELEASE_2:
case BUILT_IN_LOCK_RELEASE_4:
case BUILT_IN_LOCK_RELEASE_8:
- expand_builtin_lock_release (arglist);
+ case BUILT_IN_LOCK_RELEASE_16:
+ mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
+ expand_builtin_lock_release (mode, arglist);
return const0_rtx;
case BUILT_IN_SYNCHRONIZE:
real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
return real_identical (&c, &cint);
}
+ break;
case NOP_EXPR:
{
case CALL_EXPR:
switch (builtin_mathfn_code (t))
{
- case BUILT_IN_CEIL:
- case BUILT_IN_CEILF:
- case BUILT_IN_CEILL:
- case BUILT_IN_FLOOR:
- case BUILT_IN_FLOORF:
- case BUILT_IN_FLOORL:
- case BUILT_IN_NEARBYINT:
- case BUILT_IN_NEARBYINTF:
- case BUILT_IN_NEARBYINTL:
- case BUILT_IN_RINT:
- case BUILT_IN_RINTF:
- case BUILT_IN_RINTL:
- case BUILT_IN_ROUND:
- case BUILT_IN_ROUNDF:
- case BUILT_IN_ROUNDL:
- case BUILT_IN_TRUNC:
- case BUILT_IN_TRUNCF:
- case BUILT_IN_TRUNCL:
+ CASE_FLT_FN (BUILT_IN_CEIL):
+ CASE_FLT_FN (BUILT_IN_FLOOR):
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ CASE_FLT_FN (BUILT_IN_RINT):
+ CASE_FLT_FN (BUILT_IN_ROUND):
+ CASE_FLT_FN (BUILT_IN_TRUNC):
return true;
default:
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_LFLOOR:
- case BUILT_IN_LFLOORF:
- case BUILT_IN_LFLOORL:
- case BUILT_IN_LLFLOOR:
- case BUILT_IN_LLFLOORF:
- case BUILT_IN_LLFLOORL:
+ CASE_FLT_FN (BUILT_IN_LFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLFLOOR):
real_floor (&r, TYPE_MODE (ftype), &x);
break;
- case BUILT_IN_LCEIL:
- case BUILT_IN_LCEILF:
- case BUILT_IN_LCEILL:
- case BUILT_IN_LLCEIL:
- case BUILT_IN_LLCEILF:
- case BUILT_IN_LLCEILL:
+ CASE_FLT_FN (BUILT_IN_LCEIL):
+ CASE_FLT_FN (BUILT_IN_LLCEIL):
real_ceil (&r, TYPE_MODE (ftype), &x);
break;
- case BUILT_IN_LROUND:
- case BUILT_IN_LROUNDF:
- case BUILT_IN_LROUNDL:
- case BUILT_IN_LLROUND:
- case BUILT_IN_LLROUNDF:
- case BUILT_IN_LLROUNDL:
+ CASE_FLT_FN (BUILT_IN_LROUND):
+ CASE_FLT_FN (BUILT_IN_LLROUND):
real_round (&r, TYPE_MODE (ftype), &x);
break;
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_FFS:
- case BUILT_IN_FFSL:
- case BUILT_IN_FFSLL:
+ CASE_INT_FN (BUILT_IN_FFS):
if (lo != 0)
result = exact_log2 (lo & -lo) + 1;
else if (hi != 0)
result = 0;
break;
- case BUILT_IN_CLZ:
- case BUILT_IN_CLZL:
- case BUILT_IN_CLZLL:
+ CASE_INT_FN (BUILT_IN_CLZ):
if (hi != 0)
result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
else if (lo != 0)
result = width;
break;
- case BUILT_IN_CTZ:
- case BUILT_IN_CTZL:
- case BUILT_IN_CTZLL:
+ CASE_INT_FN (BUILT_IN_CTZ):
if (lo != 0)
result = exact_log2 (lo & -lo);
else if (hi != 0)
result = width;
break;
- case BUILT_IN_POPCOUNT:
- case BUILT_IN_POPCOUNTL:
- case BUILT_IN_POPCOUNTLL:
+ CASE_INT_FN (BUILT_IN_POPCOUNT):
result = 0;
while (lo)
result++, lo &= lo - 1;
result++, hi &= hi - 1;
break;
- case BUILT_IN_PARITY:
- case BUILT_IN_PARITYL:
- case BUILT_IN_PARITYLL:
+ CASE_INT_FN (BUILT_IN_PARITY):
result = 0;
while (lo)
result++, lo &= lo - 1;
switch (fcode)
{
- case BUILT_IN_EXP:
- case BUILT_IN_EXPF:
- case BUILT_IN_EXPL:
+ CASE_FLT_FN (BUILT_IN_EXP):
/* Prepare to do logN(exp(exponent) -> exponent*logN(e). */
x = build_real (type,
real_value_truncate (TYPE_MODE (type), dconste));
exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
break;
- case BUILT_IN_EXP2:
- case BUILT_IN_EXP2F:
- case BUILT_IN_EXP2L:
+ CASE_FLT_FN (BUILT_IN_EXP2):
/* Prepare to do logN(exp2(exponent) -> exponent*logN(2). */
x = build_real (type, dconst2);
exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
break;
- case BUILT_IN_EXP10:
- case BUILT_IN_EXP10F:
- case BUILT_IN_EXP10L:
- case BUILT_IN_POW10:
- case BUILT_IN_POW10F:
- case BUILT_IN_POW10L:
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_POW10):
/* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */
x = build_real (type, dconst10);
exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
break;
- case BUILT_IN_SQRT:
- case BUILT_IN_SQRTF:
- case BUILT_IN_SQRTL:
+ CASE_FLT_FN (BUILT_IN_SQRT):
/* Prepare to do logN(sqrt(x) -> 0.5*logN(x). */
x = TREE_VALUE (TREE_OPERAND (arg, 1));
exponent = build_real (type, dconsthalf);
break;
- case BUILT_IN_CBRT:
- case BUILT_IN_CBRTF:
- case BUILT_IN_CBRTL:
+ CASE_FLT_FN (BUILT_IN_CBRT):
/* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */
x = TREE_VALUE (TREE_OPERAND (arg, 1));
exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
dconstthird));
break;
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
+ CASE_FLT_FN (BUILT_IN_POW):
/* Prepare to do logN(pow(x,exponent) -> exponent*logN(x). */
x = TREE_VALUE (TREE_OPERAND (arg, 1));
exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
tree ind1 = fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
if (p2 && *p2 == '\0')
{
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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
return fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
if (p1 && *p1 == '\0')
{
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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
tree temp = fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
&& tree_int_cst_sgn (len) == 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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
return fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
&& tree_int_cst_sgn (len) == 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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
tree temp = fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
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 cst_uchar_ptr_node
+ = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
tree ind1 = fold_convert (integer_type_node,
build1 (INDIRECT_REF, cst_uchar_node,
fold_convert (cst_uchar_ptr_node,
c1 = TREE_REAL_CST (arg1);
c2 = TREE_REAL_CST (arg2);
+ /* c1.sign := c2.sign. */
real_copysign (&c1, &c2);
return build_real (type, c1);
- c1.sign = c2.sign;
}
/* copysign(X, Y) is fabs(X) when Y is always non-negative.
case BUILT_IN_STRLEN:
return fold_builtin_strlen (arglist);
- case BUILT_IN_FABS:
- case BUILT_IN_FABSF:
- case BUILT_IN_FABSL:
+ CASE_FLT_FN (BUILT_IN_FABS):
return fold_builtin_fabs (arglist, type);
case BUILT_IN_ABS:
case BUILT_IN_IMAXABS:
return fold_builtin_abs (arglist, type);
- case BUILT_IN_CONJ:
- case BUILT_IN_CONJF:
- case BUILT_IN_CONJL:
+ CASE_FLT_FN (BUILT_IN_CONJ):
if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
return fold_build1 (CONJ_EXPR, type, TREE_VALUE (arglist));
break;
- case BUILT_IN_CREAL:
- case BUILT_IN_CREALF:
- case BUILT_IN_CREALL:
+ CASE_FLT_FN (BUILT_IN_CREAL):
if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
return non_lvalue (fold_build1 (REALPART_EXPR, type,
TREE_VALUE (arglist)));
break;
- case BUILT_IN_CIMAG:
- case BUILT_IN_CIMAGF:
- case BUILT_IN_CIMAGL:
+ CASE_FLT_FN (BUILT_IN_CIMAG):
if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
return non_lvalue (fold_build1 (IMAGPART_EXPR, type,
TREE_VALUE (arglist)));
break;
- case BUILT_IN_CABS:
- case BUILT_IN_CABSF:
- case BUILT_IN_CABSL:
+ CASE_FLT_FN (BUILT_IN_CABS):
return fold_builtin_cabs (arglist, type);
- case BUILT_IN_SQRT:
- case BUILT_IN_SQRTF:
- case BUILT_IN_SQRTL:
+ CASE_FLT_FN (BUILT_IN_SQRT):
return fold_builtin_sqrt (arglist, type);
- case BUILT_IN_CBRT:
- case BUILT_IN_CBRTF:
- case BUILT_IN_CBRTL:
+ CASE_FLT_FN (BUILT_IN_CBRT):
return fold_builtin_cbrt (arglist, type);
- case BUILT_IN_SIN:
- case BUILT_IN_SINF:
- case BUILT_IN_SINL:
+ CASE_FLT_FN (BUILT_IN_SIN):
return fold_builtin_sin (arglist);
- case BUILT_IN_COS:
- case BUILT_IN_COSF:
- case BUILT_IN_COSL:
+ CASE_FLT_FN (BUILT_IN_COS):
return fold_builtin_cos (arglist, type, fndecl);
- case BUILT_IN_EXP:
- case BUILT_IN_EXPF:
- case BUILT_IN_EXPL:
+ CASE_FLT_FN (BUILT_IN_EXP):
return fold_builtin_exponent (fndecl, arglist, &dconste);
- case BUILT_IN_EXP2:
- case BUILT_IN_EXP2F:
- case BUILT_IN_EXP2L:
+ CASE_FLT_FN (BUILT_IN_EXP2):
return fold_builtin_exponent (fndecl, arglist, &dconst2);
- case BUILT_IN_EXP10:
- case BUILT_IN_EXP10F:
- case BUILT_IN_EXP10L:
- case BUILT_IN_POW10:
- case BUILT_IN_POW10F:
- case BUILT_IN_POW10L:
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_POW10):
return fold_builtin_exponent (fndecl, arglist, &dconst10);
- case BUILT_IN_LOG:
- case BUILT_IN_LOGF:
- case BUILT_IN_LOGL:
+ CASE_FLT_FN (BUILT_IN_LOG):
return fold_builtin_logarithm (fndecl, arglist, &dconste);
- case BUILT_IN_LOG2:
- case BUILT_IN_LOG2F:
- case BUILT_IN_LOG2L:
+ CASE_FLT_FN (BUILT_IN_LOG2):
return fold_builtin_logarithm (fndecl, arglist, &dconst2);
- case BUILT_IN_LOG10:
- case BUILT_IN_LOG10F:
- case BUILT_IN_LOG10L:
+ CASE_FLT_FN (BUILT_IN_LOG10):
return fold_builtin_logarithm (fndecl, arglist, &dconst10);
- case BUILT_IN_TAN:
- case BUILT_IN_TANF:
- case BUILT_IN_TANL:
+ CASE_FLT_FN (BUILT_IN_TAN):
return fold_builtin_tan (arglist);
- case BUILT_IN_ATAN:
- case BUILT_IN_ATANF:
- case BUILT_IN_ATANL:
+ CASE_FLT_FN (BUILT_IN_ATAN):
return fold_builtin_atan (arglist, type);
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
+ CASE_FLT_FN (BUILT_IN_POW):
return fold_builtin_pow (fndecl, arglist, type);
- case BUILT_IN_POWI:
- case BUILT_IN_POWIF:
- case BUILT_IN_POWIL:
+ CASE_FLT_FN (BUILT_IN_POWI):
return fold_builtin_powi (fndecl, arglist, type);
- case BUILT_IN_INF:
- case BUILT_IN_INFF:
- case BUILT_IN_INFL:
+ CASE_FLT_FN (BUILT_IN_INF):
+ case BUILT_IN_INFD32:
+ case BUILT_IN_INFD64:
+ case BUILT_IN_INFD128:
return fold_builtin_inf (type, true);
- case BUILT_IN_HUGE_VAL:
- case BUILT_IN_HUGE_VALF:
- case BUILT_IN_HUGE_VALL:
+ CASE_FLT_FN (BUILT_IN_HUGE_VAL):
return fold_builtin_inf (type, false);
- case BUILT_IN_NAN:
- case BUILT_IN_NANF:
- case BUILT_IN_NANL:
+ CASE_FLT_FN (BUILT_IN_NAN):
+ case BUILT_IN_NAND32:
+ case BUILT_IN_NAND64:
+ case BUILT_IN_NAND128:
return fold_builtin_nan (arglist, type, true);
- case BUILT_IN_NANS:
- case BUILT_IN_NANSF:
- case BUILT_IN_NANSL:
+ CASE_FLT_FN (BUILT_IN_NANS):
return fold_builtin_nan (arglist, type, false);
- case BUILT_IN_FLOOR:
- case BUILT_IN_FLOORF:
- case BUILT_IN_FLOORL:
+ CASE_FLT_FN (BUILT_IN_FLOOR):
return fold_builtin_floor (fndecl, arglist);
- case BUILT_IN_CEIL:
- case BUILT_IN_CEILF:
- case BUILT_IN_CEILL:
+ CASE_FLT_FN (BUILT_IN_CEIL):
return fold_builtin_ceil (fndecl, arglist);
- case BUILT_IN_TRUNC:
- case BUILT_IN_TRUNCF:
- case BUILT_IN_TRUNCL:
+ CASE_FLT_FN (BUILT_IN_TRUNC):
return fold_builtin_trunc (fndecl, arglist);
- case BUILT_IN_ROUND:
- case BUILT_IN_ROUNDF:
- case BUILT_IN_ROUNDL:
+ CASE_FLT_FN (BUILT_IN_ROUND):
return fold_builtin_round (fndecl, arglist);
- case BUILT_IN_NEARBYINT:
- case BUILT_IN_NEARBYINTF:
- case BUILT_IN_NEARBYINTL:
- case BUILT_IN_RINT:
- case BUILT_IN_RINTF:
- case BUILT_IN_RINTL:
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ CASE_FLT_FN (BUILT_IN_RINT):
return fold_trunc_transparent_mathfn (fndecl, arglist);
- case BUILT_IN_LCEIL:
- case BUILT_IN_LCEILF:
- case BUILT_IN_LCEILL:
- case BUILT_IN_LLCEIL:
- case BUILT_IN_LLCEILF:
- case BUILT_IN_LLCEILL:
- case BUILT_IN_LFLOOR:
- case BUILT_IN_LFLOORF:
- case BUILT_IN_LFLOORL:
- case BUILT_IN_LLFLOOR:
- case BUILT_IN_LLFLOORF:
- case BUILT_IN_LLFLOORL:
- case BUILT_IN_LROUND:
- case BUILT_IN_LROUNDF:
- case BUILT_IN_LROUNDL:
- case BUILT_IN_LLROUND:
- case BUILT_IN_LLROUNDF:
- case BUILT_IN_LLROUNDL:
+ CASE_FLT_FN (BUILT_IN_LCEIL):
+ CASE_FLT_FN (BUILT_IN_LLCEIL):
+ CASE_FLT_FN (BUILT_IN_LFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLFLOOR):
+ CASE_FLT_FN (BUILT_IN_LROUND):
+ CASE_FLT_FN (BUILT_IN_LLROUND):
return fold_builtin_int_roundingfn (fndecl, arglist);
- case BUILT_IN_LRINT:
- case BUILT_IN_LRINTF:
- case BUILT_IN_LRINTL:
- case BUILT_IN_LLRINT:
- case BUILT_IN_LLRINTF:
- case BUILT_IN_LLRINTL:
+ CASE_FLT_FN (BUILT_IN_LRINT):
+ CASE_FLT_FN (BUILT_IN_LLRINT):
return fold_fixed_mathfn (fndecl, arglist);
- case BUILT_IN_FFS:
- case BUILT_IN_FFSL:
- case BUILT_IN_FFSLL:
- case BUILT_IN_CLZ:
- case BUILT_IN_CLZL:
- case BUILT_IN_CLZLL:
- case BUILT_IN_CTZ:
- case BUILT_IN_CTZL:
- case BUILT_IN_CTZLL:
- case BUILT_IN_POPCOUNT:
- case BUILT_IN_POPCOUNTL:
- case BUILT_IN_POPCOUNTLL:
- case BUILT_IN_PARITY:
- case BUILT_IN_PARITYL:
- case BUILT_IN_PARITYLL:
+ CASE_INT_FN (BUILT_IN_FFS):
+ CASE_INT_FN (BUILT_IN_CLZ):
+ CASE_INT_FN (BUILT_IN_CTZ):
+ CASE_INT_FN (BUILT_IN_POPCOUNT):
+ CASE_INT_FN (BUILT_IN_PARITY):
return fold_builtin_bitop (fndecl, arglist);
case BUILT_IN_MEMCPY:
case BUILT_IN_MEMMOVE:
return fold_builtin_memmove (arglist, type);
- case BUILT_IN_SIGNBIT:
- case BUILT_IN_SIGNBITF:
- case BUILT_IN_SIGNBITL:
+ CASE_FLT_FN (BUILT_IN_SIGNBIT):
return fold_builtin_signbit (fndecl, arglist);
case BUILT_IN_ISASCII:
case BUILT_IN_ISDIGIT:
return fold_builtin_isdigit (arglist);
- case BUILT_IN_COPYSIGN:
- case BUILT_IN_COPYSIGNF:
- case BUILT_IN_COPYSIGNL:
+ CASE_FLT_FN (BUILT_IN_COPYSIGN):
return fold_builtin_copysign (fndecl, arglist, type);
- case BUILT_IN_FINITE:
- case BUILT_IN_FINITEF:
- case BUILT_IN_FINITEL:
+ CASE_FLT_FN (BUILT_IN_FINITE):
+ case BUILT_IN_FINITED32:
+ case BUILT_IN_FINITED64:
+ case BUILT_IN_FINITED128:
return fold_builtin_classify (fndecl, arglist, BUILT_IN_FINITE);
- case BUILT_IN_ISINF:
- case BUILT_IN_ISINFF:
- case BUILT_IN_ISINFL:
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ case BUILT_IN_ISINFD32:
+ case BUILT_IN_ISINFD64:
+ case BUILT_IN_ISINFD128:
return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISINF);
- case BUILT_IN_ISNAN:
- case BUILT_IN_ISNANF:
- case BUILT_IN_ISNANL:
+ CASE_FLT_FN (BUILT_IN_ISNAN):
+ case BUILT_IN_ISNAND32:
+ case BUILT_IN_ISNAND64:
+ case BUILT_IN_ISNAND128:
return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISNAN);
case BUILT_IN_ISGREATER:
return NULL_RTX;
}
+/* Default target-specific library builtin expander that does nothing. */
+
+rtx
+default_expand_library_builtin (tree exp ATTRIBUTE_UNUSED,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ return NULL_RTX;
+}
+
/* Returns true is EXP represents data that would potentially reside
in a readonly section. */
return fold_convert (type, tem);
}
+ /* The argument is const char *, and the result is char *, so we need
+ a type conversion here to avoid a warning. */
if (p2[0] == '\0')
- return s1;
+ return fold_convert (type, s1);
if (p2[1] != '\0')
return 0;
fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
{
tree fn;
- tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+ /* If we're using an unlocked function, assume the other unlocked
+ functions exist explicitly. */
+ tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
: implicit_built_in_decls[BUILT_IN_FPUTC];
- tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
+ tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
: implicit_built_in_decls[BUILT_IN_FWRITE];
- /* If the return value is used, or the replacement _DECL isn't
- initialized, don't do the transformation. */
- if (!ignore || !fn_fputc || !fn_fwrite)
+ /* If the return value is used, don't do the transformation. */
+ if (!ignore)
return 0;
/* Verify the arguments in the original call. */
gcc_unreachable ();
}
+ /* If the replacement _DECL isn't initialized, don't do the
+ transformation. */
+ if (!fn)
+ return 0;
+
/* These optimizations are only performed when the result is ignored,
hence there's no need to cast the result to integer_type_node. */
return build_function_call_expr (fn, arglist);
call = NULL_TREE;
retval = NULL_TREE;
+ if (!init_target_chars())
+ return 0;
+
/* If the format doesn't contain % args or %%, use strcpy. */
- if (strchr (fmt_str, '%') == NULL)
+ if (strchr (fmt_str, target_percent) == NULL)
{
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
}
/* If the format is "%s", use strcpy if the result isn't used. */
- else if (fmt_str && strcmp (fmt_str, "%s") == 0)
+ else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
{
tree fn, orig;
fn = implicit_built_in_decls[BUILT_IN_STRCPY];
if (fmt_str == NULL)
return;
+ if (!init_target_chars())
+ return;
+
/* If the format doesn't contain % args or %%, we know its size. */
- if (strchr (fmt_str, '%') == 0)
+ if (strchr (fmt_str, target_percent) == 0)
len = build_int_cstu (size_type_node, strlen (fmt_str));
/* If the format is "%s" and first ... argument is a string literal,
we know it too. */
- else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0)
+ else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
{
tree arg;
}
return 0;
}
- len = maxlen;
}
+ else
+ maxlen = len;
- if (tree_int_cst_lt (size, len))
+ if (tree_int_cst_lt (size, maxlen))
return 0;
}
return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
build_function_call_expr (fn, arglist));
}
- len = maxlen;
}
-
- if (! tree_int_cst_lt (len, size))
+ else
+ maxlen = len;
+
+ if (! tree_int_cst_lt (maxlen, size))
return 0;
}
if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
return 0;
- len = maxlen;
}
+ else
+ maxlen = len;
- if (tree_int_cst_lt (size, len))
+ if (tree_int_cst_lt (size, maxlen))
return 0;
}
len = NULL_TREE;
+ if (!init_target_chars())
+ return 0;
+
/* Check whether the format is a literal string constant. */
fmt_str = c_getstr (fmt);
if (fmt_str != NULL)
{
/* If the format doesn't contain % args or %%, we know the size. */
- if (strchr (fmt_str, '%') == 0)
+ if (strchr (fmt_str, target_percent) == 0)
{
if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE)
len = build_int_cstu (size_type_node, strlen (fmt_str));
}
/* If the format is "%s" and first ... argument is a string literal,
we know the size too. */
- else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0)
+ else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
{
tree arg;
{
if (fmt_str == NULL)
return 0;
- if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s"))
+ if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
return 0;
}
if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
return 0;
- len = maxlen;
}
+ else
+ maxlen = len;
- if (tree_int_cst_lt (size, len))
+ if (tree_int_cst_lt (size, maxlen))
return 0;
}
+ if (!init_target_chars())
+ return 0;
+
/* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
or if format doesn't contain % chars or is "%s". */
if (! integer_zerop (flag))
fmt_str = c_getstr (fmt);
if (fmt_str == NULL)
return 0;
- if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s"))
+ if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
return 0;
}
if (fcode == BUILT_IN_PRINTF_UNLOCKED)
{
- fn_putchar = implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
- fn_puts = implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED];
+ /* If we're using an unlocked function, assume the other
+ unlocked functions exist explicitly. */
+ fn_putchar = built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
+ fn_puts = built_in_decls[BUILT_IN_PUTS_UNLOCKED];
}
else
{
fn_puts = implicit_built_in_decls[BUILT_IN_PUTS];
}
- if (strcmp (fmt_str, "%s") == 0 || strchr (fmt_str, '%') == NULL)
+ if (!init_target_chars())
+ return 0;
+
+ if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL)
{
const char *str;
- if (strcmp (fmt_str, "%s") == 0)
+ if (strcmp (fmt_str, target_percent_s) == 0)
{
if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
return 0;
{
/* If the string was "string\n", call puts("string"). */
size_t len = strlen (str);
- if (str[len - 1] == '\n')
+ if ((unsigned char)str[len - 1] == target_newline)
{
/* Create a NUL-terminated string that's one char shorter
than the original, stripping off the trailing '\n'. */
return 0;
/* If the format specifier was "%s\n", call __builtin_puts(arg). */
- else if (strcmp (fmt_str, "%s\n") == 0)
+ else if (strcmp (fmt_str, target_percent_s_newline) == 0)
{
if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
}
/* If the format specifier was "%c", call __builtin_putchar(arg). */
- else if (strcmp (fmt_str, "%c") == 0)
+ else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
{
- fn_fputc = implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
- fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
+ /* If we're using an unlocked function, assume the other
+ unlocked functions exist explicitly. */
+ fn_fputc = built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
+ fn_fputs = built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
}
else
{
fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS];
}
+ if (!init_target_chars())
+ return 0;
+
/* If the format doesn't contain % args or %%, use strcpy. */
- if (strchr (fmt_str, '%') == NULL)
+ if (strchr (fmt_str, target_percent) == NULL)
{
if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
&& arglist)
return 0;
/* If the format specifier was "%s", call __builtin_fputs (arg, fp). */
- else if (strcmp (fmt_str, "%s") == 0)
+ else if (strcmp (fmt_str, target_percent_s) == 0)
{
if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
}
/* If the format specifier was "%c", call __builtin_fputc (arg, fp). */
- else if (strcmp (fmt_str, "%c") == 0)
+ else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
call = build_function_call_expr (fn, arglist);
return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
}
+
+/* Initialize format string characters in the target charset. */
+
+static bool
+init_target_chars (void)
+{
+ static bool init;
+ if (!init)
+ {
+ target_newline = lang_hooks.to_target_charset ('\n');
+ target_percent = lang_hooks.to_target_charset ('%');
+ target_c = lang_hooks.to_target_charset ('c');
+ target_s = lang_hooks.to_target_charset ('s');
+ if (target_newline == 0 || target_percent == 0 || target_c == 0
+ || target_s == 0)
+ return false;
+
+ target_percent_c[0] = target_percent;
+ target_percent_c[1] = target_c;
+ target_percent_c[2] = '\0';
+
+ target_percent_s[0] = target_percent;
+ target_percent_s[1] = target_s;
+ target_percent_s[2] = '\0';
+
+ target_percent_s_newline[0] = target_percent;
+ target_percent_s_newline[1] = target_s;
+ target_percent_s_newline[2] = target_newline;
+ target_percent_s_newline[3] = '\0';
+
+ init = true;
+ }
+ return true;
+}