summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorsandra <sandra@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-05 17:08:37 +0000
committersandra <sandra@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-05 17:08:37 +0000
commit122a697832d3f4ee948f12fd2676840cdbb37a9b (patch)
tree412155942760389b80c2e11cd433bae27b0a1df4 /gcc
parent81e6afc2ae19f1ae98d1bad1f2ed79f583325b3c (diff)
downloadgcc-122a697832d3f4ee948f12fd2676840cdbb37a9b.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126370 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/config/mips/mips.c32
-rw-r--r--gcc/config/mips/mips.h10
-rw-r--r--gcc/config/mips/mips.md15
-rw-r--r--gcc/config/mips/mips.opt4
-rw-r--r--gcc/doc/invoke.texi7
-rw-r--r--gcc/optabs.c246
-rw-r--r--gcc/testsuite/gcc.target/mips/smartmips-lwxs.c8
-rw-r--r--gcc/testsuite/gcc.target/mips/smartmips-ror-1.c8
-rw-r--r--gcc/testsuite/gcc.target/mips/smartmips-ror-2.c8
-rw-r--r--gcc/testsuite/gcc.target/mips/smartmips-ror-3.c10
-rw-r--r--gcc/testsuite/gcc.target/mips/smartmips-ror-4.c10
12 files changed, 269 insertions, 113 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e39fb143119..2fecaf1c0cb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index da93ddcd36f..7b101e32555 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -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);
}
+/* 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;
}
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 8338829e941..2425d13ab1e 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -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) \
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 905b365dfa7..2b7a2d2368f 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -3654,6 +3654,21 @@
[(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
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index f0c2dbf4c33..f7e751fb713 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b1bbcf0bb02..f7523c28b3a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index dd146da8b6d..c07cc06abd6 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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
index 00000000000..cd9b0b3950f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/smartmips-lwxs.c
@@ -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
index 00000000000..5ad7f3424c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/smartmips-ror-1.c
@@ -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
index 00000000000..93d376d537d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/smartmips-ror-2.c
@@ -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
index 00000000000..ec1c6e27e59
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/smartmips-ror-3.c
@@ -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
index 00000000000..2a56210539f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/smartmips-ror-4.c
@@ -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" } } */