re PR target/53513 ([SH] Add support for fpchg insn and improve fenv support)
authorOleg Endo <olegendo@gcc.gnu.org>
Thu, 16 Oct 2014 10:58:36 +0000 (10:58 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Thu, 16 Oct 2014 10:58:36 +0000 (10:58 +0000)
gcc/
PR target/53513
* config/sh/sh-protos.h (emit_sf_insn, emit_df_insn, expand_sf_unop,
expand_sf_binop, expand_df_unop, expand_df_binop): Remove.

* config/sh/sh.c (sh_emit_set_t_insn): Adjust generated insn pattern
to match fp insn patterns.
(calc_live_regs): Add FPSCR_MODES_REG and FPSCR_STAT_REG to the ignore
list.
(emit_sf_insn, emit_df_insn, expand_sf_unop, expand_sf_binop,
expand_df_unop, expand_df_binop): Remove.
(sh_conditional_register_usage): Mark FPSCR_MODES_REG and
FPSCR_STAT_REG as not call clobbered.
(sh_emit_mode_set): Emit fpscr store-modify-load sequence instead of
invoking fpscr_set_from_mem.

* config/sh/sh.h (MAX_REGISTER_NAME_LENGTH): Increase to 6.
(SH_REGISTER_NAMES_INITIALIZER): Add names for FPSCR_MODES_REG and
FPSCR_STAT_REG.
(REGISTER_NAMES): Adjust.
(SPECIAL_REGISTER_P): Add FPSCR_MODES_REG and FPSCR_STAT_REG.
(FIRST_PSEUDO_REGISTER): Increase to 156.
(DWARF_FRAME_REGISTERS): Define as 153 to keep the original value.
(FIXED_REGISTERS, CALL_USED_REGISTERS): Add FPSCR_MODES_REG and
FPSCR_STAT_REG.
(REG_CLASS_CONTENTS): Adjust ALL_REGS bit mask to include
FPSCR_MODES_REG and FPSCR_STAT_REG.
(REG_ALLOC_ORDER): Add FPSCR_MODES_REG and FPSCR_STAT_REG.

* config/sh/sh.md (FPSCR_MODES_REG, FPSCR_STAT_REG, FPSCR_PR,
FPSCR_SZ): Add new constants.
(UNSPECV_FPSCR_MODES, UNSPECV_FPSCR_STAT): Add new unspecv constants.

(movpsi): Use TARGET_FPU_ANY condition, invoke gen_fpu_switch.
(fpu_switch): Add use and set of FPSCR_STAT_REG and FPSCR_MODES_REG.
Use TARGET_FPU_ANY condition.
(fpu_switch peephole2): Remove.
(fpu_switch split): Use simple_mem_operand to capture the mem and
adjust split implementation.
(extend_psi_si, truncate_si_psi): New insns.
(toggle_sz, toggle_pr): Use FPSCR_SZ, FPSCR_PR constants.  Add
set of FPSCR_MODES_REG.

(push_e, push_4, pop_e, pop_4, movdf_i4, reload_indf__frn, movsf_ie,
reload_insf__frn, force_mode_for_call, calli, calli_tbr_rel,
calli_pcrel, call_pcrel, call_compact, call_compact_rettramp,
call_valuei, call_valuei_tbr_rel, call_valuei_pcrel, call_value_pcrel,
call_value_compact, call_value_compact_rettramp, call,
call_pop_compact, call_pop_compact_rettramp, call_value, sibcalli,
sibcalli_pcrel, sibcalli_thunk, sibcall_pcrel, sibcall_compact,
sibcall, sibcall_valuei, sibcall_valuei_pcrel, sibcall_value_pcrel,
sibcall_value_compact, sibcall_value, call_value_pop_compact,
call_value_pop_compact_rettramp, various unnamed splits):
Replace use of FPSCR_REG with use of FPSCR_MODES_REG.  Adjust gen_*
function uses.

(floatsisf2_i4, *floatsisf2_ie): Merge into floatsisf2_i4.
(fix_truncsfsi2_i4, *fixsfsi): Merge into fix_truncsfsi2_i4.
(cmpgtsf_t, cmpgtsf_t_i4): Merge into cmpgtsf_t.
(cmpeqsf_t, cmpeqsf_t_i4): Merge into cmpeqsf_t.
(ieee_ccmpeqsf_t, *ieee_ccmpeqsf_t_4): Merge into ieee_ccmpeqsf_t.

(udivsi3_i4, divsi3_i4, addsf3_i, subsf3_i, mulsf3_i, fmasf4_i,
*fmasf4, divsf3_i, floatsisf2_i4, fix_truncsfsi2_i4, cmpgtsf_t,
cmpeqsf_t, ieee_ccmpeqsf_t, sqrtsf2_i, rsqrtsf2, fsca, adddf3_i,
subdf3_i, muldf3_i, divdf3_i, floatsidf2_i, fix_truncdfsi2_i,
cmpgtdf_t, cmpeqdf_t, *ieee_ccmpeqdf_t, sqrtdf2_i, extendsfdf2_i4,
truncdfsf2_i4): Replace use of FPSCR_REG with clobber of FPSCR_STAT_REG
and use of FPSCR_MODES_REG.  Adjust gen_* function uses.

gcc/testsuite/
PR target/53513
* gcc.target/sh/pr54680.c: Adjust matching of lds insn.

From-SVN: r216307

gcc/ChangeLog
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr54680.c

index ed426f56d27757867957857444eef7ec83c95812..7f79791f9ce6e1296d1fb1cd889d6141913fe7f8 100644 (file)
@@ -1,3 +1,74 @@
+2014-10-16  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/53513
+       * config/sh/sh-protos.h (emit_sf_insn, emit_df_insn, expand_sf_unop,
+       expand_sf_binop, expand_df_unop, expand_df_binop): Remove.
+
+       * config/sh/sh.c (sh_emit_set_t_insn): Adjust generated insn pattern
+       to match fp insn patterns.
+       (calc_live_regs): Add FPSCR_MODES_REG and FPSCR_STAT_REG to the ignore
+       list.
+       (emit_sf_insn, emit_df_insn, expand_sf_unop, expand_sf_binop,
+       expand_df_unop, expand_df_binop): Remove.
+       (sh_conditional_register_usage): Mark FPSCR_MODES_REG and
+       FPSCR_STAT_REG as not call clobbered.
+       (sh_emit_mode_set): Emit fpscr store-modify-load sequence instead of
+       invoking fpscr_set_from_mem.
+
+       * config/sh/sh.h (MAX_REGISTER_NAME_LENGTH): Increase to 6.
+       (SH_REGISTER_NAMES_INITIALIZER): Add names for FPSCR_MODES_REG and
+       FPSCR_STAT_REG.
+       (REGISTER_NAMES): Adjust.
+       (SPECIAL_REGISTER_P): Add FPSCR_MODES_REG and FPSCR_STAT_REG.
+       (FIRST_PSEUDO_REGISTER): Increase to 156.
+       (DWARF_FRAME_REGISTERS): Define as 153 to keep the original value.
+       (FIXED_REGISTERS, CALL_USED_REGISTERS): Add FPSCR_MODES_REG and
+       FPSCR_STAT_REG.
+       (REG_CLASS_CONTENTS): Adjust ALL_REGS bit mask to include
+       FPSCR_MODES_REG and FPSCR_STAT_REG.
+       (REG_ALLOC_ORDER): Add FPSCR_MODES_REG and FPSCR_STAT_REG.
+
+       * config/sh/sh.md (FPSCR_MODES_REG, FPSCR_STAT_REG, FPSCR_PR,
+       FPSCR_SZ): Add new constants.
+       (UNSPECV_FPSCR_MODES, UNSPECV_FPSCR_STAT): Add new unspecv constants.
+
+       (movpsi): Use TARGET_FPU_ANY condition, invoke gen_fpu_switch.
+       (fpu_switch): Add use and set of FPSCR_STAT_REG and FPSCR_MODES_REG.
+       Use TARGET_FPU_ANY condition.
+       (fpu_switch peephole2): Remove.
+       (fpu_switch split): Use simple_mem_operand to capture the mem and
+       adjust split implementation.
+       (extend_psi_si, truncate_si_psi): New insns.
+       (toggle_sz, toggle_pr): Use FPSCR_SZ, FPSCR_PR constants.  Add
+       set of FPSCR_MODES_REG.
+
+       (push_e, push_4, pop_e, pop_4, movdf_i4, reload_indf__frn, movsf_ie,
+       reload_insf__frn, force_mode_for_call, calli, calli_tbr_rel,
+       calli_pcrel, call_pcrel, call_compact, call_compact_rettramp,
+       call_valuei, call_valuei_tbr_rel, call_valuei_pcrel, call_value_pcrel,
+       call_value_compact, call_value_compact_rettramp, call,
+       call_pop_compact, call_pop_compact_rettramp, call_value, sibcalli,
+       sibcalli_pcrel, sibcalli_thunk, sibcall_pcrel, sibcall_compact,
+       sibcall, sibcall_valuei, sibcall_valuei_pcrel, sibcall_value_pcrel,
+       sibcall_value_compact, sibcall_value, call_value_pop_compact,
+       call_value_pop_compact_rettramp, various unnamed splits):
+       Replace use of FPSCR_REG with use of FPSCR_MODES_REG.  Adjust gen_*
+       function uses.
+
+       (floatsisf2_i4, *floatsisf2_ie): Merge into floatsisf2_i4.
+       (fix_truncsfsi2_i4, *fixsfsi): Merge into fix_truncsfsi2_i4.
+       (cmpgtsf_t, cmpgtsf_t_i4): Merge into cmpgtsf_t.
+       (cmpeqsf_t, cmpeqsf_t_i4): Merge into cmpeqsf_t.
+       (ieee_ccmpeqsf_t, *ieee_ccmpeqsf_t_4): Merge into ieee_ccmpeqsf_t.
+
+       (udivsi3_i4, divsi3_i4, addsf3_i, subsf3_i, mulsf3_i, fmasf4_i,
+       *fmasf4, divsf3_i, floatsisf2_i4, fix_truncsfsi2_i4, cmpgtsf_t,
+       cmpeqsf_t, ieee_ccmpeqsf_t, sqrtsf2_i, rsqrtsf2, fsca, adddf3_i,
+       subdf3_i, muldf3_i, divdf3_i, floatsidf2_i, fix_truncdfsi2_i,
+       cmpgtdf_t, cmpeqdf_t, *ieee_ccmpeqdf_t, sqrtdf2_i, extendsfdf2_i4,
+       truncdfsf2_i4): Replace use of FPSCR_REG with clobber of FPSCR_STAT_REG
+       and use of FPSCR_MODES_REG.  Adjust gen_* function uses.
+
 2014-10-16  Martin Liska  <mliska@suse.cz>
            Jan Hubicka  <hubicka@ucw.cz>
 
index 0839e94317bdc41115fdb30c010212c0075a681a..c12a8964d7e3e11569d2c1e00ab0a8f88940210e 100644 (file)
@@ -112,8 +112,6 @@ extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool);
 extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int);
 extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
 extern bool nonpic_symbol_mentioned_p (rtx);
