]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add support for SmartMIPS ASE.
authorSandra Loosemore <sandra@codesourcery.com>
Thu, 5 Jul 2007 17:08:37 +0000 (13:08 -0400)
committerSandra Loosemore <sandra@gcc.gnu.org>
Thu, 5 Jul 2007 17:08:37 +0000 (13:08 -0400)
2007-07-05  Sandra Loosemore  <sandra@codesourcery.com>
    David Ung  <davidu@mips.com>

Add support for SmartMIPS ASE.

gcc/
* optabs.c (expand_binop_directly): New, broken out from...
(expand_binop): Here.  Make it try rotating in the other
direction even when the second operand isn't constant.
* config/mips/mips.md (*lwxs): New.
* config/mips/mips.opt (msmartmips): New.
* config/mips/mips.c (mips_lwxs_address_p): New.
(mips_rtx_costs): Make it recognize scaled indexed addressing.
* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Define
__mips_smartmips when compiling for TARGET_SMARTMIPS.
(ISA_HAS_ROR): Define for TARGET_SMARTMIPS.
(ISA_HAS_LWXS): New.
(ASM_SPEC): Add -msmartmips/-mno-smartmips.
* doc/invoke.texi (MIPS Options): Document -msmartmips/-mno-smartmips.
* testsuite/gcc.target/mips/smartmips-lwxs.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-1.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-2.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-3.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-4.c: New test case.

Co-Authored-By: David Ung <davidu@mips.com>
From-SVN: r126370

12 files changed:
gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/mips.opt
gcc/doc/invoke.texi
gcc/optabs.c
gcc/testsuite/gcc.target/mips/smartmips-lwxs.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/smartmips-ror-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/smartmips-ror-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/smartmips-ror-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/smartmips-ror-4.c [new file with mode: 0644]

index e39fb1431197b49273672a513218e950acaeb42a..2fecaf1c0cbd35307b093e62a89513f6b7c85aa7 100644 (file)
@@ -1,3 +1,27 @@
+2007-07-05  Sandra Loosemore  <sandra@codesourcery.com>
+           David Ung  <davidu@mips.com>
+
+       Add support for SmartMIPS ASE.
+
+       * optabs.c (expand_binop_directly): New, broken out from...
+       (expand_binop): Here.  Make it try rotating in the other
+       direction even when the second operand isn't constant.
+       * config/mips/mips.md (*lwxs): New.
+       * config/mips/mips.opt (msmartmips): New.
+       * config/mips/mips.c (mips_lwxs_address_p): New.
+       (mips_rtx_costs): Make it recognize scaled indexed addressing.
+       * config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Define
+       __mips_smartmips when compiling for TARGET_SMARTMIPS.
+       (ISA_HAS_ROR): Define for TARGET_SMARTMIPS.
+       (ISA_HAS_LWXS): New.
+       (ASM_SPEC): Add -msmartmips/-mno-smartmips.
+       * doc/invoke.texi (MIPS Options): Document -msmartmips/-mno-smartmips.
+       * testsuite/gcc.target/mips/smartmips-lwxs.c: New test case.
+       * testsuite/gcc.target/mips/smartmips-ror-1.c: New test case.
+       * testsuite/gcc.target/mips/smartmips-ror-2.c: New test case.
+       * testsuite/gcc.target/mips/smartmips-ror-3.c: New test case.
+       * testsuite/gcc.target/mips/smartmips-ror-4.c: New test case.
+
 2007-07-05  Dorit Nuzman  <dorit@il.ibm.com>
 
        * tree-vectorizer.c (new_loop_vec_info): Initialize
index da93ddcd36f083e71c131ec08fcb564868a1638d..7b101e32555b3b8512e83a0023f87a7df3790600 100644 (file)
@@ -2682,6 +2682,26 @@ m16_nsimm8_8 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
 }
 \f
+/* Return true if ADDR matches the pattern for the lwxs load scaled indexed
+   address instruction.  */
+
+static bool
+mips_lwxs_address_p (rtx addr)
+{
+  if (ISA_HAS_LWXS
+      && GET_CODE (addr) == PLUS
+      && REG_P (XEXP (addr, 1)))
+    {
+      rtx offset = XEXP (addr, 0);
+      if (GET_CODE (offset) == MULT
+         && REG_P (XEXP (offset, 0))
+         && GET_CODE (XEXP (offset, 1)) == CONST_INT
+         && INTVAL (XEXP (offset, 1)) == 4)
+       return true;
+    }
+  return false;
+}
+
 static bool
 mips_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
