diff options
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 194 |
1 files changed, 89 insertions, 105 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index 2592a8e7fb3..12dea75584a 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -185,9 +185,8 @@ static void store_unaligned_arguments_into_pseudos PARAMS ((struct arg_data *, static int finalize_must_preallocate PARAMS ((int, int, struct arg_data *, struct args_size *)); -static void precompute_arguments PARAMS ((int, int, int, - struct arg_data *, - struct args_size *)); +static void precompute_arguments PARAMS ((int, int, + struct arg_data *)); static int compute_argument_block_size PARAMS ((int, struct args_size *, int)); @@ -1417,23 +1416,17 @@ compute_argument_block_size (reg_parm_stack_space, args_size, FLAGS is mask of ECF_* constants. - MUST_PREALLOCATE indicates that we must preallocate stack space for - any stack arguments. - NUM_ACTUALS is the number of arguments. ARGS is an array containing information for each argument; this routine - fills in the INITIAL_VALUE and VALUE fields for each precomputed argument. - - ARGS_SIZE contains information about the size of the arg list. */ + fills in the INITIAL_VALUE and VALUE fields for each precomputed argument. + */ static void -precompute_arguments (flags, must_preallocate, num_actuals, args, args_size) +precompute_arguments (flags, num_actuals, args) int flags; - int must_preallocate; int num_actuals; struct arg_data *args; - struct args_size *args_size; { int i; @@ -1448,15 +1441,13 @@ precompute_arguments (flags, must_preallocate, num_actuals, args, args_size) on the stack, then we must precompute any parameter which contains a function call which will store arguments on the stack. Otherwise, evaluating the parameter may clobber previous parameters - which have already been stored into the stack. */ + which have already been stored into the stack. (we have code to avoid + such case by saving the ougoing stack arguments, but it results in + worse code) */ for (i = 0; i < num_actuals; i++) if ((flags & (ECF_CONST | ECF_PURE)) - || ((args_size->var != 0 || args_size->constant != 0) - && calls_function (args[i].tree_value, 1)) - || (must_preallocate - && (args_size->var != 0 || args_size->constant != 0) - && calls_function (args[i].tree_value, 0))) + || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS)) { /* If this is an addressable type, we cannot pre-evaluate it. */ if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))) @@ -2476,13 +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, must_preallocate, num_actuals, - args, &args_size); + 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. */ @@ -2490,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) { @@ -2529,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 @@ -2557,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, @@ -2569,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; @@ -2600,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); @@ -2719,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 @@ -2732,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 @@ -2747,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 @@ -3047,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 @@ -3075,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; @@ -3605,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 @@ -3620,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 @@ -3985,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; { @@ -4006,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. */ @@ -4134,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) |