-extern void emit_sf_insn (rtx);
-extern void emit_df_insn (rtx);
 extern void output_pic_addr_const (FILE *, rtx);
 extern bool expand_block_move (rtx *);
 extern void prepare_move_operands (rtx[], enum machine_mode mode);
@@ -150,10 +148,6 @@ extern void final_prescan_insn (rtx_insn *, rtx *, int);
 extern enum tls_model tls_symbolic_operand (rtx, enum machine_mode);
 extern bool system_reg_operand (rtx, enum machine_mode);
 extern bool reg_unused_after (rtx, rtx_insn *);
-extern void expand_sf_unop (rtx (*)(rtx, rtx, rtx), rtx *);
-extern void expand_sf_binop (rtx (*)(rtx, rtx, rtx, rtx), rtx *);
-extern void expand_df_unop (rtx (*)(rtx, rtx, rtx), rtx *);
-extern void expand_df_binop (rtx (*)(rtx, rtx, rtx, rtx), rtx *);
 extern int sh_insn_length_adjustment (rtx_insn *);
 extern bool sh_can_redirect_branch (rtx_insn *, rtx_insn *);
 extern void sh_expand_unop_v2sf (enum rtx_code, rtx, rtx);
index fdf61de3c630b58e50d314ce22fc4ff2c91e2d01..065ac265fee3be8f50d6bbdfa2cd01663b58c0de 100644 (file)
@@ -2281,20 +2281,20 @@ sh_eval_treg_value (rtx op)
   return t ^ (cmpval == cmpop);
 }
 
-/* Emit INSN, possibly in a PARALLEL with an USE of fpscr for SH4.  */
-
+/* Emit INSN, possibly in a PARALLEL with an USE/CLOBBER of FPSCR bits in case
+   of floating-point comparisons.  */
 static void
 sh_emit_set_t_insn (rtx insn, enum machine_mode mode)
 {
-  if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
+  if (TARGET_FPU_ANY && GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_CODE (insn) != PARALLEL)
     {
       insn = gen_rtx_PARALLEL (VOIDmode,
-                      gen_rtvec (2, insn,
-                                 gen_rtx_USE (VOIDmode, get_fpscr_rtx ())));
-      (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);
+         gen_rtvec (3, insn,
+             gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, FPSCR_STAT_REG)),
+             gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FPSCR_MODES_REG))));
     }
-  else
-    emit_insn (insn);
+  emit_insn (insn);
 }
 
 /* Prepare the operands for an scc instruction; make sure that the
@@ -7250,6 +7250,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
             && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
             && reg != RETURN_ADDRESS_POINTER_REGNUM
             && reg != T_REG && reg != GBR_REG
+            && reg != FPSCR_MODES_REG && reg != FPSCR_STAT_REG
             /* Push fpscr only on targets which have FPU */
             && (reg != FPSCR_REG || TARGET_FPU_ANY))
          : (/* Only push those regs which are used and need to be saved.  */
@@ -10070,44 +10071,6 @@ emit_fpu_switch (rtx scratch, int index)
   dst = get_fpscr_rtx ();
   emit_move_insn (dst, src);
 }
-
-void
-emit_sf_insn (rtx pat)
-{
-  emit_insn (pat);
-}
-
-void
-emit_df_insn (rtx pat)
-{
-  emit_insn (pat);
-}
-
-void
-expand_sf_unop (rtx (*fun) (rtx, rtx, rtx), rtx *operands)
-{
-  emit_sf_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ()));
-}
-
-void
-expand_sf_binop (rtx (*fun) (rtx, rtx, rtx, rtx), rtx *operands)
-{
-  emit_sf_insn ((*fun) (operands[0], operands[1], operands[2],
-                        get_fpscr_rtx ()));
-}
-
-void
-expand_df_unop (rtx (*fun) (rtx, rtx, rtx), rtx *operands)
-{
-  emit_df_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ()));
-}
-
-void
-expand_df_binop (rtx (*fun) (rtx, rtx, rtx, rtx), rtx *operands)
-{
-  emit_df_insn ((*fun) (operands[0], operands[1], operands[2],
-                       get_fpscr_rtx ()));
-}
 \f
 static rtx get_free_reg (HARD_REG_SET);
 
@@ -13308,6 +13271,9 @@ sh_conditional_register_usage (void)
     for (regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++)
       if (! fixed_regs[regno] && call_really_used_regs[regno])
        SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno);
+
+  call_really_used_regs[FPSCR_MODES_REG] = 0;
+  call_really_used_regs[FPSCR_STAT_REG] = 0;
 }
 
 /* Implement TARGET_LEGITIMATE_CONSTANT_P
@@ -13659,7 +13625,7 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
 
 static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
-                 int prev_mode, HARD_REG_SET regs_live)
+                 int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
 {
   if ((TARGET_SH4A_FP || TARGET_SH4_300)
       && prev_mode != FP_MODE_NONE && prev_mode != mode)
@@ -13668,8 +13634,36 @@ sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
       if (TARGET_FMOVD)
        emit_insn (gen_toggle_sz ());
     }
-  else
-    fpscr_set_from_mem (mode, regs_live);
+  else if (mode != FP_MODE_NONE)
+    {
+      rtx tmp0 = gen_reg_rtx (PSImode);
+      rtx tmp1 = gen_reg_rtx (SImode);
+
+      emit_move_insn (tmp0, get_fpscr_rtx ());
+      emit_insn (gen_extend_psi_si (tmp1, tmp0));
+
+      rtx i = NULL;
+
+      const unsigned HOST_WIDE_INT fpbits =
+         TARGET_FMOVD ? (FPSCR_PR | FPSCR_SZ) : FPSCR_PR;
+
+      if (prev_mode != FP_MODE_NONE && prev_mode != mode)
+       i = gen_xorsi3 (tmp1, tmp1,
+                       force_reg (SImode, GEN_INT (fpbits)));
+      else if (mode == FP_MODE_SINGLE)
+       i = gen_andsi3 (tmp1, tmp1,
+                       force_reg (SImode, GEN_INT (~fpbits)));
+      else if (mode == FP_MODE_DOUBLE)
+       i = gen_iorsi3 (tmp1, tmp1,
+                       force_reg (SImode, GEN_INT (fpbits)));
+      else
+       gcc_unreachable ();
+
+      emit_insn (i);
+
+      emit_insn (gen_truncate_si_psi (tmp0, tmp1));
+      emit_move_insn (get_fpscr_rtx (), tmp0);
+    }
 }
 
 static int
index cd058f96d43f33254e3952122c096869132cc0d0..c6e16bd15e9cd5aa06804b055282299a6cb5076b 100644 (file)
@@ -574,7 +574,7 @@ extern enum sh_divide_strategy_e sh_div_strategy;
        fr4..fr11       fp args in
        fr12..fr15      call saved floating point registers  */
 
