Finish MIPS4 support, add R5000 support.
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 17 Sep 1996 19:52:34 +0000 (19:52 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 17 Sep 1996 19:52:34 +0000 (19:52 +0000)
From-SVN: r12732

gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md

index 1bc47d407644967e5239c0cde99df2046cc0ea3b..f32117b94da5553fe91fc19651339c5c04cc5659 100644 (file)
@@ -256,7 +256,8 @@ char mips_reg_names[][8] =
  "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
- "hi",   "lo",   "accum","$fcr31","$rap"
+ "hi",   "lo",   "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
+ "$fcc5","$fcc6","$fcc7","$rap"
 };
 
 /* Mips software names for the registers, used to overwrite the
@@ -272,7 +273,8 @@ char mips_sw_reg_names[][8] =
   "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
-  "hi",   "lo",   "accum","$fcr31","$rap"
+  "hi",   "lo",   "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
+  "$fcc5","$fcc6","$fcc7","$rap"
 };
 
 /* Map hard register number to register class */
@@ -295,7 +297,8 @@ enum reg_class mips_regno_to_class[] =
   FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
   FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
   HI_REG,      LO_REG,         HILO_REG,       ST_REGS,
-  GR_REGS
+  ST_REGS,     ST_REGS,        ST_REGS,        ST_REGS,
+  ST_REGS,     ST_REGS,        ST_REGS,        GR_REGS
 };
 
 /* Map register constraint character to register class.  */
@@ -524,6 +527,40 @@ mips_const_double_ok (op, mode)
   return FALSE;
 }
 
+/* Accept the floating point constant 1 in the appropriate mode.  */
+
+int
+const_float_1_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  REAL_VALUE_TYPE d;
+  static REAL_VALUE_TYPE onedf;
+  static REAL_VALUE_TYPE onesf;
+  static int one_initialized;
+
+  if (GET_CODE (op) != CONST_DOUBLE
+      || mode != GET_MODE (op)
+      || (mode != DFmode && mode != SFmode))
+    return FALSE;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+  /* We only initialize these values if we need them, since we will
+     never get called unless mips_isa >= 4.  */
+  if (! one_initialized)
+    {
+      onedf = REAL_VALUE_ATOF ("1.0", DFmode);
+      onesf = REAL_VALUE_ATOF ("1.0", SFmode);
+      one_initialized = TRUE;
+    }
+
+  if (mode == DFmode)
+    return REAL_VALUES_EQUAL (d, onedf);
+  else
+    return REAL_VALUES_EQUAL (d, onesf);
+}
+
 /* Return truth value if a memory operand fits in a single instruction
    (ie, register + small offset).  */
 
@@ -990,6 +1027,10 @@ mips_move_1word (operands, insn, unsignedp)
       code1 = GET_CODE (op1);
     }
 
+  /* For our purposes, a condition code mode is the same as SImode.  */
+  if (mode == CCmode)
+    mode = SImode;
+
   if (code0 == REG)
     {
       int regno0 = REGNO (op0) + subreg_word0;
@@ -1017,13 +1058,16 @@ mips_move_1word (operands, insn, unsignedp)
                    ret = "mflo\t%0";
                }
 
+             else if (ST_REG_P (regno1) && mips_isa >= 4)
+               ret = "li\t%0,1\n\tmovf\t%0,%.,%1";
+
              else
                {
                  delay = DELAY_LOAD;
                  if (FP_REG_P (regno1))
                    ret = "mfc1\t%0,%1";
 
-                 else if (regno1 == FPSW_REGNUM)
+                 else if (regno1 == FPSW_REGNUM && mips_isa < 4)
                    ret = "cfc1\t%0,$31";
                }
            }
@@ -1050,7 +1094,7 @@ mips_move_1word (operands, insn, unsignedp)
                }
            }
 
-         else if (regno0 == FPSW_REGNUM)
+         else if (regno0 == FPSW_REGNUM && mips_isa < 4)
            {
              if (GP_REG_P (regno1))
                {
@@ -1079,6 +1123,7 @@ mips_move_1word (operands, insn, unsignedp)
                  ret = "lw\t%0,%1";
                  break;
                case SImode:
+               case CCmode:
                  ret = ((unsignedp && TARGET_64BIT)
                         ? "lwu\t%0,%1"
                         : "lw\t%0,%1");
@@ -1981,112 +2026,67 @@ gen_conditional_branch (operands, test_code)
      rtx operands[];
      enum rtx_code test_code;
 {
-  static enum machine_mode mode_map[(int)CMP_MAX][(int)ITEST_MAX] = {
-    {                          /* CMP_SI */
-      SImode,                  /* eq  */
-      SImode,                  /* ne  */
-      SImode,                  /* gt  */
-      SImode,                  /* ge  */
-      SImode,                  /* lt  */
-      SImode,                  /* le  */
-      SImode,                  /* gtu */
-      SImode,                  /* geu */
-      SImode,                  /* ltu */
-      SImode,                  /* leu */
-    },
-    {                          /* CMP_DI */
-      DImode,                  /* eq  */
-      DImode,                  /* ne  */
-      DImode,                  /* gt  */
-      DImode,                  /* ge  */
-      DImode,                  /* lt  */
-      DImode,                  /* le  */
-      DImode,                  /* gtu */
-      DImode,                  /* geu */
-      DImode,                  /* ltu */
-      DImode,                  /* leu */
-    },
-    {                          /* CMP_SF */
-      CC_FPmode,               /* eq  */
-      CC_REV_FPmode,           /* ne  */
-      CC_FPmode,               /* gt  */
-      CC_FPmode,               /* ge  */
-      CC_FPmode,               /* lt  */
-      CC_FPmode,               /* le  */
-      VOIDmode,                        /* gtu */
-      VOIDmode,                        /* geu */
-      VOIDmode,                        /* ltu */
-      VOIDmode,                        /* leu */
-    },
-    {                          /* CMP_DF */
-      CC_FPmode,               /* eq  */
-      CC_REV_FPmode,           /* ne  */
-      CC_FPmode,               /* gt  */
-      CC_FPmode,               /* ge  */
-      CC_FPmode,               /* lt  */
-      CC_FPmode,               /* le  */
-      VOIDmode,                        /* gtu */
-      VOIDmode,                        /* geu */
-      VOIDmode,                        /* ltu */
-      VOIDmode,                        /* leu */
-    },
-  };
-
+  enum cmp_type type = branch_type;
+  rtx cmp0 = branch_cmp[0];
+  rtx cmp1 = branch_cmp[1];
   enum machine_mode mode;
-  enum cmp_type type     = branch_type;
-  rtx cmp0               = branch_cmp[0];
-  rtx cmp1               = branch_cmp[1];
-  rtx label1             = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
-  rtx label2             = pc_rtx;
-  rtx reg                = (rtx)0;
-  int invert             = 0;
-  enum internal_test test = map_test_to_internal_test (test_code);
-
-  if (test == ITEST_MAX)
-    {
-      mode = word_mode;
-      goto fail;
-    }
-
-  /* Get the machine mode to use (CCmode, CC_EQmode, CC_FPmode, or CC_REV_FPmode).  */
-  mode = mode_map[(int)type][(int)test];
-  if (mode == VOIDmode)
-    goto fail;
+  rtx reg;
+  int invert;
+  rtx label1, label2;
 
   switch (type)
     {
     default:
-      goto fail;
+      abort_with_insn (gen_rtx (test_code, VOIDmode, cmp0, cmp1), "bad test");
 
     case CMP_SI:
     case CMP_DI:
-      reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert);
-      if (reg != (rtx)0)
+      mode = type == CMP_SI ? SImode : DImode;
+      invert = FALSE;
+      reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert);
+      if (reg)
        {
          cmp0 = reg;
          cmp1 = const0_rtx;
          test_code = NE;
        }
-
-      /* Make sure not non-zero constant if ==/!= */
       else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
-       cmp1 = force_reg (mode, cmp1);
-
+       {
+         /* We don't want to build a comparison against a non-zero
+             constant.  */
+         cmp1 = force_reg (mode, cmp1);
+       }
       break;
 
-    case CMP_DF:
     case CMP_SF:
-      {
-       rtx reg = gen_rtx (REG, mode, FPSW_REGNUM);
-       emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (test_code, mode, cmp0, cmp1)));
-       cmp0 = reg;
-       cmp1 = const0_rtx;
-       test_code = NE;
-      }
+    case CMP_DF:
+      if (mips_isa < 4)
+       reg = gen_rtx (REG, CCmode, FPSW_REGNUM);
+      else
+       reg = gen_reg_rtx (CCmode);
+
+      /* For cmp0 != cmp1, build cmp0 == cmp1, and test for result ==
+         0 in the instruction built below.  The MIPS FPU handles
+         inequality testing by testing for equality and looking for a
+         false result.  */
+      emit_insn (gen_rtx (SET, VOIDmode,
+                         reg,
+                         gen_rtx (test_code == NE ? EQ : test_code,
+                                  CCmode, cmp0, cmp1)));
+
+      test_code = test_code == NE ? EQ : NE;
+      mode = CCmode;
+      cmp0 = reg;
+      cmp1 = const0_rtx;
+      invert = FALSE;
       break;
     }
 
