mips-protos.h (gen_int_relational): Delete.
authorRichard Sandiford <rsandifo@redhat.com>
Fri, 16 Jul 2004 07:51:31 +0000 (07:51 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Fri, 16 Jul 2004 07:51:31 +0000 (07:51 +0000)
* config/mips/mips-protos.h (gen_int_relational): Delete.
(mips_emit_scc): Declare.
* config/mips/mips.c (internal_test): Delete.
(sle_operand, sleu_operand): New functions.
(map_test_to_internal_test, gen_int_relational): Delete.
(mips_emit_binary, mips_relational_operand_ok_p)
(mips_emit_int_relational, mips_zero_if_equal)
(mips_emit_scc): New functions.
(gen_conditional_branch): Rework to use mips_emit_int_relational.
* config/mips/mips.h (PREDICATE_CODES): Add sle_operand and
sleu_operand.
* config/mips/mips.md (seq, sne, sgt, sge, slt, sle, sgtu, sgeu)
(sltu, sleu): Use mips_emit_scc.
(*sge_[sd]i, *sgeu_[sd]i): New patterns.
(*sle_[sd]i, *sle_[sd]i_mips16): Use sle_operand.
(*sleu_[sd]i, *sleu_[sd]i_mips16): Use sleu_operand.

From-SVN: r84808

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md

index b747aaaff192e947930e7733b3c2f1ceef5de61e..a57ee1c7d86408b2b6ebca371d3615360e36b380 100644 (file)
@@ -1,3 +1,22 @@
+2004-07-16  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips-protos.h (gen_int_relational): Delete.
+       (mips_emit_scc): Declare.
+       * config/mips/mips.c (internal_test): Delete.
+       (sle_operand, sleu_operand): New functions.
+       (map_test_to_internal_test, gen_int_relational): Delete.
+       (mips_emit_binary, mips_relational_operand_ok_p)
+       (mips_emit_int_relational, mips_zero_if_equal)
+       (mips_emit_scc): New functions.
+       (gen_conditional_branch): Rework to use mips_emit_int_relational.
+       * config/mips/mips.h (PREDICATE_CODES): Add sle_operand and
+       sleu_operand.
+       * config/mips/mips.md (seq, sne, sgt, sge, slt, sle, sgtu, sgeu)
+       (sltu, sleu): Use mips_emit_scc.
+       (*sge_[sd]i, *sgeu_[sd]i): New patterns.
+       (*sle_[sd]i, *sle_[sd]i_mips16): Use sle_operand.
+       (*sleu_[sd]i, *sleu_[sd]i_mips16): Use sleu_operand.
+
 2004-07-16  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.md (*sgt_di_mips16): Fix destination constraint.
index 820d75f9cc0f42407f4ab048980fddf1f394e2b7..73a7e75ad9251db1123181bbd835dd70cba3b715 100644 (file)
@@ -123,7 +123,7 @@ extern void mips_split_64bit_move (rtx, rtx);
 extern const char *mips_output_move (rtx, rtx);
 extern rtx mips_gp_save_slot (void);
 #ifdef RTX_CODE
-extern rtx gen_int_relational (enum rtx_code, rtx, rtx, rtx, int *);
+extern bool mips_emit_scc (enum rtx_code, rtx);
 extern void gen_conditional_branch (rtx *, enum rtx_code);
 #endif
 extern void gen_conditional_move (rtx *);
index aed4d94d19c60c74ebff6a9e67ab874c4f347384..648abbf00d2bb494b2f9b5eacd132ca2589f357d 100644 (file)
@@ -57,24 +57,6 @@ Boston, MA 02111-1307, USA.  */
 #include "sched-int.h"
 #include "tree-gimple.h"
 
-/* Enumeration for all of the relational tests, so that we can build
-   arrays indexed by the test type, and not worry about the order
-   of EQ, NE, etc.  */
-
-enum internal_test {
-  ITEST_EQ,
-  ITEST_NE,
-  ITEST_GT,
-  ITEST_GE,
-  ITEST_LT,
-  ITEST_LE,
-  ITEST_GTU,
-  ITEST_GEU,
-  ITEST_LTU,
-  ITEST_LEU,
-  ITEST_MAX
-};
-
 /* True if X is an unspec wrapper around a SYMBOL_REF or LABEL_REF.  */
 #define UNSPEC_ADDRESS_P(X)                                    \
   (GET_CODE (X) == UNSPEC                                      \
@@ -193,7 +175,6 @@ static void mips_legitimize_const_move (enum machine_mode, rtx, rtx);
 static int m16_check_op (rtx, int, int, int);
 static bool mips_rtx_costs (rtx, int, int, int *);
 static int mips_address_cost (rtx);
-static enum internal_test map_test_to_internal_test (enum rtx_code);
 static void get_float_compare_codes (enum rtx_code, enum rtx_code *,
                                     enum rtx_code *);
 static void mips_load_call_address (rtx, rtx, int);
@@ -1343,6 +1324,24 @@ arith_operand (rtx op, enum machine_mode mode)
   return const_arith_operand (op, mode) || register_operand (op, mode);
 }
 
+/* Return true if OP can be used as the second argument to an LE operation.  */
+
+int
+sle_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return GET_CODE (op) == CONST_INT && SMALL_OPERAND (INTVAL (op) + 1);
+}
+
+/* Likewise LEU.  */
+
+int
+sleu_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (op) == CONST_INT
+         && INTVAL (op) + 1 != 0
+         && SMALL_OPERAND (INTVAL (op) + 1));
+}
+
 /* Return truth value of whether OP is an integer which fits in 16 bits.  */
 
 int
@@ -2691,248 +2690,117 @@ mips_gp_save_slot (void)
   return loc;
 }
 \f
-/* Make normal rtx_code into something we can index from an array */
+/* Emit an instruction of the form (set TARGET (CODE OP0 OP1)).  */
 
-static enum internal_test
-map_test_to_internal_test (enum rtx_code test_code)
+static void
+mips_emit_binary (enum rtx_code code, rtx target, rtx op0, rtx op1)
 {
-  enum internal_test test = ITEST_MAX;
-
-  switch (test_code)
-    {
-    case EQ:  test = ITEST_EQ;  break;
-    case NE:  test = ITEST_NE;  break;
-    case GT:  test = ITEST_GT;  break;
-    case GE:  test = ITEST_GE;  break;
-    case LT:  test = ITEST_LT;  break;
-    case LE:  test = ITEST_LE;  break;
-    case GTU: test = ITEST_GTU; break;
-    case GEU: test = ITEST_GEU; break;
-    case LTU: test = ITEST_LTU; break;
-    case LEU: test = ITEST_LEU; break;
-    default:                   break;
-    }
-
-  return test;
+  emit_insn (gen_rtx_SET (VOIDmode, target,
+                         gen_rtx_fmt_ee (code, GET_MODE (target), op0, op1)));
 }
 
-\f
-/* Generate the code to compare two integer values.  The return value is:
-   (reg:SI xx)         The pseudo register the comparison is in
-   0                   No register, generate a simple branch.
-
-   ??? This is called with result nonzero by the Scond patterns in
-   mips.md.  These patterns are called with a target in the mode of
-   the Scond instruction pattern.  Since this must be a constant, we
-   must use SImode.  This means that if RESULT is nonzero, it will
-   always be an SImode register, even if TARGET_64BIT is true.  We
-   cope with this by calling convert_move rather than emit_move_insn.
-   This will sometimes lead to an unnecessary extension of the result;
-   for example:
-
-   long long
-   foo (long long i)
-   {
-     return i < 5;
-   }
-
-   TEST_CODE is the rtx code for the comparison.
-   CMP0 and CMP1 are the two operands to compare.
-   RESULT is the register in which the result should be stored (null for
-     branches).
-   For branches, P_INVERT points to an integer that is nonzero on return
-     if the branch should be inverted.  */
-
-rtx
-gen_int_relational (enum rtx_code test_code, rtx result, rtx cmp0,
-                   rtx cmp1, int *p_invert)
-{
-  struct cmp_info
-  {
-    enum rtx_code test_code;   /* code to use in instruction (LT vs. LTU) */
-    int const_low;             /* low bound of constant we can accept */
-    int const_high;            /* high bound of constant we can accept */
-    int const_add;             /* constant to add (convert LE -> LT) */
-    int reverse_regs;          /* reverse registers in test */
-    int invert_const;          /* != 0 if invert value if cmp1 is constant */
-    int invert_reg;            /* != 0 if invert value if cmp1 is register */
-    int unsignedp;             /* != 0 for unsigned comparisons.  */
-  };
-
-  static const struct cmp_info info[ (int)ITEST_MAX ] = {
-
-    { XOR,      0,  65535,  0,  0,  0,  0, 0 },        /* EQ  */
-    { XOR,      0,  65535,  0,  0,  1,  1, 0 },        /* NE  */
-    { LT,   -32769,  32766,  1,         1,  1,  0, 0 },        /* GT  */
-    { LT,   -32768,  32767,  0,         0,  1,  1, 0 },        /* GE  */
-    { LT,   -32768,  32767,  0,         0,  0,  0, 0 },        /* LT  */
-    { LT,   -32769,  32766,  1,         1,  0,  1, 0 },        /* LE  */
-    { LTU,  -32769,  32766,  1,         1,  1,  0, 1 },        /* GTU */
-    { LTU,  -32768,  32767,  0,         0,  1,  1, 1 },        /* GEU */
-    { LTU,  -32768,  32767,  0,         0,  0,  0, 1 },        /* LTU */
-    { LTU,  -32769,  32766,  1,         1,  0,  1, 1 },        /* LEU */
-  };
-
-  enum internal_test test;
-  enum machine_mode mode;
-  const struct cmp_info *p_info;
-  int branch_p;
-  int eqne_p;
-  int invert;
-  rtx reg;
-  rtx reg2;
-
-  test = map_test_to_internal_test (test_code);
-  if (test == ITEST_MAX)
-    abort ();
-
-  p_info = &info[(int) test];
-  eqne_p = (p_info->test_code == XOR);
-
-  mode = GET_MODE (cmp0);
-  if (mode == VOIDmode)
-    mode = GET_MODE (cmp1);
+/* Return true if CMP1 is a suitable second operand for relational
+   operator CODE.  See also the *sCC patterns in mips.md.  */
 
-  /* Eliminate simple branches.  */
-  branch_p = (result == 0);
-  if (branch_p)
+static bool
+mips_relational_operand_ok_p (enum rtx_code code, rtx cmp1)
+{
+  switch (code)
     {
-      if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG)
-       {
-         /* Comparisons against zero are simple branches.  */
-         if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0
-             && (! TARGET_MIPS16 || eqne_p))
-           return 0;
-
-         /* Test for beq/bne.  */
-         if (eqne_p && ! TARGET_MIPS16)
-           return 0;
-       }
-
-      /* Allocate a pseudo to calculate the value in.  */
-      result = gen_reg_rtx (mode);
-    }
+    case GT:
+    case GTU:
+      return reg_or_0_operand (cmp1, VOIDmode);
 
-  /* Make sure we can handle any constants given to us.  */
-  if (GET_CODE (cmp0) == CONST_INT)
-    cmp0 = force_reg (mode, cmp0);
+    case GE:
+    case GEU:
+      return !TARGET_MIPS16 && cmp1 == const1_rtx;
 
-  if (GET_CODE (cmp1) == CONST_INT)
-    {
-      HOST_WIDE_INT value = INTVAL (cmp1);
+    case LT:
+    case LTU:
+      return arith_operand (cmp1, VOIDmode);
 
-      if (value < p_info->const_low
-         || value > p_info->const_high
-         /* ??? Why?  And why wasn't the similar code below modified too?  */
-         || (TARGET_64BIT
-             && HOST_BITS_PER_WIDE_INT < 64
-             && p_info->const_add != 0
-             && ((p_info->unsignedp
-                  ? ((unsigned HOST_WIDE_INT) (value + p_info->const_add)
-                     > (unsigned HOST_WIDE_INT) INTVAL (cmp1))
-                  : (value + p_info->const_add) > INTVAL (cmp1))
-                 != (p_info->const_add > 0))))
-       cmp1 = force_reg (mode, cmp1);
-    }
+    case LE:
+      return sle_operand (cmp1, VOIDmode);
 
-  /* See if we need to invert the result.  */
-  invert = (GET_CODE (cmp1) == CONST_INT
-           ? p_info->invert_const : p_info->invert_reg);
+    case LEU:
+      return sleu_operand (cmp1, VOIDmode);
 
