+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.
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);
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);
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);
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);
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;
}
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
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);
&& ! 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);
return gen_rtx_PLUS (Pmode, sum, adj.mov_disp);
}
}
-
return x;
}
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))
}
/* 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 */
{ 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. */
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
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)
}
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));
}
}
(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" [
[(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;
})
[(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;
})
(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
;; 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
;; 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)"
;; 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"