From 59257ff7b87ae9f17395c48ad6e4dd9a123b0d9d Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Wed, 6 May 1992 07:35:29 -0400 Subject: [PATCH] *** empty log message *** From-SVN: r915 --- gcc/calls.c | 15 +++-- gcc/config/rs6000/rs6000.md | 61 +++++++++++++++++- gcc/explow.c | 121 ++++++++++++++++++++++++++++++++++++ gcc/expr.h | 9 +++ gcc/function.c | 18 +++--- gcc/stmt.c | 67 +++++++++++++------- 6 files changed, 252 insertions(+), 39 deletions(-) diff --git a/gcc/calls.c b/gcc/calls.c index 90cdb8acbc99..8541d16a9e4a 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -800,7 +800,7 @@ expand_call (exp, target, ignore) if (old_stack_level == 0) { - old_stack_level = copy_to_mode_reg (Pmode, stack_pointer_rtx); + emit_stack_save (SAVE_BLOCK, &old_stack_level, 0); old_pending_adj = pending_stack_adjust; pending_stack_adjust = 0; } @@ -1060,7 +1060,7 @@ expand_call (exp, target, ignore) { if (old_stack_level == 0) { - old_stack_level = copy_to_mode_reg (Pmode, stack_pointer_rtx); + emit_stack_save (SAVE_BLOCK, &old_stack_level, 0); old_pending_adj = pending_stack_adjust; pending_stack_adjust = 0; } @@ -1520,7 +1520,7 @@ expand_call (exp, target, ignore) if (old_stack_level) { - emit_move_insn (stack_pointer_rtx, old_stack_level); + emit_stack_restore (SAVE_BLOCK, old_stack_level, 0); pending_stack_adjust = old_pending_adj; } @@ -1570,9 +1570,12 @@ expand_call (exp, target, ignore) } #endif - /* If this was alloca, record the new stack level for nonlocal gotos. */ - if (may_be_alloca && nonlocal_goto_stack_level != 0) - emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx); + /* If this was alloca, record the new stack level for nonlocal gotos. + Check for the handler slots since we might not have a save area + for non-local gotos. */ + + if (may_be_alloca && nonlocal_goto_handler_slot != 0) + emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, 0); pop_temp_slots (); diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 775d8fc56a78..d3e6bce9ccfe 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -2835,9 +2835,7 @@ ;; Next come insns related to the calling sequence. ;; ;; First, an insn to allocate new stack space for dynamic use (e.g., alloca). -;; We move the back-chain and decrement the stack pointer. This is slightly -;; less efficient than it needs to be for long constants, but that case -;; should be rare. +;; We move the back-chain and decrement the stack pointer. (define_expand "allocate_stack" [(set (reg:SI 1) @@ -2852,6 +2850,63 @@ emit_move_insn (stack_bot, chain); DONE; }") + +;; These patterns say how to save and restore the stack pointer. We need not +;; save the stack pointer at function level since we are careful to +;; preserve the backchain. At block level, we have to restore the backchain +;; when we restore the stack pointer. +;; +;; For nonlocal gotos, we must save both the stack pointer and its +;; backchain and restore both. Note that in the nonlocal case, the +;; save area is a memory location. + +(define_expand "save_stack_function" + [(use (const_int 0))] + "" + "") + +(define_expand "restore_stack_function" + [(use (const_int 0))] + "" + "") + +(define_expand "restore_stack_block" + [(set (match_dup 2) (mem:SI (match_operand:SI 0 "register_operand" ""))) + (set (match_dup 0) (match_operand:SI 1 "register_operand" "")) + (set (mem:SI (match_dup 0)) (match_dup 2))] + "" + " +{ operands[2] = gen_reg_rtx (SImode); }") + +(define_expand "save_stack_nonlocal" + [(match_operand:DI 0 "memory_operand" "") + (match_operand:SI 1 "register_operand" "")] + "" + " +{ + rtx temp = gen_reg_rtx (SImode); + + /* Copy the backchain to the first word, sp to the second. */ + emit_move_insn (temp, gen_rtx (MEM, SImode, operands[1])); + emit_move_insn (operand_subword (operands[0], 0, 0, DImode), temp); + emit_move_insn (operand_subword (operands[0], 1, 0, DImode), operands[1]); + DONE; +}") + +(define_expand "restore_stack_nonlocal" + [(match_operand:SI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" "")] + "" + " +{ + rtx temp = gen_reg_rtx (SImode); + + /* Restore the backchain from the first word, sp from the second. */ + emit_move_insn (temp, operand_subword (operands[1], 0, 0, DImode)); + emit_move_insn (operands[0], operand_subword (operands[1], 1, 0, DImode)); + emit_move_insn (gen_rtx (MEM, SImode, operands[0]), temp); + DONE; +}") ;; A function pointer is a pointer to a data area whose first word contains ;; the actual address of the function, whose second word contains a pointer diff --git a/gcc/explow.c b/gcc/explow.c index f2b72f6969c5..4504a73cd09e 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -681,6 +681,127 @@ round_push (size) return size; } +/* Save the stack pointer for the purpose in SAVE_LEVEL. PSAVE is a pointer + to a previously-created save area. If no save area has been allocated, + this function will allocate one. If a save area is specified, it + must be of the proper mode. + + The insns are emitted after insn AFTER, if nonzero, otherwise the insns + are emitted at the current position. */ + +void +emit_stack_save (save_level, psave, after) + enum save_level save_level; + rtx *psave; + rtx after; +{ + rtx sa = *psave; + /* The default is that we use a move insn and save in a Pmode object. */ + rtx (*fcn) () = gen_move_insn; + enum machine_mode mode = Pmode; + + /* See if this machine has anything special to do for this kind of save. */ + switch (save_level) + { +#ifdef HAVE_save_stack_block + case SAVE_BLOCK: + if (HAVE_save_stack_block) + { + fcn = gen_save_stack_block; + mode = insn_operand_mode[CODE_FOR_save_stack_block][0]; + } + break; +#endif +#ifdef HAVE_save_stack_function + case SAVE_FUNCTION: + if (HAVE_save_stack_function) + { + fcn = gen_save_stack_function; + mode = insn_operand_mode[CODE_FOR_save_stack_function][0]; + } + break; +#endif +#ifdef HAVE_save_stack_nonlocal + case SAVE_NONLOCAL: + if (HAVE_save_stack_nonlocal) + { + fcn = gen_save_stack_nonlocal; + mode = insn_operand_mode[CODE_FOR_save_stack_nonlocal][0]; + } + break; +#endif + } + + /* If there is no save area and we have to allocate one, do so. Otherwise + verify the save area is the proper mode. */ + + if (sa == 0) + { + if (mode != VOIDmode) + { + if (save_level == SAVE_NONLOCAL) + *psave = sa = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); + else + *psave = sa = gen_reg_rtx (mode); + } + } + else + { + if (mode == VOIDmode || GET_MODE (sa) != mode) + abort (); + } + + if (after) + emit_insn_after (fcn (sa, stack_pointer_rtx), after); + else + emit_insn (fcn (sa, stack_pointer_rtx)); +} + +/* Restore the stack pointer for the purpose in SAVE_LEVEL. SA is the save + area made by emit_stack_save. If it is zero, we have nothing to do. + + Put any emitted insns after insn AFTER, if nonzero, otherwise at + current position. */ + +void +emit_stack_restore (save_level, sa, after) + enum save_level save_level; + rtx after; + rtx sa; +{ + /* The default is that we use a move insn. */ + rtx (*fcn) () = gen_move_insn; + + /* See if this machine has anything special to do for this kind of save. */ + switch (save_level) + { +#ifdef HAVE_restore_stack_block + case SAVE_BLOCK: + if (HAVE_restore_stack_block) + fcn = gen_restore_stack_block; + break; +#endif +#ifdef HAVE_restore_stack_function + case SAVE_FUNCTION: + if (HAVE_restore_stack_function) + fcn = gen_restore_stack_function; + break; +#endif +#ifdef HAVE_restore_stack_nonlocal + + case SAVE_NONLOCAL: + if (HAVE_restore_stack_nonlocal) + fcn = gen_restore_stack_nonlocal; + break; +#endif + } + + if (after) + emit_insn_after (fcn (stack_pointer_rtx, sa), after); + else + emit_insn (fcn (stack_pointer_rtx, sa)); +} + /* Return an rtx representing the address of an area of memory dynamically pushed on the stack. This region of memory is always aligned to a multiple of BIGGEST_ALIGNMENT. diff --git a/gcc/expr.h b/gcc/expr.h index f255b78e4e1e..3a140d2db9ba 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -539,6 +539,15 @@ extern void adjust_stack (); /* Add some bytes to the stack. An rtx says how many. */ extern void anti_adjust_stack (); +/* This enum is used for the following two functions. */ +enum save_level {SAVE_BLOCK, SAVE_FUNCTION, SAVE_NONLOCAL}; + +/* Save the stack pointer at the specified level. */ +extern void emit_stack_save (); + +/* Restore the stack pointer from a save area of the specified level. */ +extern void emit_stack_restore (); + /* Allocate some space on the stack dynamically and return its address. An rtx says how many bytes. */ extern rtx allocate_dynamic_stack_space (); diff --git a/gcc/function.c b/gcc/function.c index c9a9e9520842..45dc777581af 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -2317,11 +2317,11 @@ delete_handlers () if (GET_CODE (insn) == CODE_LABEL) LABEL_PRESERVE_P (insn) = 0; if (GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET - && (SET_DEST (PATTERN (insn)) == nonlocal_goto_handler_slot - || SET_SRC (PATTERN (insn)) == nonlocal_goto_handler_slot - || SET_DEST (PATTERN (insn)) == nonlocal_goto_stack_level - || SET_SRC (PATTERN (insn)) == nonlocal_goto_stack_level)) + && ((nonlocal_goto_handler_slot != 0 + && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn))) + || (nonlocal_goto_stack_level != 0 + && reg_mentioned_p (nonlocal_goto_stack_level, + PATTERN (insn))))) delete_insn (insn); } } @@ -3961,10 +3961,10 @@ expand_function_end (filename, line) #endif if (current_function_calls_alloca) { - rtx tem = gen_reg_rtx (Pmode); - emit_insn_after (gen_rtx (SET, VOIDmode, tem, stack_pointer_rtx), - parm_birth_insn); - emit_insn (gen_rtx (SET, VOIDmode, stack_pointer_rtx, tem)); + rtx tem = 0; + + emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn); + emit_stack_restore (SAVE_FUNCTION, tem, 0); } /* If scalar return value was computed in a pseudo-reg, diff --git a/gcc/stmt.c b/gcc/stmt.c index 3f085971db6b..e2c52bfed17e 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -586,11 +586,9 @@ declare_nonlocal_label (label) { nonlocal_goto_handler_slot = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); - nonlocal_goto_stack_level - = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); - emit_insn_before (gen_move_insn (nonlocal_goto_stack_level, - stack_pointer_rtx), - tail_recursion_reentry); + emit_stack_save (SAVE_NONLOCAL, + &nonlocal_goto_stack_level, + PREV_INSN (tail_recursion_reentry)); } } @@ -609,27 +607,50 @@ expand_goto (label) struct function *p = find_function_data (context); rtx temp; p->has_nonlocal_label = 1; + + /* Copy the rtl for the slots so that they won't be shared in + case the virtual stack vars register gets instantiated differently + in the parent than in the child. */ + #if HAVE_nonlocal_goto if (HAVE_nonlocal_goto) emit_insn (gen_nonlocal_goto (lookup_static_chain (label), - p->nonlocal_goto_handler_slot, - p->nonlocal_goto_stack_level, + copy_rtx (p->nonlocal_goto_handler_slot), + copy_rtx (p->nonlocal_goto_stack_level), gen_rtx (LABEL_REF, Pmode, label_rtx (label)))); else #endif { + rtx addr; + /* Restore frame pointer for containing function. This sets the actual hard register used for the frame pointer to the location of the function's incoming static chain info. The non-local goto handler will then adjust it to contain the proper value and reload the argument pointer, if needed. */ emit_move_insn (frame_pointer_rtx, lookup_static_chain (label)); + + /* We have now loaded the frame pointer hardware register with + the address of that corresponds to the start of the virtual + stack vars. So replace virtual_stack_vars_rtx in all + addresses we use with stack_pointer_rtx. */ + /* Get addr of containing function's current nonlocal goto handler, which will do any cleanups and then jump to the label. */ - temp = copy_to_reg (p->nonlocal_goto_handler_slot); + addr = copy_rtx (p->nonlocal_goto_handler_slot); + temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx, + frame_pointer_rtx)); + /* Restore the stack pointer. Note this uses fp just restored. */ - emit_move_insn (stack_pointer_rtx, p->nonlocal_goto_stack_level); + addr = p->nonlocal_goto_stack_level; + if (addr) + addr = replace_rtx (copy_rtx (p->nonlocal_goto_stack_level), + replace_rtx (addr, virtual_stack_vars_rtx, + frame_pointer_rtx)); + + emit_stack_restore (SAVE_NONLOCAL, addr, 0); + /* Put in the static chain register the nonlocal label address. */ emit_move_insn (static_chain_rtx, gen_rtx (LABEL_REF, Pmode, label_rtx (label))); @@ -691,7 +712,7 @@ expand_goto_internal (body, label, last_insn) the stack pointer. This one should be deleted as dead by flow. */ clear_pending_stack_adjust (); do_pending_stack_adjust (); - emit_move_insn (stack_pointer_rtx, stack_level); + emit_stack_restore (SAVE_BLOCK, stack_level, 0); } if (body != 0 && DECL_TOO_LATE (body)) @@ -902,8 +923,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) /* Restore stack level for the biggest contour that this jump jumps out of. */ if (f->stack_level) - emit_insn_after (gen_move_insn (stack_pointer_rtx, f->stack_level), - f->before_jump); + emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump); f->before_jump = 0; } } @@ -2592,14 +2612,15 @@ expand_end_bindings (vars, mark_ends, dont_jump_in) if (thisblock->data.block.stack_level != 0) { - emit_move_insn (stack_pointer_rtx, - thisblock->data.block.stack_level); - if (nonlocal_goto_stack_level != 0) - emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx); + emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION, + thisblock->data.block.stack_level, 0); + if (nonlocal_goto_handler_slot != 0) + emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, 0); } /* Any gotos out of this block must also do these things. - Also report any gotos with fixups that came to labels in this level. */ + Also report any gotos with fixups that came to labels in this + level. */ fixup_gotos (thisblock, thisblock->data.block.stack_level, thisblock->data.block.cleanups, @@ -2753,8 +2774,9 @@ expand_decl (decl) if (thisblock->data.block.stack_level == 0) { do_pending_stack_adjust (); - thisblock->data.block.stack_level - = copy_to_reg (stack_pointer_rtx); + emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION, + &thisblock->data.block.stack_level, + thisblock->data.block.first_insn); stack_block_stack = thisblock; } @@ -2765,11 +2787,14 @@ expand_decl (decl) 0, VOIDmode, 0); free_temp_slots (); + /* This is equivalent to calling alloca. */ + current_function_calls_alloca = 1; + /* Allocate space on the stack for the variable. */ address = allocate_dynamic_stack_space (size, 0, DECL_ALIGN (decl)); - if (nonlocal_goto_stack_level != 0) - emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx); + if (nonlocal_goto_handler_slot != 0) + emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, 0); /* Reference the variable indirect through that rtx. */ DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), address); -- 2.43.5