]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/54089 ([SH] Refactor shift patterns)
authorOleg Endo <olegendo@gcc.gnu.org>
Tue, 25 Sep 2012 19:06:28 +0000 (19:06 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Tue, 25 Sep 2012 19:06:28 +0000 (19:06 +0000)
PR target/54089
* config/sh/constraints.md (Jhb): New constraint.
* config/sh/predicates.md (negt_reg_shl31_operand): New predicate.
* config/sh/sh.md (rotrsi3): New expander.
(rotrsi3_1, *rotrsi3_1, *rotlsi3_1): New insns.
(rotlsi3, rotlhi3): Use const_int_operand predicate instead of
immediate_operand and remove CONST_INT_P checks in expansion code.
(*rotcr): Cleanup variable usage.  Handle preceding nott insn.  Add
split with swapped operands.
(*rotcr_neg_t, *movt_msb, *negt_msb): New insns and splits.

PR target/54089
* gcc.target/sh/pr54089-1.c (test_15, test_16, test_17, test_18,
test_19, test_20, test_21, test_22, test_23): New functions.
* gcc.target/sh/pr54089-4.c: New.
* gcc.target/sh/pr54089-5.c: New.
* gcc.target/sh/pr54089-6.c: New.
* gcc.target/sh/pr54089-7.c: New.

From-SVN: r191743

gcc/ChangeLog
gcc/config/sh/constraints.md
gcc/config/sh/predicates.md
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr54089-1.c
gcc/testsuite/gcc.target/sh/pr54089-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr54089-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr54089-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr54089-7.c [new file with mode: 0644]

index f09f1c84f220583822810a691319140e1b5a196c..953b07e908a8b4bb8a2e89c7cc280b9b8797df33 100644 (file)
@@ -1,3 +1,16 @@
+2012-09-25  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54089
+       * config/sh/constraints.md (Jhb): New constraint.
+       * config/sh/predicates.md (negt_reg_shl31_operand): New predicate.
+       * config/sh/sh.md (rotrsi3): New expander.
+       (rotrsi3_1, *rotrsi3_1, *rotlsi3_1): New insns.
+       (rotlsi3, rotlhi3): Use const_int_operand predicate instead of
+       immediate_operand and remove CONST_INT_P checks in expansion code.
+       (*rotcr): Cleanup variable usage.  Handle preceding nott insn.  Add
+       split with swapped operands.
+       (*rotcr_neg_t, *movt_msb, *negt_msb): New insns and splits.
+
 2012-09-25  Aldy Hernandez  <aldyh@redhat.com>
 
        PR middle-end/53850
 2012-09-14  Christian Bruel  <christian.bruel@st.com>
 
        * config/sh/predicates.md (t_reg_operand): Check REG_P for SUBREG.
-       * config/sh/sh.c (sequence_insn_p: Check INSNP_P for SEQUENCE.
+       * config/sh/sh.c (sequence_insn_p): Check INSNP_P for SEQUENCE.
 
 2012-09-14  Jakub Jelinek  <jakub@redhat.com>
 
index 47350dff22b5f6ed13405b137e91f1e25d4d79cf..c2540e8b6683740893b382c01152265be83e27b0 100644 (file)
@@ -33,6 +33,7 @@
 ;;  J16: 0xffffffff00000000 | 0x00000000ffffffff
 ;;  Jmb: 0x000000FF
 ;;  Jmw: 0x0000FFFF
+;;  Jhb: 0x80000000
 ;;  Kxx: unsigned xx bit
 ;;  M: 1
 ;;  N: 0
   (and (match_code "const_int")
        (match_test "ival == 0xFFFF")))
 
+(define_constraint "Jhb"
+  "Highest bit constant"
+  (and (match_code "const_int")
+       (match_test "(ival & 0xFFFFFFFF) == 0x80000000")))
+
 (define_constraint "K03"
   "An unsigned 3-bit constant, as used in SH2A bclr, bset, etc."
   (and (match_code "const_int")
index 27e42f159bc169584200bf1d565f27266b5f710c..93a33bf2544b06cf64d2f6c4cbaed84466d3c2d6 100644 (file)
 (define_predicate "arith_reg_or_t_reg_operand"
   (ior (match_operand 0 "arith_reg_operand")
        (match_operand 0 "t_reg_operand")))
+
+;; A predicate describing the negated value of the T bit register shifted
+;; left by 31.
+(define_predicate "negt_reg_shl31_operand"
+  (match_code "plus,minus,if_then_else")
+{
+  /* (plus:SI (mult:SI (match_operand:SI 1 "t_reg_operand")
+                      (const_int -2147483648))  ;; 0xffffffff80000000
+             (const_int -2147483648))
+  */
+  if (GET_CODE (op) == PLUS && satisfies_constraint_Jhb (XEXP (op, 1))
+      && GET_CODE (XEXP (op, 0)) == MULT
+      && t_reg_operand (XEXP (XEXP (op, 0), 0), SImode)
+      && satisfies_constraint_Jhb (XEXP (XEXP (op, 0), 1)))
+    return true;
+
+  /* (minus:SI (const_int -2147483648)  ;; 0xffffffff80000000
+              (mult:SI (match_operand:SI 1 "t_reg_operand")
+                       (const_int -2147483648)))
+  */
+  if (GET_CODE (op) == MINUS
+      && satisfies_constraint_Jhb (XEXP (op, 0))
+      && GET_CODE (XEXP (op, 1)) == MULT
+      && t_reg_operand (XEXP (XEXP (op, 1), 0), SImode)
+      && satisfies_constraint_Jhb (XEXP (XEXP (op, 1), 1)))
+    return true;
+
+  /*  (if_then_else:SI (match_operand:SI 1 "t_reg_operand")
+                      (const_int 0)
+                      (const_int -2147483648))  ;; 0xffffffff80000000
+  */
+  if (GET_CODE (op) == IF_THEN_ELSE && t_reg_operand (XEXP (op, 0), SImode)
+      && satisfies_constraint_Z (XEXP (op, 1))
+      && satisfies_constraint_Jhb (XEXP (op, 2)))
+    return true;
+
+  return false;
+})
index 27c5633dd9dad601057dad05d6ff02f15966935d..8f0443ad6db3c58f71a3e770920aa3e9e4782d06 100644 (file)
@@ -3817,6 +3817,42 @@ label:
                              GEN_INT (56), GEN_INT (8));
 })
 
