re PR target/53513 ([SH] Add support for fpchg insn and improve fenv support)
authorOleg Endo <olegendo@gcc.gnu.org>
Sat, 18 Oct 2014 10:51:08 +0000 (10:51 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Sat, 18 Oct 2014 10:51:08 +0000 (10:51 +0000)
gcc/
PR target/53513
* config/sh/sh-modes.def (PSI): Remove.
* config/sh/sh-protos.h (get_fpscr_rtx): Remove.
* config/sh/sh.c (fpscr_rtx, get_fpscr_rtx): Remove.
(sh_reorg): Remove commented out FPSCR code.
(fpscr_set_from_mem): Use SImode instead of PSImode.  Emit lds_fpscr
insn instead of move insn.
(sh_hard_regno_mode_ok): Return SImode for FPSCR.
(sh_legitimate_address_p, sh_legitimize_reload_address): Remove PSImode
handling.
(sh_emit_mode_set): Emit lds_fpscr and sts_fpscr insns.
(sh1_builtin_p): Uncomment.
(SH_BLTIN_UV 25, SH_BLTIN_VU 26): New macros.
(bdesc): Add __builtin_sh_get_fpscr and __builtin_sh_set_fpscr.
* config/sh/sh/predicates.md (fpscr_operand): Simplify.
(fpscr_movsrc_operand, fpscr_movdst_operand): New predicates.
(general_movsrc_operand, general_movdst_operand): Disallow
fpscr_operand.
* config/sh/sh.md (FPSCR_FR): New constant.
(push_fpscr): Emit sts_fpscr insn.
(pop_fpscr): Emit lds_fpscr_insn.
(movsi_ie): Disallow FPSCR operands.
(fpu_switch, unnamed related split, extend_psi_si,
truncate_si_psi): Remove insns.
(lds_fpscr, sts_fpscr): New insns.
(toggle_sz, toggle_pr): Use SImode for FPSCR_REG instead of PSImode.

From-SVN: r216424

gcc/ChangeLog
gcc/config/sh/predicates.md
gcc/config/sh/sh-modes.def
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.md

index b2a8e7a2a6f2d3684a423a460ccf3418e5da3189..74037a227f2bcd9a3435082a24d5ea95c7829daf 100644 (file)
@@ -1,3 +1,32 @@
+2014-10-18  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/53513
+       * config/sh/sh-modes.def (PSI): Remove.
+       * config/sh/sh-protos.h (get_fpscr_rtx): Remove.
+       * config/sh/sh.c (fpscr_rtx, get_fpscr_rtx): Remove.
+       (sh_reorg): Remove commented out FPSCR code.
+       (fpscr_set_from_mem): Use SImode instead of PSImode.  Emit lds_fpscr
+       insn instead of move insn.
+       (sh_hard_regno_mode_ok): Return SImode for FPSCR.
+       (sh_legitimate_address_p, sh_legitimize_reload_address): Remove PSImode
+       handling.
+       (sh_emit_mode_set): Emit lds_fpscr and sts_fpscr insns.
+       (sh1_builtin_p): Uncomment.
+       (SH_BLTIN_UV 25, SH_BLTIN_VU 26): New macros.
+       (bdesc): Add __builtin_sh_get_fpscr and __builtin_sh_set_fpscr.
+       * config/sh/sh/predicates.md (fpscr_operand): Simplify.
+       (fpscr_movsrc_operand, fpscr_movdst_operand): New predicates.
+       (general_movsrc_operand, general_movdst_operand): Disallow
+       fpscr_operand.
+       * config/sh/sh.md (FPSCR_FR): New constant.
+       (push_fpscr): Emit sts_fpscr insn.
+       (pop_fpscr): Emit lds_fpscr_insn.
+       (movsi_ie): Disallow FPSCR operands.
+       (fpu_switch, unnamed related split, extend_psi_si,
+       truncate_si_psi): Remove insns.
+       (lds_fpscr, sts_fpscr): New insns.
+       (toggle_sz, toggle_pr): Use SImode for FPSCR_REG instead of PSImode.
+
 2014-10-17  Eric Botcazou  <ebotcazou@adacore.com>
 
        * ipa-inline-transform.c (master_clone_with_noninline_clones_p): New.
index e15388b3fbaa76186e760d5df1a07093e7a0a1ed..ff1c2f54a38221440418a7fb0de6ffd404aa2713 100644 (file)
 
       return (regno != T_REG && regno != PR_REG
              && ! TARGET_REGISTER_P (regno)
-             && regno != FPUL_REG
+             && regno != FPUL_REG && regno != FPSCR_REG
              && regno != MACH_REG && regno != MACL_REG);
     }
   /* Allow a no-op sign extension - compare LOAD_EXTEND_OP.
 
 ;; Returns true if OP is the FPSCR.
 (define_predicate "fpscr_operand"
-  (match_code "reg")
+  (and (match_code "reg")
+       (match_test "REGNO (op) == FPSCR_REG")))
+
+;; Returns true if OP is a valid source operand for a FPSCR move insn.
+(define_predicate "fpscr_movsrc_operand"
+  (match_code "reg,subreg,mem")
 {
-  return (REG_P (op)
-         && (REGNO (op) == FPSCR_REG
-             || (REGNO (op) >= FIRST_PSEUDO_REGISTER
-                 && !(reload_in_progress || reload_completed)))
-         && GET_MODE (op) == PSImode);
+  if (arith_reg_operand (op, mode))
+    return true;
+
+  return MEM_P (op) && GET_CODE (XEXP (op, 0)) == POST_INC;
+})
+
+;; Returns true if OP is a valid destination operand for a FPSCR move insn.
+(define_predicate "fpscr_movdst_operand"
+  (match_code "reg,subreg,mem")
+{
+  if (arith_reg_dest (op, mode))
+    return true;
+
+  return MEM_P (op) && GET_CODE (XEXP (op, 0)) == PRE_DEC;
 })
 
 ;; Returns true if OP is an operand that is either the fpul hard reg or
   if (t_reg_operand (op, mode))
     return 0;
 
+  if (fpscr_operand (op, mode))
+    return false;
+
   /* Disallow PC relative QImode loads, since these is no insn to do that
      and an imm8 load should be used instead.  */
   if (IS_PC_RELATIVE_LOAD_ADDR_P (op) && GET_MODE (op) == QImode)
   if (t_reg_operand (op, mode))
     return 0;
 