@@ -2778,13 +2798,21 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
     case MEM:
       {
        /* If the address is legitimate, return the number of
-          instructions it needs, otherwise use the default handling.  */
-       int n = mips_address_insns (XEXP (x, 0), GET_MODE (x));
+          instructions it needs.  */
+       rtx addr = XEXP (x, 0);
+       int n = mips_address_insns (addr, GET_MODE (x));
        if (n > 0)
          {
            *total = COSTS_N_INSNS (n + 1);
            return true;
          }
+       /* Check for scaled indexed address.  */
+       if (mips_lwxs_address_p (addr))
+         {
+           *total = COSTS_N_INSNS (2);
+           return true;
+         }
+       /* Otherwise use the default handling.  */
        return false;
       }
 
index 8338829e94188daa4e175e6c6637a8d2717dad8c..2425d13ab1ee6208c0c563bec4162f6c3470459c 100644 (file)
@@ -366,6 +366,9 @@ extern const struct mips_rtx_cost_data *mips_cost;
                                                                \
       if (TARGET_MIPS3D)                                       \
        builtin_define ("__mips3d");                            \
+                                                                \
+      if (TARGET_SMARTMIPS)                                    \
+       builtin_define ("__mips_smartmips");                    \
                                                                \
       if (TARGET_DSP)                                          \
        builtin_define ("__mips_dsp");                          \
@@ -733,7 +736,8 @@ extern const struct mips_rtx_cost_data *mips_cost;
 #define ISA_HAS_ROR            ((ISA_MIPS32R2                          \
                                  || TARGET_MIPS5400                    \
                                  || TARGET_MIPS5500                    \
-                                 || TARGET_SR71K)                      \
+                                 || TARGET_SR71K                       \
+                                 || TARGET_SMARTMIPS)                  \
                                 && !TARGET_MIPS16)
 
 /* ISA has data prefetch instructions.  This controls use of 'pref'.  */
@@ -768,6 +772,9 @@ extern const struct mips_rtx_cost_data *mips_cost;
 /* ISA has instructions for accessing top part of 64-bit fp regs.  */
 #define ISA_HAS_MXHC1          (TARGET_FLOAT64 && ISA_MIPS32R2)
 
+/* ISA has lwxs instruction (load w/scaled index address.  */
+#define ISA_HAS_LWXS           (TARGET_SMARTMIPS && !TARGET_MIPS16)
+
 /* True if the result of a load is not available to the next instruction.
    A nop will then be needed between instructions like "lw $4,..."
    and "addiu $4,$4,1".  */
@@ -883,6 +890,7 @@ extern const struct mips_rtx_cost_data *mips_cost;
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
 %{mdspr2} %{mno-dspr2} \
+%{msmartmips} %{mno-smartmips} \
 %{mmt} %{mno-mt} \
 %{mfix-vr4120} %{mfix-vr4130} \
 %(subtarget_asm_optimizing_spec) \
index 905b365dfa7bf1a7a86afafb4cb58dce0eeb48d6..2b7a2d2368f86f45e250a2f8323271c0d270e630 100644 (file)
   [(set_attr "type" "fpidxstore")
    (set_attr "mode" "<ANYF:UNITMODE>")])
 
+;; Scaled indexed address load.
+;; Per md.texi, we only need to look for a pattern with multiply in the
+;; address expression, not shift.
+
+(define_insn "*lwxs"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (mem:SI (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
+                                 (const_int 4))
+                        (match_operand:SI 2 "register_operand" "d"))))]
+  "ISA_HAS_LWXS"
+  "lwxs\t%0,%1(%2)"
+  [(set_attr "type"    "load")
+   (set_attr "mode"    "SI")
+   (set_attr "length"   "4")])
+
 ;; 16-bit Integer moves
 
 ;; Unlike most other insns, the move insns can't be split with
