From ac55736a0a271f62a2ed018a8d34039d6f458f60 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Tue, 8 Apr 2003 17:31:24 +0000 Subject: [PATCH] sh.h (NORMAL_MODE): If interrupt handler and TARGET_FMOVD, this is FP_MODE_DOUBLE . * 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. From-SVN: r65379 --- gcc/ChangeLog | 13 ++++++++++++ gcc/config/sh/sh.c | 52 ++++++++++++++++++++++++++++++++++++---------- gcc/config/sh/sh.h | 3 ++- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c2b24c357e1..9d48969342f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2003-04-08 J"orn Rennecke + + * 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 * config/rs6000/rs6000.c (rs6000_init_builtins): Set opaque types diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index e939cbb5807..6cad65136eb 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -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, ®_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, + ®_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; diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 1b2f3816e1c..35fa7c6a157 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -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) \