/* Expand builtin functions.
- Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- 2012 Free Software Foundation, Inc.
+ Copyright (C) 1988-2013 Free Software Foundation, Inc.
This file is part of GCC.
#include "target.h"
#include "langhooks.h"
#include "basic-block.h"
-#include "tree-mudflap.h"
-#include "tree-flow.h"
+#include "tree-ssanames.h"
+#include "tree-dfa.h"
#include "value-prof.h"
#include "diagnostic-core.h"
#include "builtins.h"
+#include "ubsan.h"
+#include "cilk.h"
-#ifndef PAD_VARARGS_DOWN
-#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
-#endif
static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
struct target_builtins default_target_builtins;
#endif
/* Define the names of the builtin function types and codes. */
-const char *const built_in_class_names[4]
+const char *const built_in_class_names[BUILT_IN_LAST]
= {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
initialized to NULL_TREE. */
builtin_info_type builtin_info;
+/* Non-zero if __builtin_constant_p should be folded right away. */
+bool force_folding_builtin_constant_p;
+
static const char *c_getstr (tree);
static rtx c_readstr (const char *, enum machine_mode);
static int target_char_cast (tree, char *);
return true;
if (strncmp (name, "__atomic_", 9) == 0)
return true;
+ if (flag_enable_cilkplus
+ && (!strcmp (name, "__cilkrts_detach")
+ || !strcmp (name, "__cilkrts_pop_frame")))
+ return true;
return false;
}
return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
}
+/* By default we assume that c99 functions are present at the runtime,
+ but sincos is not. */
+bool
+default_libc_has_function (enum function_class fn_class)
+{
+ if (fn_class == function_c94
+ || fn_class == function_c99_misc
+ || fn_class == function_c99_math_complex)
+ return true;
+
+ return false;
+}
+
+bool
+gnu_libc_has_function (enum function_class fn_class ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+bool
+no_c99_libc_has_function (enum function_class fn_class ATTRIBUTE_UNUSED)
+{
+ return false;
+}
/* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with
tree offset;
enum machine_mode mode;
int unsignedp, volatilep;
- unsigned int inner, align = BITS_PER_UNIT;
+ unsigned int align = BITS_PER_UNIT;
bool known_alignment = false;
/* Get the innermost object and the constant (bitpos) and possibly
/* If there is a non-constant offset part extract the maximum
alignment that can prevail. */
- inner = ~0U;
- while (offset)
+ if (offset)
{
- tree next_offset;
-
- if (TREE_CODE (offset) == PLUS_EXPR)
- {
- next_offset = TREE_OPERAND (offset, 0);
- offset = TREE_OPERAND (offset, 1);
- }
- else
- next_offset = NULL;
- if (host_integerp (offset, 1))
- {
- /* Any overflow in calculating offset_bits won't change
- the alignment. */
- unsigned offset_bits
- = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
-
- if (offset_bits)
- inner = MIN (inner, (offset_bits & -offset_bits));
- }
- else if (TREE_CODE (offset) == MULT_EXPR
- && host_integerp (TREE_OPERAND (offset, 1), 1))
- {
- /* Any overflow in calculating offset_factor won't change
- the alignment. */
- unsigned offset_factor
- = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
- * BITS_PER_UNIT);
-
- if (offset_factor)
- inner = MIN (inner, (offset_factor & -offset_factor));
- }
- else
+ int trailing_zeros = tree_ctz (offset);
+ if (trailing_zeros < HOST_BITS_PER_INT)
{
- inner = MIN (inner, BITS_PER_UNIT);
- break;
+ unsigned int inner = (1U << trailing_zeros) * BITS_PER_UNIT;
+ if (inner)
+ align = MIN (align, inner);
}
- offset = next_offset;
}
- /* Alignment is innermost object alignment adjusted by the constant
- and non-constant offset parts. */
- align = MIN (align, inner);
*alignp = align;
*bitposp = bitpos & (*alignp - 1);
}
/* Construct the trailing part of a __builtin_setjmp call. This is
- also called directly by the SJLJ exception handling code. */
+ also called directly by the SJLJ exception handling code.
+ If RECEIVER_LABEL is NULL, instead contruct a nonlocal goto handler. */
void
expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
{
rtx chain;
- /* Clobber the FP when we get here, so we have to make sure it's
+ /* Mark the FP as used when we get here, so we have to make sure it's
marked as used by this function. */
emit_use (hard_frame_pointer_rtx);
#ifdef HAVE_nonlocal_goto
if (! HAVE_nonlocal_goto)
#endif
- {
- emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
- /* This might change the hard frame pointer in ways that aren't
- apparent to early optimization passes, so force a clobber. */
- emit_clobber (hard_frame_pointer_rtx);
- }
+ /* First adjust our frame pointer to its actual value. It was
+ previously set to the start of the virtual area corresponding to
+ the stacked variables when we branched here and now needs to be
+ adjusted to the actual hardware fp value.
+
+ Assignments to virtual registers are converted by
+ instantiate_virtual_regs into the corresponding assignment
+ to the underlying register (fp in this case) that makes
+ the original assignment true.
+ So the following insn will actually be decrementing fp by
+ STARTING_FRAME_OFFSET. */
+ emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
#if !HARD_FRAME_POINTER_IS_ARG_POINTER
if (fixed_regs[ARG_POINTER_REGNUM])
{
#ifdef ELIMINABLE_REGS
+ /* If the argument pointer can be eliminated in favor of the
+ frame pointer, we don't need to restore it. We assume here
+ that if such an elimination is present, it can always be used.
+ This is the case on all known machines; if we don't make this
+ assumption, we do unnecessary saving on many machines. */
size_t i;
static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
#endif
#ifdef HAVE_builtin_setjmp_receiver
- if (HAVE_builtin_setjmp_receiver)
+ if (receiver_label != NULL && HAVE_builtin_setjmp_receiver)
emit_insn (gen_builtin_setjmp_receiver (receiver_label));
else
#endif
}
}
+static inline bool
+more_const_call_expr_args_p (const const_call_expr_arg_iterator *iter)
+{
+ return (iter->i < iter->n);
+}
+
+/* This function validates the types of a function call argument list
+ against a specified list of tree_codes. If the last specifier is a 0,
+ that represents an ellipses, otherwise the last specifier must be a
+ VOID_TYPE. */
+
+static bool
+validate_arglist (const_tree callexpr, ...)
+{
+ enum tree_code code;
+ bool res = 0;
+ va_list ap;
+ const_call_expr_arg_iterator iter;
+ const_tree arg;
+
+ va_start (ap, callexpr);
+ init_const_call_expr_arg_iterator (callexpr, &iter);
+
+ do
+ {
+ code = (enum tree_code) va_arg (ap, int);
+ switch (code)
+ {
+ case 0:
+ /* This signifies an ellipses, any further arguments are all ok. */
+ res = true;
+ goto end;
+ case VOID_TYPE:
+ /* This signifies an endlink, if no arguments remain, return
+ true, otherwise return false. */
+ res = !more_const_call_expr_args_p (&iter);
+ goto end;
+ default:
+ /* If no parameters remain or the parameter's code does not
+ match the specified code, return false. Otherwise continue
+ checking any remaining arguments. */
+ arg = next_const_call_expr_arg (&iter);
+ if (!validate_arg (arg, code))
+ goto end;
+ break;
+ }
+ }
+ while (1);
+
+ /* We need gotos here since we can only have one VA_CLOSE in a
+ function. */
+ end: ;
+ va_end (ap);
+
+ return res;
+}
+
/* Expand a call to __builtin_nonlocal_goto. We're passed the target label
and the address of the save area. */
else
#endif
emit_stack_restore (SAVE_BLOCK, old_stack_level);
- fixup_args_size_notes (call_insn, get_last_insn(), 0);
+ fixup_args_size_notes (call_insn, get_last_insn (), 0);
OK_DEFER_POP;
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_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
emit_label (lab);
return;
}
tree fndecl = get_callee_fndecl (exp);
enum machine_mode mode;
bool errno_set = false;
+ bool try_widening = false;
tree arg;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
{
CASE_FLT_FN (BUILT_IN_SQRT):
errno_set = ! tree_expr_nonnegative_p (arg);
+ try_widening = true;
builtin_optab = sqrt_optab;
break;
CASE_FLT_FN (BUILT_IN_EXP):
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
- /* Before working hard, check whether the instruction is available. */
- if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing
+ /* Before working hard, check whether the instruction is available, but try
+ to widen the mode for specific operations. */
+ if ((optab_handler (builtin_optab, mode) != CODE_FOR_nothing
+ || (try_widening && !excess_precision_type (TREE_TYPE (exp))))
&& (!errno_set || !optimize_insn_for_size_p ()))
{
- target = gen_reg_rtx (mode);
+ rtx result = gen_reg_rtx (mode);
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
start_sequence ();
- /* Compute into TARGET.
- Set TARGET to wherever the result comes back. */
- target = expand_unop (mode, builtin_optab, op0, target, 0);
+ /* Compute into RESULT.
+ Set RESULT to wherever the result comes back. */
+ result = expand_unop (mode, builtin_optab, op0, result, 0);
- if (target != 0)
+ if (result != 0)
{
if (errno_set)
- expand_errno_check (exp, target);
+ expand_errno_check (exp, result);
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insn (insns);
- return target;
+ return result;
}
/* If we were unable to expand via the builtin, stop the sequence
expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
- rtx op0, op1, insns;
+ rtx op0, op1, insns, result;
int op1_type = REAL_TYPE;
tree fndecl = get_callee_fndecl (exp);
tree arg0, arg1;
if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
return NULL_RTX;
- target = gen_reg_rtx (mode);
+ result = gen_reg_rtx (mode);
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
start_sequence ();
- /* Compute into TARGET.
- Set TARGET to wherever the result comes back. */
- target = expand_binop (mode, builtin_optab, op0, op1,
- target, 0, OPTAB_DIRECT);
+ /* Compute into RESULT.
+ Set RESULT to wherever the result comes back. */
+ result = expand_binop (mode, builtin_optab, op0, op1,
+ result, 0, OPTAB_DIRECT);
/* If we were unable to expand via the builtin, stop the sequence
(without outputting the insns) and call to the library function
with the stabilized argument list. */
- if (target == 0)
+ if (result == 0)
{
end_sequence ();
return expand_call (exp, target, target == const0_rtx);
}
if (errno_set)
- expand_errno_check (exp, target);
+ expand_errno_check (exp, result);
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insn (insns);
- return target;
+ return result;
}
/* Expand a call to the builtin trinary math functions (fma).
expand_builtin_mathfn_ternary (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
- rtx op0, op1, op2, insns;
+ rtx op0, op1, op2, insns, result;
tree fndecl = get_callee_fndecl (exp);
tree arg0, arg1, arg2;
enum machine_mode mode;
if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
return NULL_RTX;
- target = gen_reg_rtx (mode);
+ result = gen_reg_rtx (mode);
/* Always stabilize the argument list. */
CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
start_sequence ();
- /* Compute into TARGET.
- Set TARGET to wherever the result comes back. */
- target = expand_ternary_op (mode, builtin_optab, op0, op1, op2,
- target, 0);
+ /* Compute into RESULT.
+ Set RESULT to wherever the result comes back. */
+ result = expand_ternary_op (mode, builtin_optab, op0, op1, op2,
+ result, 0);
/* If we were unable to expand via the builtin, stop the sequence
(without outputting the insns) and call to the library function
with the stabilized argument list. */
- if (target == 0)
+ if (result == 0)
{
end_sequence ();
return expand_call (exp, target, target == const0_rtx);
end_sequence ();
emit_insn (insns);
- return target;
+ return result;
}
/* Expand a call to the builtin sin and cos math functions.
/* Before working hard, check whether the instruction is available. */
if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
{
- target = gen_reg_rtx (mode);
+ rtx result = gen_reg_rtx (mode);
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
start_sequence ();
- /* Compute into TARGET.
- Set TARGET to wherever the result comes back. */
+ /* Compute into RESULT.
+ Set RESULT to wherever the result comes back. */
if (builtin_optab == sincos_optab)
{
- int result;
+ int ok;
switch (DECL_FUNCTION_CODE (fndecl))
{
CASE_FLT_FN (BUILT_IN_SIN):
- result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
+ ok = expand_twoval_unop (builtin_optab, op0, 0, result, 0);
break;
CASE_FLT_FN (BUILT_IN_COS):
- result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
+ ok = expand_twoval_unop (builtin_optab, op0, result, 0, 0);
break;
default:
gcc_unreachable ();
}
- gcc_assert (result);
+ gcc_assert (ok);
}
else
- {
- target = expand_unop (mode, builtin_optab, op0, target, 0);
- }
+ result = expand_unop (mode, builtin_optab, op0, result, 0);
- if (target != 0)
+ if (result != 0)
{
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insn (insns);
- return target;
+ return result;
}
/* If we were unable to expand via the builtin, stop the sequence
end_sequence ();
}
- target = expand_call (exp, target, target == const0_rtx);
-
- return target;
+ return expand_call (exp, target, target == const0_rtx);
}
/* Given an interclass math builtin decl FNDECL and it's argument ARG
/* Compute into op1 and op2. */
expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
}
- else if (TARGET_HAS_SINCOS)
+ else if (targetm.libc_has_function (function_sincos))
{
tree call, fn = NULL_TREE;
tree top1, top2;
exp = build_call_nofold_loc (EXPR_LOCATION (exp), fallback_fndecl, 1, arg);
tmp = expand_normal (exp);
+ tmp = maybe_emit_group_store (tmp, TREE_TYPE (exp));
/* Truncate the result of floating point optab to integer
via expand_fix (). */
/* There's no easy way to detect the case we need to set EDOM. */
if (!flag_errno_math)
{
- target = gen_reg_rtx (mode);
+ rtx result = gen_reg_rtx (mode);
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
start_sequence ();
- if (expand_sfix_optab (target, op0, builtin_optab))
+ if (expand_sfix_optab (result, op0, builtin_optab))
{
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insn (insns);
- return target;
+ return result;
}
/* If we were unable to expand via the builtin, stop the sequence
fallback_fndecl, 1, arg);
target = expand_call (exp, NULL_RTX, target == const0_rtx);
+ target = maybe_emit_group_store (target, TREE_TYPE (exp));
return convert_to_mode (mode, target, 0);
}
- target = expand_call (exp, target, target == const0_rtx);
-
- return target;
+ return expand_call (exp, target, target == const0_rtx);
}
/* Expand a call to the powi built-in mathematical function. Return NULL_RTX if
if (INDIRECT_REF_P (type))
type = TREE_TYPE (type);
- else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+ else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE (type)))
type = TREE_TYPE (type);
wtype = va_list_type_node;
htype = type;
return const0_rtx;
}
-/* The "standard" implementation of va_arg: read the value from the
- current (padded) address and increment by the (padded) size. */
-
-tree
-std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
- gimple_seq *post_p)
-{
- tree addr, t, type_size, rounded_size, valist_tmp;
- unsigned HOST_WIDE_INT align, boundary;
- bool indirect;
-
-#ifdef ARGS_GROW_DOWNWARD
- /* All of the alignment and movement below is for args-grow-up machines.
- As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
- implement their own specialized gimplify_va_arg_expr routines. */
- gcc_unreachable ();
-#endif
-
- indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
- if (indirect)
- type = build_pointer_type (type);
-
- align = PARM_BOUNDARY / BITS_PER_UNIT;
- boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
-
- /* When we align parameter on stack for caller, if the parameter
- alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
- aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
- here with caller. */
- if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
- boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
-
- boundary /= BITS_PER_UNIT;
-
- /* Hoist the valist value into a temporary for the moment. */
- valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
-
- /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
- requires greater alignment, we must perform dynamic alignment. */
- if (boundary > align
- && !integer_zerop (TYPE_SIZE (type)))
- {
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
- fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
- gimplify_and_add (t, pre_p);
-
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
- fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
- valist_tmp,
- build_int_cst (TREE_TYPE (valist), -boundary)));
- gimplify_and_add (t, pre_p);
- }
- else
- boundary = align;
-
- /* If the actual alignment is less than the alignment of the type,
- adjust the type accordingly so that we don't assume strict alignment
- when dereferencing the pointer. */
- boundary *= BITS_PER_UNIT;
- if (boundary < TYPE_ALIGN (type))
- {
- type = build_variant_type_copy (type);
- TYPE_ALIGN (type) = boundary;
- }
-
- /* Compute the rounded size of the type. */
- type_size = size_in_bytes (type);
- rounded_size = round_up (type_size, align);
-
- /* Reduce rounded_size so it's sharable with the postqueue. */
- gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
-
- /* Get AP. */
- addr = valist_tmp;
- if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
- {
- /* Small args are padded downward. */
- t = fold_build2_loc (input_location, GT_EXPR, sizetype,
- rounded_size, size_int (align));
- t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
- size_binop (MINUS_EXPR, rounded_size, type_size));
- addr = fold_build_pointer_plus (addr, t);
- }
-
- /* Compute new value for AP. */
- t = fold_build_pointer_plus (valist_tmp, rounded_size);
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
- gimplify_and_add (t, pre_p);
-
- addr = fold_convert (build_pointer_type (type), addr);
-
- if (indirect)
- addr = build_va_arg_indirect_ref (addr);
-
- return build_va_arg_indirect_ref (addr);
-}
-
-/* Build an indirect-ref expression over the given TREE, which represents a
- piece of a va_arg() expansion. */
-tree
-build_va_arg_indirect_ref (tree addr)
-{
- addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
-
- if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
- mf_mark (addr);
-
- return addr;
-}
-
-/* Return a dummy expression of type TYPE in order to keep going after an
- error. */
-
-static tree
-dummy_object (tree type)
-{
- tree t = build_int_cst (build_pointer_type (type), 0);
- return build2 (MEM_REF, type, t, t);
-}
-
-/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
- builtin function, but a very special sort of operator. */
-
-enum gimplify_status
-gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
-{
- tree promoted_type, have_va_type;
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
- tree t;
- location_t loc = EXPR_LOCATION (*expr_p);
-
- /* Verify that valist is of the proper type. */
- have_va_type = TREE_TYPE (valist);
- if (have_va_type == error_mark_node)
- return GS_ERROR;
- have_va_type = targetm.canonical_va_list_type (have_va_type);
-
- if (have_va_type == NULL_TREE)
- {
- error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
- return GS_ERROR;
- }
-
- /* Generate a diagnostic for requesting data of a type that cannot
- be passed through `...' due to type promotion at the call site. */
- if ((promoted_type = lang_hooks.types.type_promotes_to (type))
- != type)
- {
- static bool gave_help;
- bool warned;
-
- /* 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. */
- warned = warning_at (loc, 0,
- "%qT is promoted to %qT when passed through %<...%>",
- type, promoted_type);
- if (!gave_help && warned)
- {
- gave_help = true;
- inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
- promoted_type, type);
- }
-
- /* We can, however, treat "undefined" any way we please.
- Call abort to encourage the user to fix the program. */
- if (warned)
- inform (loc, "if this code is reached, the program will abort");
- /* Before the abort, allow the evaluation of the va_list
- expression to exit or longjmp. */
- gimplify_and_add (valist, pre_p);
- t = build_call_expr_loc (loc,
- builtin_decl_implicit (BUILT_IN_TRAP), 0);
- gimplify_and_add (t, pre_p);
-
- /* This is dead code, but go ahead and finish so that the
- mode of the result comes out right. */
- *expr_p = dummy_object (type);
- return GS_ALL_DONE;
- }
- else
- {
- /* Make it easier for the backends by protecting the valist argument
- from multiple evaluations. */
- if (TREE_CODE (have_va_type) == ARRAY_TYPE)
- {
- /* For this case, the backends will be expecting a pointer to
- TREE_TYPE (abi), but it's possible we've
- actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
- So fix it. */
- if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
- {
- tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
- valist = fold_convert_loc (loc, p1,
- build_fold_addr_expr_loc (loc, valist));
- }
-
- gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
- }
- else
- gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
-
- if (!targetm.gimplify_va_arg_expr)
- /* FIXME: Once most targets are converted we should merely
- assert this is non-null. */
- return GS_ALL_DONE;
-
- *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
- return GS_OK;
- }
-}
-
/* Expand EXP, a call to __builtin_va_end. */
static rtx
bool alloca_with_align = (DECL_FUNCTION_CODE (get_callee_fndecl (exp))
== BUILT_IN_ALLOCA_WITH_ALIGN);
- /* Emit normal call if we use mudflap. */
- if (flag_mudflap)
- return NULL_RTX;
-
valid_arglist
= (alloca_with_align
? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
/* Round address up to desired boundary. */
temp = gen_reg_rtx (Pmode);
- addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
- mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
+ addend = gen_int_mode (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1, Pmode);
+ mask = gen_int_mode (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT, Pmode);
temp = expand_simple_binop (Pmode, PLUS, tramp, addend,
temp, 0, OPTAB_LIB_WIDEN);
within the local function's FRAME decl. Either way, let's see if
we can fill in the MEM_ATTRs for this memory. */
if (TREE_CODE (t_tramp) == ADDR_EXPR)
- set_mem_attributes_minus_bitpos (m_tramp, TREE_OPERAND (t_tramp, 0),
- true, 0);
+ set_mem_attributes (m_tramp, TREE_OPERAND (t_tramp, 0), true);
/* Creator of a heap trampoline is responsible for making sure the
address is aligned to at least STACK_BOUNDARY. Normally malloc
return MEMMODEL_SEQ_CST;
}
- if ((INTVAL(op) & MEMMODEL_MASK) >= MEMMODEL_LAST)
+ if ((INTVAL (op) & MEMMODEL_MASK) >= MEMMODEL_LAST)
{
warning (OPT_Winvalid_memory_model,
"invalid memory model argument to builtin");
STRIP_NOPS (addr);
gcc_assert (TREE_OPERAND (addr, 0) == fndecl);
- TREE_OPERAND (addr, 0) = builtin_decl_explicit(ext_call);
+ TREE_OPERAND (addr, 0) = builtin_decl_explicit (ext_call);
/* Expand the call here so we can emit trailing code. */
ret = expand_call (exp, target, ignore);
}
\f
+/* Emit code to restore the current value of stack. */
+
+static void
+expand_stack_restore (tree var)
+{
+ rtx prev, sa = expand_normal (var);
+
+ sa = convert_memory_address (Pmode, sa);
+
+ prev = get_last_insn ();
+ emit_stack_restore (SAVE_BLOCK, sa);
+ fixup_args_size_notes (prev, get_last_insn (), 0);
+}
+
+
+/* Emit code to save the current value of stack. */
+
+static rtx
+expand_stack_save (void)
+{
+ rtx ret = NULL_RTX;
+
+ do_pending_stack_adjust ();
+ emit_stack_save (SAVE_BLOCK, &ret);
+ return ret;
+}
+
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
(and in mode MODE if that's convenient).
set of builtins. */
if (!optimize
&& !called_as_built_in (fndecl)
+ && fcode != BUILT_IN_FORK
+ && fcode != BUILT_IN_EXECL
+ && fcode != BUILT_IN_EXECV
+ && fcode != BUILT_IN_EXECLP
+ && fcode != BUILT_IN_EXECLE
+ && fcode != BUILT_IN_EXECVP
+ && fcode != BUILT_IN_EXECVE
&& fcode != BUILT_IN_ALLOCA
&& fcode != BUILT_IN_ALLOCA_WITH_ALIGN
- && fcode != BUILT_IN_FREE)
+ && fcode != BUILT_IN_FREE
+ && fcode != BUILT_IN_CHKP_SET_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_INIT_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_NULL_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_COPY_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_NARROW_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_STORE_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
+ && fcode != BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
+ && fcode != BUILT_IN_CHKP_CHECK_PTR_BOUNDS
+ && fcode != BUILT_IN_CHKP_GET_PTR_LBOUND
+ && fcode != BUILT_IN_CHKP_GET_PTR_UBOUND)
return expand_call (exp, target, ignore);
/* The built-in function expanders test for target == const0_rtx
switch (fcode)
{
CASE_FLT_FN (BUILT_IN_FABS):
+ case BUILT_IN_FABSD32:
+ case BUILT_IN_FABSD64:
+ case BUILT_IN_FABSD128:
target = expand_builtin_fabs (exp, target, subtarget);
if (target)
return target;
break;
CASE_INT_FN (BUILT_IN_FFS):
- case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, ffs_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CLZ):
- case BUILT_IN_CLZIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, clz_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CTZ):
- case BUILT_IN_CTZIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, ctz_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CLRSB):
- case BUILT_IN_CLRSBIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, clrsb_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_POPCOUNT):
- case BUILT_IN_POPCOUNTIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, popcount_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_PARITY):
- case BUILT_IN_PARITYIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, parity_optab);
if (target)
expand_builtin_set_thread_pointer (exp);
return const0_rtx;
+ case BUILT_IN_CILK_DETACH:
+ expand_builtin_cilk_detach (exp);
+ return const0_rtx;
+
+ case BUILT_IN_CILK_POP_FRAME:
+ expand_builtin_cilk_pop_frame (exp);
+ return const0_rtx;
+
+ case BUILT_IN_CHKP_INIT_PTR_BOUNDS:
+ case BUILT_IN_CHKP_NULL_PTR_BOUNDS:
+ case BUILT_IN_CHKP_COPY_PTR_BOUNDS:
+ return expand_normal (CALL_EXPR_ARG (exp, 0));
+
+ case BUILT_IN_CHKP_CHECK_PTR_LBOUNDS:
+ case BUILT_IN_CHKP_CHECK_PTR_UBOUNDS:
+ case BUILT_IN_CHKP_CHECK_PTR_BOUNDS:
+ case BUILT_IN_CHKP_SET_PTR_BOUNDS:
+ case BUILT_IN_CHKP_NARROW_PTR_BOUNDS:
+ case BUILT_IN_CHKP_STORE_PTR_BOUNDS:
+ case BUILT_IN_CHKP_GET_PTR_LBOUND:
+ case BUILT_IN_CHKP_GET_PTR_UBOUND:
+ /* We allow user CHKP builtins if Pointer Bounds
+ Checker is off. */
+ if (!flag_check_pointer_bounds)
+ {
+ if (fcode == BUILT_IN_CHKP_SET_PTR_BOUNDS
+ || fcode == BUILT_IN_CHKP_NARROW_PTR_BOUNDS)
+ return expand_normal (CALL_EXPR_ARG (exp, 0));
+ else if (fcode == BUILT_IN_CHKP_GET_PTR_LBOUND)
+ return expand_normal (size_zero_node);
+ else if (fcode == BUILT_IN_CHKP_GET_PTR_UBOUND)
+ return expand_normal (size_int (-1));
+ else
+ return const0_rtx;
+ }
+ /* FALLTHROUGH */
+
+ case BUILT_IN_CHKP_BNDMK:
+ case BUILT_IN_CHKP_BNDSTX:
+ case BUILT_IN_CHKP_BNDCL:
+ case BUILT_IN_CHKP_BNDCU:
+ case BUILT_IN_CHKP_BNDLDX:
+ case BUILT_IN_CHKP_BNDRET:
+ case BUILT_IN_CHKP_INTERSECT:
+ case BUILT_IN_CHKP_ARG_BND:
+ case BUILT_IN_CHKP_NARROW:
+ case BUILT_IN_CHKP_EXTRACT_LOWER:
+ case BUILT_IN_CHKP_EXTRACT_UPPER:
+ /* Software implementation of pointers checker is NYI.
+ Target support is required. */
+ error ("Your target platform does not support -fcheck-pointers");
+ break;
+
default: /* just do library call, if unknown builtin */
break;
}
|| AGGREGATE_TYPE_P (TREE_TYPE (arg))
|| POINTER_TYPE_P (TREE_TYPE (arg))
|| cfun == 0
- || folding_initializer)
+ || folding_initializer
+ || force_folding_builtin_constant_p)
return integer_zero_node;
return NULL_TREE;
return res;
/* Canonicalize sincos to cexpi. */
- if (!TARGET_C99_FUNCTIONS)
+ if (!targetm.libc_has_function (function_c99_math_complex))
return NULL_TREE;
fn = mathfn_built_in (type, BUILT_IN_CEXPI);
if (!fn)
/* In case we can figure out the real part of arg0 and it is constant zero
fold to cexpi. */
- if (!TARGET_C99_FUNCTIONS)
+ if (!targetm.libc_has_function (function_c99_math_complex))
return NULL_TREE;
ifn = mathfn_built_in (rtype, BUILT_IN_CEXPI);
if (!ifn)
{
hi = TREE_INT_CST_HIGH (arg);
if (width < HOST_BITS_PER_DOUBLE_INT)
- hi &= ~((unsigned HOST_WIDE_INT) (-1)
- << (width - HOST_BITS_PER_WIDE_INT));
+ hi &= ~(HOST_WIDE_INT_M1U << (width - HOST_BITS_PER_WIDE_INT));
}
else
{
hi = 0;
if (width < HOST_BITS_PER_WIDE_INT)
- lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
+ lo &= ~(HOST_WIDE_INT_M1U << width);
}
switch (DECL_FUNCTION_CODE (fndecl))
break;
CASE_INT_FN (BUILT_IN_CLRSB):
+ if (width > 2 * HOST_BITS_PER_WIDE_INT)
+ return NULL_TREE;
if (width > HOST_BITS_PER_WIDE_INT
&& (hi & ((unsigned HOST_WIDE_INT) 1
<< (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
{
- hi = ~hi & ~((unsigned HOST_WIDE_INT) (-1)
+ hi = ~hi & ~(HOST_WIDE_INT_M1U
<< (width - HOST_BITS_PER_WIDE_INT - 1));
lo = ~lo;
}
else if (width <= HOST_BITS_PER_WIDE_INT
&& (lo & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
- lo = ~lo & ~((unsigned HOST_WIDE_INT) (-1) << (width - 1));
+ lo = ~lo & ~(HOST_WIDE_INT_M1U << (width - 1));
if (hi != 0)
result = width - floor_log2 (hi) - 2 - HOST_BITS_PER_WIDE_INT;
else if (lo != 0)
fold_builtin_fma (location_t loc, tree arg0, tree arg1, tree arg2, tree type)
{
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, REAL_TYPE)
- && validate_arg(arg2, REAL_TYPE))
+ && validate_arg (arg1, REAL_TYPE)
+ && validate_arg (arg2, REAL_TYPE))
{
tree tem = fold_fma (loc, type, arg0, arg1, arg2);
if (tem)
case rvc_inf:
/* If arg is Inf or NaN and we're logb, return it. */
if (TREE_CODE (rettype) == REAL_TYPE)
- return fold_convert_loc (loc, rettype, arg);
+ {
+ /* For logb(-Inf) we have to return +Inf. */
+ if (real_isinf (value) && real_isneg (value))
+ {
+ REAL_VALUE_TYPE tem;
+ real_inf (&tem);
+ return build_real (rettype, tem);
+ }
+ return fold_convert_loc (loc, rettype, arg);
+ }
/* Fall through... */
case rvc_zero:
/* Zero may set errno and/or raise an exception for logb, also
case BUILT_IN_CLASSIFY_TYPE:
return fold_builtin_classify_type (NULL_TREE);
+ case BUILT_IN_UNREACHABLE:
+ if (flag_sanitize & SANITIZE_UNREACHABLE
+ && (current_function_decl == NULL
+ || !lookup_attribute ("no_sanitize_undefined",
+ DECL_ATTRIBUTES (current_function_decl))))
+ return ubsan_instrument_unreachable (loc);
+ break;
+
default:
break;
}
return fold_builtin_strlen (loc, type, arg0);
CASE_FLT_FN (BUILT_IN_FABS):
+ case BUILT_IN_FABSD32:
+ case BUILT_IN_FABSD64:
+ case BUILT_IN_FABSD128:
return fold_builtin_fabs (loc, arg0, type);
case BUILT_IN_ABS:
break;
CASE_FLT_FN (BUILT_IN_CCOS):
- return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ false);
+ return fold_builtin_ccos (loc, arg0, type, fndecl, /*hyper=*/ false);
CASE_FLT_FN (BUILT_IN_CCOSH):
- return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ true);
+ return fold_builtin_ccos (loc, arg0, type, fndecl, /*hyper=*/ true);
CASE_FLT_FN (BUILT_IN_CPROJ):
- return fold_builtin_cproj(loc, arg0, type);
+ return fold_builtin_cproj (loc, arg0, type);
CASE_FLT_FN (BUILT_IN_CSIN):
if (validate_arg (arg0, COMPLEX_TYPE)
CASE_FLT_FN (BUILT_IN_DREM):
CASE_FLT_FN (BUILT_IN_REMAINDER):
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, REAL_TYPE))
+ && validate_arg (arg1, REAL_TYPE))
return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder);
break;
CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */
CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, POINTER_TYPE))
+ && validate_arg (arg1, POINTER_TYPE))
return do_mpfr_lgamma_r (arg0, arg1, type);
break;
CASE_FLT_FN (BUILT_IN_ATAN2):
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, REAL_TYPE))
+ && validate_arg (arg1, REAL_TYPE))
return do_mpfr_arg2 (arg0, arg1, type, mpfr_atan2);
break;
CASE_FLT_FN (BUILT_IN_FDIM):
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, REAL_TYPE))
+ && validate_arg (arg1, REAL_TYPE))
return do_mpfr_arg2 (arg0, arg1, type, mpfr_dim);
break;
CASE_FLT_FN (BUILT_IN_REMQUO):
if (validate_arg (arg0, REAL_TYPE)
- && validate_arg(arg1, REAL_TYPE)
- && validate_arg(arg2, POINTER_TYPE))
+ && validate_arg (arg1, REAL_TYPE)
+ && validate_arg (arg2, POINTER_TYPE))
return do_mpfr_remquo (arg0, arg1, arg2);
break;
return NULL_TREE;
}
-/* Builtins with folding operations that operate on "..." arguments
- need special handling; we need to store the arguments in a convenient
- data structure before attempting any folding. Fortunately there are
- only a few builtins that fall into this category. FNDECL is the
- function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
- result of the function call is ignored. */
+/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
+ list ARGS along with N new arguments in NEWARGS. SKIP is the number
+ of arguments in ARGS to be omitted. OLDNARGS is the number of
+ elements in ARGS. */
static tree
-fold_builtin_varargs (location_t loc, tree fndecl, tree exp,
- bool ignore ATTRIBUTE_UNUSED)
+rewrite_call_expr_valist (location_t loc, int oldnargs, tree *args,
+ int skip, tree fndecl, int n, va_list newargs)
{
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
- tree ret = NULL_TREE;
+ int nargs = oldnargs - skip + n;
+ tree *buffer;
- switch (fcode)
+ if (n > 0)
{
- case BUILT_IN_SPRINTF_CHK:
- case BUILT_IN_VSPRINTF_CHK:
- ret = fold_builtin_sprintf_chk (loc, exp, fcode);
- break;
+ int i, j;
- case BUILT_IN_SNPRINTF_CHK:
- case BUILT_IN_VSNPRINTF_CHK:
- ret = fold_builtin_snprintf_chk (loc, exp, NULL_TREE, fcode);
- break;
+ buffer = XALLOCAVEC (tree, nargs);
+ for (i = 0; i < n; i++)
+ buffer[i] = va_arg (newargs, tree);
+ for (j = skip; j < oldnargs; j++, i++)
+ buffer[i] = args[j];
+ }
+ else
+ buffer = args + skip;
- case BUILT_IN_FPCLASSIFY:
- ret = fold_builtin_fpclassify (loc, exp);
- break;
+ return build_call_expr_loc_array (loc, fndecl, nargs, buffer);
+}
- default:
- break;
- }
- if (ret)
- {
- ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
- SET_EXPR_LOCATION (ret, loc);
- TREE_NO_WARNING (ret) = 1;
- return ret;
- }
- return NULL_TREE;
+/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
+ list ARGS along with N new arguments specified as the "..."
+ parameters. SKIP is the number of arguments in ARGS to be omitted.
+ OLDNARGS is the number of elements in ARGS. */
+
+static tree
+rewrite_call_expr_array (location_t loc, int oldnargs, tree *args,
+ int skip, tree fndecl, int n, ...)
+{
+ va_list ap;
+ tree t;
+
+ va_start (ap, n);
+ t = rewrite_call_expr_valist (loc, oldnargs, args, skip, fndecl, n, ap);
+ va_end (ap);
+
+ return t;
}
/* Return true if FNDECL shouldn't be folded right now.
return build_call_array_loc (loc, type, fn, n, argarray);
}
-/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
- list ARGS along with N new arguments in NEWARGS. SKIP is the number
- of arguments in ARGS to be omitted. OLDNARGS is the number of
- elements in ARGS. */
-
-static tree
-rewrite_call_expr_valist (location_t loc, int oldnargs, tree *args,
- int skip, tree fndecl, int n, va_list newargs)
-{
- int nargs = oldnargs - skip + n;
- tree *buffer;
-
- if (n > 0)
- {
- int i, j;
-
- buffer = XALLOCAVEC (tree, nargs);
- for (i = 0; i < n; i++)
- buffer[i] = va_arg (newargs, tree);
- for (j = skip; j < oldnargs; j++, i++)
- buffer[i] = args[j];
- }
- else
- buffer = args + skip;
-
- return build_call_expr_loc_array (loc, fndecl, nargs, buffer);
-}
-
-/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
- list ARGS along with N new arguments specified as the "..."
- parameters. SKIP is the number of arguments in ARGS to be omitted.
- OLDNARGS is the number of elements in ARGS. */
-
-static tree
-rewrite_call_expr_array (location_t loc, int oldnargs, tree *args,
- int skip, tree fndecl, int n, ...)
-{
- va_list ap;
- tree t;
-
- va_start (ap, n);
- t = rewrite_call_expr_valist (loc, oldnargs, args, skip, fndecl, n, ap);
- va_end (ap);
-
- return t;
-}
-
/* Construct a new CALL_EXPR using the tail of the argument list of EXP
along with N new arguments specified as the "..." parameters. SKIP
is the number of arguments in EXP to be omitted. This function is used
return res;
}
-/* This function validates the types of a function call argument list
- against a specified list of tree_codes. If the last specifier is a 0,
- that represents an ellipses, otherwise the last specifier must be a
- VOID_TYPE. */
-
-bool
-validate_arglist (const_tree callexpr, ...)
-{
- enum tree_code code;
- bool res = 0;
- va_list ap;
- const_call_expr_arg_iterator iter;
- const_tree arg;
-
- va_start (ap, callexpr);
- init_const_call_expr_arg_iterator (callexpr, &iter);
-
- do
- {
- code = (enum tree_code) va_arg (ap, int);
- switch (code)
- {
- case 0:
- /* This signifies an ellipses, any further arguments are all ok. */
- res = true;
- goto end;
- case VOID_TYPE:
- /* This signifies an endlink, if no arguments remain, return
- true, otherwise return false. */
- res = !more_const_call_expr_args_p (&iter);
- goto end;
- default:
- /* If no parameters remain or the parameter's code does not
- match the specified code, return false. Otherwise continue
- checking any remaining arguments. */
- arg = next_const_call_expr_arg (&iter);
- if (!validate_arg (arg, code))
- goto end;
- break;
- }
- }
- while (1);
-
- /* We need gotos here since we can only have one VA_CLOSE in a
- function. */
- end: ;
- va_end (ap);
-
- return res;
-}
-
/* Default target-specific builtin expander that does nothing. */
rtx
BUILT_IN_VSNPRINTF_CHK. If MAXLEN is not NULL, it is maximum length
passed as second argument. */
-tree
+static tree
fold_builtin_snprintf_chk (location_t loc, tree exp, tree maxlen,
enum built_in_function fcode)
{
CALL_EXPR_ARGP (exp), maxlen, fcode);
}
+/* Builtins with folding operations that operate on "..." arguments
+ need special handling; we need to store the arguments in a convenient
+ data structure before attempting any folding. Fortunately there are
+ only a few builtins that fall into this category. FNDECL is the
+ function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
+ result of the function call is ignored. */
+
+static tree
+fold_builtin_varargs (location_t loc, tree fndecl, tree exp,
+ bool ignore ATTRIBUTE_UNUSED)
+{
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+ tree ret = NULL_TREE;
+
+ switch (fcode)
+ {
+ case BUILT_IN_SPRINTF_CHK:
+ case BUILT_IN_VSPRINTF_CHK:
+ ret = fold_builtin_sprintf_chk (loc, exp, fcode);
+ break;
+
+ case BUILT_IN_SNPRINTF_CHK:
+ case BUILT_IN_VSNPRINTF_CHK:
+ ret = fold_builtin_snprintf_chk (loc, exp, NULL_TREE, fcode);
+ break;
+
+ case BUILT_IN_FPCLASSIFY:
+ ret = fold_builtin_fpclassify (loc, exp);
+ break;
+
+ default:
+ break;
+ }
+ if (ret)
+ {
+ ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+ SET_EXPR_LOCATION (ret, loc);
+ TREE_NO_WARNING (ret) = 1;
+ return ret;
+ }
+ return NULL_TREE;
+}
+
/* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
FMT and ARG are the arguments to the call; we don't fold cases with
more than 2 arguments, and ARG may be null if this is a 1-argument case.
&& host_integerp (arg1, 0)
&& TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
{
- const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
+ const HOST_WIDE_INT n = tree_low_cst (arg1, 0);
const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
if (n == (long)n
negative integer. */
if (real_isfinite (ra)
&& ra->cl != rvc_zero
- && !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type))))
+ && !(real_isneg (ra) && real_isinteger (ra, TYPE_MODE (type))))
{
const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
const int prec = fmt->p;
mpc_t m;
mpc_init2 (m, prec);
- mpfr_from_real (mpc_realref(m), re, rnd);
- mpfr_from_real (mpc_imagref(m), im, rnd);
+ mpfr_from_real (mpc_realref (m), re, rnd);
+ mpfr_from_real (mpc_imagref (m), im, rnd);
mpfr_clear_flags ();
inexact = func (m, m, crnd);
result = do_mpc_ckconv (m, type, inexact, /*force_convert=*/ 0);
mpc_init2 (m0, prec);
mpc_init2 (m1, prec);
- mpfr_from_real (mpc_realref(m0), re0, rnd);
- mpfr_from_real (mpc_imagref(m0), im0, rnd);
- mpfr_from_real (mpc_realref(m1), re1, rnd);
- mpfr_from_real (mpc_imagref(m1), im1, rnd);
+ mpfr_from_real (mpc_realref (m0), re0, rnd);
+ mpfr_from_real (mpc_imagref (m0), im0, rnd);
+ mpfr_from_real (mpc_realref (m1), re1, rnd);
+ mpfr_from_real (mpc_imagref (m1), im1, rnd);
mpfr_clear_flags ();
inexact = func (m0, m0, m1, crnd);
result = do_mpc_ckconv (m0, type, inexact, do_nonfinite);