-#define MAX_REGISTER_NAME_LENGTH 5
+#define MAX_REGISTER_NAME_LENGTH 6
 extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1];
 
 #define SH_REGISTER_NAMES_INITIALIZER                                  \
@@ -598,7 +598,7 @@ extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1];
   "tr0",  "tr1",  "tr2",  "tr3",  "tr4",  "tr5",  "tr6",  "tr7",       \
   "xd0",  "xd2",  "xd4",  "xd6",  "xd8",  "xd10", "xd12", "xd14",      \
   "gbr",  "ap",          "pr",   "t",    "mach", "macl", "fpul", "fpscr",      \
-  "rap",  "sfp"                                                                \
+  "rap",  "sfp", "fpscr0", "fpscr1"                                    \
 }
 
 #define REGNAMES_ARR_INDEX_1(index) \
@@ -623,7 +623,7 @@ extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1];
   REGNAMES_ARR_INDEX_8 (128), \
   REGNAMES_ARR_INDEX_8 (136), \
   REGNAMES_ARR_INDEX_8 (144), \
-  REGNAMES_ARR_INDEX_2 (152) \
+  REGNAMES_ARR_INDEX_4 (152) \
 }
 
 #define ADDREGNAMES_SIZE 32
@@ -711,7 +711,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
 
 #define SPECIAL_REGISTER_P(REGNO) \
   ((REGNO) == GBR_REG || (REGNO) == T_REG \
-   || (REGNO) == MACH_REG || (REGNO) == MACL_REG)
+   || (REGNO) == MACH_REG || (REGNO) == MACL_REG \
+   || (REGNO) == FPSCR_MODES_REG || (REGNO) == FPSCR_STAT_REG)
 
 #define TARGET_REGISTER_P(REGNO) \
   ((int) (REGNO) >= FIRST_TARGET_REG && (int) (REGNO) <= LAST_TARGET_REG)
@@ -738,10 +739,10 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
    ? DImode \
    : SImode)
 
-#define FIRST_PSEUDO_REGISTER 154
+#define FIRST_PSEUDO_REGISTER 156
 
 /* Don't count soft frame pointer.  */
-#define DWARF_FRAME_REGISTERS (FIRST_PSEUDO_REGISTER - 1)
+#define DWARF_FRAME_REGISTERS (153)
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.
@@ -777,8 +778,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
   0,      0,      0,      0,      0,      0,      0,      0,           \
 /*"gbr",  "ap",          "pr",   "t",    "mach", "macl", "fpul", "fpscr", */   \
   1,      1,      1,      1,      1,      1,      0,      1,           \
-/*"rap",  "sfp" */                                                     \
-  1,     1,                                                            \
+/*"rap",  "sfp","fpscr0","fpscr1"  */                                  \
+  1,      1,      1,      1,                                           \
 }
 
 /* 1 for registers not available across function calls.
@@ -816,8 +817,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
   1,      1,      1,      1,      1,      1,      0,      0,           \
 /*"gbr",  "ap",          "pr",   "t",    "mach", "macl", "fpul", "fpscr", */   \
   1,      1,      1,      1,      1,      1,      1,      1,           \
-/*"rap",  "sfp" */                                                     \
-  1,     1,                                                            \
+/*"rap",  "sfp","fpscr0","fpscr1"  */                                  \
+  1,      1,      1,      1,                                           \
 }
 
 /* TARGET_CONDITIONAL_REGISTER_USAGE might want to make a register
@@ -1072,7 +1073,7 @@ enum reg_class
 /* TARGET_REGS:  */                                                    \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000ff },      \
 /* ALL_REGS:  */                                                       \
-  { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x03ffffff },      \
+  { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0fffffff },      \
 }
 
 /* The same information, inverted:
@@ -1122,7 +1123,7 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
    128,129,130,131,132,133,134,135, \
    /* Fixed registers */ \
     15, 16, 24, 25, 26, 27, 63,144, \
-   145,146,147,148,149,152,153 }
+   145,146,147,148,149,152,153,154,155  }
 
 /* The class value for index registers, and the one for base regs.  */
 #define INDEX_REG_CLASS \
index b43a104d31d4d7c2d005c9cef5cd3f768beaa7e5..e77e3aeeb791054c202ef9c0022f8c6884902de9 100644 (file)
 
   (FPSCR_REG   151)
 
+  ;; Virtual FPSCR - bits that are used by FP ops.
+  (FPSCR_MODES_REG 154)
+
+  ;; Virtual FPSCR - bits that are updated by FP ops.
+  (FPSCR_STAT_REG 155)
+
   (PIC_REG     12)
   (FP_REG      14)
   (SP_REG      15)
   (TR2_REG     130)
 
   (XD0_REG     136)
+
+  (FPSCR_PR    524288)
+  (FPSCR_SZ    1048576)
 ])
 
 (define_c_enum "unspec" [
   UNSPECV_GBR
   UNSPECV_SP_SWITCH_B
   UNSPECV_SP_SWITCH_E
+
+  UNSPECV_FPSCR_MODES
+  UNSPECV_FPSCR_STAT
 ])
 
 ;; -------------------------------------------------------------------------
    (clobber (reg:SI R1_REG))
    (clobber (reg:SI R4_REG))
    (clobber (reg:SI R5_REG))
-   (use (reg:PSI FPSCR_REG))
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
   "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
   "jsr @%1%#"
    (clobber (reg:SI PR_REG))
    (clobber (reg:DF DR0_REG))
    (clobber (reg:DF DR2_REG))
-   (use (reg:PSI FPSCR_REG))
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
   "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
   "jsr @%1%#"