+(define_expand "rotrsi3"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (rotatert:SI (match_operand:SI 1 "arith_reg_operand")
+                    (match_operand:SI 2 "const_int_operand")))]
+  "TARGET_SH1"
+{
+  HOST_WIDE_INT ival = INTVAL (operands[2]);
+  if (ival == 1)
+    {
+      emit_insn (gen_rotrsi3_1 (operands[0], operands[1]));
+      DONE;
+    }
+
+  FAIL;
+})
+
+(define_insn "rotrsi3_1"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+       (rotatert:SI (match_operand:SI 1 "arith_reg_operand" "0")
+                    (const_int 1)))
+   (set (reg:SI T_REG)
+       (and:SI (match_dup 1) (const_int 1)))]
+  "TARGET_SH1"
+  "rotr        %0"
+  [(set_attr "type" "arith")])
+
+;; A slimplified version of rotr for combine.
+(define_insn "*rotrsi3_1"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+       (rotatert:SI (match_operand:SI 1 "arith_reg_operand" "0")
+                    (const_int 1)))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "rotr        %0"
+  [(set_attr "type" "arith")])
+
 (define_insn "rotlsi3_1"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
        (rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
@@ -3827,6 +3863,16 @@ label:
   "rotl        %0"
   [(set_attr "type" "arith")])
 
+;; A simplified version of rotl for combine.
+(define_insn "*rotlsi3_1"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+       (rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
+                  (const_int 1)))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "rotl        %0"
+  [(set_attr "type" "arith")])
+
 (define_insn "rotlsi3_31"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
        (rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
@@ -3845,9 +3891,9 @@ label:
   [(set_attr "type" "arith")])
 
 (define_expand "rotlsi3"
-  [(set (match_operand:SI 0 "arith_reg_dest" "")
-       (rotate:SI (match_operand:SI 1 "arith_reg_operand" "")
-                  (match_operand:SI 2 "immediate_operand" "")))]
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (rotate:SI (match_operand:SI 1 "arith_reg_operand")
+                  (match_operand:SI 2 "const_int_operand")))]
   "TARGET_SH1"
 {
   static const char rot_tab[] = {
@@ -3857,12 +3903,8 @@ label:
     002, 002, 010, 000, 000, 000, 000, 000,
   };
 
-  int count, choice;
-
-  if (!CONST_INT_P (operands[2]))
-    FAIL;
-  count = INTVAL (operands[2]);
-  choice = rot_tab[count];
+  int count = INTVAL (operands[2]);
+  int choice = rot_tab[count];
   if (choice & 010 && SH_DYNAMIC_SHIFT_COST <= 1)
     FAIL;
   choice &= 7;
@@ -3908,12 +3950,12 @@ label:
   [(set_attr "type" "arith")])
 
 (define_expand "rotlhi3"
-  [(set (match_operand:HI 0 "arith_reg_operand" "")
-       (rotate:HI (match_operand:HI 1 "arith_reg_operand" "")
-                  (match_operand:HI 2 "immediate_operand" "")))]
+  [(set (match_operand:HI 0 "arith_reg_operand")
+       (rotate:HI (match_operand:HI 1 "arith_reg_operand")
+                  (match_operand:HI 2 "const_int_operand")))]
   "TARGET_SH1"
 {
-  if (!CONST_INT_P (operands[2]) || INTVAL (operands[2]) != 8)
+  if (INTVAL (operands[2]) != 8)
     FAIL;
 })
 
