calls.c (expand_call): Avoid unnecesary precalculation and outgoing parameters space guarding for...

* calls.c (expand_call): Avoid unnecesary precalculation
	and outgoing parameters space guarding for sibling calls.
	(store_one_arg): Likewise.

From-SVN: r33280
This commit is contained in:
Jan Hubicka 2000-04-20 12:20:38 +00:00 committed by Jan Hubicka
parent 48d9ade562
commit f8a097cd17
2 changed files with 86 additions and 86 deletions

View File

@ -1,3 +1,9 @@
Thu Apr 20 14:19:18 MET DST 2000 Jan Hubicka <jh@suse.cz>
* calls.c (expand_call): Avoid unnecesary precalculation
and outgoing parameters space guarding for sibling calls.
(store_one_arg): Likewise.
Thu Apr 20 08:01:07 2000 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* toplev.c (enum dump_file_index, dump_file): Add DFI_sibling.

View File

@ -2467,12 +2467,12 @@ expand_call (exp, target, ignore)
|| reg_mentioned_p (virtual_outgoing_args_rtx,
structure_value_addr))
&& (args_size.var
|| (!ACCUMULATE_OUTGOING_ARGS && args_size.constant)
))
|| (!ACCUMULATE_OUTGOING_ARGS && args_size.constant)))
structure_value_addr = copy_to_reg (structure_value_addr);
/* Precompute any arguments as needed. */
precompute_arguments (flags, num_actuals, args);
if (pass)
precompute_arguments (flags, num_actuals, args);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
@ -2480,11 +2480,14 @@ expand_call (exp, target, ignore)
start_sequence ();
old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
/* The argument block when performing a sibling call is the
incoming argument block. */
if (pass == 0)
argblock = virtual_incoming_args_rtx;
/* If we have no actual push instructions, or shouldn't use them,
make space for all args right now. */
if (args_size.var != 0)
else if (args_size.var != 0)
{
if (old_stack_level == 0)
{
@ -2519,24 +2522,24 @@ expand_call (exp, target, ignore)
{
if (ACCUMULATE_OUTGOING_ARGS)
{
/* Since the stack pointer will never be pushed, it is possible
for the evaluation of a parm to clobber something we have
already written to the stack. Since most function calls on
RISC machines do not use the stack, this is uncommon, but
must work correctly.
/* Since the stack pointer will never be pushed, it is
possible for the evaluation of a parm to clobber
something we have already written to the stack.
Since most function calls on RISC machines do not use
the stack, this is uncommon, but must work correctly.
Therefore, we save any area of the stack that was already
written and that we are using. Here we set up to do this by
making a new stack usage map from the old one. The actual
save will be done by store_one_arg.
written and that we are using. Here we set up to do this
by making a new stack usage map from the old one. The
actual save will be done by store_one_arg.
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
#ifndef OUTGOING_REG_PARM_STACK_SPACE
/* 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. */
/* 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. */
needed += reg_parm_stack_space;
#endif
@ -2547,7 +2550,8 @@ expand_call (exp, target, ignore)
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed);
#endif
stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
stack_usage_map
= (char *) alloca (highest_outgoing_arg_in_use);
if (initial_highest_arg_in_use)
bcopy (initial_stack_usage_map, stack_usage_map,
@ -2559,9 +2563,9 @@ expand_call (exp, target, ignore)
- initial_highest_arg_in_use));
needed = 0;
/* 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
/* 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;
@ -2590,63 +2594,53 @@ expand_call (exp, target, ignore)
else
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
call in ARGS. In that case, the stack pointer changes value
from the allocation point to the call point, and hence
the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
But might as well always do it. */
/* 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 call in ARGS. In that case, the stack
pointer changes value from the allocation point to the
call point, and hence the value of
VIRTUAL_OUTGOING_ARGS_RTX changes as well. But might
as well always do it. */
argblock = copy_to_reg (argblock);
}
}
}
/* The argument block when performing a sibling call is the
incoming argument block. */
if (pass == 0)
{
rtx temp = plus_constant (arg_pointer_rtx,
FIRST_PARM_OFFSET (current_function_decl));
argblock = force_reg (Pmode, force_operand (temp, NULL_RTX));
}
if (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)
{
/* 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)
{
#ifndef OUTGOING_REG_PARM_STACK_SPACE
rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
#else
rtx push_size = GEN_INT (args_size.constant);
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;
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;
}
}
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;
}
}
compute_argument_addresses (args, argblock, num_actuals);
@ -2709,7 +2703,7 @@ expand_call (exp, target, ignore)
#ifdef REG_PARM_STACK_SPACE
/* Save the fixed argument area if it's part of the caller's frame and
is clobbered by argument setup for this call. */
if (ACCUMULATE_OUTGOING_ARGS)
if (ACCUMULATE_OUTGOING_ARGS && pass)
save_area = save_fixed_argument_area (reg_parm_stack_space, argblock,
&low_to_save, &high_to_save);
#endif
@ -2722,7 +2716,7 @@ expand_call (exp, target, ignore)
for (i = 0; i < num_actuals; i++)
if (args[i].reg == 0 || args[i].pass_on_stack)
store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
store_one_arg (&args[i], argblock, flags,
args_size.var != 0, reg_parm_stack_space);
/* If we have a parm that is passed in registers but not in memory
@ -2737,7 +2731,7 @@ expand_call (exp, target, ignore)
if (reg_parm_seen)
for (i = 0; i < num_actuals; i++)
if (args[i].partial != 0 && ! args[i].pass_on_stack)
store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
store_one_arg (&args[i], argblock, flags,
args_size.var != 0, reg_parm_stack_space);
#ifdef PREFERRED_STACK_BOUNDARY
@ -3037,14 +3031,13 @@ expand_call (exp, target, ignore)
stack_usage_map = initial_stack_usage_map;
sibcall_failure = 1;
}
else if (ACCUMULATE_OUTGOING_ARGS)
else if (ACCUMULATE_OUTGOING_ARGS && pass)
{
#ifdef REG_PARM_STACK_SPACE
if (save_area)
{
restore_fixed_argument_area (save_area, argblock,
high_to_save, low_to_save);
sibcall_failure = 1;
}
#endif
@ -3065,7 +3058,6 @@ expand_call (exp, target, ignore)
validize_mem (args[i].save_area),
GEN_INT (args[i].size.constant),
PARM_BOUNDARY);
sibcall_failure = 1;
}
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
@ -3595,8 +3587,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
{
if (ACCUMULATE_OUTGOING_ARGS)
{
/* If this is being stored into a pre-allocated, fixed-size, stack
area, save any previous data at that location. */
/* If this is being stored into a pre-allocated, fixed-size,
stack area, save any previous data at that location. */
#ifdef ARGS_GROW_DOWNWARD
/* stack_slot is negative, but we want to index stack_usage_map
@ -3610,16 +3602,18 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
for (i = lower_bound; i < upper_bound; i++)
if (stack_usage_map[i]
/* Don't store things in the fixed argument area at this point;
it has already been saved. */
/* Don't store things in the fixed argument area at this
point; it has already been saved. */
&& i > reg_parm_stack_space)
break;
if (i != upper_bound)
{
/* We need to make a save area. See what mode we can make it. */
/* We need to make a save area. See what mode we can make
it. */
enum machine_mode save_mode
= mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT,
= mode_for_size (argvec[argnum].size.constant
* BITS_PER_UNIT,
MODE_INT, 1);
rtx stack_area
= gen_rtx_MEM
@ -3975,11 +3969,11 @@ target_for_arg (type, size, args_addr, offset)
FNDECL is the declaration of the function we are calling. */
static void
store_one_arg (arg, argblock, may_be_alloca, variable_size,
store_one_arg (arg, argblock, flags, variable_size,
reg_parm_stack_space)
struct arg_data *arg;
rtx argblock;
int may_be_alloca;
int flags;
int variable_size ATTRIBUTE_UNUSED;
int reg_parm_stack_space;
{
@ -3996,7 +3990,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
this argument. */
push_temp_slots ();
if (ACCUMULATE_OUTGOING_ARGS)
if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL))
{
/* If this is being stored into a pre-allocated, fixed-size, stack area,
save any previous data at that location. */
@ -4124,7 +4118,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
/* Don't allow anything left on stack from computation
of argument to alloca. */
if (may_be_alloca)
if (flags & ECF_MAY_BE_ALLOCA)
do_pending_stack_adjust ();
if (arg->value == arg->stack)