index f0c2dbf4c336c0fe4c5fba7ebb94015aca31d8ad..f7e751fb71322d1ec04a8fb56bb7c5e84a7920aa 100644 (file)
@@ -209,6 +209,10 @@ msingle-float
 Target Report RejectNegative Mask(SINGLE_FLOAT)
 Restrict the use of hardware floating-point instructions to 32-bit operations
 
+msmartmips
+Target Report RejectNegative Mask(SMARTMIPS)
+Use SmartMIPS instructions
+
 msoft-float
 Target Report RejectNegative Mask(SOFT_FLOAT)
 Prevent the use of all hardware floating-point instructions
index b1bbcf0bb02fd23f0028eecbd67e0d8ab0018d47..f7523c28b3abb555da51071ea21f126e40f92ef2 100644 (file)
@@ -622,6 +622,7 @@ Objective-C and Objective-C++ Dialects}.
 -mshared  -mno-shared  -mxgot  -mno-xgot  -mgp32  -mgp64 @gol
 -mfp32  -mfp64  -mhard-float  -msoft-float @gol
 -msingle-float  -mdouble-float  -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
+-msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
 -mips3d  -mno-mips3d  -mmt  -mno-mt @gol
 -mlong64  -mlong32  -msym32  -mno-sym32 @gol
@@ -11662,6 +11663,12 @@ Use (do not use) the MIPS DSP ASE.  @xref{MIPS DSP Built-in Functions}.
 Use (do not use) the MIPS DSP ASE REV 2.  @xref{MIPS DSP Built-in Functions}.
 The option @option{-mdspr2} implies @option{-mdsp}.
 
+@item -msmartmips
+@itemx -mno-smartmips
+@opindex msmartmips
+@opindex mno-smartmips
+Use (do not use) the MIPS SmartMIPS ASE.
+
 @item -mpaired-single
 @itemx -mno-paired-single
 @opindex mpaired-single
index dd146da8b6d3bfdde2483beee4155a60614d6535..c07cc06abd6def7e146015ec9b968a8a6c34a1ed 100644 (file)
@@ -1246,6 +1246,113 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
 }
 
 
+/* Helper function for expand_binop: handle the case where there
+   is an insn that directly implements the indicated operation.
+   Returns null if this is not possible.  */
+static rtx
+expand_binop_directly (enum machine_mode mode, optab binoptab,
+                      rtx op0, rtx op1,
+                      rtx target, int unsignedp, enum optab_methods methods,
+                      int commutative_op, rtx last)
+{
+  int icode = (int) binoptab->handlers[(int) mode].insn_code;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+  enum machine_mode tmp_mode;
+  rtx pat;
+  rtx xop0 = op0, xop1 = op1;
+  rtx temp;
+  
+  if (target)
+    temp = target;
+  else
+    temp = gen_reg_rtx (mode);
+  
+  /* If it is a commutative operator and the modes would match
+     if we would swap the operands, we can save the conversions.  */
+  if (commutative_op)
+    {
+      if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
+         && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
+       {
+         rtx tmp;
+         
+         tmp = op0; op0 = op1; op1 = tmp;
+         tmp = xop0; xop0 = xop1; xop1 = tmp;
+       }
+    }
+  
+  /* In case the insn wants input operands in modes different from
+     those of the actual operands, convert the operands.  It would
+     seem that we don't need to convert CONST_INTs, but we do, so
+     that they're properly zero-extended, sign-extended or truncated
+     for their mode.  */
+  
+  if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
+    xop0 = convert_modes (mode0,
+                         GET_MODE (op0) != VOIDmode
+                         ? GET_MODE (op0)
+                         : mode,
+                         xop0, unsignedp);
+  
+  if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
+    xop1 = convert_modes (mode1,
+                         GET_MODE (op1) != VOIDmode
+                         ? GET_MODE (op1)
+                         : mode,
+                         xop1, unsignedp);
+  
+  /* Now, if insn's predicates don't allow our operands, put them into
+     pseudo regs.  */
+  
+  if (!insn_data[icode].operand[1].predicate (xop0, mode0)
+      && mode0 != VOIDmode)
+    xop0 = copy_to_mode_reg (mode0, xop0);
+  
+  if (!insn_data[icode].operand[2].predicate (xop1, mode1)
+      && mode1 != VOIDmode)
+    xop1 = copy_to_mode_reg (mode1, xop1);
+  
+  if (binoptab == vec_pack_trunc_optab 
+      || binoptab == vec_pack_usat_optab
+      || binoptab == vec_pack_ssat_optab
+      || binoptab == vec_pack_ufix_trunc_optab
+      || binoptab == vec_pack_sfix_trunc_optab)
+    {
+      /* The mode of the result is different then the mode of the
+        arguments.  */
+      tmp_mode = insn_data[icode].operand[0].mode;
+      if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode))
+       return 0;
+    }
+  else
+    tmp_mode = mode;
+
+  if (!insn_data[icode].operand[0].predicate (temp, tmp_mode))
+    temp = gen_reg_rtx (tmp_mode);
+  
+  pat = GEN_FCN (icode) (temp, xop0, xop1);
+  if (pat)
+    {
+      /* If PAT is composed of more than one insn, try to add an appropriate
+        REG_EQUAL note to it.  If we can't because TEMP conflicts with an
+        operand, call expand_binop again, this time without a target.  */
+      if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
+         && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
+       {
+         delete_insns_since (last);
+         return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
+                              unsignedp, methods);
+       }
+      
+      emit_insn (pat);
+      return temp;
+    }
+
+  delete_insns_since (last);
+  return NULL_RTX;
+}
+
 /* Generate code to perform an operation specified by BINOPTAB
    on operands OP0 and OP1, with result having machine-mode MODE.
 
@@ -1275,7 +1382,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                  || binoptab->code == ROTATERT);
   rtx entry_last = get_last_insn ();
   rtx last;
-  bool first_pass_p = true;
 
   class = GET_MODE_CLASS (mode);
 
@@ -1329,123 +1435,43 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        }
     }
 
- retry:
-
   /* If we can do it with a three-operand insn, do so.  */
 
   if (methods != OPTAB_MUST_WIDEN
       && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
-      int icode = (int) binoptab->handlers[(int) mode].insn_code;
-      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
-      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
-      enum machine_mode tmp_mode;
-      rtx pat;
-      rtx xop0 = op0, xop1 = op1;
-
-      if (target)
-       temp = target;
-      else
-       temp = gen_reg_rtx (mode);
-
-      /* If it is a commutative operator and the modes would match
-        if we would swap the operands, we can save the conversions.  */
-      if (commutative_op)
-       {
-         if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
-             && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
-           {
-             rtx tmp;
-
-             tmp = op0; op0 = op1; op1 = tmp;
-             tmp = xop0; xop0 = xop1; xop1 = tmp;
-           }
-       }
-
-      /* In case the insn wants input operands in modes different from
-        those of the actual operands, convert the operands.  It would
-        seem that we don't need to convert CONST_INTs, but we do, so
-        that they're properly zero-extended, sign-extended or truncated
-        for their mode.  */
-
-      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
-       xop0 = convert_modes (mode0,
-                             GET_MODE (op0) != VOIDmode
-                             ? GET_MODE (op0)
-                             : mode,
-                             xop0, unsignedp);
-
-      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
-       xop1 = convert_modes (mode1,
-                             GET_MODE (op1) != VOIDmode
-                             ? GET_MODE (op1)
-                             : mode,
-                             xop1, unsignedp);
-
-      /* Now, if insn's predicates don't allow our operands, put them into
-        pseudo regs.  */
-
-      if (!insn_data[icode].operand[1].predicate (xop0, mode0)
-         && mode0 != VOIDmode)
-       xop0 = copy_to_mode_reg (mode0, xop0);
-
-      if (!insn_data[icode].operand[2].predicate (xop1, mode1)
-         && mode1 != VOIDmode)
-       xop1 = copy_to_mode_reg (mode1, xop1);
-
-      if (binoptab == vec_pack_trunc_optab 
-         || binoptab == vec_pack_usat_optab
-         || binoptab == vec_pack_ssat_optab
-         || binoptab == vec_pack_ufix_trunc_optab
-         || binoptab == vec_pack_sfix_trunc_optab)
-       {
-         /* The mode of the result is different then the mode of the
-            arguments.  */
-         tmp_mode = insn_data[icode].operand[0].mode;
-         if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode))
-           return 0;
-       }
-      else
-        tmp_mode = mode;
-
-      if (!insn_data[icode].operand[0].predicate (temp, tmp_mode))
-       temp = gen_reg_rtx (tmp_mode);
-
-      pat = GEN_FCN (icode) (temp, xop0, xop1);
-      if (pat)
-       {
-         /* If PAT is composed of more than one insn, try to add an appropriate
-            REG_EQUAL note to it.  If we can't because TEMP conflicts with an
-            operand, call ourselves again, this time without a target.  */
-         if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
-             && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
-           {
-             delete_insns_since (last);
-             return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
-                                  unsignedp, methods);
-           }
-
-         emit_insn (pat);
-         return temp;
-       }
-      else
-       delete_insns_since (last);
+      temp = expand_binop_directly (mode, binoptab, op0, op1, target,
+                                   unsignedp, methods, commutative_op, last);
+      if (temp)
+       return temp;
     }
 