@@ -3950,11 +3992,7 @@ label:
 {
   if (INTVAL (operands[2]) > 1)
     {
-      /* use plus_constant function ?? */
-      const int shift_count = INTVAL (operands[2]) - 1;
-      const rtx shift_count_rtx = GEN_INT (shift_count);
-      rtx shift_res = gen_reg_rtx (SImode);
-
+      const rtx shift_count = GEN_INT (INTVAL (operands[2]) - 1);
       rtx prev_set_t_insn = NULL_RTX;
       rtx tmp_t_reg = NULL_RTX;
 
@@ -3963,10 +4001,24 @@ label:
         shift insn before that insn, to remove the T_REG dependency.
         If the insn that sets the T_REG cannot be found, store the T_REG
         in a temporary reg and restore it after the shift.  */
-      if (sh_lshrsi_clobbers_t_reg_p (shift_count_rtx)
-         && ! sh_dynamicalize_shift_p (shift_count_rtx))
+      if (sh_lshrsi_clobbers_t_reg_p (shift_count)
+         && ! sh_dynamicalize_shift_p (shift_count))
        {
          prev_set_t_insn = prev_nonnote_insn_bb (curr_insn);
+
+         /* Skip the nott insn, which was probably inserted by the splitter
+            of *rotcr_neg_t.  Don't use one of the recog functions
+            here during insn splitting, since that causes problems in later
+            passes.  */
+         if (prev_set_t_insn != NULL_RTX)
+           {
+             rtx pat = PATTERN (prev_set_t_insn);
+             if (GET_CODE (pat) == SET
+                 && t_reg_operand (XEXP (pat, 0), SImode)
+                 && negt_reg_operand (XEXP (pat, 1), SImode))
+             prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
+           }
+
          if (! (prev_set_t_insn != NULL_RTX
                 && reg_set_p (get_t_reg_rtx (), prev_set_t_insn)
                 && ! reg_referenced_p (get_t_reg_rtx (),
@@ -3978,14 +4030,15 @@ label:
            } 
        }
 
-      rtx shift_rtx = gen_lshrsi3 (shift_res, operands[1], shift_count_rtx);
-      operands[1] = shift_res;
+      rtx shift_result = gen_reg_rtx (SImode);
+      rtx shift_insn = gen_lshrsi3 (shift_result, operands[1], shift_count);
+      operands[1] = shift_result;
 
       /* Emit the shift insn before the insn that sets T_REG, if possible.  */
       if (prev_set_t_insn != NULL_RTX)
-       emit_insn_before (shift_rtx, prev_set_t_insn);
+       emit_insn_before (shift_insn, prev_set_t_insn);
       else
-       emit_insn (shift_rtx);
+       emit_insn (shift_insn);
 
       /* Restore T_REG if it has been saved before.  */
       if (tmp_t_reg != NULL_RTX)
@@ -4007,6 +4060,20 @@ label:
   DONE;
 })
 
+;; If combine tries the same as above but with swapped operands, split
+;; it so that it will try the pattern above.
+(define_split
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (ior:SI (ashift:SI (match_operand:SI 1 "arith_reg_or_t_reg_operand")
+                          (const_int 31))
+               (lshiftrt:SI (match_operand:SI 2 "arith_reg_operand")
+                            (match_operand:SI 3 "const_int_operand"))))]
+  "TARGET_SH1 && can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (ior:SI (lshiftrt:SI (match_dup 2) (match_dup 3))
+                          (ashift:SI (match_dup 1) (const_int 31))))
+             (clobber (reg:SI T_REG))])])
+
 ;; rotcr combine bridge pattern which will make combine try out more
 ;; complex patterns.
 (define_insn_and_split "*rotcr"
@@ -4040,6 +4107,41 @@ label:
   DONE;
 })
 
