GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
static void store_unaligned_arguments_into_pseudos (struct arg_data *, int);
static int finalize_must_preallocate (int, int, struct arg_data *,
struct args_size *);
-static void precompute_arguments (int, int, struct arg_data *);
-static int compute_argument_block_size (int, struct args_size *, int);
+static void precompute_arguments (int, struct arg_data *);
+static int compute_argument_block_size (int, struct args_size *, tree, int);
static void initialize_argument_information (int, struct arg_data *,
struct args_size *, int,
tree, tree,
int, int *);
static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type,
enum machine_mode, int, va_list);
-static int special_function_p (tree, int);
+static int special_function_p (const_tree, int);
static int check_sibcall_argument_overlap_1 (rtx);
static int check_sibcall_argument_overlap (rtx, struct arg_data *, int);
even if the call has no arguments to pop. */
#if defined (HAVE_call) && defined (HAVE_call_value)
if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
- && n_popped > 0 && ! (ecf_flags & ECF_SP_DEPRESSED))
+ && n_popped > 0)
#else
if (HAVE_call_pop && HAVE_call_value_pop)
#endif
/* Find the call we just emitted. */
call_insn = last_call_insn ();
- /* Mark memory as used for "pure" function call. */
- if (ecf_flags & ECF_PURE)
- call_fusage
- = gen_rtx_EXPR_LIST
- (VOIDmode,
- gen_rtx_USE (VOIDmode,
- gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))),
- call_fusage);
-
/* Put the register usage information there. */
add_function_usage_to (call_insn, call_fusage);
/* If this is a const call, then set the insn's unchanging bit. */
- if (ecf_flags & (ECF_CONST | ECF_PURE))
- CONST_OR_PURE_CALL_P (call_insn) = 1;
+ if (ecf_flags & ECF_CONST)
+ RTL_CONST_CALL_P (call_insn) = 1;
+
+ /* If this is a pure call, then set the insn's unchanging bit. */
+ if (ecf_flags & ECF_PURE)
+ RTL_PURE_CALL_P (call_insn) = 1;
+
+ /* If this is a const call, then set the insn's unchanging bit. */
+ if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
+ RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
/* If this call can't throw, attach a REG_EH_REGION reg note to that
effect. */
if (ecf_flags & ECF_NOTHROW)
- REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx,
- REG_NOTES (call_insn));
+ add_reg_note (call_insn, REG_EH_REGION, const0_rtx);
else
{
int rn = lookup_stmt_eh_region (fntree);
/* If rn < 0, then either (1) tree-ssa not used or (2) doesn't
throw, which we already took care of. */
if (rn > 0)
- REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
- REG_NOTES (call_insn));
- note_current_region_may_contain_throw ();
+ add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn));
}
if (ecf_flags & ECF_NORETURN)
- REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx,
- REG_NOTES (call_insn));
+ add_reg_note (call_insn, REG_NORETURN, const0_rtx);
if (ecf_flags & ECF_RETURNS_TWICE)
{
- REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_SETJMP, const0_rtx,
- REG_NOTES (call_insn));
- current_function_calls_setjmp = 1;
+ add_reg_note (call_insn, REG_SETJMP, const0_rtx);
+ cfun->calls_setjmp = 1;
}
SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
if (rounded_stack_size != 0)
{
- if (ecf_flags & (ECF_SP_DEPRESSED | ECF_NORETURN))
+ if (ecf_flags & ECF_NORETURN)
/* Just pretend we did the pop. */
stack_pointer_delta -= rounded_stack_size;
else if (flag_defer_pop && inhibit_defer_pop == 0
space from the stack such as alloca. */
static int
-special_function_p (tree fndecl, int flags)
+special_function_p (const_tree fndecl, int flags)
{
if (fndecl && DECL_NAME (fndecl)
&& IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
/* Return nonzero when FNDECL represents a call to setjmp. */
int
-setjmp_call_p (tree fndecl)
+setjmp_call_p (const_tree fndecl)
{
return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
}
/* Return true when exp contains alloca call. */
bool
-alloca_call_p (tree exp)
+alloca_call_p (const_tree exp)
{
if (TREE_CODE (exp) == CALL_EXPR
&& TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
/* Detect flags (function attributes) from the function decl or type node. */
int
-flags_from_decl_or_type (tree exp)
+flags_from_decl_or_type (const_tree exp)
{
int flags = 0;
- tree type = exp;
+ const_tree type = exp;
if (DECL_P (exp))
{
if (DECL_IS_RETURNS_TWICE (exp))
flags |= ECF_RETURNS_TWICE;
- /* The function exp may have the `pure' attribute. */
- if (DECL_IS_PURE (exp))
+ /* Process the pure and const attributes. */
+ if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
+ flags |= ECF_CONST;
+ if (DECL_PURE_P (exp))
flags |= ECF_PURE;
+ if (DECL_LOOPING_CONST_OR_PURE_P (exp))
+ flags |= ECF_LOOPING_CONST_OR_PURE;
if (DECL_IS_NOVOPS (exp))
flags |= ECF_NOVOPS;
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
- if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
- flags |= ECF_CONST;
-
flags = special_function_p (exp, flags);
}
else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
if (TREE_THIS_VOLATILE (exp))
flags |= ECF_NORETURN;
- /* Mark if the function returns with the stack pointer depressed. We
- cannot consider it pure or constant in that case. */
- if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
- {
- flags |= ECF_SP_DEPRESSED;
- flags &= ~(ECF_PURE | ECF_CONST);
- }
-
return flags;
}
/* Detect flags from a CALL_EXPR. */
int
-call_expr_flags (tree t)
+call_expr_flags (const_tree t)
{
int flags;
tree decl = get_callee_fndecl (t);
args[i].tree_value = build_fold_addr_expr (args[i].tree_value);
type = TREE_TYPE (args[i].tree_value);
- *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK);
+ if (*ecf_flags & ECF_CONST)
+ *ecf_flags &= ~(ECF_CONST | ECF_LOOPING_CONST_OR_PURE);
}
else
{
store_expr (args[i].tree_value, copy, 0, false);
- if (callee_copies)
- *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK);
- else
- *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+ /* Just change the const function to pure and then let
+ the next test clear the pure based on
+ callee_copies. */
+ if (*ecf_flags & ECF_CONST)
+ {
+ *ecf_flags &= ~ECF_CONST;
+ *ecf_flags |= ECF_PURE;
+ }
+
+ if (!callee_copies && *ecf_flags & ECF_PURE)
+ *ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
args[i].tree_value
= build_fold_addr_expr (make_tree (type, copy));
|| (args[i].pass_on_stack && args[i].reg != 0))
*must_preallocate = 1;
- /* If this is an addressable type, we cannot pre-evaluate it. Thus,
- we cannot consider this function call constant. */
- if (TREE_ADDRESSABLE (type))
- *ecf_flags &= ~ECF_LIBCALL_BLOCK;
-
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
|| reg_parm_stack_space > 0
static int
compute_argument_block_size (int reg_parm_stack_space,
struct args_size *args_size,
+ tree fndecl ATTRIBUTE_UNUSED,
int preferred_stack_boundary ATTRIBUTE_UNUSED)
{
int unadjusted_args_size = args_size->constant;
/* The area corresponding to register parameters is not to count in
the size of the block we need. So make the adjustment. */
- if (!OUTGOING_REG_PARM_STACK_SPACE)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))))
args_size->var
= size_binop (MINUS_EXPR, args_size->var,
ssize_int (reg_parm_stack_space));
args_size->constant = MAX (args_size->constant,
reg_parm_stack_space);
- if (!OUTGOING_REG_PARM_STACK_SPACE)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))))
args_size->constant -= reg_parm_stack_space;
}
return unadjusted_args_size;
precomputed argument. */
static void
-precompute_arguments (int flags, int num_actuals, struct arg_data *args)
+precompute_arguments (int num_actuals, struct arg_data *args)
{
int i;
which have already been stored into the stack. (we have code to avoid
such case by saving the outgoing stack arguments, but it results in
worse code) */
- if ((flags & ECF_LIBCALL_BLOCK) == 0 && !ACCUMULATE_OUTGOING_ARGS)
+ if (!ACCUMULATE_OUTGOING_ARGS)
return;
for (i = 0; i < num_actuals; i++)
{
enum machine_mode mode;
- if ((flags & ECF_LIBCALL_BLOCK) == 0
- && TREE_CODE (args[i].tree_value) != CALL_EXPR)
+ if (TREE_CODE (args[i].tree_value) != CALL_EXPR)
continue;
/* If this is an addressable type, we cannot pre-evaluate it. */
{
HOST_WIDE_INT i;
- if (addr == current_function_internal_arg_pointer)
+ if (addr == crtl->args.internal_arg_pointer)
i = 0;
else if (GET_CODE (addr) == PLUS
- && XEXP (addr, 0) == current_function_internal_arg_pointer
+ && XEXP (addr, 0) == crtl->args.internal_arg_pointer
&& GET_CODE (XEXP (addr, 1)) == CONST_INT)
i = INTVAL (XEXP (addr, 1));
/* Return true for arg pointer based indexed addressing. */
else if (GET_CODE (addr) == PLUS
- && (XEXP (addr, 0) == current_function_internal_arg_pointer
- || XEXP (addr, 1) == current_function_internal_arg_pointer))
+ && (XEXP (addr, 0) == crtl->args.internal_arg_pointer
+ || XEXP (addr, 1) == crtl->args.internal_arg_pointer))
return true;
else
return false;
return true;
}
+/* If X is a likely-spilled register value, copy it to a pseudo
+ register and return that register. Return X otherwise. */
+
+static rtx
+avoid_likely_spilled_reg (rtx x)
+{
+ rtx new;
+
+ if (REG_P (x)
+ && HARD_REGISTER_P (x)
+ && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (x))))
+ {
+ /* Make sure that we generate a REG rather than a CONCAT.
+ Moves into CONCATs can need nontrivial instructions,
+ and the whole point of this function is to avoid
+ using the hard register directly in such a situation. */
+ generating_concat_p = 0;
+ new = gen_reg_rtx (GET_MODE (x));
+ generating_concat_p = 1;
+ emit_move_insn (new, x);
+ return new;
+ }
+ return x;
+}
+
/* Generate all the code for a CALL_EXPR exp
and return an rtx for its value.
Store the value in TARGET (specified as an rtx) if convenient.
if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
warning (OPT_Waggregate_return, "function call has aggregate value");
- /* If the result of a pure or const function call is ignored (or void),
- and none of its arguments are volatile, we can avoid expanding the
- call and just evaluate the arguments for side-effects. */
+ /* If the result of a non looping pure or const function call is
+ ignored (or void), and none of its arguments are volatile, we can
+ avoid expanding the call and just evaluate the arguments for
+ side-effects. */
if ((flags & (ECF_CONST | ECF_PURE))
+ && (!(flags & ECF_LOOPING_CONST_OR_PURE))
&& (ignore || target == const0_rtx
|| TYPE_MODE (TREE_TYPE (exp)) == VOIDmode))
{
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
#endif
- if (!OUTGOING_REG_PARM_STACK_SPACE && reg_parm_stack_space > 0 && PUSH_ARGS)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))
+ && reg_parm_stack_space > 0 && PUSH_ARGS)
must_preallocate = 1;
/* Set up a place to return a structure. */
if (aggregate_value_p (exp, fndecl))
{
/* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
#ifdef PCC_STATIC_STRUCT_RETURN
{
if (fndecl)
{
struct cgraph_rtl_info *i = cgraph_rtl_info (fndecl);
- if (i && i->preferred_incoming_stack_boundary)
+ /* Without automatic stack alignment, we can't increase preferred
+ stack boundary. With automatic stack alignment, it is
+ unnecessary since unless we can guarantee that all callers will
+ align the outgoing stack properly, callee has to align its
+ stack anyway. */
+ if (i
+ && i->preferred_incoming_stack_boundary
+ && i->preferred_incoming_stack_boundary < preferred_stack_boundary)
preferred_stack_boundary = i->preferred_incoming_stack_boundary;
}
type_arg_types = TYPE_ARG_TYPES (funtype);
if (flags & ECF_MAY_BE_ALLOCA)
- current_function_calls_alloca = 1;
+ cfun->calls_alloca = 1;
/* If struct_value_rtx is 0, it means pass the address
as if it were an extra parameter. Put the argument expression
n_named_args = num_actuals;
/* Make a vector to hold all the information about each arg. */
- args = alloca (num_actuals * sizeof (struct arg_data));
+ args = XALLOCAVEC (struct arg_data, num_actuals);
memset (args, 0, num_actuals * sizeof (struct arg_data));
/* Build up entries in the ARGS array, compute the size of the
&try_tail_call, CALL_FROM_THUNK_P (exp));
if (args_size.var)
- {
- /* If this function requires a variable-sized argument list, don't
- try to make a cse'able block for this call. We may be able to
- do this eventually, but it is too complicated to keep track of
- what insns go in the cse'able block and which don't. */
-
- flags &= ~ECF_LIBCALL_BLOCK;
- must_preallocate = 1;
- }
+ must_preallocate = 1;
/* Now make final decision about preallocating stack space. */
must_preallocate = finalize_must_preallocate (must_preallocate,
|| (fndecl && decl_function_context (fndecl) == current_function_decl)
/* If this function requires more stack slots than the current
function, we cannot change it into a sibling call.
- current_function_pretend_args_size is not part of the
+ crtl->args.pretend_args_size is not part of the
stack allocated by our caller. */
- || args_size.constant > (current_function_args_size
- - current_function_pretend_args_size)
+ || args_size.constant > (crtl->args.size
+ - crtl->args.pretend_args_size)
/* If the callee pops its own arguments, then it must pop exactly
the same number of arguments as the current function. */
|| (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant)
!= RETURN_POPS_ARGS (current_function_decl,
TREE_TYPE (current_function_decl),
- current_function_args_size))
+ crtl->args.size))
|| !lang_hooks.decls.ok_for_sibcall (fndecl))
try_tail_call = 0;
- /* Ensure current function's preferred stack boundary is at least
- what we need. We don't have to increase alignment for recursive
- functions. */
- if (cfun->preferred_stack_boundary < preferred_stack_boundary
- && fndecl != current_function_decl)
- cfun->preferred_stack_boundary = preferred_stack_boundary;
- if (fndecl == current_function_decl)
- cfun->recursive_call_emit = true;
+ /* Ensure current function's preferred stack
+ boundary is at least what we need. */
+ if (crtl->preferred_stack_boundary < preferred_stack_boundary)
+ crtl->preferred_stack_boundary = preferred_stack_boundary;
preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
int save_pending_stack_adjust = 0;
int save_stack_pointer_delta = 0;
rtx insns;
- rtx before_call, next_arg_reg;
+ rtx before_call, next_arg_reg, after_args;
if (pass == 0)
{
/* Don't let pending stack adjusts add up to too much.
Also, do all pending adjustments now if there is any chance
this might be a call to alloca or if we are expanding a sibling
- call sequence or if we are calling a function that is to return
- with stack pointer depressed.
+ call sequence.
Also do the adjustments before a throwing call, otherwise
exception handling can fail; PR 19225. */
if (pending_stack_adjust >= 32
|| (pending_stack_adjust > 0
- && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED)))
+ && (flags & ECF_MAY_BE_ALLOCA))
|| (pending_stack_adjust > 0
&& flag_exceptions && !(flags & ECF_NOTHROW))
|| pass == 0)
do_pending_stack_adjust ();
- /* When calling a const function, we must pop the stack args right away,
- so that the pop is deleted or moved with the call. */
- if (pass && (flags & ECF_LIBCALL_BLOCK))
- NO_DEFER_POP;
-
/* Precompute any arguments as needed. */
if (pass)
- precompute_arguments (flags, num_actuals, args);
+ precompute_arguments (num_actuals, args);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
+ if (pass && (flags & ECF_MALLOC))
start_sequence ();
- if (pass == 0 && cfun->stack_protect_guard)
+ if (pass == 0 && crtl->stack_protect_guard)
stack_protect_epilogue ();
adjusted_args_size = args_size;
unadjusted_args_size
= compute_argument_block_size (reg_parm_stack_space,
&adjusted_args_size,
+ fndecl,
(pass == 0 ? 0
: preferred_stack_boundary));
argblock = virtual_incoming_args_rtx;
argblock
#ifdef STACK_GROWS_DOWNWARD
- = plus_constant (argblock, current_function_pretend_args_size);
+ = plus_constant (argblock, crtl->args.pretend_args_size);
#else
- = plus_constant (argblock, -current_function_pretend_args_size);
+ = plus_constant (argblock, -crtl->args.pretend_args_size);
#endif
stored_args_map = sbitmap_alloc (args_size.constant);
sbitmap_zero (stored_args_map);
the prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow
checking). */
- if (needed > current_function_outgoing_args_size)
- current_function_outgoing_args_size = needed;
+ if (needed > crtl->outgoing_args_size)
+ crtl->outgoing_args_size = needed;
if (must_preallocate)
{
/* Since we will be writing into the entire argument area,
the map must be allocated for its entire size, not just
the part that is the responsibility of the caller. */
- if (!OUTGOING_REG_PARM_STACK_SPACE)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))))
needed += reg_parm_stack_space;
#ifdef ARGS_GROW_DOWNWARD
{
rtx push_size
= GEN_INT (adjusted_args_size.constant
- + (OUTGOING_REG_PARM_STACK_SPACE ? 0
+ + (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL
+ : TREE_TYPE (fndecl))) ? 0
: reg_parm_stack_space));
if (old_stack_level == 0)
{
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
if (pending_stack_adjust
- && ! (flags & ECF_LIBCALL_BLOCK)
&& ! inhibit_defer_pop)
{
pending_stack_adjust
/* If register arguments require space on the stack and stack space
was not preallocated, allocate stack space here for arguments
passed in registers. */
- if (OUTGOING_REG_PARM_STACK_SPACE && !ACCUMULATE_OUTGOING_ARGS
+ if (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))
+ && !ACCUMULATE_OUTGOING_ARGS
&& must_preallocate == 0 && reg_parm_stack_space > 0)
anti_adjust_stack (GEN_INT (reg_parm_stack_space));
use_reg (&call_fusage, struct_value);
}
+ after_args = get_last_insn ();
funexp = prepare_call_address (funexp, static_chain_value,
&call_fusage, reg_parm_seen, pass == 0);
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
flags, & args_so_far);
+ /* If the call setup or the call itself overlaps with anything
+ of the argument setup we probably clobbered our call address.
+ In that case we can't do sibcalls. */
+ if (pass == 0
+ && check_sibcall_argument_overlap (after_args, 0, 0))
+ sibcall_failure = 1;
+
/* If a non-BLKmode value is returned at the most significant end
of a register, shift the register right by the appropriate amount
and update VALREG accordingly. BLKmode values are handled by the
valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
}
- /* If call is cse'able, make appropriate pair of reg-notes around it.
- Test valreg so we don't crash; may safely ignore `const'
- if return type is void. Disable for PARALLEL return values, because
- we have no way to move such values into a pseudo register. */
- if (pass && (flags & ECF_LIBCALL_BLOCK))
- {
- rtx insns;
- rtx insn;
- bool failed = valreg == 0 || GET_CODE (valreg) == PARALLEL;
-
- insns = get_insns ();
-
- /* Expansion of block moves possibly introduced a loop that may
- not appear inside libcall block. */
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (JUMP_P (insn))
- failed = true;
-
- if (failed)
- {
- end_sequence ();
- emit_insn (insns);
- }
- else
- {
- rtx note = 0;
- rtx temp = gen_reg_rtx (GET_MODE (valreg));
-
- /* Mark the return value as a pointer if needed. */
- if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
- mark_reg_pointer (temp,
- TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))));
-
- end_sequence ();
- if (flag_unsafe_math_optimizations
- && fndecl
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRT
- || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTF
- || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTL))
- note = gen_rtx_fmt_e (SQRT,
- GET_MODE (temp),
- args[0].initial_value);
- else
- {
- /* Construct an "equal form" for the value which
- mentions all the arguments in order as well as
- the function name. */
- for (i = 0; i < num_actuals; i++)
- note = gen_rtx_EXPR_LIST (VOIDmode,
- args[i].initial_value, note);
- note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
-
- if (flags & ECF_PURE)
- note = gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_USE (VOIDmode,
- gen_rtx_MEM (BLKmode,
- gen_rtx_SCRATCH (VOIDmode))),
- note);
- }
- emit_libcall_block (insns, temp, valreg, note);
-
- valreg = temp;
- }
- }
- else if (pass && (flags & ECF_MALLOC))
+ if (pass && (flags & ECF_MALLOC))
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
/* The return value from a malloc-like function can not alias
anything else. */
last = get_last_insn ();
- REG_NOTES (last) =
- gen_rtx_EXPR_LIST (REG_NOALIAS, temp, REG_NOTES (last));
+ add_reg_note (last, REG_NOALIAS, temp);
/* Write out the sequence. */
insns = get_insns ();
/* We have to copy a return value in a CLASS_LIKELY_SPILLED hard
reg to a plain register. */
- if (REG_P (valreg)
- && HARD_REGISTER_P (valreg)
- && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (valreg)))
- && !(REG_P (target) && !HARD_REGISTER_P (target)))
- valreg = copy_to_reg (valreg);
+ if (!REG_P (target) || HARD_REGISTER_P (target))
+ valreg = avoid_likely_spilled_reg (valreg);
/* If TARGET is a MEM in the argument area, and we have
saved part of the argument area, then we can't store
sibcall_failure = 1;
}
else
- target = copy_to_reg (valreg);
+ target = copy_to_reg (avoid_likely_spilled_reg (valreg));
if (targetm.calls.promote_function_return(funtype))
{
/* If size of args is variable or this was a constructor call for a stack
argument, restore saved stack-pointer value. */
- if (old_stack_level && ! (flags & ECF_SP_DEPRESSED))
+ if (old_stack_level)
{
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
stack_pointer_delta = old_stack_pointer_delta;
if (tail_call_insns)
{
emit_insn (tail_call_insns);
- cfun->tail_call_emit = true;
+ crtl->tail_call_emit = true;
}
else
emit_insn (normal_call_insns);
currently_expanding_call--;
- /* If this function returns with the stack pointer depressed, ensure
- this block saves and restores the stack pointer, show it was
- changed, and adjust for any outgoing arg space. */
- if (flags & ECF_SP_DEPRESSED)
- {
- clear_pending_stack_adjust ();
- emit_insn (gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx));
- emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx);
- }
-
if (stack_usage_map_buf)
free (stack_usage_map_buf);
struct args_size original_args_size;
int argnum;
rtx fun;
+ /* Todo, choose the correct decl type of orgfun. Sadly this information
+ isn't present here, so we default to native calling abi here. */
+ tree fndecl ATTRIBUTE_UNUSED = NULL_TREE; /* library calls default to host calling abi ? */
int inc;
int count;
rtx argblock = 0;
case LCT_PURE:
flags |= ECF_PURE;
break;
- case LCT_CONST_MAKE_BLOCK:
- flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
- break;
- case LCT_PURE_MAKE_BLOCK:
- flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
- break;
case LCT_NORETURN:
flags |= ECF_NORETURN;
break;
/* Ensure current function's preferred stack boundary is at least
what we need. */
- if (cfun->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
- cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+ if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
+ crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
/* If this kind of value comes back in memory,
decide where in memory it should come back. */
mem_value = assign_temp (tfom, 0, 1, 1);
#endif
/* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
}
}
else
of the full argument passing conventions to limit complexity here since
library functions shouldn't have many args. */
- argvec = alloca ((nargs + 1) * sizeof (struct arg));
+ argvec = XALLOCAVEC (struct arg, nargs + 1);
memset (argvec, 0, (nargs + 1) * sizeof (struct arg));
#ifdef INIT_CUMULATIVE_LIBCALL_ARGS
count = 0;
- /* Now we are about to start emitting insns that can be deleted
- if a libcall is deleted. */
- if (flags & ECF_LIBCALL_BLOCK)
- start_sequence ();
-
push_temp_slots ();
/* If there's a structure value address to be passed,
int must_copy
= !reference_callee_copied (&args_so_far, mode, NULL_TREE, 1);
- /* loop.c won't look at CALL_INSN_FUNCTION_USAGE of const/pure
- functions, so we have to pretend this isn't such a function. */
- if (flags & ECF_LIBCALL_BLOCK)
- {
- rtx insns = get_insns ();
- end_sequence ();
- emit_insn (insns);
- }
- flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
-
- /* If this was a CONST function, it is now PURE since
- it now reads memory. */
+ /* If this was a CONST function, it is now PURE since it now
+ reads memory. */
if (flags & ECF_CONST)
{
flags &= ~ECF_CONST;
args_size.constant = MAX (args_size.constant,
reg_parm_stack_space);
- if (!OUTGOING_REG_PARM_STACK_SPACE)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))))
args_size.constant -= reg_parm_stack_space;
- if (args_size.constant > current_function_outgoing_args_size)
- current_function_outgoing_args_size = args_size.constant;
+ if (args_size.constant > crtl->outgoing_args_size)
+ crtl->outgoing_args_size = args_size.constant;
if (ACCUMULATE_OUTGOING_ARGS)
{
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
- if (!OUTGOING_REG_PARM_STACK_SPACE)
+ if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))))
needed += reg_parm_stack_space;
#ifdef ARGS_GROW_DOWNWARD
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
- /* If call is cse'able, make appropriate pair of reg-notes around it.
- Test valreg so we don't crash; may safely ignore `const'
- if return type is void. Disable for PARALLEL return values, because
- we have no way to move such values into a pseudo register. */
- if (flags & ECF_LIBCALL_BLOCK)
- {
- rtx insns;
-
- if (valreg == 0)
- {
- insns = get_insns ();
- end_sequence ();
- emit_insn (insns);
- }
- else
- {
- rtx note = 0;
- rtx temp;
- int i;
-
- if (GET_CODE (valreg) == PARALLEL)
- {
- temp = gen_reg_rtx (outmode);
- emit_group_store (temp, valreg, NULL_TREE,
- GET_MODE_SIZE (outmode));
- valreg = temp;
- }
-
- temp = gen_reg_rtx (GET_MODE (valreg));
-
- /* Construct an "equal form" for the value which mentions all the
- arguments in order as well as the function name. */
- for (i = 0; i < nargs; i++)
- note = gen_rtx_EXPR_LIST (VOIDmode, argvec[i].value, note);
- note = gen_rtx_EXPR_LIST (VOIDmode, fun, note);
-
- insns = get_insns ();
- end_sequence ();
-
- if (flags & ECF_PURE)
- note = gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_USE (VOIDmode,
- gen_rtx_MEM (BLKmode,
- gen_rtx_SCRATCH (VOIDmode))),
- note);
-
- emit_libcall_block (insns, temp, valreg, note);
-
- valreg = temp;
- }
- }
pop_temp_slots ();
/* Copy the value to the right place. */
with NARGS different arguments, passed as alternating rtx values
and machine_modes to convert them to.
- FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for `const'
- calls, LCT_PURE for `pure' calls, LCT_CONST_MAKE_BLOCK for `const' calls
- which should be enclosed in REG_LIBCALL/REG_RETVAL notes,
- LCT_PURE_MAKE_BLOCK for `purep' calls which should be enclosed in
- REG_LIBCALL/REG_RETVAL notes with extra (use (memory (scratch)),
- or other LCT_ value for other types of library calls. */
+ FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for
+ `const' calls, LCT_PURE for `pure' calls, or other LCT_ value for
+ other types of library calls. */
void
emit_library_call (rtx orgfun, enum libcall_type fn_type,
rtx x = arg->value;
int i = 0;
- if (XEXP (x, 0) == current_function_internal_arg_pointer
+ if (XEXP (x, 0) == crtl->args.internal_arg_pointer
|| (GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 0) ==
- current_function_internal_arg_pointer
+ crtl->args.internal_arg_pointer
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
{
- if (XEXP (x, 0) != current_function_internal_arg_pointer)
+ if (XEXP (x, 0) != crtl->args.internal_arg_pointer)
i = INTVAL (XEXP (XEXP (x, 0), 1));
/* expand_call should ensure this. */
bool
must_pass_in_stack_var_size (enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type)
+ const_tree type)
{
if (!type)
return false;
/* ??? Should be able to merge these two by examining BLOCK_REG_PADDING. */
bool
-must_pass_in_stack_var_size_or_pad (enum machine_mode mode, tree type)
+must_pass_in_stack_var_size_or_pad (enum machine_mode mode, const_tree type)
{
if (!type)
return false;