-  /* If we were trying to rotate by a constant value, and that didn't
-     work, try rotating the other direction before falling back to
-     shifts and bitwise-or.  */
-  if (first_pass_p
-      && (binoptab == rotl_optab || binoptab == rotr_optab)
-      && class == MODE_INT
-      && GET_CODE (op1) == CONST_INT
-      && INTVAL (op1) > 0
-      && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
+  /* If we were trying to rotate, and that didn't work, try rotating
+     the other direction before falling back to shifts and bitwise-or.  */
+  if (((binoptab == rotl_optab
+       && rotr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+       || (binoptab == rotr_optab
+          && rotl_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing))
+      && class == MODE_INT)
     {
-      first_pass_p = false;
-      op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
-      binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab;
-      goto retry;
+      optab otheroptab = (binoptab == rotl_optab ? rotr_optab : rotl_optab);
+      rtx newop1;
+      int bits = GET_MODE_BITSIZE (mode);
+
+      if (GET_CODE (op1) == CONST_INT)
+       newop1 = GEN_INT (bits - INTVAL (op1));
+      else if (targetm.shift_truncation_mask (mode) == bits - 1)
+       newop1 = negate_rtx (mode, op1);
+      else
+       newop1 = expand_binop (mode, sub_optab,
+                              GEN_INT (bits), op1,
+                              NULL_RTX, unsignedp, OPTAB_DIRECT);
+                                  
+      temp = expand_binop_directly (mode, otheroptab, op0, newop1,
+                                   target, unsignedp, methods,
+                                   commutative_op, last);
+      if (temp)
+       return temp;
     }
 
   /* If this is a multiply, see if we can do a widening operation that
diff --git a/gcc/testsuite/gcc.target/mips/smartmips-lwxs.c b/gcc/testsuite/gcc.target/mips/smartmips-lwxs.c
new file mode 100644 (file)
index 0000000..cd9b0b3
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
+
+int scaled_indexed_word_load (int a[], int b)
+{
+  return a[b];
+}
+/* { dg-final { scan-assembler "\tlwxs\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/smartmips-ror-1.c b/gcc/testsuite/gcc.target/mips/smartmips-ror-1.c
new file mode 100644 (file)
index 0000000..5ad7f34
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
+
+int rotate_left (unsigned a, unsigned s)
+{
+  return (a << s) | (a >> (32 - s));
+}
+/* { dg-final { scan-assembler "\tror\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/smartmips-ror-2.c b/gcc/testsuite/gcc.target/mips/smartmips-ror-2.c
new file mode 100644 (file)
index 0000000..93d376d
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
+
+int rotate_right (unsigned a, unsigned s)
+{
+  return (a >> s) | (a << (32 - s));
+}
+/* { dg-final { scan-assembler "\tror\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/smartmips-ror-3.c b/gcc/testsuite/gcc.target/mips/smartmips-ror-3.c
new file mode 100644 (file)
index 0000000..ec1c6e2
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
+
+#define S 13
+
+int rotate_left_constant (unsigned a)
+{
+  return (a << S) | (a >> (32 - S));
+}
+/* { dg-final { scan-assembler "\tror\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/smartmips-ror-4.c b/gcc/testsuite/gcc.target/mips/smartmips-ror-4.c
new file mode 100644 (file)
index 0000000..2a56210
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
+
+#define S 13
+
+int rotate_right_constant (unsigned a)
+{
+  return (a >> S) | (a << (32 - S));
+}
+/* { dg-final { scan-assembler "\tror\t" } } */