+  if (fpscr_operand (op, mode))
+    return false;
+
   if (MEM_P (op))
     {
       rtx inside = XEXP (op, 0);
index 3aa3046e37fa94a7a89ebd8e1b03703c4d1767a3..02710aa29e4160057e71845950f0b607cfbdfc89 100644 (file)
@@ -17,8 +17,6 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* The SH uses a partial integer mode to represent the FPSCR register.  */
-PARTIAL_INT_MODE (SI, 22, PSI);
 /* PDI mode is used to represent a function address in a target register.  */
 PARTIAL_INT_MODE (DI, 64, PDI);
 
index ca007b9093ceea46610f0bf6569c681f7dce4379..77c9ae4e3420aab3fcd1a5f2d3870dce3aaef357 100644 (file)
@@ -107,7 +107,6 @@ extern int barrier_align (rtx_insn *);
 extern int sh_loop_align (rtx_insn *);
 extern bool fp_zero_operand (rtx);
 extern bool fp_one_operand (rtx);
-extern rtx get_fpscr_rtx (void);
 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);
@@ -185,7 +184,6 @@ extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
 
 extern const char *output_jump_label_table (void);
 extern rtx get_t_reg_rtx (void);
-extern rtx get_fpscr_rtx (void);
 extern int sh_media_register_for_return (void);
 extern void sh_expand_prologue (void);
 extern void sh_expand_epilogue (bool);
index 7433476601deb2f95fd9aacba6ab2580d6a2cfb3..3daa375b957ac1e7f52c0359b359a064585bf4d9 100644 (file)
@@ -6443,14 +6443,6 @@ sh_reorg (void)
          emit_insn_before (gen_use_sfunc_addr (reg), insn);
        }
     }
-#if 0
-  /* fpscr is not actually a user variable, but we pretend it is for the
-     sake of the previous optimization passes, since we want it handled like
-     one.  However, we don't have any debugging information for it, so turn
-     it into a non-user variable now.  */
-  if (TARGET_SH4)
-    REG_USERVAR_P (get_fpscr_rtx ()) = 0;
-#endif
   mdep_reorg_phase = SH_AFTER_MDEP_REORG;
 }
 
