Commit fe3e478f by Oleg Endo

re PR target/53513 ([SH] Add support for fpchg insn and improve fenv support)

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
parent 7e813472
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> 2014-10-17 Eric Botcazou <ebotcazou@adacore.com>
* ipa-inline-transform.c (master_clone_with_noninline_clones_p): New. * ipa-inline-transform.c (master_clone_with_noninline_clones_p): New.
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
return (regno != T_REG && regno != PR_REG return (regno != T_REG && regno != PR_REG
&& ! TARGET_REGISTER_P (regno) && ! TARGET_REGISTER_P (regno)
&& regno != FPUL_REG && regno != FPUL_REG && regno != FPSCR_REG
&& regno != MACH_REG && regno != MACL_REG); && regno != MACH_REG && regno != MACL_REG);
} }
/* Allow a no-op sign extension - compare LOAD_EXTEND_OP. /* Allow a no-op sign extension - compare LOAD_EXTEND_OP.
...@@ -347,13 +347,27 @@ ...@@ -347,13 +347,27 @@
;; Returns true if OP is the FPSCR. ;; Returns true if OP is the FPSCR.
(define_predicate "fpscr_operand" (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) if (arith_reg_operand (op, mode))
&& (REGNO (op) == FPSCR_REG return true;
|| (REGNO (op) >= FIRST_PSEUDO_REGISTER
&& !(reload_in_progress || reload_completed))) return MEM_P (op) && GET_CODE (XEXP (op, 0)) == POST_INC;
&& GET_MODE (op) == PSImode); })
;; 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 ;; Returns true if OP is an operand that is either the fpul hard reg or
...@@ -451,6 +465,9 @@ ...@@ -451,6 +465,9 @@
if (t_reg_operand (op, mode)) if (t_reg_operand (op, mode))
return 0; return 0;
if (fpscr_operand (op, mode))
return false;
/* Disallow PC relative QImode loads, since these is no insn to do that /* Disallow PC relative QImode loads, since these is no insn to do that
and an imm8 load should be used instead. */ and an imm8 load should be used instead. */
if (IS_PC_RELATIVE_LOAD_ADDR_P (op) && GET_MODE (op) == QImode) if (IS_PC_RELATIVE_LOAD_ADDR_P (op) && GET_MODE (op) == QImode)
...@@ -546,6 +563,9 @@ ...@@ -546,6 +563,9 @@
if (t_reg_operand (op, mode)) if (t_reg_operand (op, mode))
return 0; return 0;
if (fpscr_operand (op, mode))
return false;
if (MEM_P (op)) if (MEM_P (op))
{ {
rtx inside = XEXP (op, 0); rtx inside = XEXP (op, 0);
......
...@@ -17,8 +17,6 @@ You should have received a copy of the GNU General Public License ...@@ -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 along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */ <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. */ /* PDI mode is used to represent a function address in a target register. */
PARTIAL_INT_MODE (DI, 64, PDI); PARTIAL_INT_MODE (DI, 64, PDI);
......
...@@ -107,7 +107,6 @@ extern int barrier_align (rtx_insn *); ...@@ -107,7 +107,6 @@ extern int barrier_align (rtx_insn *);
extern int sh_loop_align (rtx_insn *); extern int sh_loop_align (rtx_insn *);
extern bool fp_zero_operand (rtx); extern bool fp_zero_operand (rtx);
extern bool fp_one_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_legitimate_index_p (enum machine_mode, rtx, bool, bool);
extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int); extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
...@@ -185,7 +184,6 @@ extern void sh_cpu_cpp_builtins (cpp_reader* pfile); ...@@ -185,7 +184,6 @@ extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
extern const char *output_jump_label_table (void); extern const char *output_jump_label_table (void);
extern rtx get_t_reg_rtx (void); extern rtx get_t_reg_rtx (void);
extern rtx get_fpscr_rtx (void);
extern int sh_media_register_for_return (void); extern int sh_media_register_for_return (void);
extern void sh_expand_prologue (void); extern void sh_expand_prologue (void);
extern void sh_expand_epilogue (bool); extern void sh_expand_epilogue (bool);
......
...@@ -6443,14 +6443,6 @@ sh_reorg (void) ...@@ -6443,14 +6443,6 @@ sh_reorg (void)
emit_insn_before (gen_use_sfunc_addr (reg), insn); 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; mdep_reorg_phase = SH_AFTER_MDEP_REORG;
} }
...@@ -10009,21 +10001,6 @@ get_t_reg_rtx (void) ...@@ -10009,21 +10001,6 @@ get_t_reg_rtx (void)
return t_reg_rtx; 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 GTY(()) tree fpscr_values;
static void static void
...@@ -10055,13 +10032,12 @@ emit_fpu_switch (rtx scratch, int index) ...@@ -10055,13 +10032,12 @@ emit_fpu_switch (rtx scratch, int index)
emit_move_insn (scratch, XEXP (src, 0)); emit_move_insn (scratch, XEXP (src, 0));
if (index != 0) if (index != 0)
emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4))); 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 else
src = adjust_address (src, PSImode, index * 4); src = adjust_address (src, SImode, index * 4);
dst = get_fpscr_rtx (); emit_insn (gen_lds_fpscr (src));
emit_move_insn (dst, src);
} }
static rtx get_free_reg (HARD_REG_SET); static rtx get_free_reg (HARD_REG_SET);
...@@ -10269,8 +10245,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) ...@@ -10269,8 +10245,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
&& ! TARGET_SHMEDIA && ! TARGET_SHMEDIA
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict))
return true; return true;
else if (GET_CODE (x) == PLUS else if (GET_CODE (x) == PLUS)
&& (mode != PSImode || reload_completed))
{ {
rtx xop0 = XEXP (x, 0); rtx xop0 = XEXP (x, 0);
rtx xop1 = XEXP (x, 1); rtx xop1 = XEXP (x, 1);
...@@ -10474,7 +10449,6 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) ...@@ -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 gen_rtx_PLUS (Pmode, sum, adj.mov_disp);
} }
} }
return x; return x;
} }
...@@ -10516,7 +10490,6 @@ sh_legitimize_reload_address (rtx *p, enum machine_mode mode, int opnum, ...@@ -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)) if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1))
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true) && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true)
&& ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS)
&& (ALLOW_INDEXED_ADDRESS && (ALLOW_INDEXED_ADDRESS
|| XEXP (*p, 0) == stack_pointer_rtx || XEXP (*p, 0) == stack_pointer_rtx
|| XEXP (*p, 0) == hard_frame_pointer_rtx)) || XEXP (*p, 0) == hard_frame_pointer_rtx))
...@@ -11607,13 +11580,12 @@ shmedia_builtin_p (void) ...@@ -11607,13 +11580,12 @@ shmedia_builtin_p (void)
} }
/* This function can be used if there are any built-ins that are not for /* 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 static bool
sh1_builtin_p (void) sh1_builtin_p (void)
{ {
return TARGET_SH1; return TARGET_SH1;
} }
*/
/* describe number and signedness of arguments; arg[0] == result /* describe number and signedness of arguments; arg[0] == result
(1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */ (1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */
...@@ -11674,6 +11646,10 @@ static const char signature_args[][4] = ...@@ -11674,6 +11646,10 @@ static const char signature_args[][4] =
{ 0, 8 }, { 0, 8 },
#define SH_BLTIN_VP 24 #define SH_BLTIN_VP 24
{ 8, 0 }, { 8, 0 },
#define SH_BLTIN_UV 25
{ 1, 0 },
#define SH_BLTIN_VU 26
{ 0, 1 },
}; };
/* mcmv: operands considered unsigned. */ /* mcmv: operands considered unsigned. */
/* mmulsum_wq, msad_ubq: result considered unsigned long long. */ /* mmulsum_wq, msad_ubq: result considered unsigned long long. */
...@@ -11849,6 +11825,11 @@ static struct builtin_description bdesc[] = ...@@ -11849,6 +11825,11 @@ static struct builtin_description bdesc[] =
CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 }, CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 },
{ shmedia_builtin_p, { shmedia_builtin_p,
CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 }, 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 static void
...@@ -12162,7 +12143,7 @@ sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) ...@@ -12162,7 +12143,7 @@ sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
return mode == SImode; return mode == SImode;
if (regno == FPSCR_REG) if (regno == FPSCR_REG)
return mode == PSImode; return mode == SImode;
/* FIXME. This works around PR target/37633 for -O0. */ /* FIXME. This works around PR target/37633 for -O0. */
if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4) if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4)
...@@ -13627,33 +13608,24 @@ sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode, ...@@ -13627,33 +13608,24 @@ sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
} }
else if (mode != FP_MODE_NONE) else if (mode != FP_MODE_NONE)
{ {
rtx tmp0 = gen_reg_rtx (PSImode); rtx tmp = gen_reg_rtx (SImode);
rtx tmp1 = gen_reg_rtx (SImode); emit_insn (gen_sts_fpscr (tmp));
emit_move_insn (tmp0, get_fpscr_rtx ());
emit_insn (gen_extend_psi_si (tmp1, tmp0));
rtx i = NULL; rtx i = NULL;
const unsigned HOST_WIDE_INT fpbits = const unsigned HOST_WIDE_INT fpbits =
TARGET_FMOVD ? (FPSCR_PR | FPSCR_SZ) : FPSCR_PR; TARGET_FMOVD ? (FPSCR_PR | FPSCR_SZ) : FPSCR_PR;
if (prev_mode != FP_MODE_NONE && prev_mode != mode) if (prev_mode != FP_MODE_NONE && prev_mode != mode)
i = gen_xorsi3 (tmp1, tmp1, i = gen_xorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits)));
force_reg (SImode, GEN_INT (fpbits)));
else if (mode == FP_MODE_SINGLE) else if (mode == FP_MODE_SINGLE)
i = gen_andsi3 (tmp1, tmp1, i = gen_andsi3 (tmp, tmp, force_reg (SImode, GEN_INT (~fpbits)));
force_reg (SImode, GEN_INT (~fpbits)));
else if (mode == FP_MODE_DOUBLE) else if (mode == FP_MODE_DOUBLE)
i = gen_iorsi3 (tmp1, tmp1, i = gen_iorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits)));
force_reg (SImode, GEN_INT (fpbits)));
else else
gcc_unreachable (); gcc_unreachable ();
emit_insn (i); emit_insn (i);
emit_insn (gen_lds_fpscr (tmp));
emit_insn (gen_truncate_si_psi (tmp0, tmp1));
emit_move_insn (get_fpscr_rtx (), tmp0);
} }
} }
......
...@@ -116,8 +116,9 @@ ...@@ -116,8 +116,9 @@
(XD0_REG 136) (XD0_REG 136)
(FPSCR_PR 524288) (FPSCR_PR 524288) ;; 1 << 19
(FPSCR_SZ 1048576) (FPSCR_SZ 1048576) ;; 1 << 20
(FPSCR_FR 2097152) ;; 1 << 21
]) ])
(define_c_enum "unspec" [ (define_c_enum "unspec" [
...@@ -6508,11 +6509,11 @@ label: ...@@ -6508,11 +6509,11 @@ label:
[(const_int 0)] [(const_int 0)]
"TARGET_SH2E" "TARGET_SH2E"
{ {
rtx insn = emit_insn (gen_fpu_switch (gen_frame_mem (PSImode, add_reg_note (
gen_rtx_PRE_DEC (Pmode, emit_insn (
stack_pointer_rtx)), gen_sts_fpscr (
get_fpscr_rtx ())); gen_frame_mem (SImode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)))),
add_reg_note (insn, REG_INC, stack_pointer_rtx); REG_INC, stack_pointer_rtx);
DONE; DONE;
}) })
...@@ -6520,11 +6521,11 @@ label: ...@@ -6520,11 +6521,11 @@ label:
[(const_int 0)] [(const_int 0)]
"TARGET_SH2E" "TARGET_SH2E"
{ {
rtx insn = emit_insn (gen_fpu_switch (get_fpscr_rtx (), add_reg_note (
gen_frame_mem (PSImode, emit_insn (
gen_rtx_POST_INC (Pmode, gen_lds_fpscr (
stack_pointer_rtx)))); gen_frame_mem (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)))),
add_reg_note (insn, REG_INC, stack_pointer_rtx); REG_INC, stack_pointer_rtx);
DONE; DONE;
}) })
...@@ -6713,8 +6714,10 @@ label: ...@@ -6713,8 +6714,10 @@ label:
(match_operand:SI 1 "general_movsrc_operand" (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"))] "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) "(TARGET_SH2E || TARGET_SH2A)
&& (register_operand (operands[0], SImode) && ((register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))" && !fpscr_operand (operands[0], SImode))
|| (register_operand (operands[1], SImode)
&& !fpscr_operand (operands[1], SImode)))"
"@ "@
mov.l %1,%0 mov.l %1,%0
mov %1,%0 mov %1,%0
...@@ -12207,97 +12210,69 @@ label: ...@@ -12207,97 +12210,69 @@ label:
;; Floating point instructions. ;; Floating point instructions.
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
;; ??? All patterns should have a type attribute. ;; 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.
(define_expand "movpsi" ;; This avoids problems with reload. As a consequence, user initiated fpscr
[(set (match_operand:PSI 0 "register_operand" "") ;; stores to memory will always be ferried through a general register.
(match_operand:PSI 1 "general_movsrc_operand" ""))] ;; User initiated fpscr loads always have to undergo bit masking to preserve
"TARGET_FPU_ANY" ;; the current fpu mode settings for the compiler generated code. Thus such
{ ;; fpscr loads will always have to go through general registers anyways.
emit_insn (gen_fpu_switch (operands[0], operands[1])); (define_insn "lds_fpscr"
DONE; [(set (reg:SI FPSCR_REG)
}) (match_operand:SI 0 "fpscr_movsrc_operand" "r,>"))
;; 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))
(set (reg:SI FPSCR_STAT_REG) (set (reg:SI FPSCR_STAT_REG)
(unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_STAT)) (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_STAT))
(set (reg:SI FPSCR_MODES_REG) (set (reg:SI FPSCR_MODES_REG)
(unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
"TARGET_FPU_ANY "TARGET_FPU_ANY"
&& (! reload_completed "@
|| true_regnum (operands[0]) != FPSCR_REG lds %0,fpscr
|| !MEM_P (operands[1]) lds.l %0,fpscr"
|| GET_CODE (XEXP (operands[1], 0)) != PLUS)" [(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 fpscr,%0
sts.l fpscr,%0" sts.l fpscr,%0"
[(set_attr "length" "0,2,2,4,2,2,2,2,2") [(set_attr "type" "mac_gp,fstore")])
(set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store,
mac_gp,fstore")])
(define_split (define_expand "set_fpscr"
[(set (reg:PSI FPSCR_REG) [(parallel [(set (reg:SI FPSCR_REG)
(match_operand:PSI 0 "simple_mem_operand")) (match_operand:SI 0 "general_operand"))
(use (reg:SI FPSCR_STAT_REG)) (set (reg:SI FPSCR_STAT_REG)
(use (reg:SI FPSCR_MODES_REG)) (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))])]
(set (reg:SI FPSCR_STAT_REG) "TARGET_FPU_ANY"
(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 addrreg = XEXP (operands[0], 0); /* We have to mask out the FR, SZ and PR bits. To do that, we need to
rtx mem = replace_equiv_address (operands[0], get the current FPSCR value first.
gen_rtx_POST_INC (Pmode, addrreg)); (a & ~mask) | (b & mask) = a ^ ((a ^ b) & mask) */
add_reg_note (emit_insn (gen_fpu_switch (get_fpscr_rtx (), mem)), rtx mask = force_reg (SImode, GEN_INT (FPSCR_FR | FPSCR_SZ | FPSCR_PR));
REG_INC, addrreg);
/* Modify the address reg to compensate for the forced post-inc mode. rtx a = force_reg (SImode, operands[0]);
If the address reg becomes dead afterwards, the add will be eliminated
automatically. */
emit_insn (gen_addsi3 (addrreg, addrreg, GEN_INT (-4)));
})
;; The 'extend_psi_si' and 'truncate_si_psi' insns are needed since we can't rtx b = gen_reg_rtx (SImode);
;; do logic on PSImode. Adding PSImode logic patterns works, but loading emit_insn (gen_sts_fpscr (b));
;; 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")])
(define_insn "truncate_si_psi" rtx a_xor_b = gen_reg_rtx (SImode);
[(set (match_operand:PSI 0 "arith_reg_dest" "=r") emit_insn (gen_xorsi3 (a_xor_b, a, b));
(truncate:PSI (match_operand:SI 1 "arith_reg_operand" "0")))]
"TARGET_SH1" rtx a_xor_b_and_mask = gen_reg_rtx (SImode);
"" emit_insn (gen_andsi3 (a_xor_b_and_mask, a_xor_b, mask));
[(set_attr "length" "0")])
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. ;; ??? This uses the fp unit, but has no type indicating that.
;; If we did that, this would either give a bogus latency or introduce ;; If we did that, this would either give a bogus latency or introduce
...@@ -12306,8 +12281,8 @@ label: ...@@ -12306,8 +12281,8 @@ label:
;; it is probably best to claim no function unit, which matches the ;; it is probably best to claim no function unit, which matches the
;; current setting. ;; current setting.
(define_insn "toggle_sz" (define_insn "toggle_sz"
[(set (reg:PSI FPSCR_REG) [(set (reg:SI FPSCR_REG)
(xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_SZ))) (xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_SZ)))
(set (reg:SI FPSCR_MODES_REG) (set (reg:SI FPSCR_MODES_REG)
(unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
"(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
...@@ -12317,8 +12292,8 @@ label: ...@@ -12317,8 +12292,8 @@ label:
;; Toggle FPU precision PR mode. ;; Toggle FPU precision PR mode.
(define_insn "toggle_pr" (define_insn "toggle_pr"
[(set (reg:PSI FPSCR_REG) [(set (reg:SI FPSCR_REG)
(xor:PSI (reg:PSI FPSCR_REG) (const_int FPSCR_PR))) (xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_PR)))
(set (reg:SI FPSCR_MODES_REG) (set (reg:SI FPSCR_MODES_REG)
(unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
"TARGET_SH4A_FP" "TARGET_SH4A_FP"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment