re PR target/51244 ([SH] Inefficient conditional branch and code around T bit)
authorOleg Endo <olegendo@gcc.gnu.org>
Mon, 2 Jul 2012 19:23:56 +0000 (19:23 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Mon, 2 Jul 2012 19:23:56 +0000 (19:23 +0000)
PR target/51244
* config/sh/predicates.md (t_reg_operand, negt_reg_operand): New
predicates.
* config/sh/sh-protos.h (get_t_reg_rtx): New prototype.
* config/sh/sh.c (get_t_reg_rtx): New function.  Use it when invoking
gen_branch_true and gen_branch_false.
* config/sh/sh.md: Use get_t_reg_rtx when invoking gen_branch_true and
gen_branch_false.
(branch_true, branch_false): Use t_reg_operand predicate.
(*branch_true, *branch_false): Delete.
(movt): Use t_reg_operand predicate.
(*negnegt): Use negt_reg_operand predicate and fold little and big
endian variants.
(*movtt): Use t_reg_operand and fold little and big endian variants.
(*movt_qi): Delete.

PR target/51244
* gcc.target/sh/pr51244-1.c: Check that movt insn is not generated.

From-SVN: r189177

gcc/ChangeLog
gcc/config/sh/predicates.md
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr51244-1.c

index bee63bb8f1330cf0bcbadfbd7907d38e19c02784..231e624be899e9ef9ff93ba1d636ce56c8a803ac 100644 (file)
@@ -1,3 +1,21 @@
+2012-07-02  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/51244
+       * config/sh/predicates.md (t_reg_operand, negt_reg_operand): New
+       predicates.
+       * config/sh/sh-protos.h (get_t_reg_rtx): New prototype.
+       * config/sh/sh.c (get_t_reg_rtx): New function.  Use it when invoking
+       gen_branch_true and gen_branch_false.
+       * config/sh/sh.md: Use get_t_reg_rtx when invoking gen_branch_true and
+       gen_branch_false.
+       (branch_true, branch_false): Use t_reg_operand predicate.
+       (*branch_true, *branch_false): Delete.
+       (movt): Use t_reg_operand predicate.
+       (*negnegt): Use negt_reg_operand predicate and fold little and big
+       endian variants.
+       (*movtt): Use t_reg_operand and fold little and big endian variants.
+       (*movt_qi): Delete.
+
 2012-07-02  Steven Bosscher  <steven@gcc.gnu.org>
 
        * stmt.c (emit_case_bit_tests): Remove.
index f75675ec0964cb74f5b82364c0f56d785a408032..d58f657c857de9fc979df3ad22a65f675ec6f103 100644 (file)
            (match_test "mode != HImode")
            (match_test "TARGET_SH4A_ARCH"))))
 
+;; A predicate describing the T bit register in any form.
+(define_predicate "t_reg_operand"
+  (match_code "reg,subreg,sign_extend,zero_extend")
+{
+  switch (GET_CODE (op))
+    {
+      case REG:
+       return REGNO (op) == T_REG;
+
+      case SUBREG:
+       return REGNO (SUBREG_REG (op)) == T_REG;
+
+      case ZERO_EXTEND:
+      case SIGN_EXTEND:
+       return GET_CODE (XEXP (op, 0)) == SUBREG
+              && REGNO (SUBREG_REG (XEXP (op, 0))) == T_REG;
+
+      default:
+       return 0;
+    }
+})
+
+;; A predicate describing a negated T bit register.
+(define_predicate "negt_reg_operand"
+  (match_code "subreg,xor")
+{
+  switch (GET_CODE (op))
+    {
+      case XOR:
+       return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
+              && satisfies_constraint_M (XEXP (op, 1));
+
+      case SUBREG:
+       return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)));
+
+      default:
+       return 0;
+    }
+})
index cb9ad0f203ff42e001564518f3209da42f2750ce..3fcfe29a28acae09b7c8cf788699f9a847566896 100644 (file)
@@ -109,6 +109,7 @@ extern bool sh_vector_mode_supported_p (enum machine_mode);
 #endif /* RTX_CODE */
 
 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);
index 7e0c2c17515fef1e3e5dad427f60a34145b03382..77324b66c94b3e3e916e4dbb92e38b7ae69ff9aa 100644 (file)
@@ -1874,7 +1874,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
 void
 expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
 {
-  rtx (*branch_expander) (rtx) = gen_branch_true;
+  rtx (*branch_expander) (rtx, rtx) = gen_branch_true;
   rtx jump;
 
   comparison = prepare_cbranch_operands (operands, SImode, comparison);
@@ -1888,7 +1888,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, T_REG),
                           gen_rtx_fmt_ee (comparison, SImode,
                                           operands[1], operands[2])));
-  jump = emit_jump_insn (branch_expander (operands[3]));
+  jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ()));
   if (probability >= 0)
     add_reg_note (jump, REG_BR_PROB, GEN_INT (probability));
 
@@ -1941,7 +1941,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       if (TARGET_CMPEQDI_T)
        {
          emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
-         emit_jump_insn (gen_branch_true (operands[3]));
+         emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
          return true;
        }
       msw_skip = NE;