-  if (p_invert != (int *)0)
-    {
-      *p_invert = invert;
-      invert = 0;
+    default:
+      abort ();
     }
+}
 
-  /* Comparison to constants, may involve adding 1 to change a LT into LE.
-     Comparison between two registers, may involve switching operands.  */
-  if (GET_CODE (cmp1) == CONST_INT)
-    {
-      if (p_info->const_add != 0)
-       {
-         HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
-
-         /* If modification of cmp1 caused overflow,
-            we would get the wrong answer if we follow the usual path;
-            thus, x > 0xffffffffU would turn into x > 0U.  */
-         if ((p_info->unsignedp
-              ? (unsigned HOST_WIDE_INT) new >
-              (unsigned HOST_WIDE_INT) INTVAL (cmp1)
-              : new > INTVAL (cmp1))
-             != (p_info->const_add > 0))
-           {
-             /* This test is always true, but if INVERT is true then
-                the result of the test needs to be inverted so 0 should
-                be returned instead.  */
-             emit_move_insn (result, invert ? const0_rtx : const_true_rtx);
-             return result;
-           }
-         else
-           cmp1 = GEN_INT (new);
-       }
-    }
+/* Compare CMP0 and CMP1 using relational operator CODE and store the
+   result in TARGET.  CMP0 and TARGET are register_operands that have
+   the same integer mode.  If INVERT_PTR is nonnull, it's OK to set
+   TARGET to the inverse of the result and flip *INVERT_PTR instead.  */
 
-  else if (p_info->reverse_regs)
-    {
-      rtx temp = cmp0;
-      cmp0 = cmp1;
-      cmp1 = temp;
-    }
-
-  if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
-    reg = cmp0;
+static void
+mips_emit_int_relational (enum rtx_code code, bool *invert_ptr,
+                         rtx target, rtx cmp0, rtx cmp1)
+{
+  /* First see if there is a MIPS instruction that can do this operation
+     with CMP1 in its current form.  If not, try doing the same for the
+     inverse operation.  If that also fails, force CMP1 into a register
+     and try again.  */
+  if (mips_relational_operand_ok_p (code, cmp1))
+    mips_emit_binary (code, target, cmp0, cmp1);
   else
     {
-      reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result;
-      convert_move (reg, gen_rtx_fmt_ee (p_info->test_code,
-                                        mode, cmp0, cmp1), 0);
-    }
-
-  if (test == ITEST_NE)
-    {
-      if (! TARGET_MIPS16)
+      enum rtx_code inv_code = reverse_condition (code);
+      if (!mips_relational_operand_ok_p (inv_code, cmp1))
+       {
+         cmp1 = force_reg (GET_MODE (cmp0), cmp1);
+         mips_emit_int_relational (code, invert_ptr, target, cmp0, cmp1);
+       }
+      else if (invert_ptr == 0)
        {
-         convert_move (result, gen_rtx_GTU (mode, reg, const0_rtx), 0);
-         if (p_invert != NULL)
-           *p_invert = 0;
-         invert = 0;
+         rtx inv_target = gen_reg_rtx (GET_MODE (target));
+         mips_emit_binary (inv_code, inv_target, cmp0, cmp1);
+         mips_emit_binary (XOR, target, inv_target, const1_rtx);
        }
       else
        {
-         reg2 = invert ? gen_reg_rtx (mode) : result;
-         convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0);
-         reg = reg2;
+         *invert_ptr = !*invert_ptr;
+         mips_emit_binary (inv_code, target, cmp0, cmp1);
        }
     }
+}
 
-  else if (test == ITEST_EQ)
-    {
-      reg2 = invert ? gen_reg_rtx (mode) : result;
-      convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0);
-      reg = reg2;
-    }
+/* Return a register that is zero iff CMP0 and CMP1 are equal.
+   The register will have the same mode as CMP0.  */
 
-  if (invert)
-    {
-      rtx one;
+static rtx
+mips_zero_if_equal (rtx cmp0, rtx cmp1)
+{
+  if (cmp1 == const0_rtx)
+    return cmp0;
 
-      if (! TARGET_MIPS16)
-       one = const1_rtx;
-      else
-       {
-         /* The value is in $24.  Copy it to another register, so
-             that reload doesn't think it needs to store the $24 and
-             the input to the XOR in the same location.  */
-         reg2 = gen_reg_rtx (mode);
-         emit_move_insn (reg2, reg);
-         reg = reg2;
-         one = force_reg (mode, const1_rtx);
-       }
-      convert_move (result, gen_rtx_XOR (mode, reg, one), 0);
-    }
+  return expand_binop (GET_MODE (cmp0), xor_optab,
+                      cmp0, cmp1, 0, 0, OPTAB_DIRECT);
+}
 
