re PR target/51244 ([SH] Inefficient conditional branch and code around T bit)
authorOleg Endo <olegendo@gcc.gnu.org>
Thu, 9 Aug 2012 15:55:18 +0000 (15:55 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Thu, 9 Aug 2012 15:55:18 +0000 (15:55 +0000)
PR target/51244
* config/sh/sh.md: Add negc extu sequence peephole.
(movrt, movnegt, movrt_negc, nott): Use t_reg_operand predicate.
(*movrt_negc): New insn.
* config/sh/sync.md (atomic_test_and_set): Pass gen_t_reg_rtx to
gen_movnegt.
* config/sh/sh.c (expand_cbranchsi4, sh_emit_scc_to_t,
sh_emit_compare_and_branch, sh_emit_compare_and_set): Use get_t_reg_rtx.
(sh_expand_t_scc): Pass gen_t_reg_rtx to gen_movnegt.

PR target/51244
* gcc.target/sh/pr51244-5: New.
* gcc.target/sh/pr51244-6: New.

From-SVN: r190258

gcc/ChangeLog
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/config/sh/sync.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr51244-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr51244-6.c [new file with mode: 0644]

index d6631a91108c8b2444d371e19722f8f8bb85dfd5..318278a811a1187d0e73504c256273accf7611cd 100644 (file)
@@ -1,3 +1,15 @@
+2012-08-09  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/51244
+       * config/sh/sh.md: Add negc extu sequence peephole.
+       (movrt, movnegt, movrt_negc, nott): Use t_reg_operand predicate.
+       (*movrt_negc): New insn.
+       * config/sh/sync.md (atomic_test_and_set): Pass gen_t_reg_rtx to
+       gen_movnegt.
+       * config/sh/sh.c (expand_cbranchsi4, sh_emit_scc_to_t,
+       sh_emit_compare_and_branch, sh_emit_compare_and_set): Use get_t_reg_rtx.
+       (sh_expand_t_scc): Pass gen_t_reg_rtx to gen_movnegt.
+
 2012-08-09  Oleg Endo  <olegendo@gcc.gnu.org>
 
        PR target/50751
index 88497c78eaae687dde07180b21b257abd08dfa7b..afd6d3dae97a2201b8e6871a848ca80d4cf20806 100644 (file)
@@ -1893,7 +1893,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
       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 @@ sh_emit_set_t_insn (rtx insn, enum machine_mode mode)
 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 @@ sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode)
     }
 
   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 @@ sh_emit_compare_and_set (rtx *operands, enum machine_mode mode)
   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 ());
 }
 \f
 /* Functions to output assembly code.  */
@@ -12121,7 +12121,7 @@ sh_expand_t_scc (rtx operands[])
   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
index 0d6f161acb9917ec7ce71f433a4c77b6b9518497..c95c904844ccd630b7a32102f80a1ccb4b7fafd9 100644 (file)
@@ -9641,7 +9641,7 @@ label:
 
 (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")])
@@ -9794,28 +9794,66 @@ label:
 
 (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"
@@ -9855,7 +9893,8 @@ label:
   [(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);
index 79cd765d87f2be1395d18da18157a025e9199d78..6dabf873c17327793d17b50d7816cffeb738b99b 100644 (file)
   /* 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;
 })
 
index 021ce85fac4f0eb513aab8a6e2f04490327559dd..cffdd0b183475fda6a63a2751033978ee6b85d71 100644 (file)
@@ -1,3 +1,9 @@
+2012-08-09  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/51244
+       * gcc.target/sh/pr51244-5: New.
+       * gcc.target/sh/pr51244-6: New.
+
 2012-08-09  Michael Zolotukhin  <michael.v.zolotukhin@intel.com>
 
        * gcc.target/i386/adx-addxcarry32-3.c: New.
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-5.c b/gcc/testsuite/gcc.target/sh/pr51244-5.c
new file mode 100644 (file)
index 0000000..a99889d
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-6.c b/gcc/testsuite/gcc.target/sh/pr51244-6.c
new file mode 100644 (file)
index 0000000..cfd4661
--- /dev/null
@@ -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];
+}