From 2f4aa534294046582e026d67f9e74d01124b66cb Mon Sep 17 00:00:00 2001 From: Richard Stallman Date: Sun, 31 May 1992 20:34:00 +0000 Subject: [PATCH] *** empty log message *** From-SVN: r1132 --- gcc/calls.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/gcc/calls.c b/gcc/calls.c index 2b5da07533c..20686f11c8c 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -87,6 +87,13 @@ static char *stack_usage_map; /* 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 (); @@ -468,6 +475,7 @@ expand_call (exp, target, ignore) 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; @@ -576,6 +584,7 @@ expand_call (exp, target, ignore) if (is_integrable) { rtx temp; + rtx before_call = get_last_insn (); temp = expand_inline_function (fndecl, actparms, target, ignore, TREE_TYPE (exp), @@ -584,6 +593,39 @@ expand_call (exp, target, ignore) /* If inlining succeeded, return. */ 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 (i.e. destructors in C++). It is ok if these destructors 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. */ 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 = 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; } @@ -1064,6 +1111,11 @@ expand_call (exp, target, ignore) 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; } 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], 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 only way the stack pointer can change here is if some arguments + 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; + 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 */ if (inhibit_defer_pop == 0) { @@ -1207,6 +1273,31 @@ expand_call (exp, target, ignore) #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, since ARGBLOCK probably refers to the SP. */ if (argblock) @@ -1537,14 +1628,17 @@ expand_call (exp, target, ignore) (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); 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 else { -- 2.30.2