@@ -6444,7 +6458,7 @@ label:
 (define_expand "push_e"
   [(parallel [(set (mem:SF (pre_dec:SI (reg:SI SP_REG)))
                   (match_operand:SF 0 "" ""))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "TARGET_SH1 && ! TARGET_SH5"
   "")
@@ -6462,7 +6476,7 @@ label:
 (define_expand "push_4"
   [(parallel [(set (mem:DF (pre_dec:SI (reg:SI SP_REG)))
                   (match_operand:DF 0 "" ""))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "TARGET_SH1 && ! TARGET_SH5"
   "")
@@ -6470,7 +6484,7 @@ label:
 (define_expand "pop_e"
   [(parallel [(set (match_operand:SF 0 "" "")
              (mem:SF (post_inc:SI (reg:SI SP_REG))))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "TARGET_SH1 && ! TARGET_SH5"
   "")
@@ -6485,7 +6499,7 @@ label:
 (define_expand "pop_4"
   [(parallel [(set (match_operand:DF 0 "" "")
                   (mem:DF (post_inc:SI (reg:SI SP_REG))))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "TARGET_SH1 && ! TARGET_SH5"
   "")
@@ -7655,8 +7669,8 @@ label:
 (define_insn "movdf_i4"
   [(set (match_operand:DF 0 "general_movdst_operand" "=d,r,d,d,m,r,r,m,!??r,!???d")
        (match_operand:DF 1 "general_movsrc_operand"  "d,r,F,m,d,FQ,m,r,d,r"))
-   (use (match_operand:PSI 2 "fpscr_operand"          "c,c,c,c,c,c,c,c,c,c"))
-   (clobber (match_scratch:SI 3                      "=X,X,&z,X,X,X,X,X,X,X"))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2                      "=X,X,&z,X,X,X,X,X,X,X"))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)
    && (arith_reg_operand (operands[0], DFmode)
        || arith_reg_operand (operands[1], DFmode))"
@@ -7711,8 +7725,8 @@ label:
 (define_split
   [(set (match_operand:DF 0 "register_operand")
        (match_operand:DF 1 "register_operand"))
-   (use (match_operand:PSI 2 "fpscr_operand"))
-   (clobber (match_scratch:SI 3))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && reload_completed
    && (true_regnum (operands[0]) < 16) != (true_regnum (operands[1]) < 16)"
   [(const_int 0)]
@@ -7728,7 +7742,7 @@ label:
   else
     tos = gen_tmp_stack_mem (DFmode,
                             gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx));
-  insn = emit_insn (gen_movdf_i4 (tos, operands[1], operands[2]));
+  insn = emit_insn (gen_movdf_i4 (tos, operands[1]));
   if (! (TARGET_SH5 && true_regnum (operands[1]) < 16))
     add_reg_note (insn, REG_INC, stack_pointer_rtx);
   if (TARGET_SH5 && true_regnum (operands[0]) < 16)
@@ -7736,7 +7750,7 @@ label:
   else
     tos = gen_tmp_stack_mem (DFmode,
                             gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
-  insn = emit_insn (gen_movdf_i4 (operands[0], tos, operands[2]));
+  insn = emit_insn (gen_movdf_i4 (operands[0], tos));
   if (TARGET_SH5 && true_regnum (operands[0]) < 16)
     emit_move_insn (stack_pointer_rtx,
                    plus_constant (Pmode, stack_pointer_rtx, 8));
@@ -7752,8 +7766,8 @@ label:
 (define_split
   [(set (match_operand:DF 0 "general_movdst_operand" "")
        (match_operand:DF 1 "general_movsrc_operand"  ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)
    && reload_completed
    && true_regnum (operands[0]) < 16
@@ -7824,18 +7838,18 @@ label:
 (define_split
   [(set (match_operand:DF 0 "register_operand" "")
        (match_operand:DF 1 "memory_operand"  ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI R0_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && reload_completed"
   [(parallel [(set (match_dup 0) (match_dup 1))
-             (use (match_dup 2))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "")
 
 (define_expand "reload_indf__frn"
   [(parallel [(set (match_operand:DF 0 "register_operand" "=a")
                   (match_operand:DF 1 "immediate_operand" "FQ"))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (match_operand:SI 2 "register_operand" "=&z"))])]
   "TARGET_SH1"
   "")
@@ -7851,8 +7865,8 @@ label:
 (define_split
   [(set (match_operand:SF 0 "register_operand" "")
        (match_operand:SF 1 "register_operand" ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "TARGET_SH2E && reload_completed
    && true_regnum (operands[0]) == true_regnum (operands[1])"
   [(set (match_dup 0) (match_dup 0))]
@@ -7862,8 +7876,8 @@ label:
 (define_split
   [(set (match_operand:DF 0 "register_operand" "")
        (match_operand:DF 1 "register_operand" ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "TARGET_SH4 && ! TARGET_FMOVD && reload_completed
    && FP_OR_XD_REGISTER_P (true_regnum (operands[0]))
    && FP_OR_XD_REGISTER_P (true_regnum (operands[1]))"
@@ -7871,17 +7885,17 @@ label:
 {
   int dst = true_regnum (operands[0]), src = true_regnum (operands[1]);
   emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, dst),
-                          gen_rtx_REG (SFmode, src), operands[2]));
+                          gen_rtx_REG (SFmode, src)));
   emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, dst + 1),
-                          gen_rtx_REG (SFmode, src + 1), operands[2]));
+                          gen_rtx_REG (SFmode, src + 1)));
   DONE;
 })
 
 (define_split
   [(set (match_operand:DF 0 "register_operand" "")
        (mem:DF (match_operand:SI 1 "register_operand" "")))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed
    && FP_OR_XD_REGISTER_P (true_regnum (operands[0]))
    && find_regno_note (insn, REG_DEAD, true_regnum (operands[1]))"
@@ -7894,20 +7908,19 @@ label:
     = change_address (mem, SFmode, gen_rtx_POST_INC (Pmode, operands[1]));
   insn = emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode,
                                               regno + SH_REG_MSW_OFFSET),
-                                 mem2, operands[2]));
+                                 mem2));
   add_reg_note (insn, REG_INC, operands[1]);
   insn = emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode,
                                               regno + SH_REG_LSW_OFFSET),
-                                 change_address (mem, SFmode, NULL_RTX),
-                                 operands[2]));
+                                 change_address (mem, SFmode, NULL_RTX)));
   DONE;
 })
 
 (define_split
   [(set (match_operand:DF 0 "register_operand" "")
        (match_operand:DF 1 "memory_operand" ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed
    && FP_OR_XD_REGISTER_P (true_regnum (operands[0]))"
   [(const_int 0)]
@@ -7930,10 +7943,10 @@ label:
       if (! arith_reg_operand (operands[1], SFmode))
        {
          XEXP (mem2, 0) = addr = gen_rtx_POST_INC (SImode, addr);
-         insn = emit_insn (gen_movsf_ie (reg0, mem2, operands[2]));
+         insn = emit_insn (gen_movsf_ie (reg0, mem2));
          add_reg_note (insn, REG_INC, XEXP (addr, 0));
          
-         emit_insn (gen_movsf_ie (reg1, operands[1], operands[2]));
+         emit_insn (gen_movsf_ie (reg1, operands[1]));
 
          /* If we have modified the stack pointer, the value that we have
             read with post-increment might be modified by an interrupt,
@@ -7948,17 +7961,17 @@ label:
       /* Fall through.  */
 
     case PLUS:
-      emit_insn (gen_movsf_ie (reg0, operands[1], operands[2]));
+      emit_insn (gen_movsf_ie (reg0, operands[1]));
       operands[1] = copy_rtx (operands[1]);
       XEXP (operands[1], 0) = plus_constant (Pmode, addr, 4);
-      emit_insn (gen_movsf_ie (reg1, operands[1], operands[2]));
+      emit_insn (gen_movsf_ie (reg1, operands[1]));
       break;
 
     case POST_INC:
-      insn = emit_insn (gen_movsf_ie (reg0, operands[1], operands[2]));
+      insn = emit_insn (gen_movsf_ie (reg0, operands[1]));
       add_reg_note (insn, REG_INC, XEXP (addr, 0));
 
-      insn = emit_insn (gen_movsf_ie (reg1, operands[1], operands[2]));
+      insn = emit_insn (gen_movsf_ie (reg1, operands[1]));
       add_reg_note (insn, REG_INC, XEXP (addr, 0));
       break;
 
@@ -7973,8 +7986,8 @@ label:
 (define_split
   [(set (match_operand:DF 0 "memory_operand" "")
        (match_operand:DF 1 "register_operand" ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
-   (clobber (match_scratch:SI 3 ""))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed
    && FP_OR_XD_REGISTER_P (true_regnum (operands[1]))"
   [(const_int 0)]
@@ -7997,12 +8010,12 @@ label:
       if (! arith_reg_operand (operands[0], SFmode))
        {
          emit_insn (gen_addsi3 (addr, addr, GEN_INT (4)));
-         emit_insn (gen_movsf_ie (operands[0], reg1, operands[2]));
+         emit_insn (gen_movsf_ie (operands[0], reg1));
 
          operands[0] = copy_rtx (operands[0]);
          XEXP (operands[0], 0) = addr = gen_rtx_PRE_DEC (SImode, addr);
          
-         insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2]));
+         insn = emit_insn (gen_movsf_ie (operands[0], reg0));
          add_reg_note (insn, REG_INC, XEXP (addr, 0));
          break;
        }
@@ -8014,12 +8027,12 @@ label:
         register component of the address.  Just emit the lower numbered
         register first, to the lower address, then the higher numbered
         register to the higher address.  */
-      emit_insn (gen_movsf_ie (operands[0], reg0, operands[2]));
+      emit_insn (gen_movsf_ie (operands[0], reg0));
 
       operands[0] = copy_rtx (operands[0]);
       XEXP (operands[0], 0) = plus_constant (Pmode, addr, 4);
 
-      emit_insn (gen_movsf_ie (operands[0], reg1, operands[2]));
+      emit_insn (gen_movsf_ie (operands[0], reg1));
       break;
 
     case PRE_DEC:
@@ -8027,10 +8040,10 @@ label:
          first (ie the word in the higher numbered register) then the
         word to go to the lower address.  */
 
-      insn = emit_insn (gen_movsf_ie (operands[0], reg1, operands[2]));
+      insn = emit_insn (gen_movsf_ie (operands[0], reg1));
       add_reg_note (insn, REG_INC, XEXP (addr, 0));
 
-      insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2]));
+      insn = emit_insn (gen_movsf_ie (operands[0], reg0));
       add_reg_note (insn, REG_INC, XEXP (addr, 0));
       break;
 
@@ -8112,7 +8125,7 @@ label:
     }
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      emit_df_insn (gen_movdf_i4 (operands[0], operands[1], get_fpscr_rtx ()));
+      emit_insn (gen_movdf_i4 (operands[0], operands[1]));
       DONE;
     }
 })
@@ -8357,12 +8370,12 @@ label:
         "=f,r,f,f,fy,f,m,r,r,m,f,y,y,rf,r,y,<,y,y")
        (match_operand:SF 1 "general_movsrc_operand"
          "f,r,G,H,FQ,mf,f,FQ,mr,r,y,f,>,fr,y,r,y,>,y"))
-   (use (match_operand:PSI 2 "fpscr_operand" "c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c"))
-   (clobber (match_scratch:SI 3 "=X,X,Bsc,Bsc,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))]
+   (use (reg:SI FPSCR_MODES_REG))
+   (clobber (match_scratch:SI 2 "=X,X,Bsc,Bsc,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))]
   "TARGET_SH2E
    && (arith_reg_operand (operands[0], SFmode) || fpul_operand (operands[0], SFmode)
        || arith_reg_operand (operands[1], SFmode) || fpul_operand (operands[1], SFmode)
-       || arith_reg_operand (operands[3], SImode))"
+       || arith_reg_operand (operands[2], SImode))"
   "@
        fmov    %1,%0
        mov     %1,%0
@@ -8441,14 +8454,14 @@ label:
 (define_split
   [(set (match_operand:SF 0 "register_operand" "")
        (match_operand:SF 1 "register_operand" ""))
-   (use (match_operand:PSI 2 "fpscr_operand" ""))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI FPUL_REG))]
   "TARGET_SH1"
   [(parallel [(set (reg:SF FPUL_REG) (match_dup 1))
-             (use (match_dup 2))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])
    (parallel [(set (match_dup 0) (reg:SF FPUL_REG))
-             (use (match_dup 2))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (scratch:SI))])]
   "")
 
@@ -8468,7 +8481,7 @@ label:
     }
   if (TARGET_SH2E)
     {
-      emit_sf_insn (gen_movsf_ie (operands[0], operands[1], get_fpscr_rtx ()));
+      emit_insn (gen_movsf_ie (operands[0], operands[1]));
       DONE;
     }
 })
@@ -8483,7 +8496,7 @@ label:
 (define_expand "reload_insf__frn"
   [(parallel [(set (match_operand:SF 0 "register_operand" "=a")
                   (match_operand:SF 1 "immediate_operand" "FQ"))
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (match_operand:SI 2 "register_operand" "=&z"))])]
   "TARGET_SH1"
   "")
@@ -8929,7 +8942,7 @@ label:
 })
 
 (define_insn "force_mode_for_call"
-  [(use (reg:PSI FPSCR_REG))]
+  [(use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SHCOMPACT"
   ""
   [(set_attr "length" "0")
@@ -8940,7 +8953,7 @@ label:
 (define_insn "calli"
   [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SH1"
 {
@@ -8962,7 +8975,7 @@ label:
 (define_insn "calli_tbr_rel"
   [(call (mem (match_operand:SI 0 "symbol_ref_operand" ""))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SH2A && sh2a_is_function_vector_call (operands[0])"
 {
@@ -8983,7 +8996,7 @@ label:
 (define_insn "calli_pcrel"
   [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI PR_REG))]
@@ -9002,7 +9015,7 @@ label:
 (define_insn_and_split "call_pcrel"
   [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" ""))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (clobber (reg:SI PR_REG))
    (clobber (match_scratch:SI 2 "=r"))]
@@ -9033,7 +9046,7 @@ label:
    (match_operand 2 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && ! (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))"
   "jsr @%0%#"
@@ -9049,7 +9062,7 @@ label:
    (match_operand 2 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI R10_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))"
@@ -9072,7 +9085,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SH1"
 {
@@ -9095,7 +9108,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" ""))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SH2A && sh2a_is_function_vector_call (operands[1])"
 {
@@ -9116,7 +9129,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI PR_REG))]
@@ -9136,7 +9149,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" ""))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (clobber (reg:SI PR_REG))
    (clobber (match_scratch:SI 3 "=r"))]
@@ -9169,7 +9182,7 @@ label:
    (match_operand 3 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && ! (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))"
   "jsr @%1%#"
@@ -9186,7 +9199,7 @@ label:
    (match_operand 3 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI R10_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))"
@@ -9210,7 +9223,7 @@ label:
   [(parallel [(call (mem:SI (match_operand 0 "arith_reg_operand" ""))
                            (match_operand 1 "" ""))
              (match_operand 2 "" "")
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (reg:SI PR_REG))])]
   ""
 {
@@ -9309,7 +9322,7 @@ label:
                                 (match_operand 3 "immediate_operand" "n")))
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && ! (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))"
   "jsr @%0%#"
@@ -9327,7 +9340,7 @@ label:
                                 (match_operand 3 "immediate_operand" "n")))
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI R10_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))"
@@ -9398,7 +9411,7 @@ label:
                   (call (mem:SI (match_operand 1 "arith_reg_operand" ""))
                                 (match_operand 2 "" "")))
              (match_operand 3 "" "")
