#include "tm_p.h"
#include "timevar.h"
#include "sbitmap.h"
+#include "langhooks.h"
+#include "target.h"
#if !defined FUNCTION_OK_FOR_SIBCALL
#define FUNCTION_OK_FOR_SIBCALL(DECL) 1
#define ECF_SP_DEPRESSED 1024
/* Nonzero if this call is known to always return. */
#define ECF_ALWAYS_RETURN 2048
+/* Create libcall block around the call. */
+#define ECF_LIBCALL_BLOCK 4096
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
- rtx, int, rtx, int));
+ rtx, int, rtx, int,
+ CUMULATIVE_ARGS *));
static void precompute_register_parameters PARAMS ((int,
struct arg_data *,
int *));
static void
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop,
- call_fusage, ecf_flags)
+ call_fusage, ecf_flags, args_so_far)
rtx funexp;
tree fndecl ATTRIBUTE_UNUSED;
tree funtype ATTRIBUTE_UNUSED;
int old_inhibit_defer_pop;
rtx call_fusage;
int ecf_flags;
+ CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED;
{
rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
rtx call_insn;
struct_value_size_rtx = GEN_INT (struct_value_size);
#endif
+#ifdef CALL_POPS_ARGS
+ n_popped += CALL_POPS_ARGS (* args_so_far);
+#endif
+
/* Ensure address is valid. SYMBOL_REF is already valid, so no need,
and we don't want to load it into a register as an optimization,
because prepare_call_address already did it if it should be done. */
return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
}
-/* Detect flags (function attributes) from the function type node. */
+/* Detect flags (function attributes) from the function decl or type node. */
static int
flags_from_decl_or_type (exp)
tree exp;
{
int flags = 0;
-
+ tree type = exp;
/* ??? We can't set IS_MALLOC for function types? */
if (DECL_P (exp))
{
+ type = TREE_TYPE (exp);
+
/* The function exp may have the `malloc' attribute. */
if (DECL_P (exp) && DECL_IS_MALLOC (exp))
flags |= ECF_MALLOC;
/* The function exp may have the `pure' attribute. */
if (DECL_P (exp) && DECL_IS_PURE (exp))
- flags |= ECF_PURE;
+ flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
}
if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
- flags |= ECF_CONST;
+ flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
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 | ECF_LIBCALL_BLOCK);
+ }
+
return flags;
}
if (save_mode == BLKmode)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
- /* Cannot use emit_block_move here because it can be done by a
- library call which in turn gets into this place again and deadly
- infinite recursion happens. */
- move_by_pieces (validize_mem (save_area), stack_area, num_to_save,
- PARM_BOUNDARY);
+ emit_block_move (validize_mem (save_area), stack_area,
+ GEN_INT (num_to_save), BLOCK_OP_CALL_PARM);
}
else
{
if (save_mode != BLKmode)
emit_move_insn (stack_area, save_area);
else
- /* Cannot use emit_block_move here because it can be done by a library
- call which in turn gets into this place again and deadly infinite
- recursion happens. */
- move_by_pieces (stack_area, validize_mem (save_area),
- high_to_save - low_to_save + 1, PARM_BOUNDARY);
+ emit_block_move (stack_area, validize_mem (save_area),
+ GEN_INT (high_to_save - low_to_save + 1),
+ BLOCK_OP_CALL_PARM);
}
#endif /* REG_PARM_STACK_SPACE */
args[i].tree_value);
type = build_pointer_type (type);
}
+ else if (TREE_CODE (args[i].tree_value) == TARGET_EXPR)
+ {
+ /* In the V3 C++ ABI, parameters are destroyed in the caller.
+ We implement this by passing the address of the temporary
+ rather than expanding it into another allocated slot. */
+ args[i].tree_value = build1 (ADDR_EXPR,
+ build_pointer_type (type),
+ args[i].tree_value);
+ type = build_pointer_type (type);
+ }
else
{
/* We make a copy of the object and pass the address to the
copy = assign_temp (type, 0, 1, 0);
store_expr (args[i].tree_value, copy, 0);
- *ecf_flags &= ~(ECF_CONST | ECF_PURE);
+ *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
/* 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_CONST | ECF_PURE);
+ *ecf_flags &= ~ECF_LIBCALL_BLOCK;
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
worse code) */
for (i = 0; i < num_actuals; i++)
- if ((flags & (ECF_CONST | ECF_PURE))
+ if ((flags & ECF_LIBCALL_BLOCK)
|| calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
{
enum machine_mode mode;
if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
abort ();
- push_temp_slots ();
-
args[i].value
= expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
- preserve_temp_slots (args[i].value);
- pop_temp_slots ();
-
/* ANSI doesn't require a sequence point here,
but PCC has one, so this will avoid some problems. */
emit_queue ();
args[i].initial_value
= gen_lowpart_SUBREG (mode, args[i].value);
SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
- SUBREG_PROMOTED_UNSIGNED_P (args[i].initial_value)
- = args[i].unsignedp;
+ SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
+ args[i].unsignedp);
}
#endif
}
timevar_pop (TV_INTEGRATION);
/* If inlining succeeded, return. */
- if (temp != (rtx) (HOST_WIDE_INT) - 1)
+ if (temp != (rtx) (size_t) - 1)
{
if (ACCUMULATE_OUTGOING_ARGS)
{
NULL_RTX, BITS_PER_UNIT);
seq = get_insns ();
end_sequence ();
- emit_insns_before (seq, first_insn);
+ emit_insn_before (seq, first_insn);
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
}
}
warning_with_decl (fndecl, "inlining failed in call to `%s'");
warning ("called from here");
}
- mark_addressable (fndecl);
- return (rtx) (HOST_WIDE_INT) - 1;
+ (*lang_hooks.mark_addressable) (fndecl);
+ return (rtx) (size_t) - 1;
}
/* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments
warning_with_decl (fndecl, "can't inline call to `%s'");
warning ("called from here");
}
- mark_addressable (fndecl);
+ (*lang_hooks.mark_addressable) (fndecl);
}
flags |= flags_from_decl_or_type (fndecl);
else
flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
- /* Mark if the function returns with the stack pointer depressed. */
- if (TREE_CODE (TREE_TYPE (TREE_TYPE (p))) == FUNCTION_TYPE
- && TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (TREE_TYPE (p))))
- {
- flags |= ECF_SP_DEPRESSED;
- flags &= ~(ECF_PURE | ECF_CONST);
- }
-
#ifdef REG_PARM_STACK_SPACE
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
if (aggregate_value_p (exp))
{
/* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE);
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
#ifdef PCC_STATIC_STRUCT_RETURN
{
/* In case this is a static function, note that it has been
used. */
if (! TREE_ADDRESSABLE (fndecl))
- mark_addressable (fndecl);
+ (*lang_hooks.mark_addressable) (fndecl);
is_integrable = 0;
}
}
rtx temp = try_to_integrate (fndecl, actparms, target,
ignore, TREE_TYPE (exp),
structure_value_addr);
- if (temp != (rtx) (HOST_WIDE_INT) - 1)
+ if (temp != (rtx) (size_t) - 1)
return temp;
}
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_CONST | ECF_PURE);
+ flags &= ~ECF_LIBCALL_BLOCK;
must_preallocate = 1;
}
!= RETURN_POPS_ARGS (current_function_decl,
TREE_TYPE (current_function_decl),
current_function_args_size))
- try_tail_call = 0;
+ try_tail_call = 0;
if (try_tail_call || try_tail_recursion)
{
/* 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. */
+ call sequence or if we are calling a function that is to return
+ with stack pointer depressed. */
if (pending_stack_adjust >= 32
- || (pending_stack_adjust > 0 && (flags & ECF_MAY_BE_ALLOCA))
+ || (pending_stack_adjust > 0
+ && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED)))
|| 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 (flags & (ECF_CONST | ECF_PURE))
+ if (pass && (flags & ECF_LIBCALL_BLOCK))
NO_DEFER_POP;
- /* Push the temporary stack slot level so that we can free any
- temporaries we make. */
- push_temp_slots ();
-
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
args_size.var);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
+ if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
start_sequence ();
adjusted_args_size = args_size;
if (pass == 0)
{
argblock = virtual_incoming_args_rtx;
+ argblock
+#ifdef STACK_GROWS_DOWNWARD
+ = plus_constant (argblock, current_function_pretend_args_size);
+#else
+ = plus_constant (argblock, -current_function_pretend_args_size);
+#endif
stored_args_map = sbitmap_alloc (args_size.constant);
sbitmap_zero (stored_args_map);
}
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
if (pending_stack_adjust
- && ! (flags & (ECF_CONST | ECF_PURE))
+ && ! (flags & ECF_LIBCALL_BLOCK)
&& ! inhibit_defer_pop)
{
pending_stack_adjust
emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
adjusted_args_size.constant, struct_value_size,
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
- flags);
+ flags, & args_so_far);
/* Verify that we've deallocated all the stack we used. */
if (pass
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_CONST | ECF_PURE))
- && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+ if (pass && (flags & ECF_LIBCALL_BLOCK))
{
- rtx note = 0;
- rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx insns;
- /* 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))));
-
- /* 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);
-
- 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;
- }
- else if (flags & (ECF_CONST | ECF_PURE))
- {
- /* Otherwise, just write out the sequence without a note. */
- rtx insns = get_insns ();
-
- end_sequence ();
- emit_insns (insns);
+ if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+ {
+ insns = get_insns ();
+ 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))));
+
+ /* 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);
+
+ 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;
+ }
}
- else if (flags & ECF_MALLOC)
+ else if (pass && (flags & ECF_MALLOC))
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
/* Write out the sequence. */
insns = get_insns ();
end_sequence ();
- emit_insns (insns);
+ emit_insn (insns);
valreg = temp;
}
if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
|| ignore)
- {
- target = const0_rtx;
- }
+ target = const0_rtx;
else if (structure_value_addr)
{
if (target == 0 || GET_CODE (target) != MEM)
}
target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
SUBREG_PROMOTED_VAR_P (target) = 1;
- SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
+ SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
}
#endif
if (save_mode != BLKmode)
emit_move_insn (stack_area, args[i].save_area);
else
- emit_block_move (stack_area,
- validize_mem (args[i].save_area),
- GEN_INT (args[i].size.constant));
+ emit_block_move (stack_area, args[i].save_area,
+ GEN_INT (args[i].size.constant),
+ BLOCK_OP_CALL_PARM);
}
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
- pop_temp_slots ();
-
/* Free up storage we no longer need. */
for (i = 0; i < num_actuals; ++i)
if (args[i].aligned_regs)
tail_recursion_label));
}
else
- emit_insns (normal_call_insns);
+ emit_insn (normal_call_insns);
currently_expanding_call--;
int reg_parm_stack_space = 0;
int needed;
rtx before_call;
+ tree tfom; /* type_for_mode (outmode, 0) */
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
switch (fn_type)
{
case LCT_NORMAL:
+ break;
case LCT_CONST:
+ flags |= ECF_CONST;
+ break;
case LCT_PURE:
- /* Nothing to do here. */
+ flags |= ECF_PURE;
break;
case LCT_CONST_MAKE_BLOCK:
- flags |= ECF_CONST;
+ flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
break;
case LCT_PURE_MAKE_BLOCK:
- flags |= ECF_PURE;
+ flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
break;
case LCT_NORETURN:
flags |= ECF_NORETURN;
/* If this kind of value comes back in memory,
decide where in memory it should come back. */
- if (outmode != VOIDmode && aggregate_value_p (type_for_mode (outmode, 0)))
+ if (outmode != VOIDmode)
{
+ tfom = (*lang_hooks.types.type_for_mode) (outmode, 0);
+ if (aggregate_value_p (tfom))
+ {
#ifdef PCC_STATIC_STRUCT_RETURN
- rtx pointer_reg
- = hard_function_value (build_pointer_type (type_for_mode (outmode, 0)),
- 0, 0);
- mem_value = gen_rtx_MEM (outmode, pointer_reg);
- pcc_struct_value = 1;
- if (value == 0)
- value = gen_reg_rtx (outmode);
+ rtx pointer_reg
+ = hard_function_value (build_pointer_type (tfom), 0, 0);
+ mem_value = gen_rtx_MEM (outmode, pointer_reg);
+ pcc_struct_value = 1;
+ if (value == 0)
+ value = gen_reg_rtx (outmode);
#else /* not PCC_STATIC_STRUCT_RETURN */
- struct_value_size = GET_MODE_SIZE (outmode);
- if (value != 0 && GET_CODE (value) == MEM)
- mem_value = value;
- else
- mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1);
+ struct_value_size = GET_MODE_SIZE (outmode);
+ if (value != 0 && GET_CODE (value) == MEM)
+ mem_value = value;
+ else
+ mem_value = assign_temp (tfom, 0, 1, 1);
#endif
-
- /* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE);
+ /* This call returns a big structure. */
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+ }
}
+ else
+ tfom = void_type_node;
/* ??? Unfinished: must pass the memory address as an argument. */
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (flags & (ECF_CONST | ECF_PURE))
+ if (flags & ECF_LIBCALL_BLOCK)
start_sequence ();
push_temp_slots ();
#endif
;
+ /* 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 (GET_MODE (val) == MEM && ! must_copy)
slot = val;
else if (must_copy)
{
- slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1);
+ slot = assign_temp ((*lang_hooks.types.type_for_mode) (mode, 0),
+ 0, 1, 1);
emit_move_insn (slot, val);
}
else
{
- tree type = type_for_mode (mode, 0);
+ tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
slot = gen_rtx_MEM (mode,
expand_expr (build1 (ADDR_EXPR,
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
set_mem_align (save_area, PARM_BOUNDARY);
- emit_block_move (validize_mem (save_area), stack_area,
- GEN_INT (num_to_save));
+ emit_block_move (save_area, stack_area, GEN_INT (num_to_save),
+ BLOCK_OP_CALL_PARM);
}
else
{
}
}
- emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
- argblock, GEN_INT (argvec[argnum].offset.constant),
+ emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY,
+ partial, reg, 0, argblock,
+ GEN_INT (argvec[argnum].offset.constant),
reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
/* Now mark the segment we just used. */
emit_call_1 (fun,
get_identifier (XSTR (orgfun, 0)),
- build_function_type (outmode == VOIDmode ? void_type_node
- : type_for_mode (outmode, 0), NULL_TREE),
+ build_function_type (tfom, NULL_TREE),
original_args_size.constant, args_size.constant,
struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
valreg,
- old_inhibit_defer_pop + 1, call_fusage, flags);
+ old_inhibit_defer_pop + 1, call_fusage, flags, & args_so_far);
/* For calls to `setjmp', etc., inform flow.c it should complain
if nonvolatile values are live. For functions that cannot return,
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_CONST | ECF_PURE))
- && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+ if (flags & ECF_LIBCALL_BLOCK)
{
- rtx note = 0;
- rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx insns;
- int i;
- /* 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);
+ if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+ {
+ insns = get_insns ();
+ end_sequence ();
+ emit_insn (insns);
+ }
+ else
+ {
+ rtx note = 0;
+ rtx temp = gen_reg_rtx (GET_MODE (valreg));
+ int i;
- insns = get_insns ();
- end_sequence ();
+ /* 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);
- if (flags & ECF_PURE)
- note = gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_USE (VOIDmode,
- gen_rtx_MEM (BLKmode,
- gen_rtx_SCRATCH (VOIDmode))), note);
+ insns = get_insns ();
+ end_sequence ();
- emit_libcall_block (insns, temp, valreg, note);
+ if (flags & ECF_PURE)
+ note = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_USE (VOIDmode,
+ gen_rtx_MEM (BLKmode,
+ gen_rtx_SCRATCH (VOIDmode))),
+ note);
- valreg = temp;
- }
- else if (flags & (ECF_CONST | ECF_PURE))
- {
- /* Otherwise, just write out the sequence without a note. */
- rtx insns = get_insns ();
+ emit_libcall_block (insns, temp, valreg, note);
- end_sequence ();
- emit_insns (insns);
+ valreg = temp;
+ }
}
pop_temp_slots ();
if (save_mode != BLKmode)
emit_move_insn (stack_area, save_area);
else
- emit_block_move (stack_area, validize_mem (save_area),
- GEN_INT (high_to_save - low_to_save + 1));
+ emit_block_move (stack_area, save_area,
+ GEN_INT (high_to_save - low_to_save + 1),
+ BLOCK_OP_CALL_PARM);
}
#endif
arg->save_area = assign_temp (nt, 0, 1, 1);
preserve_temp_slots (arg->save_area);
emit_block_move (validize_mem (arg->save_area), stack_area,
- expr_size (arg->tree_value));
+ expr_size (arg->tree_value),
+ BLOCK_OP_CALL_PARM);
}
else
{
/* If this isn't going to be placed on both the stack and in registers,
set up the register and number of words. */
if (! arg->pass_on_stack)
- reg = arg->reg, partial = arg->partial;
+ {
+ if (flags & ECF_SIBCALL)
+ reg = arg->tail_call_reg;
+ else
+ reg = arg->reg;
+ partial = arg->partial;
+ }
if (reg != 0 && partial == 0)
/* Being passed entirely in a register. We shouldn't be called in
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0,
- partial, reg, used - size, argblock,
+ emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
+ PARM_BOUNDARY, partial, reg, used - size, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
+
+ /* Unless this is a partially-in-register argument, the argument is now
+ in the stack. */
+ if (partial == 0)
+ arg->value = arg->stack;
}
else
{
{
rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
- TYPE_ALIGN (TREE_TYPE (pval)), partial, reg,
- excess, argblock, ARGS_SIZE_RTX (arg->offset),
- reg_parm_stack_space,
+ MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+ partial, reg, excess, argblock,
+ ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
}
}
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
- TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, excess,
- argblock, ARGS_SIZE_RTX (arg->offset),
- reg_parm_stack_space,
+ MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+ partial, reg, excess, argblock,
+ ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
- }
- /* Unless this is a partially-in-register argument, the argument is now
- in the stack.
+ /* Unless this is a partially-in-register argument, the argument is now
+ in the stack.
- ??? Note that this can change arg->value from arg->stack to
- arg->stack_slot and it matters when they are not the same.
- It isn't totally clear that this is correct in all cases. */
- if (partial == 0)
- arg->value = arg->stack_slot;
+ ??? Unlike the case above, in which we want the actual
+ address of the data, so that we can load it directly into a
+ register, here we want the address of the stack slot, so that
+ it's properly aligned for word-by-word copying or something
+ like that. It's not clear that this is always correct. */
+ if (partial == 0)
+ arg->value = arg->stack_slot;
+ }
/* Once we have pushed something, pops can't safely
be deferred during the rest of the arguments. */