@@ -10009,21 +10001,6 @@ get_t_reg_rtx (void)
   return t_reg_rtx;
 }
 
-static GTY(()) rtx fpscr_rtx;
-rtx
-get_fpscr_rtx (void)
-{
-  if (! fpscr_rtx)
-    {
-      fpscr_rtx = gen_rtx_REG (PSImode, FPSCR_REG);
-      REG_USERVAR_P (fpscr_rtx) = 1;
-      mark_user_reg (fpscr_rtx);
-    }
-  if (! reload_completed || mdep_reorg_phase != SH_AFTER_MDEP_REORG)
-    mark_user_reg (fpscr_rtx);
-  return fpscr_rtx;
-}
-
 static GTY(()) tree fpscr_values;
 
 static void
@@ -10055,13 +10032,12 @@ emit_fpu_switch (rtx scratch, int index)
       emit_move_insn (scratch, XEXP (src, 0));
       if (index != 0)
        emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4)));
-      src = adjust_automodify_address (src, PSImode, scratch, index * 4);
+      src = adjust_automodify_address (src, SImode, scratch, index * 4);
     }
   else
-    src = adjust_address (src, PSImode, index * 4);
+    src = adjust_address (src, SImode, index * 4);
 
-  dst = get_fpscr_rtx ();
-  emit_move_insn (dst, src);
+  emit_insn (gen_lds_fpscr (src));
 }
 \f
 static rtx get_free_reg (HARD_REG_SET);
@@ -10269,8 +10245,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
           && ! TARGET_SHMEDIA
           && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict))
     return true;
-  else if (GET_CODE (x) == PLUS
-          && (mode != PSImode || reload_completed))
+  else if (GET_CODE (x) == PLUS)
     {
       rtx xop0 = XEXP (x, 0);
       rtx xop1 = XEXP (x, 1);
@@ -10474,7 +10449,6 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
          return gen_rtx_PLUS (Pmode, sum, adj.mov_disp);
        }
     }
-
   return x;
 }
 
@@ -10516,7 +10490,6 @@ sh_legitimize_reload_address (rtx *p, enum machine_mode mode, int opnum,
 
   if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1))
       && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true)
-      && ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS)
       && (ALLOW_INDEXED_ADDRESS
          || XEXP (*p, 0) == stack_pointer_rtx
          || XEXP (*p, 0) == hard_frame_pointer_rtx))
@@ -11607,13 +11580,12 @@ shmedia_builtin_p (void)
 }
 
 /* This function can be used if there are any built-ins that are not for
-   SHmedia.  It's commented out to avoid the defined-but-unused warning.
+   SHmedia.  It's commented out to avoid the defined-but-unused warning.  */
 static bool
 sh1_builtin_p (void)
 {
   return TARGET_SH1;
 }
-*/
 
 /* describe number and signedness of arguments; arg[0] == result
    (1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */
@@ -11674,6 +11646,10 @@ static const char signature_args[][4] =
   { 0, 8 },
 #define SH_BLTIN_VP 24
   { 8, 0 },
+#define SH_BLTIN_UV 25
+  { 1, 0 },
+#define SH_BLTIN_VU 26
+  { 0, 1 },
 };
 /* mcmv: operands considered unsigned.  */
 /* mmulsum_wq, msad_ubq: result considered unsigned long long.  */
@@ -11849,6 +11825,11 @@ static struct builtin_description bdesc[] =
     CODE_FOR_byterev,  "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 },
   { shmedia_builtin_p,
     CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 },
+
+  { sh1_builtin_p,
+    CODE_FOR_sts_fpscr, "__builtin_sh_get_fpscr", SH_BLTIN_UV, 0 },
+  { sh1_builtin_p,
+    CODE_FOR_set_fpscr, "__builtin_sh_set_fpscr", SH_BLTIN_VU, 0 },
 };
 
 static void
@@ -12162,7 +12143,7 @@ sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
     return mode == SImode;
 
   if (regno == FPSCR_REG)
-    return mode == PSImode;
+    return mode == SImode;
 
   /* FIXME.  This works around PR target/37633 for -O0.  */
   if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4)