+;; rotcr combine patterns for rotating in the negated T_REG value.
+(define_insn_and_split "*rotcr_neg_t"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (ior:SI (match_operand:SI 1 "negt_reg_shl31_operand")
+               (lshiftrt:SI (match_operand:SI 2 "arith_reg_operand")
+                            (match_operand:SI 3 "const_int_operand"))))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (ior:SI (lshiftrt:SI (match_dup 2) (match_dup 3))
+                          (ashift:SI (reg:SI T_REG) (const_int 31))))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_nott (get_t_reg_rtx ()));
+})
+
+(define_insn_and_split "*rotcr_neg_t"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (ior:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand")
+                            (match_operand:SI 2 "const_int_operand"))
+               (match_operand:SI 3 "negt_reg_shl31_operand")))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (ior:SI (lshiftrt:SI (match_dup 1) (match_dup 2))
+                          (ashift:SI (reg:SI T_REG) (const_int 31))))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_nott (get_t_reg_rtx ()));
+})
+
 ;; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 ;; SImode shift left
 
@@ -10720,6 +10822,53 @@ label:
   operands[0] = gen_reg_rtx (SImode);
 })
 
+;; Store T bit as MSB in a reg.
+;; T = 0: 0x00000000 -> reg
+;; T = 1: 0x80000000 -> reg
+(define_insn_and_split "*movt_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (mult:SI (match_operand:SI 1 "t_reg_operand")
+                (const_int -2147483648)))  ;; 0xffffffff80000000
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& 1"
+  [(set (match_dup 0) (ashift:SI (reg:SI T_REG) (const_int 31)))])
+
+;; Store inverted T bit as MSB in a reg.
+;; T = 0: 0x80000000 -> reg
+;; T = 1: 0x00000000 -> reg
+;; On SH2A we can get away without clobbering the T_REG.
+(define_insn_and_split "*negt_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (match_operand:SI 1 "negt_reg_shl31_operand"))]
+  "TARGET_SH2A"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(const_int 0)]
+{
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_insn (gen_movrt (tmp, get_t_reg_rtx ()));
+  emit_insn (gen_rotrsi3 (operands[0], tmp, const1_rtx));
+  DONE;
+})
+
+(define_insn_and_split "*negt_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (match_operand:SI 1 "negt_reg_shl31_operand"))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1 && !TARGET_SH2A"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(const_int 0)]
+{
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_move_insn (tmp, get_t_reg_rtx ());
+  emit_insn (gen_cmpeqsi_t (tmp, const0_rtx));
+  emit_insn (gen_rotcr (operands[0], tmp, get_t_reg_rtx ()));
+  DONE;
+})
+
 ;; The *cset_zero patterns convert optimizations such as
 ;;     "if (test) x = 0;" to "x &= -(test == 0);"
 ;; back to conditional branch sequences if zero-displacement branches
index 4d4162c86214614e7a74d3f4e165d97dc95c158f..dfbab8205cbc276404e149357a1b27fb1ed66535 100644 (file)
@@ -1,3 +1,13 @@
+2012-09-25  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54089
+       * gcc.target/sh/pr54089-1.c (test_15, test_16, test_17, test_18,
+       test_19, test_20, test_21, test_22, test_23): New functions.
+       * gcc.target/sh/pr54089-4.c: New.
+       * gcc.target/sh/pr54089-5.c: New.
+       * gcc.target/sh/pr54089-6.c: New.
+       * gcc.target/sh/pr54089-7.c: New.
+
 2012-09-25  Richard Guenther  <rguenther@suse.de>
 
        PR lto/54625
index 77924554f38e0c60b1a716f8444add09e791a541..399b0a53e22c8cfb7cd2d777530792dcfc8ac9c1 100644 (file)
@@ -2,7 +2,7 @@
 /* { dg-do compile { target "sh*-*-*" } } */
 /* { dg-options "-O1" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
-/* { dg-final { scan-assembler-times "rotcr" 15 } } */
+/* { dg-final { scan-assembler-times "rotcr" 24 } } */
 /* { dg-final { scan-assembler-times "shll\t" 1 } } */
 
 typedef char bool;
@@ -109,3 +109,66 @@ test_14 (unsigned int a, int b)
   bool r = b < 0;
   return ((a >> 1) | (r << 31));
 }