-             (use (reg:PSI FPSCR_REG))
+             (use (reg:SI FPSCR_MODES_REG))
              (clobber (reg:SI PR_REG))])]
   ""
 {
@@ -9493,7 +9506,7 @@ label:
 (define_insn "sibcalli"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "k"))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (return)]
   "TARGET_SH1"
   "jmp @%0%#"
@@ -9507,7 +9520,7 @@ label:
   [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "k"))
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (return)]
   "TARGET_SH2"
 {
@@ -9525,7 +9538,7 @@ label:
   [(call (mem:SI (unspec:SI [(match_operand:SI 0 "symbol_ref_operand" "")]
                             UNSPEC_THUNK))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (return)]
   "TARGET_SH1"
   "bra %O0"
@@ -9539,7 +9552,7 @@ label:
 (define_insn_and_split "sibcall_pcrel"
   [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" ""))
         (match_operand 1 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (match_scratch:SI 2 "=k"))
    (return)]
   "TARGET_SH2"
@@ -9568,7 +9581,7 @@ label:
    (return)
    (use (match_operand:SI 2 "register_operand" "z,x"))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    ;; We want to make sure the `x' above will only match MACH_REG
    ;; because sibcall_epilogue may clobber MACL_REG.
    (clobber (reg:SI MACL_REG))]
@@ -9602,7 +9615,7 @@ label:
     [(call (mem:SI (match_operand 0 "arith_reg_operand" ""))
           (match_operand 1 "" ""))
      (match_operand 2 "" "")
-     (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
      (return)])]
   ""
 {
@@ -9699,7 +9712,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "register_operand" "k"))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (return)]
   "TARGET_SH1"
   "jmp @%1%#"
@@ -9714,7 +9727,7 @@ label:
        (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "k"))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (return)]
   "TARGET_SH2"
 {
@@ -9731,7 +9744,7 @@ label:
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" ""))
              (match_operand 2 "" "")))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (match_scratch:SI 3 "=k"))
    (return)]
   "TARGET_SH2"
@@ -9763,7 +9776,7 @@ label:
    (return)
    (use (match_operand:SI 3 "register_operand" "z,x"))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    ;; We want to make sure the `x' above will only match MACH_REG
    ;; because sibcall_epilogue may clobber MACL_REG.
    (clobber (reg:SI MACL_REG))]
@@ -9799,7 +9812,7 @@ label:
          (call (mem:SI (match_operand 1 "arith_reg_operand" ""))
                (match_operand 2 "" "")))
      (match_operand 3 "" "")
-     (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
      (return)])]
   ""
 {
@@ -9905,7 +9918,7 @@ label:
    (match_operand 3 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && ! (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))"
   "jsr @%1%#"
@@ -9924,7 +9937,7 @@ label:
    (match_operand 3 "immediate_operand" "n")
    (use (reg:SI R0_REG))
    (use (reg:SI R1_REG))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (clobber (reg:SI R10_REG))
    (clobber (reg:SI PR_REG))]
   "TARGET_SHCOMPACT && (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))"
@@ -10430,7 +10443,7 @@ label:
        (call:SI (mem:SI (unspec:SI [(match_operand:SI 1 "" "")]
                                  UNSPEC_TLSGD))
              (const_int 0)))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (clobber (reg:SI PR_REG))
    (clobber (scratch:SI))]
@@ -10457,7 +10470,7 @@ label:
        (call:SI (mem:SI (unspec:SI [(match_operand:SI 1 "" "")]
                                  UNSPEC_TLSLDM))
              (const_int 0)))