-  /* Generate the jump */
+  /* Generate the branch.  */
+
+  label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
+  label2 = pc_rtx;
+
   if (invert)
     {
       label2 = label1;
@@ -2099,13 +2099,102 @@ gen_conditional_branch (operands, test_code)
                                    gen_rtx (test_code, mode, cmp0, cmp1),
                                    label1,
                                    label2)));
+}
 
-  return;
+/* Emit the common code for conditional moves.  OPERANDS is the array
+   of operands passed to the conditional move defined_expand.  */
 
-fail:
-  abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test");
-}
+void
+gen_conditional_move (operands)
+     rtx *operands;
+{
+  rtx op0 = branch_cmp[0];
+  rtx op1 = branch_cmp[1];
+  enum machine_mode mode = GET_MODE (branch_cmp[0]);
+  enum rtx_code cmp_code = GET_CODE (operands[1]);
+  enum rtx_code move_code = NE;
+  enum machine_mode op_mode = GET_MODE (operands[0]);
+  enum machine_mode cmp_mode;
+  rtx cmp_reg;
+
+  if (GET_MODE_CLASS (mode) != MODE_FLOAT)
+    {
+      switch (cmp_code)
+       {
+       case EQ:
+         cmp_code = XOR;
+         move_code = EQ;
+         break;
+       case NE:
+         cmp_code = XOR;
+         break;
+       case LT:
+         break;
+       case GE:
+         cmp_code = LT;
+         move_code = EQ;
+         break;
+       case GT:
+         cmp_code = LT;
+         op0 = force_reg (mode, branch_cmp[1]);
+         op1 = branch_cmp[0];
+         break;
+       case LE:
+         cmp_code = LT;
+         op0 = force_reg (mode, branch_cmp[1]);
+         op1 = branch_cmp[0];
+         move_code = EQ;
+         break;
+       case LTU:
+         break;
+       case GEU:
+         cmp_code = LTU;
+         move_code = EQ;
+         break;
+       case GTU:
+         cmp_code = LTU;
+         op0 = force_reg (mode, branch_cmp[1]);
+         op1 = branch_cmp[0];
+         break;
+       case LEU:
+         cmp_code = LTU;
+         op0 = force_reg (mode, branch_cmp[1]);
+         op1 = branch_cmp[0];
+         move_code = EQ;
+         break;
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+      if (cmp_code == NE)
+       {
+         cmp_code = EQ;
+         move_code = EQ;
+       }
+    }
+         
+  if (mode == SImode || mode == DImode)
+    cmp_mode = mode;
+  else if (mode == SFmode || mode == DFmode)
+    cmp_mode = CCmode;
+  else
+    abort ();
 
+  cmp_reg = gen_reg_rtx (cmp_mode);
+  emit_insn (gen_rtx (SET, cmp_mode,
+                     cmp_reg,
+                     gen_rtx (cmp_code, cmp_mode, op0, op1)));
+  emit_insn (gen_rtx (SET, op_mode,
+                     operands[0],
+                     gen_rtx (IF_THEN_ELSE, op_mode,
+                              gen_rtx (move_code, VOIDmode,
+                                       cmp_reg,
+                                       CONST0_RTX (SImode)),
+                              operands[2],
+                              operands[3])));
+}
 \f
 #if 0
 /* Internal code to generate the load and store of one word/short/byte.
@@ -3443,6 +3532,11 @@ override_options ()
            mips_cpu = PROCESSOR_R4650;
          break;
 
+       case '5':
+         if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
+           mips_cpu = PROCESSOR_R5000;
+         break;
+
        case '6':
          if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
            mips_cpu = PROCESSOR_R6000;
@@ -3459,7 +3553,10 @@ override_options ()
          break;
        }
 
-      if (seen_v && mips_cpu != PROCESSOR_R4300 && mips_cpu != PROCESSOR_R4100)
+      if (seen_v
+         && mips_cpu != PROCESSOR_R4300
+         && mips_cpu != PROCESSOR_R4100
+         && mips_cpu != PROCESSOR_R5000)
        mips_cpu = PROCESSOR_DEFAULT;
 
       if (mips_cpu == PROCESSOR_DEFAULT)
@@ -3642,8 +3739,15 @@ override_options ()
        {
          register int temp;
 
-         if (mode == CC_FPmode || mode == CC_REV_FPmode)
-           temp = (regno == FPSW_REGNUM);
+         if (mode == CCmode)
+           {
+             if (mips_isa < 4)
+               temp = (regno == FPSW_REGNUM);
+             else
+               temp = (ST_REG_P (regno)
+                       || GP_REG_P (regno)
+                       || FP_REG_P (regno));
+           }
 
          else if (GP_REG_P (regno))
            temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
@@ -3745,6 +3849,7 @@ mips_debugger_offset (addr, offset)
    'b'  print 'n' for EQ, 'z' for NE
    'T'  print 'f' for EQ, 't' for NE
    't'  print 't' for EQ, 'f' for NE
+   'Z'  print register and a comma, but print nothing for $fcc0
    '(' Turn on .set noreorder
    ')' Turn on .set reorder
    '[' Turn on .set noat
@@ -3935,6 +4040,19 @@ print_operand (file, op, letter)
       assemble_name (file, buffer);
     }
 
+  else if (letter == 'Z')
+    {
+      register int regnum;
+
+      if (code != REG)
+       abort ();
+      regnum = REGNO (op);
+      if (! ST_REG_P (regnum))
+       abort ();
+      if (regnum != ST_REG_FIRST)
+       fprintf (file, "%s,", reg_names[regnum]);
+    }
+
   else if (code == REG)
     {
       register int regnum = REGNO (op);
@@ -5853,5 +5971,26 @@ mips_secondary_reload_class (class, mode, x, in_p)
       return GR_REGS;
     }
 
+  /* We can only copy a value to a condition code register from a
+     floating point register, and even then we require a scratch
+     floating point register.  We can only copy a value out of a
+     condition code register into a general register.  */
+  if (class == ST_REGS)
+    {
+      if (in_p)
+       return FP_REGS;
+      if (GP_REG_P (regno))
+       return NO_REGS;
+      return GR_REGS;
+    }
+  if (ST_REG_P (regno))
+    {
+      if (! in_p)
+       return FP_REGS;
+      if (class == GR_REGS)
+       return NO_REGS;
+      return GR_REGS;
+    }
+
   return NO_REGS;
 }
