summaryrefslogtreecommitdiff
path: root/gcc/config/bfin
diff options
context:
space:
mode:
authorbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2005-11-05 11:29:33 +0000
committerbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2005-11-05 11:29:33 +0000
commit345458f37f0b8f265755372eb4148510c08b8f2a (patch)
tree5bcf7bbd2f9f6163b05471cb42850dbddbfa018f /gcc/config/bfin
parent14aa86fc690c30e2dbc9cf9b73e6b07b9dfb0178 (diff)
downloadgcc-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.c92
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