-   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI FPSCR_MODES_REG))
    (use (reg:SI PIC_REG))
    (clobber (reg:SI PR_REG))
    (clobber (scratch:SI))]
@@ -12199,8 +12212,11 @@ label:
 (define_expand "movpsi"
   [(set (match_operand:PSI 0 "register_operand" "")
        (match_operand:PSI 1 "general_movsrc_operand" ""))]
-  "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
-  "")
+  "TARGET_FPU_ANY"
+{
+  emit_insn (gen_fpu_switch (operands[0], operands[1]));
+  DONE;
+})
 
 ;; The c / m alternative is a fake to guide reload to load directly into
 ;; fpscr, since reload doesn't know how to use post-increment.
@@ -12211,8 +12227,14 @@ label:
 ;; like a mac -> gpr move.
 (define_insn "fpu_switch"
   [(set (match_operand:PSI 0 "general_movdst_operand" "=c,c,r,c,c,r,m,r,<")
-       (match_operand:PSI 1 "general_movsrc_operand" "c,>,m,m,r,r,r,!c,c"))]
-  "TARGET_SH2E
+       (match_operand:PSI 1 "general_movsrc_operand" " c,>,m,m,r,r,r,!c,c"))
+   (use (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))
+   (set (reg:SI FPSCR_STAT_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_STAT))
+   (set (reg:SI FPSCR_MODES_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
+  "TARGET_FPU_ANY
    && (! reload_completed
        || true_regnum (operands[0]) != FPSCR_REG
        || !MEM_P (operands[1])
@@ -12231,43 +12253,51 @@ label:
    (set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store,
                     mac_gp,fstore")])
 
-(define_peephole2
+(define_split
   [(set (reg:PSI FPSCR_REG)
-       (mem:PSI (match_operand:SI 0 "register_operand" "")))]
-  "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && peep2_reg_dead_p (1, operands[0])"
+        (match_operand:PSI 0 "simple_mem_operand"))
+   (use (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))
+   (set (reg:SI FPSCR_STAT_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_STAT))
+   (set (reg:SI FPSCR_MODES_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
+  "TARGET_FPU_ANY && reload_completed"
   [(const_int 0)]
 {
-  rtx fpscr, mem, new_insn;
+  rtx addrreg = XEXP (operands[0], 0);
+  rtx mem = replace_equiv_address (operands[0],
+                                  gen_rtx_POST_INC (Pmode, addrreg));
 
-  fpscr = SET_DEST (PATTERN (curr_insn));
-  mem = SET_SRC (PATTERN (curr_insn));
-  mem = replace_equiv_address (mem, gen_rtx_POST_INC (Pmode, operands[0]));
+  add_reg_note (emit_insn (gen_fpu_switch (get_fpscr_rtx (), mem)),
+               REG_INC, addrreg);
 
-  new_insn = emit_insn (gen_fpu_switch (fpscr, mem));
-  add_reg_note (new_insn, REG_INC, operands[0]);
-  DONE;
+  /* Modify the address reg to compensate for the forced post-inc mode.
+     If the address reg becomes dead afterwards, the add will be eliminated
+     automatically.  */
+  emit_insn (gen_addsi3 (addrreg, addrreg, GEN_INT (-4)));
 })
 
-(define_split
-  [(set (reg:PSI FPSCR_REG)
-       (mem:PSI (match_operand:SI 0 "register_operand" "")))]
-  "(TARGET_SH4 || TARGET_SH2A_DOUBLE)
-   && (flag_peephole2 ? epilogue_completed : reload_completed)"
-  [(const_int 0)]
-{
-  rtx fpscr, mem, new_insn;
-
-  fpscr = SET_DEST (PATTERN (curr_insn));
-  mem = SET_SRC (PATTERN (curr_insn));
-  mem = replace_equiv_address (mem, gen_rtx_POST_INC (Pmode, operands[0]));
+;; The 'extend_psi_si' and 'truncate_si_psi' insns are needed since we can't
+;; do logic on PSImode.  Adding PSImode logic patterns works, but loading
+;; a PSImode constant causes a double indirection, since the SH constant pool
+;; is not aware of it.
+;; FIXME: We could treat the FPSCR reg as SImode, but currently this causes
+;; additional troubles.
+(define_insn "extend_psi_si"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+       (zero_extend:SI (match_operand:PSI 1 "arith_reg_operand" "0")))]
+  "TARGET_SH1"
+  ""
+  [(set_attr "length" "0")])
 
-  new_insn = emit_insn (gen_fpu_switch (fpscr, mem));
-  add_reg_note (new_insn, REG_INC, operands[0]);
+(define_insn "truncate_si_psi"
+  [(set (match_operand:PSI 0 "arith_reg_dest" "=r")
+       (truncate:PSI (match_operand:SI 1 "arith_reg_operand" "0")))]
+  "TARGET_SH1"
+  ""
+  [(set_attr "length" "0")])
 
-  if (!find_regno_note (curr_insn, REG_DEAD, true_regnum (operands[0])))
-    emit_insn (gen_addsi3 (operands[0], operands[0], GEN_INT (-4)));
-  DONE;
-})
 
 ;; ??? This uses the fp unit, but has no type indicating that.
 ;; If we did that, this would either give a bogus latency or introduce
@@ -12277,7 +12307,9 @@ label:
 ;; current setting.
 (define_insn "toggle_sz"
   [(set (reg:PSI FPSCR_REG)
-       (xor:PSI (reg:PSI FPSCR_REG) (const_int 1048576)))]
+       (xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_SZ)))
+   (set (reg:SI FPSCR_MODES_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fschg"
   [(set_attr "type" "fpscr_toggle") (set_attr "fp_set" "unknown")])
@@ -12286,7 +12318,9 @@ label:
 
 (define_insn "toggle_pr"
   [(set (reg:PSI FPSCR_REG)
-       (xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
+       (xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_PR)))
+   (set (reg:SI FPSCR_MODES_REG)
+       (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
   "TARGET_SH4A_FP"
   "fpchg"
   [(set_attr "type" "fpscr_toggle")])
@@ -12299,7 +12333,7 @@ label:
 {
   if (TARGET_SH2E)
     {
-      expand_sf_binop (&gen_addsf3_i, operands);
+      emit_insn (gen_addsf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12398,7 +12432,8 @@ label:
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (plus:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0")
                 (match_operand:SF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E"
   "fadd        %2,%0"
   [(set_attr "type" "fp")
@@ -12412,7 +12447,7 @@ label:
 {
   if (TARGET_SH2E)
     {
-      expand_sf_binop (&gen_subsf3_i, operands);
+      emit_insn (gen_subsf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12429,7 +12464,8 @@ label:
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (minus:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")
                 (match_operand:SF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E"
   "fsub        %2,%0"
   [(set_attr "type" "fp")
@@ -12443,8 +12479,7 @@ label:
 {
   if (TARGET_SH2E)
     {
-      emit_insn (gen_mulsf3_i (operands[0], operands[1], operands[2],
-                get_fpscr_rtx ()));
+      emit_insn (gen_mulsf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12461,7 +12496,8 @@ label:
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0")
                 (match_operand:SF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E"
   "fmul        %2,%0"
   [(set_attr "type" "fp")
@@ -12477,8 +12513,8 @@ label:
 {
   if (TARGET_SH2E)
     {
-      emit_sf_insn (gen_fmasf4_i (operands[0], operands[1], operands[2],
-                                 operands[3], get_fpscr_rtx ()));
+      emit_insn (gen_fmasf4_i (operands[0], operands[1], operands[2],
+                              operands[3]));
       DONE;
     }
 })
@@ -12488,7 +12524,8 @@ label:
        (fma:SF (match_operand:SF 1 "fp_arith_reg_operand" "w")
                (match_operand:SF 2 "fp_arith_reg_operand" "f")
                (match_operand:SF 3 "fp_arith_reg_operand" "0")))
-   (use (match_operand:PSI 4 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E"
   "fmac        %1,%2,%0"
   [(set_attr "type" "fp")
@@ -12511,13 +12548,15 @@ label:
        (plus:SF (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%w")
                          (match_operand:SF 2 "fp_arith_reg_operand" "f"))
                 (match_operand:SF 3 "arith_reg_operand" "0")))
-   (use (match_operand:PSI 4 "fpscr_operand"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E && flag_fp_contract_mode != FP_CONTRACT_OFF"
   "fmac        %1,%2,%0"
   "&& can_create_pseudo_p ()"
   [(parallel [(set (match_dup 0)
                   (fma:SF (match_dup 1) (match_dup 2) (match_dup 3)))
-             (use (match_dup 4))])]
+             (clobber (reg:SI FPSCR_STAT_REG))
+             (use (reg:SI FPSCR_MODES_REG))])]
 {
   /* Change 'b * a + a' into 'a * b + a'.
      This is better for register allocation.  */
@@ -12548,7 +12587,7 @@ label:
 {
   if (TARGET_SH2E)
     {
-      expand_sf_binop (&gen_divsf3_i, operands);
+      emit_insn (gen_divsf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12565,7 +12604,8 @@ label:
   [(set (match_operand:SF 0 "fp_arith_reg_dest" "=f")
        (div:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")
                 (match_operand:SF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH2E"
   "fdiv        %2,%0"
   [(set_attr "type" "fdiv")
@@ -12583,10 +12623,9 @@ label:
        (float:SF (match_operand:SI 1 "fpul_operand" "")))]
   "TARGET_SH2E || TARGET_SHMEDIA_FPU"
 {
-  if (TARGET_SH4 || TARGET_SH2A_SINGLE)
+  if (!TARGET_SHMEDIA_FPU)
     {
-      emit_sf_insn (gen_floatsisf2_i4 (operands[0], operands[1],
-                                      get_fpscr_rtx ()));
+      emit_insn (gen_floatsisf2_i4 (operands[0], operands[1]));
       DONE;
     }
 })
@@ -12601,19 +12640,13 @@ label:
 (define_insn "floatsisf2_i4"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (float:SF (match_operand:SI 1 "fpul_operand" "y")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
-  "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_SH2E"
   "float       %1,%0"
   [(set_attr "type" "fp")
    (set_attr "fp_mode" "single")])
 
-(define_insn "*floatsisf2_ie"
-  [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
-       (float:SF (match_operand:SI 1 "fpul_operand" "y")))]
-  "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-  "float       %1,%0"
-  [(set_attr "type" "fp")])
-
 (define_insn "fix_truncsfdi2"
   [(set (match_operand:DI 0 "fp_arith_reg_dest" "=f")
        (fix:DI (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
@@ -12626,10 +12659,9 @@ label:
        (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
   "TARGET_SH2E || TARGET_SHMEDIA_FPU"
 {
-  if (TARGET_SH4 || TARGET_SH2A_SINGLE)
+  if (!TARGET_SHMEDIA_FPU)
     {
-      emit_sf_insn (gen_fix_truncsfsi2_i4 (operands[0], operands[1],
-                                          get_fpscr_rtx ()));
+      emit_insn (gen_fix_truncsfsi2_i4 (operands[0], operands[1]));
       DONE;
     }
 })
@@ -12644,98 +12676,43 @@ label:
 (define_insn "fix_truncsfsi2_i4"
   [(set (match_operand:SI 0 "fpul_operand" "=y")
        (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
-  "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_SH2E"
   "ftrc        %1,%0"
   [(set_attr "type" "ftrc_s")
    (set_attr "fp_mode" "single")])
 
-;; ??? This pattern is used nowhere.  fix_truncsfsi2 always expands to
-;; fix_truncsfsi2_i4.
-;; (define_insn "fix_truncsfsi2_i4_2"
-;;  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-;;     (fix:SI (match_operand:SF 1 "arith_reg_operand" "f")))
-;;   (use (reg:PSI FPSCR_REG))
-;;   (clobber (reg:SI FPUL_REG))]
-;;  "TARGET_SH4"
-;;  "#"
-;;  [(set_attr "length" "4")
-;;   (set_attr "fp_mode" "single")])
-
-;;(define_split
-;;  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-;;     (fix:SI (match_operand:SF 1 "arith_reg_operand" "f")))
-;;   (use (match_operand:PSI 2 "fpscr_operand" "c"))
-;;   (clobber (reg:SI FPUL_REG))]
-;;  "TARGET_SH4"
-;;  [(parallel [(set (reg:SI FPUL_REG) (fix:SI (match_dup 1)))
-;;           (use (match_dup 2))])
-;;   (set (match_dup 0) (reg:SI FPUL_REG))])
-
-(define_insn "*fixsfsi"
-  [(set (match_operand:SI 0 "fpul_operand" "=y")
-       (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
-  "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-  "ftrc        %1,%0"
-  [(set_attr "type" "fp")])
-
 (define_insn "cmpgtsf_t"
-  [(set (reg:SI T_REG)
-       (gt:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
-              (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
-  "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-  "fcmp/gt     %1,%0"
-  [(set_attr "type" "fp_cmp")
-   (set_attr "fp_mode" "single")])
-
-(define_insn "cmpeqsf_t"
-  [(set (reg:SI T_REG)
-       (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
-              (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
-  "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-  "fcmp/eq     %1,%0"
-  [(set_attr "type" "fp_cmp")
-   (set_attr "fp_mode" "single")])
-
-(define_insn "ieee_ccmpeqsf_t"
-  [(set (reg:SI T_REG)
-       (ior:SI (reg:SI T_REG)
-               (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
-                      (match_operand:SF 1 "fp_arith_reg_operand" "f"))))]
-  "TARGET_SH2E && TARGET_IEEE && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-{
-  return output_ieee_ccmpeq (insn, operands);
-}
-  [(set_attr "length" "4")])
-
-
-(define_insn "cmpgtsf_t_i4"
   [(set (reg:SI T_REG)
        (gt:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
               (match_operand:SF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
-  "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_SH2E || TARGET_SH4 || TARGET_SH2A_SINGLE"
   "fcmp/gt     %1,%0"
   [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
-(define_insn "cmpeqsf_t_i4"
+(define_insn "cmpeqsf_t"
   [(set (reg:SI T_REG)
        (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
               (match_operand:SF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
-  "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_SH2E || TARGET_SH4 || TARGET_SH2A_SINGLE"
   "fcmp/eq     %1,%0"
   [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
-(define_insn "*ieee_ccmpeqsf_t_4"
+(define_insn "ieee_ccmpeqsf_t"
   [(set (reg:SI T_REG)
        (ior:SI (reg:SI T_REG)
                (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f")
                       (match_operand:SF 1 "fp_arith_reg_operand" "f"))))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
-  "TARGET_IEEE && (TARGET_SH4 || TARGET_SH2A_SINGLE)"
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_IEEE && TARGET_SH2E"
 {
   return output_ieee_ccmpeq (insn, operands);
 }
@@ -12817,7 +12794,7 @@ label:
 {
   if (TARGET_SH3E)
     {
-      expand_sf_unop (&gen_sqrtsf2_i, operands);
+      emit_insn (gen_sqrtsf2_i (operands[0], operands[1]));
       DONE;
     }
 })
@@ -12832,7 +12809,8 @@ label:
 (define_insn "sqrtsf2_i"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (sqrt:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_SH3E"
   "fsqrt       %0"
   [(set_attr "type" "fdiv")
@@ -12842,7 +12820,8 @@ label:
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
        (div:SF (match_operand:SF 1 "immediate_operand" "i")
                (sqrt:SF (match_operand:SF 2 "fp_arith_reg_operand" "0"))))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_FPU_ANY && TARGET_FSRRA
    && operands[1] == CONST1_RTX (SFmode)"
   "fsrra       %0"
@@ -12864,10 +12843,9 @@ label:
   rtx fsca = gen_reg_rtx (V2SFmode);
   rtx scale_reg = force_reg (SFmode, sh_fsca_sf2int ());
 
-  emit_sf_insn (gen_mulsf3 (scaled, operands[2], scale_reg));
-  emit_sf_insn (gen_fix_truncsfsi2 (truncated, scaled));
-  emit_sf_insn (gen_fsca (fsca, truncated, sh_fsca_int2sf (),
-                         get_fpscr_rtx ()));
+  emit_insn (gen_mulsf3 (scaled, operands[2], scale_reg));
+  emit_insn (gen_fix_truncsfsi2 (truncated, scaled));
+  emit_insn (gen_fsca (fsca, truncated, sh_fsca_int2sf ()));
 
   emit_move_insn (operands[0], gen_rtx_SUBREG (SFmode, fsca, 4));
   emit_move_insn (operands[1], gen_rtx_SUBREG (SFmode, fsca, 0));
@@ -12883,7 +12861,8 @@ label:
                    ] UNSPEC_FSINA)
         (unspec:SF [(mult:SF (float:SF (match_dup 1)) (match_dup 2))
                    ] UNSPEC_FCOSA)))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_FPU_ANY && TARGET_FSCA"
   "fsca        fpul,%d0"
   "&& !fpul_operand (operands[1], SImode)"
@@ -12898,9 +12877,8 @@ label:
       gcc_assert (GET_CODE (x) == FIX || GET_CODE (x) == FLOAT);
       x = XEXP (x, 0);
     }
-
   gcc_assert (x != NULL_RTX && fpul_operand (x, SImode));
-  emit_insn (gen_fsca (operands[0], x, operands[2], operands[3]));
+  emit_insn (gen_fsca (operands[0], x, operands[2]));
   DONE;
 }
   [(set_attr "type" "fsca")
@@ -12933,7 +12911,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      expand_df_binop (&gen_adddf3_i, operands);
+      emit_insn (gen_adddf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12950,7 +12928,8 @@ label:
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (plus:DF (match_operand:DF 1 "fp_arith_reg_operand" "%0")
                 (match_operand:DF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fadd        %2,%0"
   [(set_attr "type" "dfp_arith")
@@ -12964,7 +12943,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      expand_df_binop (&gen_subdf3_i, operands);
+      emit_insn (gen_subdf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -12981,7 +12960,8 @@ label:
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (minus:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")
                  (match_operand:DF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fsub        %2,%0"
   [(set_attr "type" "dfp_arith")
@@ -12995,7 +12975,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      expand_df_binop (&gen_muldf3_i, operands);
+      emit_insn (gen_muldf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -13012,7 +12992,8 @@ label:
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (mult:DF (match_operand:DF 1 "fp_arith_reg_operand" "%0")
                 (match_operand:DF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fmul        %2,%0"
   [(set_attr "type" "dfp_mul")
@@ -13026,7 +13007,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      expand_df_binop (&gen_divdf3_i, operands);
+      emit_insn (gen_divdf3_i (operands[0], operands[1], operands[2]));
       DONE;
     }
 })
@@ -13043,7 +13024,8 @@ label:
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (div:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")
                (match_operand:DF 2 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fdiv        %2,%0"
   [(set_attr "type" "dfdiv")
@@ -13063,8 +13045,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      emit_df_insn (gen_floatsidf2_i (operands[0], operands[1],
-                                     get_fpscr_rtx ()));
+      emit_insn (gen_floatsidf2_i (operands[0], operands[1]));
       DONE;
     }
 })
@@ -13079,7 +13060,8 @@ label:
 (define_insn "floatsidf2_i"
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (float:DF (match_operand:SI 1 "fpul_operand" "y")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "float       %1,%0"
   [(set_attr "type" "dfp_conv")
@@ -13099,8 +13081,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      emit_df_insn (gen_fix_truncdfsi2_i (operands[0], operands[1],
-                                         get_fpscr_rtx ()));
+      emit_insn (gen_fix_truncdfsi2_i (operands[0], operands[1]));
       DONE;
     }
 })
@@ -13115,40 +13096,20 @@ label:
 (define_insn "fix_truncdfsi2_i"
   [(set (match_operand:SI 0 "fpul_operand" "=y")
        (fix:SI (match_operand:DF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "ftrc        %1,%0"
   [(set_attr "type" "dfp_conv")
    (set_attr "dfp_comp" "no")
    (set_attr "fp_mode" "double")])
 
-;; ??? This pattern is used nowhere.  fix_truncdfsi2 always expands to
-;; fix_truncdfsi2_i.
-;; (define_insn "fix_truncdfsi2_i4"
-;;   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-;;     (fix:SI (match_operand:DF 1 "arith_reg_operand" "f")))
-;;    (use (match_operand:PSI 2 "fpscr_operand" "c"))
-;;    (clobber (reg:SI FPUL_REG))]
-;;   "TARGET_SH4"
-;;   "#"
-;;   [(set_attr "length" "4")
-;;    (set_attr "fp_mode" "double")])
-;;
-;; (define_split
-;;   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
-;;     (fix:SI (match_operand:DF 1 "arith_reg_operand" "f")))
-;;    (use (match_operand:PSI 2 "fpscr_operand" "c"))
-;;    (clobber (reg:SI FPUL_REG))]
-;;   "TARGET_SH4"
-;;   [(parallel [(set (reg:SI FPUL_REG) (fix:SI (match_dup 1)))
-;;           (use (match_dup 2))])
-;;    (set (match_dup 0) (reg:SI FPUL_REG))])
-
 (define_insn "cmpgtdf_t"
   [(set (reg:SI T_REG)
        (gt:SI (match_operand:DF 0 "fp_arith_reg_operand" "f")
               (match_operand:DF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fcmp/gt     %1,%0"
   [(set_attr "type" "dfp_cmp")
@@ -13158,7 +13119,8 @@ label:
   [(set (reg:SI T_REG)
        (eq:SI (match_operand:DF 0 "fp_arith_reg_operand" "f")
               (match_operand:DF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fcmp/eq     %1,%0"
   [(set_attr "type" "dfp_cmp")
@@ -13169,7 +13131,8 @@ label:
        (ior:SI (reg:SI T_REG)
                (eq:SI (match_operand:DF 0 "fp_arith_reg_operand" "f")
                       (match_operand:DF 1 "fp_arith_reg_operand" "f"))))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "TARGET_IEEE && (TARGET_SH4 || TARGET_SH2A_DOUBLE)"
 {
   return output_ieee_ccmpeq (insn, operands);
@@ -13252,7 +13215,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      expand_df_unop (&gen_sqrtdf2_i, operands);
+      emit_insn (gen_sqrtdf2_i (operands[0], operands[1]));
       DONE;
     }
 })
@@ -13267,7 +13230,8 @@ label:
 (define_insn "sqrtdf2_i"
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (sqrt:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fsqrt       %0"
   [(set_attr "type" "dfdiv")
@@ -13299,8 +13263,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      emit_df_insn (gen_extendsfdf2_i4 (operands[0], operands[1],
-                                       get_fpscr_rtx ()));
+      emit_insn (gen_extendsfdf2_i4 (operands[0], operands[1]));
       DONE;
     }
 })
@@ -13315,7 +13278,8 @@ label:
 (define_insn "extendsfdf2_i4"
   [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
        (float_extend:DF (match_operand:SF 1 "fpul_operand" "y")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fcnvsd  %1,%0"
   [(set_attr "type" "fp")
@@ -13328,8 +13292,7 @@ label:
 {
   if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
-      emit_df_insn (gen_truncdfsf2_i4 (operands[0], operands[1],
-                                      get_fpscr_rtx ()));
+      emit_insn (gen_truncdfsf2_i4 (operands[0], operands[1]));
       DONE;
     }
 })
@@ -13344,7 +13307,8 @@ label:
 (define_insn "truncdfsf2_i4"
   [(set (match_operand:SF 0 "fpul_operand" "=y")
        (float_truncate:SF (match_operand:DF 1 "fp_arith_reg_operand" "f")))
-   (use (match_operand:PSI 2 "fpscr_operand" "c"))]
+   (clobber (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fcnvds  %1,%0"
   [(set_attr "type" "fp")
index 32e80803734d3ccaf22d6557e062971a0cbd8802..21e3e06f031e848b7234218f7c8ddf70a60cff80 100644 (file)
@@ -1,3 +1,8 @@
+2014-10-16  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/53513
+       * gcc.target/sh/pr54680.c: Adjust matching of lds insn.
+
 2014-10-16  Martin Liska  <mliska@suse.cz>
            Jan Hubicka  <hubicka@ucw.cz>
 
@@ -45,7 +50,7 @@
        * gcc.target/i386/bmi-2.c: Likewise.
        * gcc.target/i386/pr56564-2.c: Likewise.
 
-2014-10-16  Richard Biener  <rguenther@suse.de>i
+2014-10-16  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/63168
        * gcc.dg/tree-ssa/loop-40.c: New testcase.
index 9171eeaf65c252656a338dbd6ace8037a2a7351c..8c5d5e18c716d7cea9ba40cc8a785a366d440792 100644 (file)
@@ -6,7 +6,7 @@
 /* { dg-skip-if "" { "sh*-*-*" } { "-m1" "-m2*" "-m3*" "-m4al" "*nofpu" "-m4-340*" "-m4-400*" "-m4-500*" "-m5*" } { "" } }  */
 /* { dg-final { scan-assembler-times "fsca" 7 } } */
 /* { dg-final { scan-assembler-times "shad" 1 } } */
-/* { dg-final { scan-assembler-times "lds\t" 6 } } */
+/* { dg-final { scan-assembler-times "lds\tr\[0-9\],fpul" 6 } } */
 /* { dg-final { scan-assembler-times "fmul" 2 } } */
 /* { dg-final { scan-assembler-times "ftrc" 1 } } */