index a1f0b26b32aa188635dba4a8aa9e26e0713413c7..c683852e4ff9b95f226142485535b649e29b33a1 100644 (file)
@@ -70,6 +70,7 @@ enum processor_type {
   PROCESSOR_R4300,
   PROCESSOR_R4600,
   PROCESSOR_R4650,
+  PROCESSOR_R5000,
   PROCESSOR_R8000
 };
 
@@ -168,6 +169,7 @@ extern int          function_arg_partial_nregs ();
 extern void            function_epilogue ();
 extern void            function_prologue ();
 extern void            gen_conditional_branch ();
+extern void            gen_conditional_move ();
 extern struct rtx_def * gen_int_relational ();
 extern void            init_cumulative_args ();
 extern int             large_int ();
@@ -555,6 +557,18 @@ do                                                                 \
                                                                        \
        for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)       \
          fixed_regs[regno] = call_used_regs[regno] = 1;                \
+       for (regno = ST_REG_FIRST; regno <= ST_REG_LAST; regno++)       \
+         fixed_regs[regno] = call_used_regs[regno] = 1;                \
+      }                                                                        \
+    else if (mips_isa < 4)                                             \
+      {                                                                        \
+       int regno;                                                      \
+                                                                       \
+       /* We only have a single condition code register.  We           \
+           implement this by hiding all the condition code registers,  \
+           and generating RTL that refers directly to ST_REG_FIRST.  */        \
+       for (regno = ST_REG_FIRST; regno <= ST_REG_LAST; regno++)       \
+         fixed_regs[regno] = call_used_regs[regno] = 1;                \
       }                                                                        \
     SUBTARGET_CONDITIONAL_REGISTER_USAGE                               \
   }                                                                    \
@@ -1200,14 +1214,16 @@ do {                                                  \
    even those that are not normally considered general registers.
 
    On the Mips, we have 32 integer registers, 32 floating point
-   registers and the special registers hi, lo, hilo, fp status, and rap.
-   The hilo register is only used in 64 bit mode.  It represents a 64
-   bit value stored as two 32 bit values in the hi and lo registers;
-   this is the result of the mult instruction.  rap is a pointer to the
-   stack where the return address reg ($31) was stored.  This is needed
-   for C++ exception handling.  */
+   registers, 8 condition code registers, and the special registers
+   hi, lo, hilo, and rap.  The 8 condition code registers are only
+   used if mips_isa >= 4.  The hilo register is only used in 64 bit
+   mode.  It represents a 64 bit value stored as two 32 bit values in
+   the hi and lo registers; this is the result of the mult
+   instruction.  rap is a pointer to the stack where the return
+   address reg ($31) was stored.  This is needed for C++ exception
+   handling.  */
 
-#define FIRST_PSEUDO_REGISTER 69
+#define FIRST_PSEUDO_REGISTER 76
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.
@@ -1220,7 +1236,7 @@ do {                                                  \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1,                      \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      \
-  0, 0, 0, 1, 1                                                                \
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1                                   \
 }
 
 
@@ -1237,7 +1253,7 @@ do {                                                  \
   0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,                      \
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                      \
   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      \
-  1, 1, 1, 1, 1                                                                \
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1                                   \
 }
 
 
@@ -1260,21 +1276,25 @@ do {                                                  \
 #define MD_REG_NUM   (MD_REG_LAST - MD_REG_FIRST + 1)
 
 #define ST_REG_FIRST 67
-#define ST_REG_LAST  67
+#define ST_REG_LAST  74
 #define ST_REG_NUM   (ST_REG_LAST - ST_REG_FIRST + 1)
 
-#define RAP_REG_NUM   68
+#define RAP_REG_NUM   75
 
 #define AT_REGNUM      (GP_REG_FIRST + 1)
 #define HI_REGNUM      (MD_REG_FIRST + 0)
 #define LO_REGNUM      (MD_REG_FIRST + 1)
 #define HILO_REGNUM    (MD_REG_FIRST + 2)
+
+/* FPSW_REGNUM is the single condition code used if mips_isa < 4.  If
+   mips_isa >= 4, it should not be used, and an arbitrary ST_REG
+   should be used instead.  */
 #define FPSW_REGNUM    ST_REG_FIRST
 
 #define GP_REG_P(REGNO) ((unsigned) ((REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define FP_REG_P(REGNO) ((unsigned) ((REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) ((unsigned) ((REGNO) - MD_REG_FIRST) < MD_REG_NUM)
-#define ST_REG_P(REGNO) ((REGNO) == ST_REG_FIRST)
+#define ST_REG_P(REGNO) ((unsigned) ((REGNO) - ST_REG_FIRST) < ST_REG_NUM)
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
@@ -1464,8 +1484,8 @@ enum reg_class
   { 0x00000000, 0x00000000, 0x00000002 },      /* lo register */       \
   { 0x00000000, 0x00000000, 0x00000004 },      /* hilo register */     \
   { 0x00000000, 0x00000000, 0x00000003 },      /* mul/div registers */ \
-  { 0x00000000, 0x00000000, 0x00000008 },      /* status registers */  \
-  { 0xffffffff, 0xffffffff, 0x0000000f }       /* all registers */     \
+  { 0x00000000, 0x00000000, 0x000007f8 },      /* status registers */  \
+  { 0xffffffff, 0xffffffff, 0x000007ff }       /* all registers */     \
 }
 
 
@@ -1625,7 +1645,8 @@ extern enum reg_class mips_char_to_class[];
           || (CLASS2 == GR_REGS && CLASS1 == FP_REGS))))
 
 /* The HI and LO registers can only be reloaded via the general
-   registers.  */
+   registers.  Condition code registers can only be loaded to the
+   general registers, and from the floating point registers.  */
 
 #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)                   \
   mips_secondary_reload_class (CLASS, MODE, X, 1)
