===================================================================
@@ -0,0 +1,32 @@
+/* Check that inverted conditional branch logic does not generate
+ unnecessary explicit T bit extractions, inversions and
+ test instructions. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1 -mbranch-cost=2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
+/* { dg-final { scan-assembler-not "tst|negc|extu" } } */
+
+int
+testfunc_00 (int a, int b, int c, int d)
+{
+ return (a != b || a != d) ? b : c;
+}
+
+int
+testfunc_01 (int a, char* p, int b, int c)
+{
+ return (a == b && a == c) ? b : c;
+}
+
+int
+testfunc_02 (int a, char* p, int b, int c)
+{
+ return (a == b && a == c) ? b : c;
+}
+
+int
+testfunc_03 (int a, char* p, int b, int c)
+{
+ return (a != b && a != c) ? b : c;
+}
+
===================================================================
@@ -0,0 +1,18 @@
+/* Check that when taking the complement of the T bit using the negc
+ instruction pattern, the constant -1 is loaded only once.
+ On SH2A this test is skipped because the movrt instruction is used
+ to get the complement of the T bit. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1 -mbranch-cost=2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */
+/* { dg-final { scan-assembler-times "mov\t#-1" 1 } } */
+
+void
+testfunc_00 (int* a, int* b, int c, int d)
+{
+ b[0] = a[0] != c;
+ b[1] = a[1] != d;
+ b[2] = a[2] != c;
+ b[3] = a[3] != d;
+}
+
===================================================================
@@ -0,0 +1,16 @@
+/* Check that when taking the complement of the T bit on SH2A,
+ the movrt instruction is being generated. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1 -mbranch-cost=2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
+/* { dg-final { scan-assembler-times "movrt" 4 } } */
+
+void
+testfunc_00 (int* a, int* b, int c, int d)
+{
+ b[0] = a[0] != c;
+ b[1] = a[1] != d;
+ b[2] = a[2] != c;
+ b[3] = a[3] != d;
+}
+
===================================================================
@@ -11883,15 +11883,8 @@
val = INTVAL (op1);
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result));
- else if (TARGET_SH2A && ((code == EQ && val == 0)
- || (code == NE && val == 1)))
- emit_insn (gen_xorsi3_movrt (result));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
- {
- emit_clobber (result);
- emit_insn (gen_subc (result, result, result));
- emit_insn (gen_addsi3 (result, result, const1_rtx));
- }
+ emit_insn (gen_movnegt (result));
else if (code == EQ || code == NE)
emit_insn (gen_move_insn (result, GEN_INT (code == NE)));
else
===================================================================
@@ -3354,15 +3354,6 @@
xori %1, %2, %0"
[(set_attr "type" "arith_media")])
-;; Store the complements of the T bit in a register.
-(define_insn "xorsi3_movrt"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (xor:SI (reg:SI T_REG)
- (const_int 1)))]
- "TARGET_SH2A"
- "movrt\\t%0"
- [(set_attr "type" "arith")])
-
(define_insn "xordi3"
[(set (match_operand:DI 0 "arith_reg_dest" "=r,r")
(xor:DI (match_operand:DI 1 "arith_reg_operand" "%r,r")
@@ -4387,7 +4378,17 @@
;; Unary arithmetic
;; -------------------------------------------------------------------------
-(define_insn "negc"
+(define_expand "negc"
+ [(parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (neg:SI (plus:SI (reg:SI T_REG)
+ (match_operand:SI 1 "arith_reg_operand" ""))))
+ (set (reg:SI T_REG)
+ (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
+ (const_int 0)))])]
+ ""
+ "")
+
+(define_insn "*negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(neg:SI (plus:SI (reg:SI T_REG)
(match_operand:SI 1 "arith_reg_operand" "r"))))
@@ -9528,6 +9529,13 @@
"movt %0"
[(set_attr "type" "arith")])
+(define_insn "movrt"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (xor:SI (reg:SI T_REG) (const_int 1)))]
+ "TARGET_SH2A"
+ "movrt %0"
+ [(set_attr "type" "arith")])
+
(define_expand "cstore4_media"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "sh_float_comparison_operator"
@@ -9654,40 +9662,55 @@
DONE;
")
-;; sne moves the complement of the T reg to DEST like this:
-;; cmp/eq ...
-;; mov #-1,temp
-;; negc temp,dest
-;; This is better than xoring compare result with 1 because it does
-;; not require r0 and further, the -1 may be CSE-ed or lifted out of a
-;; loop.
+;; Move the complement of the T reg to a reg.
+;; On SH2A the movrt insn can be used.
+;; On anything else than SH2A this has to be done with multiple instructions.
+;; One obvious way would be:
+;; cmp/eq ...
+;; movt r0
+;; xor #1,r0
+;;
+;; However, this puts pressure on r0 in most cases and thus the following is
+;; more appealing:
+;; cmp/eq ...
+;; mov #-1,temp
+;; negc temp,dest
+;;
+;; If the constant -1 can be CSE-ed or lifted out of a loop it effectively
+;; becomes a one instruction operation. Moreover, care must be taken that
+;; the insn can still be combined with inverted compare and branch code
+;; around it.
+;; The expander will reserve the constant -1, the insn makes the whole thing
+;; combinable, the splitter finally emits the insn if it was not combined
+;; away.
+;; Notice that when using the negc variant the T bit also gets inverted.
(define_expand "movnegt"
[(set (match_dup 1) (const_int -1))
- (parallel [(set (match_operand:SI 0 "" "")
- (neg:SI (plus:SI (reg:SI T_REG)
- (match_dup 1))))
- (set (reg:SI T_REG)
- (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
- (const_int 0)))])]
+ (parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (xor:SI (reg:SI T_REG) (const_int 1)))
+ (use (match_dup 1))])]
""
- "
{
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.
-
-(define_split
- [(set (match_operand:SI 0 "arith_reg_dest" "")
- (plus:SI (reg:SI T_REG)
- (const_int -1)))]
+(define_insn_and_split "*movnegt"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (xor:SI (reg:SI T_REG) (const_int 1)))
+ (use (match_operand:SI 1 "arith_reg_operand" "r"))]
"TARGET_SH1"
- [(set (match_dup 0) (eq:SI (reg:SI T_REG) (const_int 1)))
- (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))]
- "")
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ if (TARGET_SH2A)
+ emit_insn (gen_movrt (operands[0]));
+ else
+ emit_insn (gen_negc (operands[0], operands[1]));
+ DONE;
+}
+ [(set_attr "type" "arith")])
(define_expand "cstoresf4"
[(set (match_operand:SI 0 "register_operand" "=r")