@@ -13627,33 +13608,24 @@ sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
     }
   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 tmp = gen_reg_rtx (SImode);
+      emit_insn (gen_sts_fpscr (tmp));
       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)));
+       i = gen_xorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits)));
       else if (mode == FP_MODE_SINGLE)
-       i = gen_andsi3 (tmp1, tmp1,
-                       force_reg (SImode, GEN_INT (~fpbits)));
+       i = gen_andsi3 (tmp, tmp, force_reg (SImode, GEN_INT (~fpbits)));
       else if (mode == FP_MODE_DOUBLE)
-       i = gen_iorsi3 (tmp1, tmp1,
-                       force_reg (SImode, GEN_INT (fpbits)));
+       i = gen_iorsi3 (tmp, tmp, 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);
+      emit_insn (gen_lds_fpscr (tmp));
     }
 }
 
index e77e3aeeb791054c202ef9c0022f8c6884902de9..675017c2c977d4778f03ab29748f533a1b68d0b4 100644 (file)
 
   (XD0_REG     136)
 
-  (FPSCR_PR    524288)
-  (FPSCR_SZ    1048576)
+  (FPSCR_PR    524288)  ;; 1 << 19
+  (FPSCR_SZ    1048576) ;; 1 << 20
+  (FPSCR_FR    2097152) ;; 1 << 21
 ])
 
 (define_c_enum "unspec" [
@@ -6508,11 +6509,11 @@ label:
   [(const_int 0)]
   "TARGET_SH2E"
 {
-  rtx insn = emit_insn (gen_fpu_switch (gen_frame_mem (PSImode,
-                                                gen_rtx_PRE_DEC (Pmode,
-                                                         stack_pointer_rtx)),
-                                       get_fpscr_rtx ()));
-  add_reg_note (insn, REG_INC, stack_pointer_rtx);
+  add_reg_note (
+    emit_insn (
+      gen_sts_fpscr (
+       gen_frame_mem (SImode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)))),
+    REG_INC, stack_pointer_rtx);
   DONE;
 })
 
@@ -6520,11 +6521,11 @@ label:
   [(const_int 0)]
   "TARGET_SH2E"
 {
-  rtx insn = emit_insn (gen_fpu_switch (get_fpscr_rtx (),
-                                       gen_frame_mem (PSImode,
-                                                gen_rtx_POST_INC (Pmode,
-                                                         stack_pointer_rtx))));
-  add_reg_note (insn, REG_INC, stack_pointer_rtx);
+  add_reg_note (
+    emit_insn (
+      gen_lds_fpscr (
+       gen_frame_mem (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)))),
+    REG_INC, stack_pointer_rtx);
   DONE;
 })
 