@@ -1969,7 +1969,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       if (TARGET_CMPEQDI_T)
        {
          emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
-         emit_jump_insn (gen_branch_false (operands[3]));
+         emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
          return true;
        }
       msw_taken = NE;
@@ -2304,9 +2304,9 @@ sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode)
     sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode);
 
   if (branch_code == code)
-    emit_jump_insn (gen_branch_true (operands[3]));
+    emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
   else
-    emit_jump_insn (gen_branch_false (operands[3]));
+    emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
 }
 
 void
@@ -2340,7 +2340,7 @@ sh_emit_compare_and_set (rtx *operands, enum machine_mode mode)
             {
               lab = gen_label_rtx ();
               sh_emit_scc_to_t (EQ, op0, op1);
-              emit_jump_insn (gen_branch_true (lab));
+              emit_jump_insn (gen_branch_true (lab, get_t_reg_rtx ()));
               code = GT;
            }
           else
@@ -3360,7 +3360,7 @@ gen_shifty_op (int code, rtx *operands)
       if (code == LSHIFTRT)
        {
          emit_insn (gen_rotlsi3_1 (operands[0], operands[0]));
-         emit_insn (gen_movt (operands[0]));
+         emit_insn (gen_movt (operands[0], get_t_reg_rtx ()));
          return;
        }
       else if (code == ASHIFT)
@@ -9504,6 +9504,15 @@ reg_unused_after (rtx reg, rtx insn)
 \f
 #include "ggc.h"
 
+static GTY(()) rtx t_reg_rtx;
+rtx
+get_t_reg_rtx (void)
+{
+  if (! t_reg_rtx)
+    t_reg_rtx = gen_rtx_REG (SImode, T_REG);
+  return t_reg_rtx;
+}
+
 static GTY(()) rtx fpscr_rtx;
 rtx
 get_fpscr_rtx (void)
@@ -12049,7 +12058,7 @@ sh_expand_t_scc (rtx operands[])
     result = gen_reg_rtx (SImode);
   val = INTVAL (op1);
   if ((code == EQ && val == 1) || (code == NE && val == 0))
-    emit_insn (gen_movt (result));
+    emit_insn (gen_movt (result, get_t_reg_rtx ()));
   else if ((code == EQ && val == 0) || (code == NE && val == 1))
     emit_insn (gen_movnegt (result));
   else if (code == EQ || code == NE)
index 852f9fd36ea0543ee6397d5d6be636c868639188..4e2425f4888e0d706ea11fae490ac2a3d34542f9 100644 (file)
@@ -4450,8 +4450,8 @@ label:
   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));
+                 ? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
+                 : gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
 
   emit_label_after (skip_neg_label,
                    emit_insn (gen_negsi2 (operands[0], operands[1])));
@@ -4519,8 +4519,8 @@ label:
   emit_insn (gen_movsi (high_dst, high_src));
 
   emit_jump_insn (INTVAL (operands[3]) 
-                 ? gen_branch_true (skip_neg_label)
-                 : gen_branch_false (skip_neg_label));
+                 ? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
+                 : gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
 
   if (!INTVAL (operands[3]))
     emit_insn (gen_clrt ());