-  return result;
+/* Try comparing cmp_operands[0] and cmp_operands[1] using rtl code CODE.
+   Store the result in TARGET and return true if successful.
+
+   On 64-bit targets, TARGET may be wider than cmp_operands[0].  */
+
+bool
+mips_emit_scc (enum rtx_code code, rtx target)
+{
+  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
+    return false;
+
+  target = gen_lowpart (GET_MODE (cmp_operands[0]), target);
+  if (code == EQ || code == NE)
+    {
+      rtx zie = mips_zero_if_equal (cmp_operands[0], cmp_operands[1]);
+      mips_emit_binary (code, target, zie, const0_rtx);
+    }
+  else
+    mips_emit_int_relational (code, 0, target,
+                             cmp_operands[0], cmp_operands[1]);
+  return true;
 }
 \f
 /* Work out how to check a floating-point condition.  We need a
@@ -2970,74 +2838,67 @@ get_float_compare_codes (enum rtx_code in_code, enum rtx_code *cmp_code,
 void
 gen_conditional_branch (rtx *operands, enum rtx_code test_code)
 {
-  rtx cmp0 = cmp_operands[0];
-  rtx cmp1 = cmp_operands[1];
+  rtx cmp0, cmp1, target;
   enum machine_mode mode;
   enum rtx_code cmp_code;
-  rtx reg;
-  int invert;
-  rtx label1, label2;
 
-  switch (GET_MODE (cmp0))
+  switch (GET_MODE (cmp_operands[0]))
     {
     case SImode:
     case DImode:
-      mode = GET_MODE (cmp0);
-      invert = 0;
-      reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert);
-
-      if (reg)
+      mode = GET_MODE (cmp_operands[0]);
+      if (!TARGET_MIPS16 && cmp_operands[1] == const0_rtx)
+       {
+         cmp0 = cmp_operands[0];
+         cmp1 = cmp_operands[1];
+       }
+      else if (test_code == EQ || test_code == NE)
+       {
+         if (TARGET_MIPS16)
+           {
+             cmp0 = mips_zero_if_equal (cmp_operands[0], cmp_operands[1]);
+             cmp1 = const0_rtx;
+           }
+         else
+           {
+             cmp0 = cmp_operands[0];
+             cmp1 = force_reg (mode, cmp_operands[1]);
+           }
+       }
+      else
        {
-         cmp0 = reg;
+         bool invert = false;
+         cmp0 = gen_reg_rtx (mode);
          cmp1 = const0_rtx;
-         test_code = NE;
+         mips_emit_int_relational (test_code, &invert, cmp0,
+                                   cmp_operands[0], cmp_operands[1]);
+         test_code = (invert ? EQ : NE);
        }
-      else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
-       /* We don't want to build a comparison against a nonzero
-          constant.  */
-       cmp1 = force_reg (mode, cmp1);
-
       break;
 
     case SFmode:
     case DFmode:
-      if (! ISA_HAS_8CC)
-       reg = gen_rtx_REG (CCmode, FPSW_REGNUM);
+      mode = CCmode;
+      if (!ISA_HAS_8CC)
+       cmp0 = gen_rtx_REG (mode, FPSW_REGNUM);
       else
-       reg = gen_reg_rtx (CCmode);
+       cmp0 = gen_reg_rtx (mode);
+      cmp1 = const0_rtx;
 
       get_float_compare_codes (test_code, &cmp_code, &test_code);
-      emit_insn (gen_rtx_SET (VOIDmode, reg,
-                             gen_rtx_fmt_ee (cmp_code, CCmode, cmp0, cmp1)));
-
-      mode = CCmode;
-      cmp0 = reg;
-      cmp1 = const0_rtx;
-      invert = 0;
+      mips_emit_binary (cmp_code, cmp0, cmp_operands[0], cmp_operands[1]);
       break;
 
     default:
