bfin.c (n_dregs_to_save, [...]): New argument IS_INTHANDLER; all callers changed.
authorBernd Schmidt <bernd.schmidt@analog.com>
Sat, 5 Nov 2005 11:29:33 +0000 (11:29 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Sat, 5 Nov 2005 11:29:33 +0000 (11:29 +0000)
* 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.

From-SVN: r106526

gcc/ChangeLog
gcc/config/bfin/bfin.c

index 7f8e742789c1ae18c8db443fe63e82f6fc264417..b556cc57bfe20a5ae0705e5c0720d9cdba804127 100644 (file)
@@ -1,3 +1,16 @@
+2005-11-05  Bernd Schmidt  <bernd.schmidt@analog.com>
+
+       * 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.
+
 2005-11-05  Jan Hubicka  <jh@suse.cz>
 
        PR rtl-optimization/23490
index 18092ad767d67bf6297bfa48ce24032af0e8b69c..be028f74528277f07ead54f06159fa92f7e7d206 100644 (file)
@@ -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;
 }
 \f
 /* Emit RTL insns to initialize the variable parts of a trampoline at