@@ -2868,7 +2889,8 @@ while (0)
       enum machine_mode xmode = GET_MODE (X);                          \
       if (xmode == SFmode)                                             \
        {                                                               \
-         if (mips_cpu == PROCESSOR_R3000)                              \
+         if (mips_cpu == PROCESSOR_R3000                               \
+             || mips_cpu == PROCESSOR_R5000)                           \
            return COSTS_N_INSNS (4);                                   \
          else if (mips_cpu == PROCESSOR_R6000)                         \
            return COSTS_N_INSNS (5);                                   \
@@ -2878,7 +2900,8 @@ while (0)
                                                                        \
       if (xmode == DFmode)                                             \
        {                                                               \
-         if (mips_cpu == PROCESSOR_R3000)                              \
+         if (mips_cpu == PROCESSOR_R3000                               \
+             || mips_cpu == PROCESSOR_R5000)                           \
            return COSTS_N_INSNS (5);                                   \
          else if (mips_cpu == PROCESSOR_R6000)                         \
            return COSTS_N_INSNS (6);                                   \
@@ -2890,6 +2913,8 @@ while (0)
        return COSTS_N_INSNS (12);                                      \
       else if (mips_cpu == PROCESSOR_R6000)                            \
        return COSTS_N_INSNS (17);                                      \
+      else if (mips_cpu == PROCESSOR_R5000)                            \
+       return COSTS_N_INSNS (5);                                       \
       else                                                             \
        return COSTS_N_INSNS (10);                                      \
     }                                                                  \
@@ -2926,6 +2951,8 @@ while (0)
       return COSTS_N_INSNS (35);                                       \
     else if (mips_cpu == PROCESSOR_R6000)                              \
       return COSTS_N_INSNS (38);                                       \
+    else if (mips_cpu == PROCESSOR_R5000)                              \
+      return COSTS_N_INSNS (36);                                       \
     else                                                               \
       return COSTS_N_INSNS (69);
 
@@ -3001,6 +3028,8 @@ while (0)
    : (((TO) == HI_REG || (TO) == LO_REG                                        \
        || (TO) == MD_REGS || (FROM) == HILO_REG)                       \
       && (FROM) == GR_REGS) ? 6                                                \
+   : (FROM) == ST_REGS && (TO) == GR_REGS ? 4                          \
+   : (FROM) == FP_REGS && (TO) == ST_REGS ? 8                          \
    : 12)
 
 /* ??? Fix this to be right for the R8000.  */
@@ -3053,6 +3082,7 @@ while (0)
   {"small_int",                        { CONST_INT }},                         \
   {"large_int",                        { CONST_INT }},                         \
   {"mips_const_double_ok",     { CONST_DOUBLE }},                      \
+  {"const_float_1_operand",    { CONST_DOUBLE }},                      \
   {"simple_memory_operand",    { MEM, SUBREG }},                       \
   {"equality_op",              { EQ, NE }},                            \
   {"cmp_op",                   { EQ, NE, GT, GE, GTU, GEU, LT, LE,     \
@@ -3082,40 +3112,6 @@ while (0)
 #define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS)                     \
   final_prescan_insn (INSN, OPVEC, NOPERANDS)
 
-\f
-/* Tell final.c how to eliminate redundant test instructions.
-   Here we define machine-dependent flags and fields in cc_status
-   (see `conditions.h').  */
-
-/* A list of names to be used for additional modes for condition code
-   values in registers.  These names are added to `enum machine_mode'
-   and all have class `MODE_CC'.  By convention, they should start
-   with `CC' and end with `mode'.
-
-   You should only define this macro if your machine does not use
-   `cc0' and only if additional modes are required.
-
-   On the MIPS, we use CC_FPmode for all floating point except for not
-   equal, CC_REV_FPmode for not equal (to reverse the sense of the
-   jump), CC_EQmode for integer equality/inequality comparisons,
-   CC_0mode for comparisons against 0, and CCmode for other integer
-   comparisons. */
-
-#define EXTRA_CC_MODES CC_EQmode, CC_FPmode, CC_0mode, CC_REV_FPmode
-
-/* A list of C strings giving the names for the modes listed in
-   `EXTRA_CC_MODES'.  */
-
-#define EXTRA_CC_NAMES "CC_EQ", "CC_FP", "CC_0", "CC_REV_FP"
-
-/* Returns a mode from class `MODE_CC' to be used when comparison
-   operation code OP is applied to rtx X.  */
-
-#define SELECT_CC_MODE(OP, X, Y)                                       \
-  (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT                         \
-       ? SImode                                                        \
-       : ((OP == NE) ? CC_REV_FPmode : CC_FPmode))
-
 \f
 /* Control the assembler format that we output.  */
 
@@ -3217,6 +3213,13 @@ while (0)
   &mips_reg_names[66][0],                                              \
   &mips_reg_names[67][0],                                              \
   &mips_reg_names[68][0],                                              \
+  &mips_reg_names[69][0],                                              \
+  &mips_reg_names[70][0],                                              \
+  &mips_reg_names[71][0],                                              \
+  &mips_reg_names[72][0],                                              \
+  &mips_reg_names[73][0],                                              \
+  &mips_reg_names[74][0],                                              \
+  &mips_reg_names[75][0],                                              \
 }
 
 /* print-rtl.c can't use REGISTER_NAMES, since it depends on mips.c.
@@ -3231,7 +3234,8 @@ while (0)
   "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",      \
   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",      \
   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",      \
-  "hi",   "lo",   "accum","$fcr31","$rap"                              \
+  "hi",   "lo",   "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",     \
+  "$fcc5","$fcc6","$fcc7","$rap"                                       \
 }
 
 /* If defined, a C initializer for an array of structures
@@ -3310,8 +3314,7 @@ while (0)
   { "fp",      30 + GP_REG_FIRST },                                    \
   { "ra",      31 + GP_REG_FIRST },                                    \
   { "$sp",     29 + GP_REG_FIRST },                                    \
-  { "$fp",     30 + GP_REG_FIRST },                                    \
-  { "cc",      FPSW_REGNUM },                                          \
+  { "$fp",     30 + GP_REG_FIRST }                                     \
 }
 
 /* Define results of standard character escape sequences.  */
index da9502ac5d0abda8186ef852614ede1cfc7b9026..4a61c4f23492b13bbd406b9d2dfbe69d56b4bec8 100644 (file)
@@ -3,7 +3,7 @@
 ;;  Changes by       Michael Meissner, meissner@osf.org
 ;;  64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
 ;;  Brendan Eich, brendan@microunity.com.
-;;  Copyright (C) 1989, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc.
+;;  Copyright (C) 1989, 90-5, 1996 Free Software Foundation, Inc.
 
 ;; This file is part of GNU CC.
 
 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
-;; ??? MIPS4 has 8 floating point condition codes.  This is not supported yet.
-
-;; ??? MIPS4 has floating point doubleword/word load/stores that accept a
-;; base+index addressing mode.  There are no such load/stores for the integer
-;; registers.  This is not supported yet.
-
 ;; ??? Currently does not have define_function_unit support for the R8000.
 ;; Must include new entries for fmadd in addition to existing entries.
 
@@ -93,7 +87,8 @@
 ;;          (const_string "default"))))
 
 ;; ??? Fix everything that tests this attribute.
-(define_attr "cpu" "default,r3000,r6000,r4000,r4100,r4300,r4600,r4650,r8000"
+(define_attr "cpu"
+  "default,r3000,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r8000"
   (const (symbol_ref "mips_cpu_attr")))
 
 ;; Attribute defining whether or not we can use the branch-likely instructions
 ;; Make the default case (PROCESSOR_DEFAULT) handle the worst case
 
 (define_function_unit "memory" 1 0
-  (and (eq_attr "type" "load") (eq_attr "cpu" "!r3000,r4600,r4650,r4100,r4300"))
+  (and (eq_attr "type" "load")
+       (eq_attr "cpu" "!r3000,r4600,r4650,r4100,r4300,r5000"))
   3 0)
 
 (define_function_unit "memory" 1 0
-  (and (eq_attr "type" "load") (eq_attr "cpu" "r3000,r4600,r4650,r4100,r4300"))
+  (and (eq_attr "type" "load")
+       (eq_attr "cpu" "r3000,r4600,r4650,r4100,r4300,r5000"))
   2 0)
 
 (define_function_unit "memory"   1 0 (eq_attr "type" "store") 1 0)
   1 3)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300"))