@@ -6713,8 +6714,10 @@ label:
        (match_operand:SI 1 "general_movsrc_operand"
         "Q,r,I08,I20,I28,mr,x,l,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))]
   "(TARGET_SH2E || TARGET_SH2A)
-   && (register_operand (operands[0], SImode)
-       || register_operand (operands[1], SImode))"
+   && ((register_operand (operands[0], SImode)
+       && !fpscr_operand (operands[0], SImode))
+       || (register_operand (operands[1], SImode)
+          && !fpscr_operand (operands[1], SImode)))"
   "@
        mov.l   %1,%0
        mov     %1,%0
@@ -12207,97 +12210,69 @@ label:
 ;; Floating point instructions.
 ;; -------------------------------------------------------------------------
 
-;; ??? All patterns should have a type attribute.
-
-(define_expand "movpsi"
-  [(set (match_operand:PSI 0 "register_operand" "")
-       (match_operand:PSI 1 "general_movsrc_operand" ""))]
-  "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.
-;; TARGET_LEGITIMATE_ADDRESS_P guards about bogus addresses before reload,
-;; SECONDARY_INPUT_RELOAD_CLASS does this during reload, and the insn's
-;; predicate after reload.
-;; The mac_gp type for r/!c might look a bit odd, but it actually schedules
-;; 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"))
-   (use (reg:SI FPSCR_STAT_REG))
-   (use (reg:SI FPSCR_MODES_REG))
+;; FIXME: For now we disallow any memory operands for fpscr loads/stores,
+;; except for post-inc loads and pre-dec stores for push/pop purposes.
+;; This avoids problems with reload.  As a consequence, user initiated fpscr
+;; stores to memory will always be ferried through a general register.
+;; User initiated fpscr loads always have to undergo bit masking to preserve
+;; the current fpu mode settings for the compiler generated code.  Thus such
+;; fpscr loads will always have to go through general registers anyways.
+(define_insn "lds_fpscr"
+  [(set (reg:SI FPSCR_REG)
+       (match_operand:SI 0 "fpscr_movsrc_operand" "r,>"))
    (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])
-       || GET_CODE (XEXP (operands[1], 0)) != PLUS)"
+  "TARGET_FPU_ANY"
+  "@
+       lds     %0,fpscr
+       lds.l   %0,fpscr"
+  [(set_attr "type" "gp_fpscr,mem_fpscr")])
+
+;; A move fpscr -> reg schedules like a move mac -> reg.  Thus we use mac_gp
+;; type for it.
+(define_insn "sts_fpscr"
+  [(set (match_operand:SI 0 "fpscr_movdst_operand" "=r,<")
+       (reg:SI FPSCR_REG))
+   (use (reg:SI FPSCR_STAT_REG))
+   (use (reg:SI FPSCR_MODES_REG))]
+  "TARGET_FPU_ANY"
   "@
-       ! precision stays the same
-       lds.l   %1,fpscr
-       mov.l   %1,%0
-       #
-       lds     %1,fpscr
-       mov     %1,%0
-       mov.l   %1,%0
        sts     fpscr,%0
        sts.l   fpscr,%0"
-  [(set_attr "length" "0,2,2,4,2,2,2,2,2")
-   (set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store,
-                    mac_gp,fstore")])
+  [(set_attr "type" "mac_gp,fstore")])
 
-(define_split
-  [(set (reg:PSI FPSCR_REG)
-        (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)]
+(define_expand "set_fpscr"
+  [(parallel [(set (reg:SI FPSCR_REG)
+                  (match_operand:SI 0 "general_operand"))
+             (set (reg:SI FPSCR_STAT_REG)
+                  (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))])]
+  "TARGET_FPU_ANY"
 {
-  rtx addrreg = XEXP (operands[0], 0);
-  rtx mem = replace_equiv_address (operands[0],
-                                  gen_rtx_POST_INC (Pmode, addrreg));
+  /* We have to mask out the FR, SZ and PR bits.  To do that, we need to
+     get the current FPSCR value first.
+     (a & ~mask) | (b & mask) = a ^ ((a ^ b) & mask)  */
 
-  add_reg_note (emit_insn (gen_fpu_switch (get_fpscr_rtx (), mem)),
-               REG_INC, addrreg);
+  rtx mask = force_reg (SImode, GEN_INT (FPSCR_FR | FPSCR_SZ | FPSCR_PR));
 
-  /* 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)));
-})
+  rtx a = force_reg (SImode, 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")])
+  rtx b = gen_reg_rtx (SImode);
+  emit_insn (gen_sts_fpscr (b));
 
-(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")])
+  rtx a_xor_b = gen_reg_rtx (SImode);
+  emit_insn (gen_xorsi3 (a_xor_b, a, b));
+
+  rtx a_xor_b_and_mask = gen_reg_rtx (SImode);
+  emit_insn (gen_andsi3 (a_xor_b_and_mask, a_xor_b, mask));
+
+  rtx r = gen_reg_rtx (SImode);
+  emit_insn (gen_xorsi3 (r, a_xor_b_and_mask, a));
+  emit_insn (gen_lds_fpscr (r));
 
+  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
@@ -12306,8 +12281,8 @@ label:
 ;; it is probably best to claim no function unit, which matches the
 ;; current setting.
 (define_insn "toggle_sz"
-  [(set (reg:PSI FPSCR_REG)
-       (xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_SZ)))
+  [(set (reg:SI FPSCR_REG)
+       (xor:SI (reg:SI 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)"
@@ -12317,8 +12292,8 @@ label:
 ;; Toggle FPU precision PR mode.
 
 (define_insn "toggle_pr"
-  [(set (reg:PSI FPSCR_REG)
-       (xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_PR)))
+  [(set (reg:SI FPSCR_REG)
+       (xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_PR)))
    (set (reg:SI FPSCR_MODES_REG)
        (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
   "TARGET_SH4A_FP"