+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
#include "real.h"
#include "langhooks.h"
#include "basic-block.h"
+#include "ra.h"
int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
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));
/* 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, ®_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);
}
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))
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)
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])
{
(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 ());
int save_flags = target_flags;
int frame_size;
+ int fpscr_deferred = 0;
d = calc_live_regs (&live_regs_mask);
/* 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)
{
{
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,
+ ®_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;