+  (and (eq_attr "type" "imul")
+       (eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300,r5000"))
   17 17)
 
 (define_function_unit "imuldiv"  1 0
   4 4)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "imul") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
+  (and (eq_attr "type" "imul")
+       (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
   1 1)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "imul") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
+  (and (eq_attr "type" "imul")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
   4 4)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "imul") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300")))
+  (and (eq_attr "type" "imul")
+       (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300,r5000")))
   5 5)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "imul") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
+  (and (eq_attr "type" "imul")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
   8 8)
 
 (define_function_unit "imuldiv"  1 0
-  (and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300"))
+  (and (eq_attr "type" "imul")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
+  9 9)
+
+(define_function_unit "imuldiv"  1 0
+  (and (eq_attr "type" "idiv")
+       (eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300,r5000"))
   38 38)
 
 (define_function_unit "imuldiv"  1 0
   69 69)
 
 (define_function_unit "imuldiv" 1 0
-  (and (eq_attr "type" "idiv") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
   35 35)
 
 (define_function_unit "imuldiv" 1 0
-  (and (eq_attr "type" "idiv") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
   67 67)
 
 (define_function_unit "imuldiv" 1 0
-  (and (eq_attr "type" "idiv") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300")))
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300")))
   37 37)
 
 (define_function_unit "imuldiv" 1 0
-  (and (eq_attr "type" "idiv") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
   69 69)
 
+(define_function_unit "imuldiv" 1 0
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5000")))
+  36 36)
+
+(define_function_unit "imuldiv" 1 0
+  (and (eq_attr "type" "idiv")
+       (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
+  68 68)
+
 ;; The R4300 does *NOT* have a seperate Floating Point Unit, instead
 ;; the FP hardware is part of the normal ALU circuitry.  This means FP
 ;; instructions affect the pipe-line, and no functional unit
 ;; instructions to be processed in the "imuldiv" unit.
 
 (define_function_unit "adder" 1 1
-  (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r6000,r4300"))
+  (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r6000,r4300,r5000"))
   3 0)
 
 (define_function_unit "adder" 1 1
   (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r6000"))
   2 0)
 
+(define_function_unit "adder" 1 1
+  (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r5000"))
+  1 0)
+
 (define_function_unit "adder" 1 1
   (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r6000,r4300"))
   4 0)
   3 0)
 
 (define_function_unit "adder" 1 1
-  (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000,r4600,r4650,r4300"))
+  (and (eq_attr "type" "fabs,fneg")
+       (eq_attr "cpu" "!r3000,r4600,r4650,r4300,r5000"))
   2 0)
 
 (define_function_unit "adder" 1 1
-  (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r4600,r4650"))
+  (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r4600,r4650,r5000"))
   1 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "SF")
+           (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300,r5000")))
   7 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000,r5000")))
   4 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
   5 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
   8 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4300")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4300,r5000")))
   8 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000,r5000")))
   5 0)
 
 (define_function_unit "mult" 1 1
-  (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
+  (and (eq_attr "type" "fmul")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
   6 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "SF")
+           (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300,r5000")))
   23 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
   12 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
   15 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
   32 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000")))
+  21 0)
+
+(define_function_unit "divide" 1 1
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "DF")
+           (eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300")))
   36 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
   19 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
   16 0)
 
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
+  (and (eq_attr "type" "fdiv")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
   61 0)
 
 ;;; ??? Is this number right?
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300")))
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
   54 0)
+
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
   31 0)
 
+(define_function_unit "divide" 1 1
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000")))
+  21 0)
+
 ;;; ??? Is this number right?
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300")))
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
   112 0)
+
 (define_function_unit "divide" 1 1
-  (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
   60 0)
 
+(define_function_unit "divide" 1 1
+  (and (eq_attr "type" "fsqrt")
+       (and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000")))
+  36 0)
+
 ;; R4300 FP instruction classes treated as part of the "imuldiv"
 ;; functional unit:
 
        (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
                          (match_operand:DF 2 "register_operand" "f"))
                 (match_operand:DF 3 "register_operand" "f")))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "madd.d\\t%0,%3,%1,%2"
   [(set_attr "type"    "fmadd")
    (set_attr "mode"    "DF")
        (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
                           (match_operand:DF 2 "register_operand" "f"))
                  (match_operand:DF 3 "register_operand" "f")))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "msub.d\\t%0,%3,%1,%2"
   [(set_attr "type"    "fmadd")
    (set_attr "mode"    "DF")
        (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
                                  (match_operand:DF 2 "register_operand" "f"))
                         (match_operand:DF 3 "register_operand" "f"))))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "nmadd.d\\t%0,%3,%1,%2"
   [(set_attr "type"    "fmadd")
    (set_attr "mode"    "DF")
        (minus:DF (match_operand:DF 1 "register_operand" "f")
                  (mult:DF (match_operand:DF 2 "register_operand" "f")
                           (match_operand:DF 3 "register_operand" "f"))))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "nmsub.d\\t%0,%1,%2,%3"
   [(set_attr "type"    "fmadd")
    (set_attr "mode"    "DF")
    (set_attr "mode"    "SF")
    (set_attr "length"  "1")])
 
+(define_insn ""
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (div:DF (match_operand:DF 1 "const_float_1_operand" "")
+               (match_operand:DF 2 "register_operand" "f")))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math"
+  "recip.d\\t%0,%2"
+  [(set_attr "type"    "fdiv")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+               (match_operand:SF 2 "register_operand" "f")))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && flag_fast_math"
+  "recip.s\\t%0,%2"
+  [(set_attr "type"    "fdiv")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
 ;; If optimizing, prefer the divmod functions over separate div and
 ;; mod functions, since this will allow using one instruction for both
 ;; the quotient and remainder.  At present, the divmod is not moved out
    (set_attr "mode"    "SF")
    (set_attr "length"  "1")])
 
+(define_insn ""
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (div:DF (match_operand:DF 1 "const_float_1_operand" "")
+               (sqrt:DF (match_operand:DF 2 "register_operand" "f"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math"
+  "rsqrt.d\\t%0,%2"
+  [(set_attr "type"    "fsqrt")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+               (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && flag_fast_math"
+  "rsqrt.s\\t%0,%2"
+  [(set_attr "type"    "fsqrt")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
 \f
 ;;
 ;;  ....................
@@ -3499,6 +3605,182 @@ move\\t%0,%z4\\n\\
   DONE;
 }")
 
+;; This insn handles moving CCmode values.  It's really just a
+;; slightly simplified copy of movsi_internal2, with additional cases
+;; to move a condition register to a general register and to move
+;; between the general registers and the floating point registers.
+
+(define_insn "movcc"
+  [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*d,*R,*m,*d,*f,*f,*f,*f,*R,*m")
+       (match_operand:CC 1 "general_operand" "z,*d,*R,*m,*d,*d,*f,*d,*f,*R,*m,*f,*f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "* return mips_move_1word (operands, insn, FALSE);"
+  [(set_attr "type"    "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store")
+   (set_attr "mode"    "SI")
+   (set_attr "length"  "2,1,1,2,1,2,1,1,1,1,2,1,2")])
+
+;; Reload condition code registers.  These need scratch registers.
+
+(define_expand "reload_incc"
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (match_operand:CC 1 "general_operand" "z"))
+   (clobber (match_operand:TF 2 "register_operand" "=&f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "
+{
+  rtx source;
+  rtx fp1, fp2;
+
+  /* This is called when are copying some value into a condition code
+     register.  Operand 0 is the condition code register.  Operand 1
+     is the source.  Operand 2 is a scratch register; we use TFmode
+     because we actually need two floating point registers.  */
+  if (! ST_REG_P (true_regnum (operands[0]))
+      || ! FP_REG_P (true_regnum (operands[2])))
+    abort ();
+
+  /* We need to get the source in SFmode so that the insn is
+     recognized.  */
+  if (GET_CODE (operands[1]) == MEM)
+    source = change_address (operands[1], SFmode, NULL_RTX);
+  else if (GET_CODE (operands[1]) == REG || GET_CODE (operands[1]) == SUBREG)
+    source = gen_rtx (REG, SFmode, true_regnum (operands[1]));
+  else
+    source = operands[1];
+
+  fp1 = gen_rtx (REG, SFmode, REGNO (operands[2]));
+  fp2 = gen_rtx (REG, SFmode, REGNO (operands[2]) + 1);
+
+  emit_insn (gen_move_insn (fp1, source));
+  emit_insn (gen_move_insn (fp2, gen_rtx (REG, SFmode, 0)));
+  emit_insn (gen_rtx (SET, VOIDmode, operands[0],
+                     gen_rtx (LT, CCmode, fp2, fp1)));
+
+  DONE;
+}")
+
+(define_expand "reload_outcc"
+  [(set (match_operand:CC 0 "general_operand" "=z")
+       (match_operand:CC 1 "register_operand" "z"))
+   (clobber (match_operand:CC 2 "register_operand" "=&d"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "
+{
+  /* This is called when we are copying a condition code register out
+     to save it somewhere.  Operand 0 should be the location we are
+     going to save it to.  Operand 1 should be the condition code
+     register.  Operand 2 should be a scratch general purpose register
+     created for us by reload.  The mips_secondary_reload_class
+     function should have told reload that we don't need a scratch
+     register if the destination is a general purpose register anyhow.  */
+  if (ST_REG_P (true_regnum (operands[0]))
+      || GP_REG_P (true_regnum (operands[0]))
+      || ! ST_REG_P (true_regnum (operands[1]))
+      || ! GP_REG_P (true_regnum (operands[2])))
+    abort ();
+
+  /* All we have to do is copy the value from the condition code to
+     the data register, which movcc can handle, and then store the
+     value into the real final destination.  */
+  emit_insn (gen_move_insn (operands[2], operands[1]));
+  emit_insn (gen_move_insn (operands[0], operands[2]));
+
+  DONE;
+}")
+
+;; MIPS4 supports loading and storing a floating point register from
+;; the sum of two general registers.  We use two versions for each of
+;; these four instructions: one where the two general registers are
+;; SImode, and one where they are DImode.  This is because general
+;; registers will be in SImode when they hold 32 bit values, but,
+;; since the 32 bit values are always sign extended, the [ls][wd]xc1
+;; instructions will still work correctly.
+
+;; ??? Perhaps it would be better to support these instructions by
+;; modifying GO_IF_LEGITIMATE_ADDRESS and friends.  However, since
+;; these instructions can only be used to load and store floating
+;; point registers, that would probably cause trouble in reload.
+
+(define_insn ""
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d")
+                        (match_operand:SI 2 "register_operand" "d"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "lwxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "load")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (mem:SF (plus:DI (match_operand:DI 1 "register_operand" "d")
+                        (match_operand:DI 2 "register_operand" "d"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "lwxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "load")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d")
+                        (match_operand:SI 2 "register_operand" "d"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
+  "ldxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "load")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (mem:DF (plus:DI (match_operand:DI 1 "register_operand" "d")
+                        (match_operand:DI 2 "register_operand" "d"))))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
+  "ldxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "load")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d")
+                        (match_operand:SI 2 "register_operand" "d")))
+       (match_operand:SF 0 "register_operand" "=f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "swxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "store")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (mem:SF (plus:DI (match_operand:DI 1 "register_operand" "d")
+                        (match_operand:DI 2 "register_operand" "d")))
+       (match_operand:SF 0 "register_operand" "=f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "swxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "store")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d")
+                        (match_operand:SI 2 "register_operand" "d")))
+       (match_operand:DF 0 "register_operand" "=f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
+  "sdxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "store")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
+(define_insn ""
+  [(set (mem:DF (plus:DI (match_operand:DI 1 "register_operand" "d")
+                        (match_operand:DI 2 "register_operand" "d")))
+       (match_operand:DF 0 "register_operand" "=f"))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
+  "sdxc1\\t%0,%1(%2)"
+  [(set_attr "type"    "store")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "1")])
+
 ;; 16-bit Integer moves
 
 ;; Unlike most other insns, the move insns can't be split with
@@ -4625,8 +4907,8 @@ move\\t%0,%z4\\n\\
 
 (define_expand "cmpdf"
   [(set (cc0)
-       (compare:CC_FP (match_operand:DF 0 "register_operand" "")
-                      (match_operand:DF 1 "register_operand" "")))]
+       (compare:CC (match_operand:DF 0 "register_operand" "")
+                   (match_operand:DF 1 "register_operand" "")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "
 {
@@ -4641,8 +4923,8 @@ move\\t%0,%z4\\n\\
 
 (define_expand "cmpsf"
   [(set (cc0)
-       (compare:CC_FP (match_operand:SF 0 "register_operand" "")
-                      (match_operand:SF 1 "register_operand" "")))]
+       (compare:CC (match_operand:SF 0 "register_operand" "")
+                   (match_operand:SF 1 "register_operand" "")))]
   "TARGET_HARD_FLOAT"
   "
 {
@@ -4665,31 +4947,15 @@ move\\t%0,%z4\\n\\
 
 (define_insn "branch_fp_ne"
   [(set (pc)
-       (if_then_else (ne:CC_FP (reg:CC_FP 67)
-                               (const_int 0))
-                     (match_operand 0 "pc_or_label_operand" "")
-                     (match_operand 1 "pc_or_label_operand" "")))]
-  "TARGET_HARD_FLOAT"
-  "*
-{
-  mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
-  return (operands[0] != pc_rtx) ? \"%*bc1t%?\\t%0\" : \"%*bc1f%?\\t%1\";
-}"
-  [(set_attr "type"    "branch")
-   (set_attr "mode"    "none")
-   (set_attr "length"  "1")])
-
-(define_insn "branch_fp_ne_rev"
-  [(set (pc)
-       (if_then_else (ne:CC_REV_FP (reg:CC_REV_FP 67)
-                                   (const_int 0))
-                     (match_operand 0 "pc_or_label_operand" "")
-                     (match_operand 1 "pc_or_label_operand" "")))]
+       (if_then_else (ne:CC (match_operand:CC 0 "register_operand" "z")
+                            (const_int 0))
+                     (match_operand 1 "pc_or_label_operand" "")
+                     (match_operand 2 "pc_or_label_operand" "")))]
   "TARGET_HARD_FLOAT"
   "*
 {
   mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
-  return (operands[0] != pc_rtx) ? \"%*bc1f%?\\t%0\" : \"%*bc1t%?\\t%1\";
+  return (operands[1] != pc_rtx) ? \"%*bc1t%?\\t%Z0%1\" : \"%*bc1f%?\\t%Z0%2\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")
@@ -4697,37 +4963,20 @@ move\\t%0,%z4\\n\\
 
 (define_insn "branch_fp_eq"
   [(set (pc)
-       (if_then_else (eq:CC_FP (reg:CC_FP 67)
-                               (const_int 0))
-                     (match_operand 0 "pc_or_label_operand" "")
-                     (match_operand 1 "pc_or_label_operand" "")))]
-  "TARGET_HARD_FLOAT"
-  "*
-{
-  mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
-  return (operands[0] != pc_rtx) ? \"%*bc1f%?\\t%0\" : \"%*bc1t%?\\t%1\";
-}"
-  [(set_attr "type"    "branch")
-   (set_attr "mode"    "none")
-   (set_attr "length"  "1")])
-
-(define_insn "branch_fp_eq_rev"
-  [(set (pc)
-       (if_then_else (eq:CC_REV_FP (reg:CC_REV_FP 67)
-                                   (const_int 0))
-                     (match_operand 0 "pc_or_label_operand" "")
-                     (match_operand 1 "pc_or_label_operand" "")))]
+       (if_then_else (eq:CC (match_operand:CC 0 "register_operand" "z")
+                            (const_int 0))
+                     (match_operand 1 "pc_or_label_operand" "")
+                     (match_operand 2 "pc_or_label_operand" "")))]
   "TARGET_HARD_FLOAT"
   "*
 {
   mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
-  return (operands[0] != pc_rtx) ? \"%*bc1t%?\\t%0\" : \"%*bc1f%?\\t%1\";
+  return (operands[1] != pc_rtx) ? \"%*bc1f%?\\t%Z0%1\" : \"%*bc1t%?\\t%Z0%2\";
 }"
   [(set_attr "type"    "branch")
    (set_attr "mode"    "none")
    (set_attr "length"  "1")])
 
-
 (define_insn "branch_zero"
   [(set (pc)
        (if_then_else (match_operator:SI 0 "cmp_op"
@@ -4860,8 +5109,8 @@ move\\t%0,%z4\\n\\
 
 (define_expand "beq"
   [(set (pc)
-       (if_then_else (eq:CC_EQ (cc0)
-                               (const_int 0))
+       (if_then_else (eq:CC (cc0)
+                            (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
   ""
@@ -4876,8 +5125,8 @@ move\\t%0,%z4\\n\\
 
 (define_expand "bne"
   [(set (pc)
-       (if_then_else (ne:CC_EQ (cc0)
-                               (const_int 0))
+       (if_then_else (ne:CC (cc0)
+                            (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
   ""
@@ -5749,216 +5998,130 @@ move\\t%0,%z4\\n\\
 ;;  ....................
 
 (define_insn "seq_df"
-  [(set (reg:CC_FP 67)
-       (eq:CC_FP (match_operand:DF 0 "register_operand" "f")
-                 (match_operand:DF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (eq:CC (match_operand:DF 1 "register_operand" "f")
+              (match_operand:DF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.eq.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
-}"
- [(set_attr "type"     "fcmp")
-  (set_attr "mode"     "FPSW")
-  (set_attr "length"   "1")])
-
-(define_insn "sne_df"
-  [(set (reg:CC_REV_FP 67)
-       (ne:CC_REV_FP (match_operand:DF 0 "register_operand" "f")
-                     (match_operand:DF 1 "register_operand" "f")))]
-  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.eq.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.eq.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "slt_df"
-  [(set (reg:CC_FP 67)
-       (lt:CC_FP (match_operand:DF 0 "register_operand" "f")
-                 (match_operand:DF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (lt:CC (match_operand:DF 1 "register_operand" "f")
+              (match_operand:DF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.lt.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.lt.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sle_df"
-  [(set (reg:CC_FP 67)
-       (le:CC_FP (match_operand:DF 0 "register_operand" "f")
-                 (match_operand:DF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (le:CC (match_operand:DF 1 "register_operand" "f")
+              (match_operand:DF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.le.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.le.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sgt_df"
-  [(set (reg:CC_FP 67)
-       (gt:CC_FP (match_operand:DF 0 "register_operand" "f")
-                 (match_operand:DF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (gt:CC (match_operand:DF 1 "register_operand" "f")
+              (match_operand:DF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.lt.d\\t%1,%0\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.lt.d\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sge_df"
-  [(set (reg:CC_FP 67)
-       (ge:CC_FP (match_operand:DF 0 "register_operand" "f")
-                 (match_operand:DF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (ge:CC (match_operand:DF 1 "register_operand" "f")
+              (match_operand:DF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.le.d\\t%1,%0\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.le.d\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "seq_sf"
-  [(set (reg:CC_FP 67)
-       (eq:CC_FP (match_operand:SF 0 "register_operand" "f")
-                 (match_operand:SF 1 "register_operand" "f")))]
-  "TARGET_HARD_FLOAT"
-  "*
-{
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.eq.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
-}"
- [(set_attr "type"     "fcmp")
-  (set_attr "mode"     "FPSW")
-  (set_attr "length"   "1")])
-
-(define_insn "sne_sf"
-  [(set (reg:CC_REV_FP 67)
-       (ne:CC_REV_FP (match_operand:SF 0 "register_operand" "f")
-                     (match_operand:SF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (eq:CC (match_operand:SF 1 "register_operand" "f")
+              (match_operand:SF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.eq.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.eq.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "slt_sf"
-  [(set (reg:CC_FP 67)
-       (lt:CC_FP (match_operand:SF 0 "register_operand" "f")
-                 (match_operand:SF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (lt:CC (match_operand:SF 1 "register_operand" "f")
+              (match_operand:SF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.lt.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.lt.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sle_sf"
-  [(set (reg:CC_FP 67)
-       (le:CC_FP (match_operand:SF 0 "register_operand" "f")
-                 (match_operand:SF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (le:CC (match_operand:SF 1 "register_operand" "f")
+              (match_operand:SF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.le.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.le.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sgt_sf"
-  [(set (reg:CC_FP 67)
-       (gt:CC_FP (match_operand:SF 0 "register_operand" "f")
-                 (match_operand:SF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (gt:CC (match_operand:SF 1 "register_operand" "f")
+              (match_operand:SF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.lt.s\\t%1,%0\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.lt.s\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
   (set_attr "length"   "1")])
 
 (define_insn "sge_sf"
-  [(set (reg:CC_FP 67)
-       (ge:CC_FP (match_operand:SF 0 "register_operand" "f")
-                 (match_operand:SF 1 "register_operand" "f")))]
+  [(set (match_operand:CC 0 "register_operand" "=z")
+       (ge:CC (match_operand:SF 1 "register_operand" "f")
+              (match_operand:SF 2 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
   "*
 {
-  rtx xoperands[10];
-  xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-  xoperands[1] = operands[0];
-  xoperands[2] = operands[1];
-
-  return mips_fill_delay_slot (\"c.le.s\\t%1,%0\", DELAY_FCMP, xoperands, insn);
+  return mips_fill_delay_slot (\"c.le.s\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
 }"
  [(set_attr "type"     "fcmp")
   (set_attr "mode"     "FPSW")
@@ -6769,13 +6932,16 @@ move\\t%0,%z4\\n\\
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=d,d")
        (if_then_else:SI
-        (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)])
+        (match_operator 3 "equality_op" [(match_operand:CC 4
+                                                           "register_operand"
+                                                           "z,z")
+                                         (const_int 0)])
         (match_operand:SI 1 "reg_or_0_operand" "dJ,0")
         (match_operand:SI 2 "reg_or_0_operand" "0,dJ")))]
-  "mips_isa >= 4"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
   "@
-    mov%T3\\t%0,%z1,$fcc0
-    mov%t3\\t%0,%z2,$fcc0"
+    mov%T3\\t%0,%z1,%4
+    mov%t3\\t%0,%z2,%4"
   [(set_attr "type" "move")
    (set_attr "mode" "SI")])
 
@@ -6812,13 +6978,16 @@ move\\t%0,%z4\\n\\
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=d,d")
        (if_then_else:DI
-        (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)])
+        (match_operator 3 "equality_op" [(match_operand:CC 4
+                                                           "register_operand"
+                                                           "z,z")
+                                         (const_int 0)])
         (match_operand:DI 1 "reg_or_0_operand" "dJ,0")
         (match_operand:DI 2 "reg_or_0_operand" "0,dJ")))]
-  "mips_isa >= 4"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
   "@
-    mov%T3\\t%0,%z1,$fcc0
-    mov%t3\\t%0,%z2,$fcc0"
+    mov%T3\\t%0,%z1,%4
+    mov%t3\\t%0,%z2,%4"
   [(set_attr "type" "move")
    (set_attr "mode" "DI")])
 
@@ -6840,13 +7009,16 @@ move\\t%0,%z4\\n\\
 (define_insn ""
   [(set (match_operand:SF 0 "register_operand" "=f,f")
        (if_then_else:SF
-        (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)])
+        (match_operator 3 "equality_op" [(match_operand:CC 4
+                                                           "register_operand"
+                                                           "z,z")
+                                         (const_int 0)])
         (match_operand:SF 1 "register_operand" "f,0")
         (match_operand:SF 2 "register_operand" "0,f")))]
   "mips_isa >= 4 && TARGET_HARD_FLOAT"
   "@
-    mov%T3.s\\t%0,%1,$fcc0
-    mov%t3.s\\t%0,%2,$fcc0"
+    mov%T3.s\\t%0,%1,%4
+    mov%t3.s\\t%0,%2,%4"
   [(set_attr "type" "move")
    (set_attr "mode" "SF")])
 
@@ -6858,7 +7030,7 @@ move\\t%0,%z4\\n\\
                          (const_int 0)])
         (match_operand:DF 2 "register_operand" "f,0")
         (match_operand:DF 3 "register_operand" "0,f")))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "@
     mov%B4.d\\t%0,%2,%1
     mov%b4.d\\t%0,%3,%1"
@@ -6868,13 +7040,16 @@ move\\t%0,%z4\\n\\
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f,f")
        (if_then_else:DF
-        (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)])
+        (match_operator 3 "equality_op" [(match_operand:CC 4
+                                                           "register_operand"
+                                                           "z,z")
+                                         (const_int 0)])
         (match_operand:DF 1 "register_operand" "f,0")
         (match_operand:DF 2 "register_operand" "0,f")))]
-  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
   "@
-    mov%T3.d\\t%0,%1,$fcc0
-    mov%t3.d\\t%0,%2,$fcc0"
+    mov%T3.d\\t%0,%1,%4
+    mov%t3.d\\t%0,%2,%4"
   [(set_attr "type" "move")
    (set_attr "mode" "DF")])
 
@@ -6889,85 +7064,45 @@ move\\t%0,%z4\\n\\
   "mips_isa >= 4"
   "
 {
-  rtx op0 = branch_cmp[0];
-  rtx op1 = branch_cmp[1];
-  enum machine_mode mode = GET_MODE (branch_cmp[0]);
-  enum rtx_code compare_code = GET_CODE (operands[1]);
-  enum rtx_code move_code = NE;
+  gen_conditional_move (operands);
+  DONE;
+}")
 
-  if (GET_MODE_CLASS (mode) != MODE_FLOAT)
-    {
-      switch (compare_code)
-       {
-       case EQ:
-         compare_code = XOR;
-         move_code = EQ;
-         break;
-       case NE:
-         compare_code = XOR;
-         break;
-       case LT:
-         break;
-       case GE:
-         compare_code = LT;
-         move_code = EQ;
-         break;
-       case GT:
-         compare_code = LT;
-         op0 = force_reg (mode, branch_cmp[1]);
-         op1 = branch_cmp[0];
-         break;
-       case LE:
-         compare_code = LT;
-         op0 = force_reg (mode, branch_cmp[1]);
-         op1 = branch_cmp[0];
-         move_code = EQ;
-         break;
-       case LTU:
-         break;
-       case GEU:
-         compare_code = LTU;
-         move_code = EQ;
-         break;
-       case GTU:
-         compare_code = LTU;
-         op0 = force_reg (mode, branch_cmp[1]);
-         op1 = branch_cmp[0];
-         break;
-       case LEU:
-         compare_code = LTU;
-         op0 = force_reg (mode, branch_cmp[1]);
-         op1 = branch_cmp[0];
-         move_code = EQ;
-         break;
-       default:
-         abort ();
-       }
-    }
-  else
-    {
-      if (compare_code == NE)
-       {
-         /* ??? Perhaps we need to use CC_FP_REVmode here?  */
-         compare_code = EQ;
-         move_code = EQ;
-       }
-    }
-         
-  if (mode == SImode || mode == DImode)
-    {
-      operands[1] = gen_rtx (compare_code, mode, op0, op1);
-      operands[4] = gen_reg_rtx (mode);
-    }
-  else if (mode == SFmode || mode == DFmode)
-    {
-      operands[1] = gen_rtx (compare_code, CC_FPmode, op0, op1);
-      operands[4] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
-    }
+(define_expand "movdicc"
+  [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
+   (set (match_operand:DI 0 "register_operand" "")
+       (if_then_else:DI (match_dup 5)
+                        (match_operand:DI 2 "reg_or_0_operand" "")
+                        (match_operand:DI 3 "reg_or_0_operand" "")))]
+  "mips_isa >= 4"
+  "
+{
+  gen_conditional_move (operands);
+  DONE;
+}")
 
-  operands[5] = gen_rtx (move_code, VOIDmode, operands[4],
-                        CONST0_RTX (SImode));
+(define_expand "movsfcc"
+  [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
+   (set (match_operand:SF 0 "register_operand" "")
+       (if_then_else:SF (match_dup 5)
+                        (match_operand:SF 2 "reg_or_0_operand" "")
+                        (match_operand:SF 3 "reg_or_0_operand" "")))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT"
+  "
+{
+  gen_conditional_move (operands);
+  DONE;
 }")
 
-;; ??? Need movdicc, movsfcc, and movdfcc patterns.  They should be
-;; very similar to the above movsicc pattern.
+(define_expand "movdfcc"
+  [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
+   (set (match_operand:DF 0 "register_operand" "")
+       (if_then_else:DF (match_dup 5)
+                        (match_operand:DF 2 "reg_or_0_operand" "")
+                        (match_operand:DF 3 "reg_or_0_operand" "")))]
+  "mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
+  "
+{
+  gen_conditional_move (operands);
+  DONE;
+}")