*** empty log message ***
From-SVN: r1132
This commit is contained in:
parent
8ac9cb56c4
commit
2f4aa53429
106
gcc/calls.c
106
gcc/calls.c
@ -87,6 +87,13 @@ static char *stack_usage_map;
|
|||||||
|
|
||||||
/* Size of STACK_USAGE_MAP. */
|
/* Size of STACK_USAGE_MAP. */
|
||||||
static int highest_outgoing_arg_in_use;
|
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
|
#endif
|
||||||
|
|
||||||
static void store_one_arg ();
|
static void store_one_arg ();
|
||||||
@ -468,6 +475,7 @@ expand_call (exp, target, ignore)
|
|||||||
|
|
||||||
rtx old_stack_level = 0;
|
rtx old_stack_level = 0;
|
||||||
int old_pending_adj;
|
int old_pending_adj;
|
||||||
|
int old_stack_arg_under_construction;
|
||||||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||||
tree old_cleanups = cleanups_this_call;
|
tree old_cleanups = cleanups_this_call;
|
||||||
|
|
||||||
@ -576,6 +584,7 @@ expand_call (exp, target, ignore)
|
|||||||
if (is_integrable)
|
if (is_integrable)
|
||||||
{
|
{
|
||||||
rtx temp;
|
rtx temp;
|
||||||
|
rtx before_call = get_last_insn ();
|
||||||
|
|
||||||
temp = expand_inline_function (fndecl, actparms, target,
|
temp = expand_inline_function (fndecl, actparms, target,
|
||||||
ignore, TREE_TYPE (exp),
|
ignore, TREE_TYPE (exp),
|
||||||
@ -584,6 +593,39 @@ expand_call (exp, target, ignore)
|
|||||||
/* If inlining succeeded, return. */
|
/* If inlining succeeded, return. */
|
||||||
if ((int) temp != -1)
|
if ((int) temp != -1)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* 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, seq;
|
||||||
|
|
||||||
|
for (insn = NEXT_INSN (before_call); insn;
|
||||||
|
insn = NEXT_INSN (insn))
|
||||||
|
if (GET_CODE (insn) == CALL_INSN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (insn)
|
||||||
|
{
|
||||||
|
start_sequence ();
|
||||||
|
emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
|
||||||
|
allocate_dynamic_stack_space (gen_rtx (CONST_INT, VOIDmode,
|
||||||
|
highest_outgoing_arg_in_use),
|
||||||
|
0, BITS_PER_UNIT);
|
||||||
|
seq = get_insns ();
|
||||||
|
end_sequence ();
|
||||||
|
emit_insns_before (seq, NEXT_INSN (before_call));
|
||||||
|
emit_stack_restore (SAVE_BLOCK, old_stack_level, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform all cleanups needed for the arguments of this call
|
/* Perform all cleanups needed for the arguments of this call
|
||||||
(i.e. destructors in C++). It is ok if these destructors
|
(i.e. destructors in C++). It is ok if these destructors
|
||||||
clobber RETURN_VALUE_REG, because the only time we care about
|
clobber RETURN_VALUE_REG, because the only time we care about
|
||||||
@ -701,10 +743,15 @@ expand_call (exp, target, ignore)
|
|||||||
as if it were an extra parameter. */
|
as if it were an extra parameter. */
|
||||||
if (structure_value_addr && struct_value_rtx == 0)
|
if (structure_value_addr && struct_value_rtx == 0)
|
||||||
{
|
{
|
||||||
|
/* 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));
|
||||||
actparms
|
actparms
|
||||||
= tree_cons (error_mark_node,
|
= tree_cons (error_mark_node,
|
||||||
make_tree (build_pointer_type (TREE_TYPE (funtype)),
|
make_tree (build_pointer_type (TREE_TYPE (funtype)),
|
||||||
force_reg (Pmode, structure_value_addr)),
|
temp),
|
||||||
actparms);
|
actparms);
|
||||||
structure_value_addr_parm = 1;
|
structure_value_addr_parm = 1;
|
||||||
}
|
}
|
||||||
@ -1064,6 +1111,11 @@ expand_call (exp, target, ignore)
|
|||||||
emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
|
emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
|
||||||
old_pending_adj = pending_stack_adjust;
|
old_pending_adj = pending_stack_adjust;
|
||||||
pending_stack_adjust = 0;
|
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;
|
||||||
}
|
}
|
||||||
argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
|
argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
|
||||||
}
|
}
|
||||||
@ -1118,10 +1170,24 @@ expand_call (exp, target, ignore)
|
|||||||
bzero (&stack_usage_map[initial_highest_arg_in_use],
|
bzero (&stack_usage_map[initial_highest_arg_in_use],
|
||||||
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
|
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
|
||||||
needed = 0;
|
needed = 0;
|
||||||
/* No need to copy this virtual register; the space we're
|
|
||||||
using gets preallocated at the start of the function
|
/* The only way the stack pointer can change here is if some arguments
|
||||||
so the stack pointer won't change here. */
|
which are passed in memory are constructed in place in the outgoing
|
||||||
|
argument area. All objects which are constructed in place have
|
||||||
|
pass_on_stack == 1 (see store_one_arg ()).
|
||||||
|
|
||||||
|
The test for arguments being constructed on the stack is just an
|
||||||
|
optimization: it would be correct but suboptimal to call
|
||||||
|
copy_addr_to_reg () unconditionally. */
|
||||||
|
|
||||||
argblock = virtual_outgoing_args_rtx;
|
argblock = virtual_outgoing_args_rtx;
|
||||||
|
for (i = 0; i < num_actuals; i++)
|
||||||
|
if (args[i].pass_on_stack)
|
||||||
|
{
|
||||||
|
argblock = copy_addr_to_reg (argblock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* not ACCUMULATE_OUTGOING_ARGS */
|
#else /* not ACCUMULATE_OUTGOING_ARGS */
|
||||||
if (inhibit_defer_pop == 0)
|
if (inhibit_defer_pop == 0)
|
||||||
{
|
{
|
||||||
@ -1207,6 +1273,31 @@ expand_call (exp, target, ignore)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
rtx push_size = gen_rtx (CONST_INT, VOIDmode,
|
||||||
|
highest_outgoing_arg_in_use);
|
||||||
|
if (old_stack_level == 0)
|
||||||
|
{
|
||||||
|
emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
|
||||||
|
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, 0, BITS_PER_UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
/* Don't try to defer pops if preallocating, not even from the first arg,
|
/* Don't try to defer pops if preallocating, not even from the first arg,
|
||||||
since ARGBLOCK probably refers to the SP. */
|
since ARGBLOCK probably refers to the SP. */
|
||||||
if (argblock)
|
if (argblock)
|
||||||
@ -1537,14 +1628,17 @@ expand_call (exp, target, ignore)
|
|||||||
(i.e. destructors in C++). */
|
(i.e. destructors in C++). */
|
||||||
expand_cleanups_to (old_cleanups);
|
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)
|
if (old_stack_level)
|
||||||
{
|
{
|
||||||
emit_stack_restore (SAVE_BLOCK, old_stack_level, 0);
|
emit_stack_restore (SAVE_BLOCK, old_stack_level, 0);
|
||||||
pending_stack_adjust = old_pending_adj;
|
pending_stack_adjust = old_pending_adj;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACCUMULATE_OUTGOING_ARGS
|
#ifdef ACCUMULATE_OUTGOING_ARGS
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user