@@ -7195,66 +7195,22 @@ label:
 ;; ------------------------------------------------------------------------
 
 (define_insn "branch_true"
-  [(set (pc) (if_then_else (ne (reg:SI T_REG) (const_int 0))
-                          (label_ref (match_operand 0 "" ""))
-                          (pc)))]
-  "TARGET_SH1"
-{
-  return output_branch (1, insn, operands);
-}
-  [(set_attr "type" "cbranch")])
-
-;; The *branch_true patterns help combine when trying to invert conditions.
-(define_insn "*branch_true"
-  [(set (pc) (if_then_else (ne (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
+  [(set (pc) (if_then_else (ne (match_operand 1 "t_reg_operand" "")
                               (const_int 0))
                           (label_ref (match_operand 0 "" ""))
                           (pc)))]
-  "TARGET_SH1 && TARGET_LITTLE_ENDIAN"
-{
-  return output_branch (1, insn, operands);
-}
-  [(set_attr "type" "cbranch")])
-
-(define_insn "*branch_true"
-  [(set (pc) (if_then_else (ne (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
-                              (const_int 0))
-                          (label_ref (match_operand 0 "" ""))
-                          (pc)))]
-  "TARGET_SH1 && ! TARGET_LITTLE_ENDIAN"
+  "TARGET_SH1"
 {
   return output_branch (1, insn, operands);
 }
   [(set_attr "type" "cbranch")])
 
 (define_insn "branch_false"
-  [(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
-                          (label_ref (match_operand 0 "" ""))
-                          (pc)))]
-  "TARGET_SH1"
-{
-  return output_branch (0, insn, operands);
-}
-  [(set_attr "type" "cbranch")])
-
-;; The *branch_false patterns help combine when trying to invert conditions.
-(define_insn "*branch_false"
-  [(set (pc) (if_then_else (eq (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
-                              (const_int 0))
-                          (label_ref (match_operand 0 "" ""))
-                          (pc)))]
-  "TARGET_SH1 && TARGET_LITTLE_ENDIAN"
-{
-  return output_branch (0, insn, operands);
-}
-  [(set_attr "type" "cbranch")])
-
-(define_insn "*branch_false"
-  [(set (pc) (if_then_else (eq (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
+  [(set (pc) (if_then_else (eq (match_operand 1 "t_reg_operand" "")
                               (const_int 0))
                           (label_ref (match_operand 0 "" ""))
                           (pc)))]
-  "TARGET_SH1 && ! TARGET_LITTLE_ENDIAN"
+  "TARGET_SH1"
 {
   return output_branch (0, insn, operands);
 }
@@ -9672,7 +9628,7 @@ label:
 
 (define_insn "movt"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
-       (eq:SI (reg:SI T_REG) (const_int 1)))]
+       (match_operand:SI 1 "t_reg_operand"))]
   "TARGET_SH1"
   "movt        %0"
   [(set_attr "type" "arith")])
@@ -9854,62 +9810,25 @@ label:
   "negc        %1,%0"
   [(set_attr "type" "arith")])
 
-;; The *negnegt patterns help the combine pass to figure out how to fold 
+;; The *negnegt pattern helps the combine pass to figure out how to fold 
 ;; an explicit double T bit negation.
 (define_insn_and_split "*negnegt"
   [(set (reg:SI T_REG)
-       (eq:SI (subreg:QI (xor:SI (reg:SI T_REG) (const_int 1)) 3)
-        (const_int 0)))]
-  "! TARGET_LITTLE_ENDIAN"
-  "#"
-  ""
-  [(const_int 0)])
-
-(define_insn_and_split "*negnegt"
-  [(set (reg:SI T_REG)
-       (eq:SI (subreg:QI (xor:SI (reg:SI T_REG) (const_int 1)) 0)
-        (const_int 0)))]
-  "TARGET_LITTLE_ENDIAN"
-  "#"
-  ""
-  [(const_int 0)])
-
-;; The *movtt patterns eliminate redundant T bit to T bit moves / tests.
-(define_insn_and_split "*movtt"
-  [(set (reg:SI T_REG)
-       (eq:SI (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
-        (const_int 1)))]
-  "! TARGET_LITTLE_ENDIAN"
+       (eq:SI (match_operand 0 "negt_reg_operand" "") (const_int 0)))]
+  "TARGET_SH1"
   "#"
   ""
   [(const_int 0)])
 
+;; The *movtt pattern eliminates redundant T bit to T bit moves / tests.
 (define_insn_and_split "*movtt"
   [(set (reg:SI T_REG)
-       (eq:SI (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
-        (const_int 1)))]
-  "TARGET_LITTLE_ENDIAN"
+       (eq:SI (match_operand 0 "t_reg_operand" "") (const_int 1)))]
+  "TARGET_SH1"
   "#"
   ""
   [(const_int 0)])
 
-;; The *movt_qi patterns help the combine pass convert a movrt_negc pattern
-;; into a movt Rn, xor #1 Rn pattern.  This can happen when e.g. a function
-;; returns the inverted T bit value.
-(define_insn "*movt_qi"
-  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
-       (zero_extend:SI (subreg:QI (reg:SI T_REG) 3)))]
-  "! TARGET_LITTLE_ENDIAN"
-  "movt        %0"
-  [(set_attr "type" "arith")])
-
-(define_insn "*movt_qi"
-  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
-       (zero_extend:SI (subreg:QI (reg:SI T_REG) 0)))]
-  "TARGET_LITTLE_ENDIAN"
-  "movt        %0"
-  [(set_attr "type" "arith")])
-
 (define_expand "cstoresf4"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (match_operator:SI 1 "sh_float_comparison_operator"
@@ -13960,7 +13879,7 @@ label:
   else
     {
       emit_insn (gen_stack_protect_test_si (operands[0], operands[1]));
-      emit_jump_insn (gen_branch_true (operands[2]));
+      emit_jump_insn (gen_branch_true (operands[2], get_t_reg_rtx ()));
     }
 
   DONE;
index b62e76f0b4f89798cf9971446f7d967fd860ea40..916fcfbb606f5d9e7ea68175240dff377cf43c52 100644 (file)
@@ -1,3 +1,8 @@
+2012-07-02  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/51244
+       * gcc.target/sh/pr51244-1.c: Check that movt insn is not generated.
+
 2012-07-02  Jason Merrill  <jason@redhat.com>
 
        PR c++/53821
index 34e1b0233266705c04e19945baa8ecf463819c45..601c1c1c2697c9e6e8dced485fa30ad8c0c97e6a 100644 (file)
@@ -4,7 +4,7 @@
 /* { dg-do compile { target "sh*-*-*" } } */
 /* { dg-options "-O1 -mbranch-cost=2" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
-/* { dg-final { scan-assembler-not "tst|negc|extu" } } */
+/* { dg-final { scan-assembler-not "movt|tst|negc|extu" } } */
 
 int
 testfunc_00 (int a, int b, int c, int d)