diff options
author | bernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-11-05 11:29:33 +0000 |
---|---|---|
committer | bernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-11-05 11:29:33 +0000 |
commit | 345458f37f0b8f265755372eb4148510c08b8f2a (patch) | |
tree | 5bcf7bbd2f9f6163b05471cb42850dbddbfa018f /gcc/config/bfin | |
parent | 14aa86fc690c30e2dbc9cf9b73e6b07b9dfb0178 (diff) | |
download | gcc-345458f37f0b8f265755372eb4148510c08b8f2a.tar.gz |
* config/bfin/bfin.c (n_dregs_to_save, n_pregs_to_save,
expand_prologue_reg_save, expand_epilogue_reg_restore): New argument
IS_INTHANDLER; all callers changed.
(n_regs_saved_by_prologue): Take interrupt handler attributes into
account.
(do_link, do_unlink): New argument ALL; all callers changed.
(expand_interrupt_handler_prologue, expand_interrupt_handler_epilogue):
If function isn't leaf, save and restore all registers.
(bfin_function_ok_for_sibcall): Only true if not an interrupt or
exception handler.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@106526 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/bfin')
-rw-r--r-- | gcc/config/bfin/bfin.c | 92 |
1 files changed, 56 insertions, 36 deletions
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c index 18092ad767d..be028f74528 100644 --- a/gcc/config/bfin/bfin.c +++ b/gcc/config/bfin/bfin.c @@ -212,16 +212,18 @@ legitimize_pic_address (rtx orig, rtx reg, rtx picreg) /* Compute the number of DREGS to save with a push_multiple operation. This could include registers that aren't modified in the function, - since push_multiple only takes a range of registers. */ + since push_multiple only takes a range of registers. + If IS_INTHANDLER, then everything that is live must be saved, even + if normally call-clobbered. */ static int -n_dregs_to_save (void) +n_dregs_to_save (bool is_inthandler) { unsigned i; for (i = REG_R0; i <= REG_R7; i++) { - if (regs_ever_live[i] && ! call_used_regs[i]) + if (regs_ever_live[i] && (is_inthandler || ! call_used_regs[i])) return REG_R7 - i + 1; if (current_function_calls_eh_return) @@ -244,12 +246,12 @@ n_dregs_to_save (void) /* Like n_dregs_to_save, but compute number of PREGS to save. */ static int -n_pregs_to_save (void) +n_pregs_to_save (bool is_inthandler) { unsigned i; for (i = REG_P0; i <= REG_P5; i++) - if ((regs_ever_live[i] && ! call_used_regs[i]) + if ((regs_ever_live[i] && (is_inthandler || ! call_used_regs[i])) || (i == PIC_OFFSET_TABLE_REGNUM && (current_function_uses_pic_offset_table || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf)))) @@ -262,7 +264,7 @@ n_pregs_to_save (void) static bool must_save_fp_p (void) { - return (frame_pointer_needed || regs_ever_live[REG_FP]); + return frame_pointer_needed || regs_ever_live[REG_FP]; } static bool @@ -277,13 +279,14 @@ stack_frame_needed_p (void) /* Emit code to save registers in the prologue. SAVEALL is nonzero if we must save all registers; this is used for interrupt handlers. - SPREG contains (reg:SI REG_SP). */ + SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing + this for an interrupt (or exception) handler. */ static void -expand_prologue_reg_save (rtx spreg, int saveall) +expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler) { - int ndregs = saveall ? 8 : n_dregs_to_save (); - int npregs = saveall ? 6 : n_pregs_to_save (); + int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler); + int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler); int dregno = REG_R7 + 1 - ndregs; int pregno = REG_P5 + 1 - npregs; int total = ndregs + npregs; @@ -328,13 +331,14 @@ expand_prologue_reg_save (rtx spreg, int saveall) /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we must save all registers; this is used for interrupt handlers. - SPREG contains (reg:SI REG_SP). */ + SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing + this for an interrupt (or exception) handler. */ static void -expand_epilogue_reg_restore (rtx spreg, int saveall) +expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler) { - int ndregs = saveall ? 8 : n_dregs_to_save (); - int npregs = saveall ? 6 : n_pregs_to_save (); + int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler); + int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler); int total = ndregs + npregs; int i, regno; rtx pat, insn; @@ -449,9 +453,15 @@ static int n_regs_saved_by_prologue (void) { e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); - int n = n_dregs_to_save () + n_pregs_to_save (); + bool is_inthandler = fkind != SUBROUTINE; + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE + || (is_inthandler && !current_function_is_leaf)); + int ndregs = all ? 8 : n_dregs_to_save (is_inthandler); + int npregs = all ? 6 : n_pregs_to_save (is_inthandler); + int n = ndregs + npregs; - if (stack_frame_needed_p ()) + if (all || stack_frame_needed_p ()) /* We use a LINK instruction in this case. */ n += 2; else @@ -464,8 +474,6 @@ n_regs_saved_by_prologue (void) if (fkind != SUBROUTINE) { - tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - tree all = lookup_attribute ("saveall", attrs); int i; /* Increment once for ASTAT. */ @@ -640,14 +648,16 @@ arg_area_size (void) return 0; } -/* Save RETS and FP, and allocate a stack frame. */ +/* Save RETS and FP, and allocate a stack frame. ALL is true if the + function must save all its registers (true only for certain interrupt + handlers). */ static void -do_link (rtx spreg, HOST_WIDE_INT frame_size) +do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all) { frame_size += arg_area_size (); - if (stack_frame_needed_p () + if (all || stack_frame_needed_p () || (must_save_fp_p () && ! current_function_is_leaf)) emit_link_insn (spreg, frame_size); else @@ -675,11 +685,11 @@ do_link (rtx spreg, HOST_WIDE_INT frame_size) /* Like do_link, but used for epilogues to deallocate the stack frame. */ static void -do_unlink (rtx spreg, HOST_WIDE_INT frame_size) +do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all) { frame_size += arg_area_size (); - if (stack_frame_needed_p ()) + if (all || stack_frame_needed_p ()) emit_insn (gen_unlink ()); else { @@ -713,7 +723,7 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) rtx predec = gen_rtx_MEM (SImode, predec1); rtx insn; tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - tree all = lookup_attribute ("saveall", attrs); + bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; tree kspisusp = lookup_attribute ("kspisusp", attrs); if (kspisusp) @@ -733,7 +743,11 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT)); RTX_FRAME_RELATED_P (insn) = 1; - expand_prologue_reg_save (spreg, all != NULL_TREE); + /* If we're calling other functions, they won't save their call-clobbered + registers, so we must save everything here. */ + if (!current_function_is_leaf) + all = true; + expand_prologue_reg_save (spreg, all, true); for (i = REG_P7 + 1; i < REG_CC; i++) if (all @@ -757,7 +771,7 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) RTX_FRAME_RELATED_P (insn) = 1; } - do_link (spreg, frame_size); + do_link (spreg, frame_size, all); if (fkind == EXCPT_HANDLER) { @@ -792,19 +806,19 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) SPREG contains (reg:SI REG_SP). */ static void -expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) +expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) { int i; rtx postinc1 = gen_rtx_POST_INC (SImode, spreg); rtx postinc = gen_rtx_MEM (SImode, postinc1); tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - tree all = lookup_attribute ("saveall", attrs); + bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; /* A slightly crude technique to stop flow from trying to delete "dead" insns. */ MEM_VOLATILE_P (postinc) = 1; - do_unlink (spreg, get_frame_size ()); + do_unlink (spreg, get_frame_size (), all); if (lookup_attribute ("nesting", attrs)) { @@ -814,9 +828,14 @@ expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) emit_move_insn (srcreg, postinc); } + /* If we're calling other functions, they won't save their call-clobbered + registers, so we must save (and restore) everything here. */ + if (!current_function_is_leaf) + all = true; + for (i = REG_CC - 1; i > REG_P7; i--) if (all - || regs_ever_live[i] + || regs_ever_live[i] || (!leaf_function_p () && call_used_regs[i])) { if (i == REG_A0 || i == REG_A1) @@ -829,7 +848,7 @@ expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) emit_move_insn (gen_rtx_REG (SImode, i), postinc); } - expand_epilogue_reg_restore (spreg, all != NULL_TREE); + expand_epilogue_reg_restore (spreg, all, true); emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc); @@ -909,9 +928,9 @@ bfin_expand_prologue (void) emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim)); emit_insn (gen_trapifcc ()); } - expand_prologue_reg_save (spreg, 0); + expand_prologue_reg_save (spreg, 0, false); - do_link (spreg, frame_size); + do_link (spreg, frame_size, false); if (TARGET_ID_SHARED_LIBRARY && (current_function_uses_pic_offset_table @@ -935,9 +954,9 @@ bfin_expand_epilogue (int need_return, int eh_return) return; } - do_unlink (spreg, get_frame_size ()); + do_unlink (spreg, get_frame_size (), false); - expand_epilogue_reg_restore (spreg, 0); + expand_epilogue_reg_restore (spreg, false, false); /* Omit the return insn if this is for a sibcall. */ if (! need_return) @@ -1469,7 +1488,8 @@ static bool bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, tree exp ATTRIBUTE_UNUSED) { - return true; + e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); + return fkind == SUBROUTINE; } /* Emit RTL insns to initialize the variable parts of a trampoline at |