EXPR_LIST if the arg is to be copied into multiple different
registers. */
rtx reg;
+ /* If REG was promoted from the actual mode of the argument expression,
+ indicates whether the promotion is sign- or zero-extended. */
+ int unsignedp;
/* Number of registers to use. 0 means put the whole arg in registers.
Also 0 if not passed in registers. */
int partial;
- /* Non-zero if argument must be passed on stack. */
+ /* Non-zero if argument must be passed on stack.
+ Note that some arguments may be passed on the stack
+ even though pass_on_stack is zero, just because FUNCTION_ARG says so.
+ pass_on_stack identifies arguments that *cannot* go in registers. */
int pass_on_stack;
/* Offset of this argument from beginning of stack-args. */
struct args_size offset;
/* Size of STACK_USAGE_MAP. */
static int highest_outgoing_arg_in_use;
+
+/* stack_arg_under_construction is nonzero when an argument may be
+ initialized with a constructor call (including a C function that
+ returns a BLKmode struct) and expand_call must take special action
+ to make sure the object being constructed does not overlap the
+ argument list for the constructor call. */
+int stack_arg_under_construction;
#endif
static void store_one_arg ();
/* Only expressions and references can contain calls. */
- if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r')
+ if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r'
+ && type != 'b')
return 0;
switch (TREE_CODE (exp))
break;
case BLOCK:
- /* Must not look at BLOCK_SUPERCONTEXT since it will point back to
- us. */
- length = 3;
- break;
+ {
+ register tree local;
+
+ for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))
+ if (DECL_INITIAL (local) != 0 && calls_alloca (DECL_INITIAL (local)))
+ return 1;
+ }
+ {
+ register tree subblock;
+
+ for (subblock = BLOCK_SUBBLOCKS (exp);
+ subblock;
+ subblock = TREE_CHAIN (subblock))
+ if (calls_alloca (subblock))
+ return 1;
+ }
+ return 0;
case METHOD_CALL_EXPR:
length = 3;
rtx use_insns;
int is_const;
{
- rtx stack_size_rtx = gen_rtx (CONST_INT, VOIDmode, stack_size);
- rtx struct_value_size_rtx = gen_rtx (CONST_INT, VOIDmode, struct_value_size);
+ rtx stack_size_rtx = GEN_INT (stack_size);
+ rtx struct_value_size_rtx = GEN_INT (struct_value_size);
rtx call_insn;
int already_popped = 0;
if (HAVE_call_pop && HAVE_call_value_pop
&& (RETURN_POPS_ARGS (funtype, stack_size) > 0 || stack_size == 0))
{
- rtx n_pop = gen_rtx (CONST_INT, VOIDmode,
- RETURN_POPS_ARGS (funtype, stack_size));
+ rtx n_pop = GEN_INT (RETURN_POPS_ARGS (funtype, stack_size));
rtx pat;
/* If this subroutine pops its own args, record that in the call insn
if (!already_popped)
emit_insn (gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx));
stack_size -= RETURN_POPS_ARGS (funtype, stack_size);
- stack_size_rtx = gen_rtx (CONST_INT, VOIDmode, stack_size);
+ stack_size_rtx = GEN_INT (stack_size);
}
if (stack_size != 0)
#endif
#endif
- /* Size of the stack reserved for paramter registers. */
+ /* Size of the stack reserved for parameter registers. */
int reg_parm_stack_space = 0;
/* 1 if scanning parms front to back, -1 if scanning back to front. */
rtx old_stack_level = 0;
int old_pending_adj;
+ int old_stack_arg_under_construction;
int old_inhibit_defer_pop = inhibit_defer_pop;
tree old_cleanups = cleanups_this_call;
Use abstraction instead of setting TREE_ADDRESSABLE
directly. */
- if (TREE_INLINE (fndecl) && extra_warnings && !flag_no_inline)
+ if (DECL_INLINE (fndecl) && extra_warnings && !flag_no_inline)
warning_with_decl (fndecl, "can't inline call to `%s' which was declared inline");
mark_addressable (fndecl);
}
if (is_integrable)
{
rtx temp;
+ rtx before_call = get_last_insn ();
temp = expand_inline_function (fndecl, actparms, target,
ignore, TREE_TYPE (exp),
structure_value_addr);
/* If inlining succeeded, return. */
- if ((int) temp != -1)
+ if ((HOST_WIDE_INT) temp != -1)
{
+ int i;
+
/* Perform all cleanups needed for the arguments of this call
(i.e. destructors in C++). It is ok if these destructors
clobber RETURN_VALUE_REG, because the only time we care about
care to never return that register directly. */
expand_cleanups_to (old_cleanups);
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* If the outgoing argument list must be preserved, push
+ the stack before executing the inlined function if it
+ makes any calls. */
+
+ for (i = reg_parm_stack_space - 1; i >= 0; i--)
+ if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
+ break;
+
+ if (stack_arg_under_construction || i >= 0)
+ {
+ rtx insn = NEXT_INSN (before_call), seq;
+
+ /* Look for a call in the inline function code.
+ If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is
+ nonzero then there is a call and it is not necessary
+ to scan the insns. */
+
+ if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0)
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == CALL_INSN)
+ break;
+
+ if (insn)
+ {
+ /* Reserve enough stack space so that the largest
+ argument list of any function call in the inline
+ function does not overlap the argument list being
+ evaluated. This is usually an overestimate because
+ allocate_dynamic_stack_space reserves space for an
+ outgoing argument list in addition to the requested
+ space, but there is no way to ask for stack space such
+ that an argument list of a certain length can be
+ safely constructed. */
+
+ int adjust = OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl));
+#ifdef REG_PARM_STACK_SPACE
+ /* Add the stack space reserved for register arguments
+ in the inline function. What is really needed is the
+ largest value of reg_parm_stack_space in the inline
+ function, but that is not available. Using the current
+ value of reg_parm_stack_space is wrong, but gives
+ correct results on all supported machines. */
+ adjust += reg_parm_stack_space;
+#endif
+ start_sequence ();
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
+ allocate_dynamic_stack_space (GEN_INT (adjust),
+ NULL_RTX, BITS_PER_UNIT);
+ seq = get_insns ();
+ end_sequence ();
+ emit_insns_before (seq, NEXT_INSN (before_call));
+ emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+ }
+ }
+#endif
+
/* If the result is equivalent to TARGET, return TARGET to simplify
checks in store_expr. They can be equivalent but not equal in the
case of a function that returns BLKmode. */
push_temp_slots ();
/* Start updating where the next arg would go. */
- INIT_CUMULATIVE_ARGS (args_so_far, funtype, 0);
+ INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_PTR);
/* If struct_value_rtx is 0, it means pass the address
as if it were an extra parameter. */
if (structure_value_addr && struct_value_rtx == 0)
{
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* If the stack will be adjusted, make sure the structure address
+ does not refer to virtual_outgoing_args_rtx. */
+ rtx temp = (stack_arg_under_construction
+ ? copy_addr_to_reg (structure_value_addr)
+ : force_reg (Pmode, structure_value_addr));
+#else
+ rtx temp = force_reg (Pmode, structure_value_addr);
+#endif
+
actparms
= tree_cons (error_mark_node,
make_tree (build_pointer_type (TREE_TYPE (funtype)),
- force_reg (Pmode, structure_value_addr)),
+ temp),
actparms);
structure_value_addr_parm = 1;
}
for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
{
tree type = TREE_TYPE (TREE_VALUE (p));
+ enum machine_mode mode;
args[i].tree_value = TREE_VALUE (p);
{
/* This is a variable-sized object. Make space on the stack
for it. */
- rtx size_rtx = expand_expr (size_in_bytes (type), 0,
+ rtx size_rtx = expand_expr (size_in_bytes (type), NULL_RTX,
VOIDmode, 0);
if (old_stack_level == 0)
{
- emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
old_pending_adj = pending_stack_adjust;
pending_stack_adjust = 0;
}
copy = gen_rtx (MEM, BLKmode,
- allocate_dynamic_stack_space (size_rtx, 0,
+ allocate_dynamic_stack_space (size_rtx, NULL_RTX,
TYPE_ALIGN (type)));
}
else
}
#endif
- args[i].reg = FUNCTION_ARG (args_so_far, TYPE_MODE (type), type,
+ mode = TYPE_MODE (type);
+
+#ifdef PROMOTE_FUNCTION_ARGS
+ /* Compute the mode in which the arg is actually to be extended to. */
+ if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE || TREE_CODE (type) == CHAR_TYPE
+ || TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == POINTER_TYPE
+ || TREE_CODE (type) == OFFSET_TYPE)
+ {
+ int unsignedp = TREE_UNSIGNED (type);
+ PROMOTE_MODE (mode, unsignedp, type);
+ args[i].unsignedp = unsignedp;
+ }
+#endif
+
+ args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
argpos < n_named_args);
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (args[i].reg)
args[i].partial
- = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, TYPE_MODE (type), type,
+ = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
argpos < n_named_args);
#endif
- args[i].pass_on_stack = MUST_PASS_IN_STACK (TYPE_MODE (type), type);
+ args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
/* If FUNCTION_ARG returned an (expr_list (nil) FOO), it means that
we are to pass this arg in the register(s) designated by FOO, but
+= int_size_in_bytes (TREE_TYPE (args[i].tree_value));
}
- if (copy_to_evaluate_size >= args_size.constant / 2)
+ if (copy_to_evaluate_size * 2 >= args_size.constant
+ && args_size.constant > 0)
must_preallocate = 1;
}
&& calls_alloca (args[i].tree_value)))
{
args[i].initial_value = args[i].value
- = expand_expr (args[i].tree_value, 0, VOIDmode, 0);
+ = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
preserve_temp_slots (args[i].value);
free_temp_slots ();
{
if (old_stack_level == 0)
{
- emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
old_pending_adj = pending_stack_adjust;
pending_stack_adjust = 0;
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* stack_arg_under_construction says whether a stack arg is
+ being constructed at the old stack level. Pushing the stack
+ gets a clean outgoing argument block. */
+ old_stack_arg_under_construction = stack_arg_under_construction;
+ stack_arg_under_construction = 0;
+#endif
}
argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
}
bzero (&stack_usage_map[initial_highest_arg_in_use],
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
needed = 0;
- /* No need to copy this virtual register; the space we're
- using gets preallocated at the start of the function
- so the stack pointer won't change here. */
+
+ /* The address of the outgoing argument list must not be copied to a
+ register here, because argblock would be left pointing to the
+ wrong place after the call to allocate_dynamic_stack_space below. */
+
argblock = virtual_outgoing_args_rtx;
+
#else /* not ACCUMULATE_OUTGOING_ARGS */
if (inhibit_defer_pop == 0)
{
if (needed == 0)
argblock = virtual_outgoing_args_rtx;
else
- argblock = push_block (gen_rtx (CONST_INT, VOIDmode, needed), 0, 0);
+ argblock = push_block (GEN_INT (needed), 0, 0);
/* We only really need to call `copy_to_reg' in the case where push
insns are going to be used to pass ARGBLOCK to a function
#endif /* not ACCUMULATE_OUTGOING_ARGS */
}
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* The save/restore code in store_one_arg handles all cases except one:
+ a constructor call (including a C function returning a BLKmode struct)
+ to initialize an argument. */
+ if (stack_arg_under_construction)
+ {
+#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+ rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
+#else
+ rtx push_size = GEN_INT (args_size.constant);
+#endif
+ if (old_stack_level == 0)
+ {
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+ old_pending_adj = pending_stack_adjust;
+ pending_stack_adjust = 0;
+ /* stack_arg_under_construction says whether a stack arg is
+ being constructed at the old stack level. Pushing the stack
+ gets a clean outgoing argument block. */
+ old_stack_arg_under_construction = stack_arg_under_construction;
+ stack_arg_under_construction = 0;
+ /* Make a new map for the new argument list. */
+ stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use);
+ bzero (stack_usage_map, highest_outgoing_arg_in_use);
+ highest_outgoing_arg_in_use = 0;
+ }
+ allocate_dynamic_stack_space (push_size, NULL_RTX, BITS_PER_UNIT);
+ }
+ /* If argument evaluation might modify the stack pointer, copy the
+ address of the argument list to a register. */
+ for (i = 0; i < num_actuals; i++)
+ if (args[i].pass_on_stack)
+ {
+ argblock = copy_addr_to_reg (argblock);
+ break;
+ }
+#endif
+
+
/* If we preallocated stack space, compute the address of each argument.
We need not ensure it is a valid memory address here; it will be
validized when it is used. */
/* If we push args individually in reverse order, perform stack alignment
before the first push (the last arg). */
if (argblock == 0)
- anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
- (args_size.constant
- - original_args_size.constant)));
+ anti_adjust_stack (GEN_INT (args_size.constant
+ - original_args_size.constant));
#endif
#endif
else
/* Generate an rtx (probably a pseudo-register) for the address. */
{
- funexp = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+ funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
free_temp_slots (); /* FUNEXP can't be BLKmode */
emit_queue ();
}
for (i = 0; i < num_actuals; i++)
if (args[i].reg != 0 && ! args[i].pass_on_stack)
{
+ enum machine_mode mode;
+
reg_parm_seen = 1;
if (args[i].value == 0)
{
- args[i].value = expand_expr (args[i].tree_value, 0, VOIDmode, 0);
+ args[i].value = expand_expr (args[i].tree_value, NULL_RTX,
+ VOIDmode, 0);
preserve_temp_slots (args[i].value);
free_temp_slots ();
but PCC has one, so this will avoid some problems. */
emit_queue ();
}
+
+ /* If we are to promote the function arg to a wider mode,
+ do it now. */
+ mode = (GET_CODE (args[i].reg) == EXPR_LIST
+ ? GET_MODE (XEXP (args[i].reg, 0)) : GET_MODE (args[i].reg));
+
+ if (GET_MODE (args[i].value) != mode)
+ args[i].value = convert_to_mode (mode, args[i].value,
+ args[i].unsignedp);
}
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 1);
emit_block_move (validize_mem (save_area), stack_area,
- gen_rtx (CONST_INT, VOIDmode, num_to_save),
+ GEN_INT (num_to_save),
PARM_BOUNDARY / BITS_PER_UNIT);
}
else
/* If we pushed args in forward order, perform stack alignment
after pushing the last arg. */
if (argblock == 0)
- anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
- (args_size.constant
- - original_args_size.constant)));
+ anti_adjust_stack (GEN_INT (args_size.constant
+ - original_args_size.constant));
#endif
#endif
+ /* If register arguments require space on the stack and stack space
+ was not preallocated, allocate stack space here for arguments
+ passed in registers. */
+#if ! defined(ALLOCATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
+ if (must_preallocate == 0 && reg_parm_stack_space > 0)
+ anti_adjust_stack (GEN_INT (reg_parm_stack_space));
+#endif
+
/* Pass the function the address in which to return a structure value. */
if (structure_value_addr && ! structure_value_addr_parm)
{
emit_move_insn (struct_value_rtx,
force_reg (Pmode,
- force_operand (structure_value_addr, 0)));
+ force_operand (structure_value_addr,
+ NULL_RTX)));
if (GET_CODE (struct_value_rtx) == REG)
{
push_to_sequence (use_insns);
else if (structure_value_addr)
{
if (target == 0 || GET_CODE (target) != MEM)
- target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
- memory_address (TYPE_MODE (TREE_TYPE (exp)),
- structure_value_addr));
+ {
+ target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
+ memory_address (TYPE_MODE (TREE_TYPE (exp)),
+ structure_value_addr));
+ MEM_IN_STRUCT_P (target)
+ = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE);
+ }
}
else if (pcc_struct_value)
{
if (target == 0)
- target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
- copy_to_reg (valreg));
+ {
+ target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
+ copy_to_reg (valreg));
+ MEM_IN_STRUCT_P (target)
+ = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE);
+ }
else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
emit_move_insn (target, gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
copy_to_reg (valreg)));
expr_size (exp),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
}
- else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
+ else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
+ && GET_MODE (target) == GET_MODE (valreg))
/* TARGET and VALREG cannot be equal at this point because the latter
would not have REG_FUNCTION_VALUE_P true, while the former would if
it were referring to the same register.
else
target = copy_to_reg (valreg);
+#ifdef PROMOTE_FUNCTION_RETURN
+ /* If we promoted this return value, make the proper SUBREG. */
+ if (GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+ {
+ enum machine_mode mode = GET_MODE (target);
+ int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+
+ if (TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == ENUMERAL_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == CHAR_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == REAL_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE)
+ {
+ PROMOTE_MODE (mode, unsignedp, TREE_TYPE (exp));
+ }
+
+ target = gen_rtx (SUBREG, TYPE_MODE (TREE_TYPE (exp)), target, 0);
+ SUBREG_PROMOTED_VAR_P (target) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
+ }
+#endif
+
/* Perform all cleanups needed for the arguments of this call
(i.e. destructors in C++). */
expand_cleanups_to (old_cleanups);
- /* If size of args is variable, restore saved stack-pointer value. */
+ /* 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)
{
- emit_stack_restore (SAVE_BLOCK, old_stack_level, 0);
+ emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
pending_stack_adjust = old_pending_adj;
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ stack_arg_under_construction = old_stack_arg_under_construction;
+ highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+ stack_usage_map = initial_stack_usage_map;
+#endif
}
-
#ifdef ACCUMULATE_OUTGOING_ARGS
else
{
emit_move_insn (stack_area, save_area);
else
emit_block_move (stack_area, validize_mem (save_area),
- gen_rtx (CONST_INT, VOIDmode,
- high_to_save - low_to_save + 1,
- PARM_BOUNDARY / BITS_PER_UNIT));
+ GEN_INT (high_to_save - low_to_save + 1),
+ PARM_BOUNDARY / BITS_PER_UNIT);
}
#endif
emit_move_insn (stack_area, args[i].save_area);
else
emit_block_move (stack_area, validize_mem (args[i].save_area),
- gen_rtx (CONST_INT, VOIDmode,
- args[i].size.constant),
+ GEN_INT (args[i].size.constant),
PARM_BOUNDARY / BITS_PER_UNIT);
}
for non-local gotos. */
if (may_be_alloca && nonlocal_goto_handler_slot != 0)
- emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, 0);
+ emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
pop_temp_slots ();
arg->save_area = assign_stack_temp (BLKmode,
arg->size.constant, 1);
emit_block_move (validize_mem (arg->save_area), stack_area,
- gen_rtx (CONST_INT, VOIDmode,
- arg->size.constant),
+ GEN_INT (arg->size.constant),
PARM_BOUNDARY / BITS_PER_UNIT);
}
else
/* If this is being passes partially in a register, we can't evaluate
it directly into its stack slot. Otherwise, we can. */
if (arg->value == 0)
- arg->value = expand_expr (pval, partial ? 0 : arg->stack, VOIDmode, 0);
+ {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* stack_arg_under_construction is nonzero if a function argument is
+ being evaluated directly into the outgoing argument list and
+ expand_call must take special action to preserve the argument list
+ if it is called recursively.
+
+ For scalar function arguments stack_usage_map is sufficient to
+ determine which stack slots must be saved and restored. Scalar
+ arguments in general have pass_on_stack == 0.
+
+ If this argument is initialized by a function which takes the
+ address of the argument (a C++ constructor or a C function
+ returning a BLKmode structure), then stack_usage_map is
+ insufficient and expand_call must push the stack around the
+ function call. Such arguments have pass_on_stack == 1.
+
+ Note that it is always safe to set stack_arg_under_construction,
+ but this generates suboptimal code if set when not needed. */
+
+ if (arg->pass_on_stack)
+ stack_arg_under_construction++;
+#endif
+ arg->value = expand_expr (pval, partial ? NULL_RTX : arg->stack,
+ VOIDmode, 0);
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ if (arg->pass_on_stack)
+ stack_arg_under_construction--;
+#endif
+ }
/* Don't allow anything left on stack from computation
of argument to alloca. */
emit_push_insn for BLKmode is careful to avoid it. */
excess = (arg->size.constant - TREE_INT_CST_LOW (size)
+ partial * UNITS_PER_WORD);
- size_rtx = expand_expr (size, 0, VOIDmode, 0);
+ size_rtx = expand_expr (size, NULL_RTX, VOIDmode, 0);
}
emit_push_insn (arg->value, TYPE_MODE (TREE_TYPE (pval)),