-      fatal_insn ("bad test",
-                 gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));
+      abort ();
     }
 
   /* Generate the branch.  */
-
-  label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
-  label2 = pc_rtx;
-
-  if (invert)
-    {
-      label2 = label1;
-      label1 = pc_rtx;
-    }
-
-  emit_jump_insn
-    (gen_rtx_SET (VOIDmode, pc_rtx,
-                 gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                       gen_rtx_fmt_ee (test_code, mode,
-                                                       cmp0, cmp1),
-                                       label1, label2)));
+  target = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                                gen_rtx_fmt_ee (test_code, mode, cmp0, cmp1),
+                                gen_rtx_LABEL_REF (VOIDmode, operands[0]),
+                                pc_rtx);
+  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, target));
 }
 
 /* Emit the common code for conditional moves.  OPERANDS is the array
index 562374ae5297ac8eab674354355afcc54365d984..f0f06ada15cf2833d3a61671fe0d45a3f6fd5b67 100644 (file)
@@ -2727,6 +2727,8 @@ typedef struct mips_args {
                                  UNSPEC_VOLATILE }},                   \
   {"arith_operand",            { REG, CONST_INT, CONST, SUBREG }},     \
   {"reg_or_0_operand",         { REG, CONST_INT, CONST_DOUBLE, SUBREG }}, \
+  {"sle_operand",              { CONST_INT }},                         \
+  {"sleu_operand",             { CONST_INT }},                         \
   {"small_int",                        { CONST_INT }},                         \
   {"const_float_1_operand",    { CONST_DOUBLE }},                      \
   {"reg_or_const_float_1_operand", { CONST_DOUBLE, REG}},               \
index cad6dbfdb4511f0429f4f9f80866467e93bf2cc4..08f04f8ded327cd1d3f546b9fd6565cb8014af21 100644 (file)
@@ -6012,14 +6012,7 @@ dsrl\t%3,%3,1\n\
        (eq:SI (match_dup 1)
               (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (EQ, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
-
+  { if (mips_emit_scc (EQ, operands[0])) DONE; else FAIL; })
 
 (define_insn "*seq_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6057,20 +6050,15 @@ dsrl\t%3,%3,1\n\
   [(set_attr "type" "slt")
    (set_attr "mode" "DI")])
 
-;; On the mips16 the default code is better than using sltu.
+;; "sne" uses sltu instructions in which the first operand is $0.
+;; This isn't possible in mips16 code.
 
 (define_expand "sne"
   [(set (match_operand:SI 0 "register_operand")
        (ne:SI (match_dup 1)
               (match_dup 2)))]
   "!TARGET_MIPS16"
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (NE, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (NE, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sne_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6095,13 +6083,7 @@ dsrl\t%3,%3,1\n\
        (gt:SI (match_dup 1)
               (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (GT, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (GT, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sgt_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6144,26 +6126,32 @@ dsrl\t%3,%3,1\n\
        (ge:SI (match_dup 1)
               (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
+  { if (mips_emit_scc (GE, operands[0])) DONE; else FAIL; })
 
-  gen_int_relational (GE, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+(define_insn "*sge_si"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (ge:SI (match_operand:SI 1 "register_operand" "d")
+              (const_int 1)))]
+  "!TARGET_MIPS16"
+  "slt\t%0,%.,%1"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "SI")])
+
+(define_insn "*sge_di"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ge:DI (match_operand:DI 1 "register_operand" "d")
+              (const_int 1)))]
+  "TARGET_64BIT && !TARGET_MIPS16"
+  "slt\t%0,%.,%1"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "DI")])
 
 (define_expand "slt"
   [(set (match_operand:SI 0 "register_operand")
        (lt:SI (match_dup 1)
               (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (LT, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (LT, operands[0])) DONE; else FAIL; })
 
 (define_insn "*slt_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6216,19 +6204,13 @@ dsrl\t%3,%3,1\n\
        (le:SI (match_dup 1)
               (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (LE, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (LE, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sle_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
        (le:SI (match_operand:SI 1 "register_operand" "d")
-              (match_operand:SI 2 "small_int" "I")))]
-  "!TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+              (match_operand:SI 2 "sle_operand" "")))]
+  "!TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "slt\t%0,%1,%2";
@@ -6239,8 +6221,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sle_si_mips16"
   [(set (match_operand:SI 0 "register_operand" "=t")
        (le:SI (match_operand:SI 1 "register_operand" "d")
-              (match_operand:SI 2 "small_int" "I")))]
-  "TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+              (match_operand:SI 2 "sle_operand" "")))]
+  "TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "slt\t%1,%2";
@@ -6254,8 +6236,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sle_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
        (le:DI (match_operand:DI 1 "register_operand" "d")
-              (match_operand:DI 2 "small_int" "I")))]
-  "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+              (match_operand:DI 2 "sle_operand" "")))]
+  "TARGET_64BIT && !TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "slt\t%0,%1,%2";
@@ -6266,8 +6248,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sle_di_mips16"
   [(set (match_operand:DI 0 "register_operand" "=t")
        (le:DI (match_operand:DI 1 "register_operand" "d")
-              (match_operand:DI 2 "small_int" "I")))]
-  "TARGET_64BIT && TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+              (match_operand:DI 2 "sle_operand" "")))]
+  "TARGET_64BIT && TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "slt\t%1,%2";
@@ -6283,13 +6265,7 @@ dsrl\t%3,%3,1\n\
        (gtu:SI (match_dup 1)
                (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (GTU, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (GTU, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sgtu_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6332,26 +6308,32 @@ dsrl\t%3,%3,1\n\
         (geu:SI (match_dup 1)
                 (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
+  { if (mips_emit_scc (GEU, operands[0])) DONE; else FAIL; })
 
-  gen_int_relational (GEU, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+(define_insn "*sge_si"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (geu:SI (match_operand:SI 1 "register_operand" "d")
+               (const_int 1)))]
+  "!TARGET_MIPS16"
+  "sltu\t%0,%.,%1"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "SI")])
+
+(define_insn "*sge_di"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (geu:DI (match_operand:DI 1 "register_operand" "d")
+               (const_int 1)))]
+  "TARGET_64BIT && !TARGET_MIPS16"
+  "sltu\t%0,%.,%1"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "DI")])
 
 (define_expand "sltu"
   [(set (match_operand:SI 0 "register_operand")
        (ltu:SI (match_dup 1)
                (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (LTU, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (LTU, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sltu_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -6404,19 +6386,13 @@ dsrl\t%3,%3,1\n\
        (leu:SI (match_dup 1)
                (match_dup 2)))]
   ""
-{
-  if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) != MODE_INT)
-    FAIL;
-
-  gen_int_relational (LEU, operands[0], cmp_operands[0], cmp_operands[1], NULL);
-  DONE;
-})
+  { if (mips_emit_scc (LEU, operands[0])) DONE; else FAIL; })
 
 (define_insn "*sleu_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
        (leu:SI (match_operand:SI 1 "register_operand" "d")
-               (match_operand:SI 2 "small_int" "I")))]
-  "!TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+               (match_operand:SI 2 "sleu_operand" "")))]
+  "!TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "sltu\t%0,%1,%2";
@@ -6427,8 +6403,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sleu_si_mips16"
   [(set (match_operand:SI 0 "register_operand" "=t")
        (leu:SI (match_operand:SI 1 "register_operand" "d")
-               (match_operand:SI 2 "small_int" "I")))]
-  "TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+               (match_operand:SI 2 "sleu_operand" "")))]
+  "TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "sltu\t%1,%2";
@@ -6442,8 +6418,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sleu_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
        (leu:DI (match_operand:DI 1 "register_operand" "d")
-               (match_operand:DI 2 "small_int" "I")))]
-  "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+               (match_operand:DI 2 "sleu_operand" "")))]
+  "TARGET_64BIT && !TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "sltu\t%0,%1,%2";
@@ -6454,8 +6430,8 @@ dsrl\t%3,%3,1\n\
 (define_insn "*sleu_di_mips16"
   [(set (match_operand:DI 0 "register_operand" "=t")
        (leu:DI (match_operand:DI 1 "register_operand" "d")
-               (match_operand:DI 2 "small_int" "I")))]
-  "TARGET_64BIT && TARGET_MIPS16 && INTVAL (operands[2]) < 32767"
+               (match_operand:DI 2 "sleu_operand" "")))]
+  "TARGET_64BIT && TARGET_MIPS16"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
   return "sltu\t%1,%2";