+
+unsigned int
+test_15 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 1) | (r << 31));
+}
+
+unsigned int
+test_16 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 2) | (r << 31));
+}
+
+unsigned int
+test_17 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 3) | (r << 31));
+}
+
+unsigned int
+test_18 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 4) | (r << 31));
+}
+
+unsigned int
+test_19 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 5) | (r << 31));
+}
+
+unsigned int
+test_20 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 6) | (r << 31));
+}
+
+unsigned int
+test_21 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 7) | (r << 31));
+}
+
+unsigned int
+test_22 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 8) | (r << 31));
+}
+
+unsigned int
+test_23 (unsigned int a, int b, int c)
+{
+  bool r = b != c;
+  return ((a >> 31) | (r << 31));
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54089-4.c b/gcc/testsuite/gcc.target/sh/pr54089-4.c
new file mode 100644 (file)
index 0000000..4617c3a
--- /dev/null
@@ -0,0 +1,15 @@
+/* Check that the rotcr instruction is generated when shifting the
+   negated T bit on non-SH2A.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } }  */
+/* { dg-final { scan-assembler-times "rotcr" 1 } } */
+/* { dg-final { scan-assembler-times "tst" 1 } } */
+/* { dg-final { scan-assembler-times "movt" 1 } } */
+
+int
+test_00 (int a, int b)
+{
+  int r = a != b;
+  return r << 31;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54089-5.c b/gcc/testsuite/gcc.target/sh/pr54089-5.c
new file mode 100644 (file)
index 0000000..f781aca
--- /dev/null
@@ -0,0 +1,14 @@
+/* Check that the movrt rotr instruction sequence is generated when shifting
+   the negated T bit on SH2A.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
+/* { dg-final { scan-assembler-times "movrt" 1 } } */
+/* { dg-final { scan-assembler-times "rotr" 1 } } */
+
+int
+test_00 (int a, int b)
+{
+  int r = a != b;
+  return r << 31;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54089-6.c b/gcc/testsuite/gcc.target/sh/pr54089-6.c
new file mode 100644 (file)
index 0000000..a12a0e9
--- /dev/null
@@ -0,0 +1,30 @@
+/* Check that the rotr and rotl instructions are generated.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } }  */
+/* { dg-final { scan-assembler-times "rotr" 2 } } */
+/* { dg-final { scan-assembler-times "rotl" 2 } } */
+
+int
+test_00 (int a)
+{
+  return (a << 1) | ((a >> 31) & 1);
+}
+
+int
+test_01 (int a)
+{
+  return (a << 1) | ((unsigned int)a >> 31);
+}
+
+int
+test_02 (int a)
+{
+  return ((unsigned int)a >> 1) | (a << 31);
+}
+
+int
+test_03 (int a)
+{
+  return ((a >> 1) & 0x7FFFFFFF) | (a << 31);
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54089-7.c b/gcc/testsuite/gcc.target/sh/pr54089-7.c
new file mode 100644 (file)
index 0000000..40ca821
--- /dev/null
@@ -0,0 +1,63 @@
+/* Check that the rotcr instruction is generated.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+/* { dg-final { scan-assembler-times "rotcr" 4 } } */
+/* { dg-final { scan-assembler-not "movt" } } */
+/* { dg-final { scan-assembler-not "or\t" } } */
+/* { dg-final { scan-assembler-not "rotr" } } */
+/* { dg-final { scan-assembler-not "and" } } */
+
+typedef char bool;
+
+int
+test_00 (int* a, int* b)
+{
+  int i;
+  unsigned int r = 0;
+  for (i = 0; i < 16; ++i)
+    {
+      bool t = a[i] == b[i];
+      r = (t << 31) | (r >> 1);
+    }
+  return r;
+}
+
+int
+test_01 (int* a, int* b)
+{
+  int i;
+  unsigned int r = 0;
+  for (i = 0; i < 16; ++i)
+    {
+      bool t = a[i] == b[i];
+      r = (t << 31) | (r >> 2);
+    }
+  return r;
+}
+
+int
+test_02 (int* a, int* b)
+{
+  int i;
+  unsigned int r = 0;
+  for (i = 0; i < 16; ++i)
+    {
+      bool t = a[i] == b[i];
+      r = (t << 31) | (r >> 3);
+    }
+  return r;
+}
+
+unsigned int
+test_03 (const bool* a)
+{
+  int i;
+  unsigned int r = 0;
+  for (i = 0; i < 32; ++i)
+    {
+      bool t = a[i];
+      r = (t << 31) | (r >> 1);
+    }
+  return r;
+}