===================================================================
@@ -0,0 +1,50 @@
+/* Check that no unnecessary sign or zero extension insn is generated after
+ a negc or movrt insn that stores the inverted T bit in a reg. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "extu|exts" } } */
+
+int
+test_00 (int a, int b, int* c, short* d, int x)
+{
+ *d = x != 0;
+ *c = -1;
+
+ if (x != 0)
+ return a > 0;
+
+ return 0;
+}
+
+unsigned char
+test_01 (int x)
+{
+ if (x < 58 && x > 47)
+ return 1;
+ return 0;
+}
+
+char
+test_02 (int x)
+{
+ if (x < 58 && x > 47)
+ return 1;
+ return 0;
+}
+
+unsigned short
+test_03 (int x)
+{
+ if (x < 58 && x > 47)
+ return 1;
+ return 0;
+}
+
+short
+test_04 (int x)
+{
+ if (x < 58 && x > 47)
+ return 1;
+ return 0;
+}
===================================================================
@@ -0,0 +1,15 @@
+/* Check that no unnecessary sign or zero extension insn is generated after
+ a negc or movrt insn that stores the inverted T bit in a reg. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m1" "-m2" "-m3" "-m4al" "*nofpu" "-m4-340*" "-m4-400*" "-m4-500*" "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "extu|exts" } } */
+
+float
+test_00 (float q[4], float m[9])
+{
+ float s0 = m[0] + m[1];
+ float s1 = m[0] - m[1];
+
+ return q[s0 > s1 ? 0 : 1];
+}
===================================================================
@@ -9515,7 +9515,7 @@
(define_insn "movrt"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (xor:SI (reg:SI T_REG) (const_int 1)))]
+ (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))]
"TARGET_SH2A"
"movrt %0"
[(set_attr "type" "arith")])
@@ -9668,28 +9668,66 @@
(define_expand "movnegt"
[(set (match_operand:SI 0 "arith_reg_dest" "")
- (xor:SI (reg:SI T_REG) (const_int 1)))]
- ""
+ (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))]
+ "TARGET_SH1"
{
if (TARGET_SH2A)
- emit_insn (gen_movrt (operands[0]));
+ emit_insn (gen_movrt (operands[0], operands[1]));
else
{
rtx val = force_reg (SImode, gen_int_mode (-1, SImode));
- emit_insn (gen_movrt_negc (operands[0], val));
+ emit_insn (gen_movrt_negc (operands[0], operands[1], val));
}
DONE;
})
(define_insn "movrt_negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (xor:SI (reg:SI T_REG) (const_int 1)))
+ (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
(set (reg:SI T_REG) (const_int 1))
- (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+ (use (match_operand:SI 2 "arith_reg_operand" "r"))]
"TARGET_SH1"
- "negc %1,%0"
+ "negc %2,%0"
[(set_attr "type" "arith")])
+;; The -1 constant will not be CSE-ed for the *movrt_negc pattern, but the
+;; pattern can be used by the combine pass. Using a scratch reg for the
+;; -1 constant results in slightly better register allocations compared to
+;; generating a pseudo reg before reload.
+(define_insn_and_split "*movrt_negc"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
+ (clobber (match_scratch:SI 2 "=r"))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1 && ! TARGET_SH2A"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 2) (const_int -1))
+ (parallel
+ [(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1)))
+ (set (reg:SI T_REG) (const_int 1))
+ (use (match_dup 2))])])
+
+;; In some cases the zero extension does not get combined away and a
+;; sequence like the following might remain:
+;; mov #-1,r2
+;; tst r1,r1
+;; negc r2,r1
+;; extu.b r1,r1
+(define_peephole2
+ [(parallel
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
+ (set (reg:SI T_REG) (const_int 1))
+ (use (match_operand:SI 2 "arith_reg_operand" ""))])
+ (set (match_dup 0)
+ (zero_extend:SI (match_operand 3 "arith_reg_operand" "")))]
+ "TARGET_SH1 && REGNO (operands[0]) == REGNO (operands[3])"
+ [(parallel
+ [(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1)))
+ (set (reg:SI T_REG) (const_int 1))
+ (use (match_dup 2))])])
+
;; The *negnegt pattern helps the combine pass to figure out how to fold
;; an explicit double T bit negation.
(define_insn_and_split "*negnegt"
@@ -9729,7 +9767,8 @@
[(const_int 0)])
(define_insn_and_split "nott"
- [(set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))]
+ [(set (reg:SI T_REG)
+ (xor:SI (match_operand:SI 0 "t_reg_operand" "") (const_int 1)))]
"TARGET_SH1"
{
gcc_assert (TARGET_SH2A);
===================================================================
@@ -1893,7 +1893,7 @@
branch_expander = gen_branch_false;
default: ;
}
- emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, T_REG),
+ emit_insn (gen_rtx_SET (VOIDmode, get_t_reg_rtx (),
gen_rtx_fmt_ee (comparison, SImode,
operands[1], operands[2])));
jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ()));
@@ -2129,7 +2129,7 @@
void
sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1)
{
- rtx t_reg = gen_rtx_REG (SImode, T_REG);
+ rtx t_reg = get_t_reg_rtx ();
enum rtx_code oldcode = code;
enum machine_mode mode;
@@ -2304,7 +2304,7 @@
}
insn = gen_rtx_SET (VOIDmode,
- gen_rtx_REG (SImode, T_REG),
+ get_t_reg_rtx (),
gen_rtx_fmt_ee (branch_code, SImode, op0, op1));
sh_emit_set_t_insn (insn, mode);
@@ -2369,9 +2369,9 @@
if (lab)
emit_label (lab);
if (invert)
- emit_insn (gen_movnegt (operands[0]));
+ emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
else
- emit_move_insn (operands[0], gen_rtx_REG (SImode, T_REG));
+ emit_move_insn (operands[0], get_t_reg_rtx ());
}
/* Functions to output assembly code. */
@@ -12121,7 +12121,7 @@
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result, get_t_reg_rtx ()));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
- emit_insn (gen_movnegt (result));
+ emit_insn (gen_movnegt (result, get_t_reg_rtx ()));
else if (code == EQ || code == NE)
emit_insn (gen_move_insn (result, GEN_INT (code == NE)));
else
===================================================================
@@ -830,7 +830,7 @@
/* The result of the test op is the inverse of what we are
supposed to return. Thus invert the T bit. The inversion will be
potentially optimized away and integrated into surrounding code. */
- emit_insn (gen_movnegt (operands[0]));
+ emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
DONE;
})