+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
 
       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 ()));
 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;
 
     }
 
   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);
   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.  */
   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
 
 
 (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")])
 
 (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"
   [(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);
 
   /* 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;
 })
 
 
+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.
 
--- /dev/null
+/* 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;
+}
 
--- /dev/null
+/* 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];
+}