* sh.h (NORMAL_MODE): If interrupt handler and TARGET_FMOVD,
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 8 Apr 2003 17:31:24 +0000 (17:31 +0000)
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 8 Apr 2003 17:31:24 +0000 (17:31 +0000)
this is FP_MODE_DOUBLE .
* sh.c (ra.h): #include.
(push_regs): Add second parameter.  Changed all callers.
If necessary, set fpscr before saving floating point registers.
(calc_live_regs): If interrupt handler and TARGET_FMOVD, always
do saves / restores with SZ == 1.
(sh_expand_prologue): If interrupt handler, don't use gen_toggle_sz.
(sh_expand_epilogue): Likewise.  For TARGET_FMOVD, if floating point
registers are being restored, restore FPSCR only after restoring them.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65379 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/sh/sh.c
gcc/config/sh/sh.h

index c2b24c3..9d48969 100644 (file)
@@ -1,3 +1,16 @@
+2003-04-08  J"orn Rennecke <joern.rennecke@superh.com>
+
+       * sh.h (NORMAL_MODE): If interrupt handler and TARGET_FMOVD,
+       this is FP_MODE_DOUBLE .
+       * sh.c (ra.h): #include.
+       (push_regs): Add second parameter.  Changed all callers.
+       If necessary, set fpscr before saving floating point registers.
+       (calc_live_regs): If interrupt handler and TARGET_FMOVD, always
+       do saves / restores with SZ == 1.
+       (sh_expand_prologue): If interrupt handler, don't use gen_toggle_sz.
+       (sh_expand_epilogue): Likewise.  For TARGET_FMOVD, if floating point
+       registers are being restored, restore FPSCR only after restoring them.
+
 2003-04-08  Aldy Hernandez  <aldyh@redhat.com>
 
         * config/rs6000/rs6000.c (rs6000_init_builtins): Set opaque types
index e939cbb..6cad651 100644 (file)
@@ -46,6 +46,7 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "langhooks.h"
 #include "basic-block.h"
+#include "ra.h"
 
 int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
 
@@ -189,7 +190,7 @@ static void output_stack_adjust PARAMS ((int, rtx, int, rtx (*) (rtx)));
 static rtx frame_insn PARAMS ((rtx));
 static rtx push PARAMS ((int));
 static void pop PARAMS ((int));
-static void push_regs PARAMS ((HARD_REG_SET *));
+static void push_regs PARAMS ((HARD_REG_SET *, int));
 static int calc_live_regs PARAMS ((HARD_REG_SET *));
 static void mark_use PARAMS ((rtx, rtx *));
 static HOST_WIDE_INT rounded_frame_size PARAMS ((int));
@@ -4658,17 +4659,36 @@ pop (rn)
 /* Generate code to push the regs specified in the mask.  */
 
 static void
-push_regs (mask)
+push_regs (mask, interrupt_handler)
      HARD_REG_SET *mask;
+     int interrupt_handler;
 {
   int i;
+  int skip_fpscr = 0;
 
   /* Push PR last; this gives better latencies after the prologue, and
      candidates for the return delay slot when there are no general
      registers pushed.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (i != PR_REG && TEST_HARD_REG_BIT (*mask, i))
-      push (i);
+    {
+      /* If this is an interrupt handler, and the SZ bit varies,
+        and we have to push any floating point register, we need
+        to switch to the correct precision first.  */
+      if (i == FIRST_FP_REG && interrupt_handler && TARGET_FMOVD
+         && hard_regs_intersect_p (mask, &reg_class_contents[DF_REGS]))
+       {
+         HARD_REG_SET unsaved;
+
+         push (FPSCR_REG);
+         COMPL_HARD_REG_SET(unsaved, *mask);
+         fpscr_set_from_mem (NORMAL_MODE (FP_MODE), unsaved);
+         skip_fpscr = 1;
+       }
+      if (i != PR_REG
+         && (i != FPSCR_REG || ! skip_fpscr)
+         && TEST_HARD_REG_BIT (*mask, i))
+       push (i);
+    }
   if (TEST_HARD_REG_BIT (*mask, PR_REG))
     push (PR_REG);
 }
