;;- Machine description for Renesas / SuperH SH.
;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
;; Free Software Foundation, Inc.
;; Contributed by Steve Chamberlain (sac@cygnus.com).
;; Improved by Jim Wilson (wilson@cygnus.com).
;; ??? This looks ugly because genattrtab won't allow if_then_else or cond
;; inside an le.
(define_attr "short_cbranch_p" "no,yes"
- (cond [(ne (symbol_ref "mdep_reorg_phase <= SH_FIXUP_PCLOAD") (const_int 0))
+ (cond [(match_test "mdep_reorg_phase <= SH_FIXUP_PCLOAD")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 252)) (const_int 506))
(const_string "yes")
- (ne (symbol_ref "NEXT_INSN (PREV_INSN (insn)) != insn") (const_int 0))
+ (match_test "NEXT_INSN (PREV_INSN (insn)) != insn")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 252)) (const_int 508))
(const_string "yes")
(cond [(leu (plus (minus (match_dup 0) (pc)) (const_int 990))
(const_int 1988))
(const_string "yes")
- (ne (symbol_ref "mdep_reorg_phase <= SH_FIXUP_PCLOAD") (const_int 0))
+ (match_test "mdep_reorg_phase <= SH_FIXUP_PCLOAD")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 4092))
(const_int 8186))
(cond [(leu (plus (minus (match_dup 0) (pc)) (const_int 988))
(const_int 1986))
(const_string "yes")
- (ne (symbol_ref "mdep_reorg_phase <= SH_FIXUP_PCLOAD") (const_int 0))
+ (match_test "mdep_reorg_phase <= SH_FIXUP_PCLOAD")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 4090))
(const_int 8184))
] (const_string "no")))
(define_attr "braf_branch_p" "no,yes"
- (cond [(ne (symbol_ref "! TARGET_SH2") (const_int 0))
+ (cond [(match_test "! TARGET_SH2")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 10330))
(const_int 20660))
(const_string "yes")
- (ne (symbol_ref "mdep_reorg_phase <= SH_FIXUP_PCLOAD") (const_int 0))
+ (match_test "mdep_reorg_phase <= SH_FIXUP_PCLOAD")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 32764))
(const_int 65530))
] (const_string "no")))
(define_attr "braf_cbranch_p" "no,yes"
- (cond [(ne (symbol_ref "! TARGET_SH2") (const_int 0))
+ (cond [(match_test "! TARGET_SH2")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 10328))
(const_int 20658))
(const_string "yes")
- (ne (symbol_ref "mdep_reorg_phase <= SH_FIXUP_PCLOAD") (const_int 0))
+ (match_test "mdep_reorg_phase <= SH_FIXUP_PCLOAD")
(const_string "no")
(leu (plus (minus (match_dup 0) (pc)) (const_int 32762))
(const_int 65528))
;; ??? using pc is not computed transitively.
(ne (match_dup 0) (match_dup 0))
(const_int 14)
- (ne (symbol_ref ("flag_pic")) (const_int 0))
+ (match_test "flag_pic")
(const_int 24)
] (const_int 16))
(eq_attr "type" "jump")
(cond [(eq_attr "med_branch_p" "yes")
(const_int 2)
- (and (ne (symbol_ref "prev_nonnote_insn (insn)")
- (const_int 0))
- (and (eq (symbol_ref "GET_CODE (prev_nonnote_insn (insn))")
- (symbol_ref "INSN"))
- (eq (symbol_ref "INSN_CODE (prev_nonnote_insn (insn))")
- (symbol_ref "code_for_indirect_jump_scratch"))))
+ (and (match_test "prev_nonnote_insn (insn)")
+ (and (eq (symbol_ref "GET_CODE (prev_nonnote_insn (insn))") (symbol_ref "INSN"))
+ (eq (symbol_ref "INSN_CODE (prev_nonnote_insn (insn))") (symbol_ref "code_for_indirect_jump_scratch"))))
(cond [(eq_attr "braf_branch_p" "yes")
(const_int 6)
- (eq (symbol_ref "flag_pic") (const_int 0))
+ (not (match_test "flag_pic"))
(const_int 10)
- (ne (symbol_ref "TARGET_SH2") (const_int 0))
+ (match_test "TARGET_SH2")
(const_int 10)] (const_int 18))
(eq_attr "braf_branch_p" "yes")
(const_int 10)
;; ??? using pc is not computed transitively.
(ne (match_dup 0) (match_dup 0))
(const_int 12)
- (ne (symbol_ref ("flag_pic")) (const_int 0))
+ (match_test "flag_pic")
(const_int 22)
] (const_int 14))
(eq_attr "type" "pt_media")
- (if_then_else (ne (symbol_ref "TARGET_SHMEDIA64") (const_int 0))
+ (if_then_else (match_test "TARGET_SHMEDIA64")
(const_int 20) (const_int 12))
(and (eq_attr "type" "jump_media")
- (ne (symbol_ref "TARGET_SH5_CUT2_WORKAROUND") (const_int 0)))
+ (match_test "TARGET_SH5_CUT2_WORKAROUND"))
(const_int 8)
- ] (if_then_else (ne (symbol_ref "TARGET_SHMEDIA") (const_int 0))
+ ] (if_then_else (match_test "TARGET_SHMEDIA")
(const_int 4)
(const_int 2))))
(define_attr "needs_delay_slot" "yes,no" (const_string "no"))
(define_attr "banked" "yes,no"
- (cond [(eq (symbol_ref "sh_loads_bankedreg_p (insn)")
- (const_int 1))
+ (cond [(match_test "sh_loads_bankedreg_p (insn)")
(const_string "yes")]
(const_string "no")))
;; ??? This should be (nil) instead of (const_int 0)
(define_attr "hit_stack" "yes,no"
- (cond [(eq (symbol_ref "find_regno_note (insn, REG_INC, SP_REG)")
- (const_int 0))
+ (cond [(not (match_test "find_regno_note (insn, REG_INC, SP_REG)"))
(const_string "no")]
(const_string "yes")))
(eq_attr "type" "!pload,prset"))
(and (eq_attr "interrupt_function" "yes")
(ior
- (eq (symbol_ref "TARGET_SH3") (const_int 0))
+ (not (match_test "TARGET_SH3"))
(eq_attr "hit_stack" "no")
(eq_attr "banked" "no"))))) (nil) (nil)])
(define_delay
(and (eq_attr "type" "cbranch")
- (ne (symbol_ref "TARGET_SH2") (const_int 0)))
+ (match_test "TARGET_SH2"))
;; SH2e has a hardware bug that pretty much prohibits the use of
;; annuled delay slots.
[(eq_attr "cond_delay_slot" "yes") (and (eq_attr "cond_delay_slot" "yes")
;; SImode signed integer comparisons
;; -------------------------------------------------------------------------
-(define_insn ""
+;; Various patterns to generate the TST #imm, R0 instruction.
+;; Although this adds some pressure on the R0 register, it can potentially
+;; result in faster code, even if the operand has to be moved to R0 first.
+;; This is because on SH4 TST #imm, R0 and MOV Rm, Rn are both MT group
+;; instructions and thus will be executed in parallel. On SH4A TST #imm, R0
+;; is an EX group instruction but still can be executed in parallel with the
+;; MT group MOV Rm, Rn instruction.
+
+;; Usual TST #imm, R0 patterns for SI, HI and QI
+;; This is usually used for bit patterns other than contiguous bits
+;; and single bits.
+
+(define_insn "tstsi_t"
[(set (reg:SI T_REG)
- (eq:SI (and:SI (match_operand:SI 0 "arith_reg_operand" "z,r")
+ (eq:SI (and:SI (match_operand:SI 0 "logical_operand" "%z,r")
(match_operand:SI 1 "logical_operand" "K08,r"))
(const_int 0)))]
"TARGET_SH1"
"tst %1,%0"
[(set_attr "type" "mt_group")])
+(define_insn "tsthi_t"
+ [(set (reg:SI T_REG)
+ (eq:SI (subreg:SI (and:HI (match_operand:HI 0 "logical_operand" "%z")
+ (match_operand 1 "const_int_operand")) 0)
+ (const_int 0)))]
+ "TARGET_SH1
+ && CONST_OK_FOR_K08 (INTVAL (operands[1]))"
+ "tst %1,%0"
+ [(set_attr "type" "mt_group")])
+
+(define_insn "tstqi_t"
+ [(set (reg:SI T_REG)
+ (eq:SI (subreg:SI (and:QI (match_operand:QI 0 "logical_operand" "%z")
+ (match_operand 1 "const_int_operand")) 0)
+ (const_int 0)))]
+ "TARGET_SH1
+ && (CONST_OK_FOR_K08 (INTVAL (operands[1]))
+ || CONST_OK_FOR_I08 (INTVAL (operands[1])))"
+{
+ operands[1] = GEN_INT (INTVAL (operands[1]) & 255);
+ return "tst %1,%0";
+}
+ [(set_attr "type" "mt_group")])
+
+;; Test low QI subreg against zero.
+;; This avoids unecessary zero extension before the test.
+
+(define_insn "tstqi_t_zero"
+ [(set (reg:SI T_REG)
+ (eq:SI (match_operand:QI 0 "logical_operand" "z") (const_int 0)))]
+ "TARGET_SH1"
+ "tst #255,%0"
+ [(set_attr "type" "mt_group")])
+
+;; Extract LSB, negate and store in T bit.
+
+(define_insn "tstsi_t_and_not"
+ [(set (reg:SI T_REG)
+ (and:SI (not:SI (match_operand:SI 0 "logical_operand" "z"))
+ (const_int 1)))]
+ "TARGET_SH1"
+ "tst #1,%0"
+ [(set_attr "type" "mt_group")])
+
+;; Extract contiguous bits and compare them against zero.
+
+(define_insn "tstsi_t_zero_extract_eq"
+ [(set (reg:SI T_REG)
+ (eq:SI (zero_extract:SI (match_operand 0 "logical_operand" "z")
+ (match_operand:SI 1 "const_int_operand")
+ (match_operand:SI 2 "const_int_operand"))
+ (const_int 0)))]
+ "TARGET_SH1
+ && CONST_OK_FOR_K08 (ZERO_EXTRACT_ANDMASK (operands[1], operands[2]))"
+{
+ operands[1] = GEN_INT (ZERO_EXTRACT_ANDMASK (operands[1], operands[2]));
+ return "tst %1,%0";
+}
+ [(set_attr "type" "mt_group")])
+
+;; This split is required when testing bits in a QI subreg.
+
+(define_split
+ [(set (reg:SI T_REG)
+ (eq:SI (if_then_else:SI (zero_extract:SI
+ (match_operand 0 "logical_operand" "")
+ (match_operand 1 "const_int_operand")
+ (match_operand 2 "const_int_operand"))
+ (match_operand 3 "const_int_operand")
+ (const_int 0))
+ (const_int 0)))]
+ "TARGET_SH1
+ && ZERO_EXTRACT_ANDMASK (operands[1], operands[2]) == INTVAL (operands[3])
+ && CONST_OK_FOR_K08 (INTVAL (operands[3]))"
+ [(set (reg:SI T_REG) (eq:SI (and:SI (match_dup 0) (match_dup 3))
+ (const_int 0)))]
+ "
+{
+ if (GET_MODE (operands[0]) == QImode)
+ operands[0] = simplify_gen_subreg (SImode, operands[0], QImode, 0);
+}")
+
+;; Extract single bit, negate and store it in the T bit.
+;; Not used for SH4A.
+
+(define_insn "tstsi_t_zero_extract_xor"
+ [(set (reg:SI T_REG)
+ (zero_extract:SI (xor:SI (match_operand:SI 0 "logical_operand" "z")
+ (match_operand:SI 3 "const_int_operand"))
+ (match_operand:SI 1 "const_int_operand")
+ (match_operand:SI 2 "const_int_operand")))]
+ "TARGET_SH1
+ && ZERO_EXTRACT_ANDMASK (operands[1], operands[2]) == INTVAL (operands[3])
+ && CONST_OK_FOR_K08 (INTVAL (operands[3]))"
+ "tst %3,%0"
+ [(set_attr "type" "mt_group")])
+
+;; Extract single bit, negate and store it in the T bit.
+;; Used for SH4A little endian.
+
+(define_insn "tstsi_t_zero_extract_subreg_xor_little"
+ [(set (reg:SI T_REG)
+ (zero_extract:SI
+ (subreg:QI (xor:SI (match_operand:SI 0 "logical_operand" "z")
+ (match_operand:SI 3 "const_int_operand")) 0)
+ (match_operand:SI 1 "const_int_operand")
+ (match_operand:SI 2 "const_int_operand")))]
+ "TARGET_SH1 && TARGET_LITTLE_ENDIAN
+ && ZERO_EXTRACT_ANDMASK (operands[1], operands[2])
+ == (INTVAL (operands[3]) & 255)
+ && CONST_OK_FOR_K08 (INTVAL (operands[3]) & 255)"
+{
+ operands[3] = GEN_INT (INTVAL (operands[3]) & 255);
+ return "tst %3,%0";
+}
+ [(set_attr "type" "mt_group")])
+
+;; Extract single bit, negate and store it in the T bit.
+;; Used for SH4A big endian.
+
+(define_insn "tstsi_t_zero_extract_subreg_xor_big"
+ [(set (reg:SI T_REG)
+ (zero_extract:SI
+ (subreg:QI (xor:SI (match_operand:SI 0 "logical_operand" "z")
+ (match_operand:SI 3 "const_int_operand")) 3)
+ (match_operand:SI 1 "const_int_operand")
+ (match_operand:SI 2 "const_int_operand")))]
+ "TARGET_SH1 && ! TARGET_LITTLE_ENDIAN
+ && ZERO_EXTRACT_ANDMASK (operands[1], operands[2])
+ == (INTVAL (operands[3]) & 255)
+ && CONST_OK_FOR_K08 (INTVAL (operands[3]) & 255)"
+{
+ operands[3] = GEN_INT (INTVAL (operands[3]) & 255);
+ return "tst %3,%0";
+}
+ [(set_attr "type" "mt_group")])
+
;; ??? Perhaps should only accept reg/constant if the register is reg 0.
;; That would still allow reload to create cmpi instructions, but would
;; perhaps allow forcing the constant into a register when that is better.
&& (arith_reg_operand (operands[1], SImode)
|| (immediate_operand (operands[1], SImode)
&& satisfies_constraint_I08 (operands[1])))"
- "bt 0f\;mov %1,%0\\n0:"
+ "bt 0f\;mov %1,%0\\n0:"
[(set_attr "type" "mt_group,arith") ;; poor approximation
(set_attr "length" "4")])
&& (arith_reg_operand (operands[1], SImode)
|| (immediate_operand (operands[1], SImode)
&& satisfies_constraint_I08 (operands[1])))"
- "bf 0f\;mov %1,%0\\n0:"
+ "bf 0f\;mov %1,%0\\n0:"
[(set_attr "type" "mt_group,arith") ;; poor approximation
(set_attr "length" "4")])
;; -------------------------------------------------------------------------
(define_insn "*andsi3_compact"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r,z")
+ [(set (match_operand:SI 0 "arith_reg_dest" "=z,r")
(and:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
- (match_operand:SI 2 "logical_operand" "r,K08")))]
+ (match_operand:SI 2 "logical_operand" "K08,r")))]
"TARGET_SH1"
"and %2,%0"
[(set_attr "type" "arith")])
;;
;; shift left
-(define_insn "ashlsi3_sh2a"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0")
- (match_operand:SI 2 "arith_reg_operand" "r")))]
- "TARGET_SH2A"
- "shad %2,%0"
- [(set_attr "type" "arith")
- (set_attr "length" "4")])
-
;; This pattern is used by init_expmed for computing the costs of shift
;; insns.
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0,0,0")
(match_operand:SI 2 "nonmemory_operand" "r,M,P27,?ri")))
(clobber (match_scratch:SI 3 "=X,X,X,&r"))]
- "TARGET_SH3
+ "(TARGET_SH3 || TARGET_SH2A)
|| (TARGET_SH1 && satisfies_constraint_P27 (operands[2]))"
"@
shld %2,%0
add %0,%0
shll%O2 %0
#"
- "TARGET_SH3
+ "(TARGET_SH3 || TARGET_SH2A)
&& reload_completed
&& CONST_INT_P (operands[2])
&& ! satisfies_constraint_P27 (operands[2])"
"TARGET_SH1 && ! sh_dynamicalize_shift_p (operands[2])"
"#"
[(set (attr "length")
- (cond [(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 1))
+ (cond [(match_test "shift_insns_rtx (insn)")
(const_string "2")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 2))
(const_string "4")
if (CONST_INT_P (operands[2])
&& sh_dynamicalize_shift_p (operands[2]))
operands[2] = force_reg (SImode, operands[2]);
- if (TARGET_SH3)
+ if (TARGET_SH3 || TARGET_SH2A)
{
emit_insn (gen_ashlsi3_std (operands[0], operands[1], operands[2]));
DONE;
"TARGET_SH1"
"#"
[(set (attr "length")
- (cond [(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 1))
+ (cond [(match_test "shift_insns_rtx (insn)")
(const_string "2")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 2))
(const_string "4")]
; arithmetic shift right
;
-(define_insn "ashrsi3_sh2a"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
- (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
- "TARGET_SH2A"
- "shad %2,%0"
- [(set_attr "type" "dyn_shift")
- (set_attr "length" "4")])
-
(define_insn "ashrsi3_k"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
- "TARGET_SH3"
+ "TARGET_SH3 || TARGET_SH2A"
"shad %2,%0"
[(set_attr "type" "dyn_shift")])
;; logical shift right
-(define_insn "lshrsi3_sh2a"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
- (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
- "TARGET_SH2A"
- "shld %2,%0"
- [(set_attr "type" "dyn_shift")
- (set_attr "length" "4")])
-
(define_insn "lshrsi3_d"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
- "TARGET_SH3"
+ "TARGET_SH3 || TARGET_SH2A"
"shld %2,%0"
[(set_attr "type" "dyn_shift")])
"TARGET_SH1 && ! sh_dynamicalize_shift_p (operands[2])"
"#"
[(set (attr "length")
- (cond [(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 1))
+ (cond [(match_test "shift_insns_rtx (insn)")
(const_string "2")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 2))
(const_string "4")
if (CONST_INT_P (operands[2])
&& sh_dynamicalize_shift_p (operands[2]))
operands[2] = force_reg (SImode, operands[2]);
- if (TARGET_SH3 && arith_reg_operand (operands[2], GET_MODE (operands[2])))
+ if ((TARGET_SH3 || TARGET_SH2A)
+ && arith_reg_operand (operands[2], GET_MODE (operands[2])))
{
rtx count = copy_to_mode_reg (SImode, operands[2]);
emit_insn (gen_negsi2 (count, count));
"TARGET_SH1 && (unsigned)shl_sext_kind (operands[2], operands[3], 0) - 1 < 5"
"#"
[(set (attr "length")
- (cond [(eq (symbol_ref "shl_sext_length (insn)") (const_int 1))
+ (cond [(match_test "shl_sext_length (insn)")
(const_string "2")
(eq (symbol_ref "shl_sext_length (insn)") (const_int 2))
(const_string "4")
"sub r63, %1, %0"
[(set_attr "type" "arith_media")])
+;; Don't expand immediately because otherwise neg:DI (abs:DI) will not be
+;; combined.
(define_expand "negdi2"
- [(set (match_operand:DI 0 "arith_reg_operand" "")
- (neg:DI (match_operand:DI 1 "arith_reg_operand" "")))]
+ [(set (match_operand:DI 0 "arith_reg_dest" "")
+ (neg:DI (match_operand:DI 1 "arith_reg_operand" "")))
+ (clobber (reg:SI T_REG))]
""
+ "")
+
+(define_insn_and_split "*negdi2"
+ [(set (match_operand:DI 0 "arith_reg_dest" "=r")
+ (neg:DI (match_operand:DI 1 "arith_reg_operand" "r")))]
+ "TARGET_SH1"
+ "#"
+ "TARGET_SH1"
+ [(const_int 0)]
"
{
- if (TARGET_SH1)
- {
- int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1);
- int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
+ int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1);
+ int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
- rtx low_src = operand_subword (operands[1], low_word, 0, DImode);
- rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
+ rtx low_src = operand_subword (operands[1], low_word, 0, DImode);
+ rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
- rtx low_dst = operand_subword (operands[0], low_word, 1, DImode);
- rtx high_dst = operand_subword (operands[0], high_word, 1, DImode);
+ rtx low_dst = operand_subword (operands[0], low_word, 1, DImode);
+ rtx high_dst = operand_subword (operands[0], high_word, 1, DImode);
- emit_insn (gen_clrt ());
- emit_insn (gen_negc (low_dst, low_src));
- emit_insn (gen_negc (high_dst, high_src));
- DONE;
- }
+ emit_insn (gen_clrt ());
+ emit_insn (gen_negc (low_dst, low_src));
+ emit_insn (gen_negc (high_dst, high_src));
+ DONE;
}")
(define_insn "negsi2"
(const_int -1)))]
"TARGET_SHMEDIA" "")
-/* The SH4 202 can do zero-offset branches without pipeline stalls.
- This can be used as some kind of conditional execution, which is useful
- for abs. */
-(define_split
+(define_expand "abssi2"
[(set (match_operand:SI 0 "arith_reg_dest" "")
- (plus:SI (xor:SI (neg:SI (reg:SI T_REG))
- (match_operand:SI 1 "arith_reg_operand" ""))
- (reg:SI T_REG)))]
- "TARGET_HARD_SH4"
+ (abs:SI (match_operand:SI 1 "arith_reg_operand" "")))
+ (clobber (reg:SI T_REG))]
+ ""
+ "")
+
+(define_insn_and_split "*abssi2"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (abs:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
+ "TARGET_SH1"
+ "#"
+ "TARGET_SH1"
[(const_int 0)]
- "emit_insn (gen_movsi_i (operands[0], operands[1]));
- emit_insn (gen_cneg (operands[0], operands[0], operands[0]));
- DONE;")
+ "
+{
+ emit_insn (gen_cmpgesi_t (operands[1], const0_rtx));
+ emit_insn (gen_negsi_cond (operands[0], operands[1], operands[1],
+ const1_rtx));
+ DONE;
+}")
-(define_insn "cneg"
+(define_insn_and_split "*negabssi2"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (if_then_else:SI (eq:SI (reg:SI T_REG) (const_int 0))
- (match_operand:SI 1 "arith_reg_operand" "0")
- (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
+ (neg:SI (abs:SI (match_operand:SI 1 "arith_reg_operand" "r"))))]
+ "TARGET_SH1"
+ "#"
+ "TARGET_SH1"
+ [(const_int 0)]
+ "
+{
+ emit_insn (gen_cmpgesi_t (operands[1], const0_rtx));
+ emit_insn (gen_negsi_cond (operands[0], operands[1], operands[1],
+ const0_rtx));
+ DONE;
+}")
+
+;; The SH4 202 can do zero-offset branches without pipeline stalls.
+;; This can be used as some kind of conditional execution, which is useful
+;; for abs.
+;; Actually the instruction scheduling should decide whether to use a
+;; zero-offset branch or not for any generic case involving a single
+;; instruction on SH4 202.
+
+(define_insn_and_split "negsi_cond"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+ (if_then_else:SI (eq:SI (reg:SI T_REG)
+ (match_operand:SI 3 "const_int_operand" "M,N"))
+ (match_operand:SI 1 "arith_reg_operand" "0,0")
+ (neg:SI (match_operand:SI 2 "arith_reg_operand" "r,r"))))]
"TARGET_HARD_SH4"
- "bf 0f\;neg %2,%0\\n0:"
+ "@
+ bt\\t0f\;neg\\t%2,%0\\n0:
+ bf\\t0f\;neg\\t%2,%0\\n0:"
+ "!TARGET_HARD_SH4"
+ [(const_int 0)]
+ "
+{
+ rtx skip_neg_label = gen_label_rtx ();
+
+ emit_insn (gen_movsi (operands[0], operands[1]));
+
+ emit_jump_insn (INTVAL (operands[3])
+ ? gen_branch_true (skip_neg_label)
+ : gen_branch_false (skip_neg_label));
+
+ emit_label_after (skip_neg_label,
+ emit_insn (gen_negsi2 (operands[0], operands[1])));
+ DONE;
+}"
[(set_attr "type" "arith") ;; poor approximation
(set_attr "length" "4")])
ld%M1.uw %m1, %0"
[(set_attr "type" "*,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
ld%M1.ub %m1, %0"
[(set_attr "type" "arith_media,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
ld%M1.uw %m1, %0"
[(set_attr "type" "arith_media,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
ld%M1.ub %m1, %0"
[(set_attr "type" "arith_media,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
fmov.sl %1, %0"
[(set_attr "type" "arith_media,load_media,fpconv_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "extend")))])
ld%M1.w %m1, %0"
[(set_attr "type" "*,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
ld%M1.b %m1, %0"
[(set_attr "type" "*,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
ld%M1.w %m1, %0"
[(set_attr "type" "arith_media,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
(set_attr_alternative "length"
[(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))])])
(define_insn "*extendqisi2_media"
ld%M1.b %m1, %0"
[(set_attr "type" "arith_media,load_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
(set_attr_alternative "length"
[(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))])])
/* It would seem useful to combine the truncXi patterns into the movXi
fmov.s %T1, %0"
[(set_attr "type" "arith_media,store_media,fstore_media,fload_media,fpconv_media,fmove_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "extend")))])
[(set_attr "type" "arith_media,store_media")
(set_attr "length" "8,4")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "extend")))])
st%M0.b %m0, %1"
[(set_attr "type" "arith_media,store")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "extend")))])
;; -------------------------------------------------------------------------
(const_int 4)
(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(const_int 2)
(const_int 2)
(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(const_int 2)
(const_int 2)
[(set_attr "type" "arith_media,arith_media,*,load_media,store_media,fload_media,fstore_media,fload_media,fpconv_media,fmove_media,ptabs_media,gettr_media,pt_media")
(set_attr "length" "4,4,8,4,4,4,4,4,4,4,4,4,12")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
[(set_attr "type" "arith_media,arith_media,*,load_media,store_media,ptabs_media,gettr_media,pt_media")
(set_attr "length" "4,4,8,4,4,4,4,12")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
[(const_int 2)
(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(const_int 2)
(const_int 2)
st%M0.b %m0, %N1"
[(set_attr "type" "arith_media,arith_media,load_media,store_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
operands[3] = gen_rtx_REG (DImode, REGNO (operands[2]));
}")
-/* When storing r0, we have to avoid reg+reg addressing. */
+;; When storing r0, we have to avoid reg+reg addressing.
(define_insn "movhi_i"
[(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m,r,l,r")
(match_operand:HI 1 "general_movsrc_operand" "Q,rI08,m,t,r,l,r,i"))]
st%M0.w %m0, %N1"
[(set_attr "type" "arith_media,arith_media,*,load_media,store_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
;; We can't use 4-byte push/pop on SHcompact, so we have to
;; increment or decrement r15 explicitly.
(if_then_else
- (ne (symbol_ref "TARGET_SHCOMPACT") (const_int 0))
+ (match_test "TARGET_SHCOMPACT")
(const_int 10) (const_int 8))
(if_then_else
- (ne (symbol_ref "TARGET_SHCOMPACT") (const_int 0))
+ (match_test "TARGET_SHCOMPACT")
(const_int 10) (const_int 8))])
(set_attr "type" "fmove,move,pcfload,fload,fstore,pcload,load,store,load,fload")
(set_attr "late_fp_use" "*,*,*,*,yes,*,*,*,*,*")
st%M0.l %m0, %N1"
[(set_attr "type" "fmove_media,fload_media,fpconv_media,arith_media,*,fload_media,fstore_media,load_media,store_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
st%M0.l %m0, %N1"
[(set_attr "type" "arith_media,*,load_media,store_media")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
(const_int 2)
(const_int 4)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(const_int 2)
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(if_then_else
- (ne (symbol_ref "TARGET_SH2A") (const_int 0))
+ (match_test "TARGET_SH2A")
(const_int 4) (const_int 2))
(const_int 2)
(const_int 2)
(set_attr "fp_set" "unknown")])
;; This is TBR relative jump instruction for SH2A architecture.
-;; Its use is enabled assigning an attribute "function_vector"
+;; Its use is enabled by assigning an attribute "function_vector"
;; and the vector number to a function during its declaration.
(define_insn "call_valuei_tbr_rel"
DONE;
")
-
-
;; sne moves the complement of the T reg to DEST like this:
;; cmp/eq ...
;; mov #-1,temp
operands[1] = gen_reg_rtx (SImode);
}")
-
;; Recognize mov #-1/negc/neg sequence, and change it to movt/add #-1.
;; This prevents a regression that occurred when we switched from xor to
;; mov/neg for sne.
DONE;
")
-
;; -------------------------------------------------------------------------
;; Instructions to cope with inline literal tables
;; -------------------------------------------------------------------------
[(set_attr "type" "arith_media,arith_media,*,load_media,store_media")
(set_attr "length" "4,4,16,4,4")
(set (attr "highpart")
- (cond [(ne (symbol_ref "sh_contains_memref_p (insn)") (const_int 0))
+ (cond [(match_test "sh_contains_memref_p (insn)")
(const_string "user")]
(const_string "ignore")))])
[(set_attr "type" "arith_media")
(set_attr "highpart" "ignore")])
-/* These are useful to expand ANDs and as combiner patterns. */
+;; These are useful to expand ANDs and as combiner patterns.
(define_insn_and_split "mshfhi_l_di"
[(set (match_operand:DI 0 "arith_reg_dest" "=r,f")
(ior:DI (lshiftrt:DI (match_operand:DI 1 "arith_reg_or_0_operand" "rZ,f")
"ld%M1.q\t%m1, %0\;ld%M2.q\t%m2, %3\;cmpeq\t%0, %3, %0\;movi\t0, %3"
[(set_attr "type" "other")
(set_attr "length" "16")])
+
+(include "sync.md")