@@ -4693,8 +4713,11 @@ calc_live_regs (live_regs_mask)
 
   for (count = 0; 32 * count < FIRST_PSEUDO_REGISTER; count++)
     CLEAR_HARD_REG_SET (*live_regs_mask);
+  if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler
+      && regs_ever_live[FPSCR_REG])
+    target_flags &= ~FPU_SINGLE_BIT;
   /* If we can save a lot of saves by switching to double mode, do that.  */
-  if (TARGET_SH4 && TARGET_FMOVD && TARGET_FPU_SINGLE)
+  else if (TARGET_SH4 && TARGET_FMOVD && TARGET_FPU_SINGLE)
     for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
       if (regs_ever_live[reg] && regs_ever_live[reg+1]
          && (! call_used_regs[reg] || (interrupt_handler && ! pragma_trapa))
@@ -4911,7 +4934,7 @@ sh_expand_prologue ()
   d = calc_live_regs (&live_regs_mask);
   /* ??? Maybe we could save some switching if we can move a mode switch
      that already happens to be at the function start into the prologue.  */
-  if (target_flags != save_flags)
+  if (target_flags != save_flags && ! current_function_interrupt)
     emit_insn (gen_toggle_sz ());
     
   if (TARGET_SH5)
@@ -5068,7 +5091,7 @@ sh_expand_prologue ()
        abort ();
     }
   else
-    push_regs (&live_regs_mask);
+    push_regs (&live_regs_mask, current_function_interrupt);
 
   if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
     {
@@ -5102,7 +5125,7 @@ sh_expand_prologue ()
                 (GEN_INT (-SHMEDIA_REGS_STACK_ADJUST ())));
     }
 
-  if (target_flags != save_flags)
+  if (target_flags != save_flags && ! current_function_interrupt)
     {
       rtx insn = emit_insn (gen_toggle_sz ());
 
@@ -5143,6 +5166,7 @@ sh_expand_epilogue ()
 
   int save_flags = target_flags;
   int frame_size;
+  int fpscr_deferred = 0;
 
   d = calc_live_regs (&live_regs_mask);
 
@@ -5188,7 +5212,7 @@ sh_expand_epilogue ()
 
   /* Pop all the registers.  */
 
-  if (target_flags != save_flags)
+  if (target_flags != save_flags && ! current_function_interrupt)
     emit_insn (gen_toggle_sz ());
   if (TARGET_SH5)
     {
@@ -5341,11 +5365,17 @@ sh_expand_epilogue ()
     {
       int j = (FIRST_PSEUDO_REGISTER - 1) - i;
 
-      if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
+      if (j == FPSCR_REG && current_function_interrupt && TARGET_FMOVD
+         && hard_regs_intersect_p (&live_regs_mask,
+                                   &reg_class_contents[DF_REGS]))
+       fpscr_deferred = 1;
+      else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
        pop (j);
+      if (j == FIRST_FP_REG && fpscr_deferred)
+       pop (FPSCR_REG);
     }
  finish:
-  if (target_flags != save_flags)
+  if (target_flags != save_flags && ! current_function_interrupt)
     emit_insn (gen_toggle_sz ());
   target_flags = save_flags;
 
index 1b2f381..35fa7c6 100644 (file)
@@ -3292,7 +3292,8 @@ extern int rtx_equal_function_value_matters;
   (TARGET_FPU_SINGLE ? FP_MODE_SINGLE : FP_MODE_DOUBLE)
 
 #define NORMAL_MODE(ENTITY) \
-  (sh_cfun_interrupt_handler_p () ? FP_MODE_NONE \
+  (sh_cfun_interrupt_handler_p () \
+   ? (TARGET_FMOVD ? FP_MODE_DOUBLE : FP_MODE_NONE) \
    : ACTUAL_NORMAL_MODE (ENTITY))
 
 #define EPILOGUE_USES(REGNO)       ((TARGET_SH2E || TARGET_SH4)                \