mips-protos.h (mips_subword, [...]): Declare.
authorRichard Sandiford <rsandifo@redhat.com>
Tue, 6 May 2003 11:23:42 +0000 (11:23 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Tue, 6 May 2003 11:23:42 +0000 (11:23 +0000)
* config/mips/mips-protos.h (mips_subword, mips_output_move): Declare.
(mips_move_1word, mips_move_2words): Remove declaration.
(mips_split_64bit_move_p, mips_split_64bit_move): Declare.
(mips_restore_gp): Remove insn argument.
* config/mips/mips.h (FP_REG_RTX_P): New macro.
* config/mips/mips.c (volatile_buffer): Remove.
(mips_subword, mips_split_64bit_move_p, mips_split_64bit_move): New.
(mips_move_1word, mips_move_2words): Remove, replacing with...
(mips_output_move): ...this new function.
(mips_restore_gp): Remove insn argument.  Adjust for above changes.
(print_operand): Make '%h' print %hi(op) for HIGH operands.  Remove
handling of floating-point constants.  Handle zero CONST_DOUBLE
arguments.
(mips_annotate_frame_insn): Replace with...
(mips_set_frame_expr): ...this, which just takes one argument.
(mips_frame_set): Change the register argument to an rtx.
(mips_emit_frame_related_store): Use mips_split_64bit_move_p to
check whether moves should be split.  Use mips_split_64bit_move
to split them.  Use mips_subword to generate the high and low
parts of a paired FPR.  Adjust calls to frame_set and
mips_set_frame_expr.
(mips_expand_prologue): Simplify due to above changes.
* config/mips/mips.md: Add splitters for 64-bit moves on 32-bit
targets, replacing xisting register-only versions.
(UNSPEC_STORE_DF_HIGH): New unspec.
(UNSPEC_LOAD_DF_LOW, UNSPEC_LOAD_DF_HIGH): New unspecs.
(mulsi3_r4000, muldi3_internal2): Avoid use of mips_move_1word.
(*paradoxical_extendhidi2): Remove.
(movdi_internal, movdi_internal2): Use mips_output_move.
(*movdi_internal2_mips16, movsi_internal, movcc): Likewise.
(movsf_internal1, movsf_internal2): Likewise.
(movdf_internal1a): Likewise.  Fix length and type of f <- G case.
(movdf_internal1b): Use mips_output_move.  Fix type of f <- G case.
(movdf_internal2): Use mips_output_move.  Fix lengths of FPR moves.
Add m <- G alternative.
(load_df_low, load_df_high, store_df_low): New patterns.
(movhi_internal): Use @ template instead of calling a function.
Remove unnecessary 'z' alternatives.
(movqi_internal): Likewise.
(exception_receiver): Update call to mips_restore_gp.

From-SVN: r66521

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

index 6af29241e297db16805fa45d890e3e8923192046..70bdd48f249b6d3e55dffbbc898ec230f7d2a40b 100644 (file)
@@ -1,3 +1,46 @@
+2003-05-06  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips-protos.h (mips_subword, mips_output_move): Declare.
+       (mips_move_1word, mips_move_2words): Remove declaration.
+       (mips_split_64bit_move_p, mips_split_64bit_move): Declare.
+       (mips_restore_gp): Remove insn argument.
+       * config/mips/mips.h (FP_REG_RTX_P): New macro.
+       * config/mips/mips.c (volatile_buffer): Remove.
+       (mips_subword, mips_split_64bit_move_p, mips_split_64bit_move): New.
+       (mips_move_1word, mips_move_2words): Remove, replacing with...
+       (mips_output_move): ...this new function.
+       (mips_restore_gp): Remove insn argument.  Adjust for above changes.
+       (print_operand): Make '%h' print %hi(op) for HIGH operands.  Remove
+       handling of floating-point constants.  Handle zero CONST_DOUBLE
+       arguments.
+       (mips_annotate_frame_insn): Replace with...
+       (mips_set_frame_expr): ...this, which just takes one argument.
+       (mips_frame_set): Change the register argument to an rtx.
+       (mips_emit_frame_related_store): Use mips_split_64bit_move_p to
+       check whether moves should be split.  Use mips_split_64bit_move
+       to split them.  Use mips_subword to generate the high and low
+       parts of a paired FPR.  Adjust calls to frame_set and
+       mips_set_frame_expr.
+       (mips_expand_prologue): Simplify due to above changes.
+       * config/mips/mips.md:  Add splitters for 64-bit moves on 32-bit
+       targets, replacing xisting register-only versions.
+       (UNSPEC_STORE_DF_HIGH): New unspec.
+       (UNSPEC_LOAD_DF_LOW, UNSPEC_LOAD_DF_HIGH): New unspecs.
+       (mulsi3_r4000, muldi3_internal2): Avoid use of mips_move_1word.
+       (*paradoxical_extendhidi2): Remove.
+       (movdi_internal, movdi_internal2): Use mips_output_move.
+       (*movdi_internal2_mips16, movsi_internal, movcc): Likewise.
+       (movsf_internal1, movsf_internal2): Likewise.
+       (movdf_internal1a): Likewise.  Fix length and type of f <- G case.
+       (movdf_internal1b): Use mips_output_move.  Fix type of f <- G case.
+       (movdf_internal2): Use mips_output_move.  Fix lengths of FPR moves.
+       Add m <- G alternative.
+       (load_df_low, load_df_high, store_df_low): New patterns.
+       (movhi_internal): Use @ template instead of calling a function.
+       Remove unnecessary 'z' alternatives.
+       (movqi_internal): Likewise.
+       (exception_receiver): Update call to mips_restore_gp.
+
 2003-05-06  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips-protos.h (mips_simplify_dwarf_addr): Remove.
index 140e60b01964003b58435f3e9114e3e005682792..9e2c156eb05e286e71cd15ce813c9f745bd98190 100644 (file)
@@ -100,10 +100,12 @@ extern HOST_WIDE_INT      mips_debugger_offset PARAMS ((rtx, HOST_WIDE_INT));
 extern const char      *mips_fill_delay_slot PARAMS ((const char *,
                                                      enum delay_type, rtx *,
                                                      rtx));
-extern const char      *mips_move_1word PARAMS ((rtx *, rtx, int));
-extern const char      *mips_move_2words PARAMS ((rtx *, rtx));
+extern rtx             mips_subword PARAMS ((rtx, int));
+extern bool            mips_split_64bit_move_p PARAMS ((rtx, rtx));
+extern void            mips_split_64bit_move PARAMS ((rtx, rtx));
+extern const char      *mips_output_move PARAMS ((rtx, rtx));
 extern const char      *mips_emit_prefetch PARAMS ((rtx *));
-extern const char      *mips_restore_gp PARAMS ((rtx *, rtx));
+extern const char      *mips_restore_gp PARAMS ((rtx *));
 extern const char      *output_block_move PARAMS ((rtx, rtx *, int,
                                                   enum block_move_type));
 extern void            override_options PARAMS ((void));
index 754a69dcbd4ae477a2a0653029092a12cf646c91..caebfbbf6ea5e4b66d6da527c592c2390c502806 100644 (file)
@@ -233,9 +233,8 @@ static void mips_arg_info           PARAMS ((const CUMULATIVE_ARGS *,
 static bool mips_get_unaligned_mem             PARAMS ((rtx *, unsigned int,
                                                         int, rtx *, rtx *));
 static rtx mips_add_large_offset_to_sp         PARAMS ((HOST_WIDE_INT));
-static void mips_annotate_frame_insn           PARAMS ((rtx, rtx));
-static rtx mips_frame_set                      PARAMS ((enum machine_mode,
-                                                        int, int));
+static void mips_set_frame_expr                        PARAMS ((rtx));
+static rtx mips_frame_set                      PARAMS ((rtx, int));
 static void mips_emit_frame_related_store      PARAMS ((rtx, rtx,
                                                         HOST_WIDE_INT));
 static void save_restore_insns                 PARAMS ((int, rtx, long));
@@ -593,10 +592,6 @@ char mips_print_operand_punct[256];
 /* Map GCC register number to debugger register number.  */
 int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
 
-/* Buffer to use to enclose a load/store operation with %{ %} to
-   turn on .set volatile.  */
-static char volatile_buffer[60];
-
 /* An alias set for the GOT.  */
 static int mips_got_alias_set;
 
@@ -1324,7 +1319,7 @@ mips_const_insns (x)
 
        case CONSTANT_RELOC:
          /* When generating mips16 code, we need to set the destination to
-            $0 and then add in the signed offset.  See mips_move_1word.  */
+            $0 and then add in the signed offset.  See mips_output_move.  */
          return (TARGET_MIPS16 ? 3 : 1);
 
        case CONSTANT_SYMBOLIC:
@@ -2962,391 +2957,252 @@ embedded_pic_offset (x)
                   gen_rtx_MINUS (Pmode, x,
                                  XEXP (DECL_RTL (current_function_decl), 0)));
 }
+\f
+/* Return one word of double-word value OP, taking into account the fixed
+   endianness of certain registers.  HIGH_P is true to select the high part,
+   false to select the low part.  */
 
-/* Return the appropriate instructions to move one operand to another.  */
+rtx
+mips_subword (op, high_p)
+     rtx op;
+     int high_p;
+{
+  unsigned int byte;
+  enum machine_mode mode;
 
-const char *
-mips_move_1word (operands, insn, unsignedp)
-     rtx operands[];
-     rtx insn;
-     int unsignedp;
-{
-  const char *ret = 0;
-  rtx op0 = operands[0];
-  rtx op1 = operands[1];
-  enum rtx_code code0 = GET_CODE (op0);
-  enum rtx_code code1 = GET_CODE (op1);
-  enum machine_mode mode = GET_MODE (op0);
-  int subreg_offset0 = 0;
-  int subreg_offset1 = 0;
-  enum delay_type delay = DELAY_NONE;
-  struct mips_constant_info c;
+  mode = GET_MODE (op);
+  if (mode == VOIDmode)
+    mode = DImode;
 
-  while (code0 == SUBREG)
-    {
-      subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
-                                            GET_MODE (SUBREG_REG (op0)),
-                                            SUBREG_BYTE (op0),
-                                            GET_MODE (op0));
-      op0 = SUBREG_REG (op0);
-      code0 = GET_CODE (op0);
-    }
+  if (TARGET_BIG_ENDIAN ? !high_p : high_p)
+    byte = UNITS_PER_WORD;
+  else
+    byte = 0;
 
-  while (code1 == SUBREG)
+  if (GET_CODE (op) == REG)
     {
-      subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
-                                            GET_MODE (SUBREG_REG (op1)),
-                                            SUBREG_BYTE (op1),
-                                            GET_MODE (op1));
-      op1 = SUBREG_REG (op1);
-      code1 = GET_CODE (op1);
+      if (FP_REG_P (REGNO (op)))
+       return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
+      if (REGNO (op) == HI_REGNUM)
+       return gen_rtx_REG (word_mode, high_p ? HI_REGNUM : LO_REGNUM);
     }
 
-  /* 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_offset0;
-
-      if (code1 == REG)
-       {
-         int regno1 = REGNO (op1) + subreg_offset1;
-
-         /* Just in case, don't do anything for assigning a register
-            to itself, unless we are filling a delay slot.  */
-         if (regno0 == regno1 && set_nomacro == 0)
-           ret = "";
-
-         else if (GP_REG_P (regno0))
-           {
-             if (GP_REG_P (regno1))
-               ret = "move\t%0,%1";
-
-             else if (MD_REG_P (regno1))
-               {
-                 delay = DELAY_HILO;
-                 if (regno1 != HILO_REGNUM)
-                   ret = "mf%1\t%0";
-                 else
-                   ret = "mflo\t%0";
-               }
-
-             else if (ST_REG_P (regno1) && ISA_HAS_8CC)
-               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 (ALL_COP_REG_P (regno1))
-                   {
-                     static char retval[] = "mfc_\t%0,%1";
+  if (GET_CODE (op) == MEM)
+    return adjust_address (op, word_mode, byte);
 
-                     retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
-                     ret = retval;
-                   }
-                 else if (regno1 == FPSW_REGNUM && ! ISA_HAS_8CC)
-                   ret = "cfc1\t%0,$31";
-               }
-           }
+  return simplify_gen_subreg (word_mode, op, mode, byte);
+}
 
-         else if (FP_REG_P (regno0))
-           {
-             if (GP_REG_P (regno1))
-               {
-                 delay = DELAY_LOAD;
-                 ret = "mtc1\t%1,%0";
-               }
 
-             if (FP_REG_P (regno1))
-               ret = "mov.s\t%0,%1";
-           }
+/* Return true if a 64-bit move from SRC to DEST should be split into two.  */
 
-         else if (MD_REG_P (regno0))
-           {
-             if (GP_REG_P (regno1))
-               {
-                 delay = DELAY_HILO;
-                 if (regno0 != HILO_REGNUM && ! TARGET_MIPS16)
-                   ret = "mt%0\t%1";
-               }
-           }
+bool
+mips_split_64bit_move_p (dest, src)
+     rtx dest, src;
+{
+  if (TARGET_64BIT)
+    return false;
 
-         else if (regno0 == FPSW_REGNUM && ! ISA_HAS_8CC)
-           {
-             if (GP_REG_P (regno1))
-               {
-                 delay = DELAY_LOAD;
-                 ret = "ctc1\t%0,$31";
-               }
-           }
-         else if (ALL_COP_REG_P (regno0))
-           {
-             if (GP_REG_P (regno1))
-               {
-                 static char retval[] = "mtc_\t%1,%0";
-                 char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
-                 if (cop == '0')
-                   abort_with_insn (insn,
-                                    "mtc0 not supported; it disturbs virtual address translation");
-                 delay = DELAY_LOAD;
-                 retval[3] = cop;
-                 ret = retval;
-               }
-           }
-       }
+  /* FP->FP moves can be done in a single instruction.  */
+  if (FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
+    return false;
 
-      else if (code1 == MEM)
-       {
-         delay = DELAY_LOAD;
+  /* Check for floating-point loads and stores.  They can be done using
+     ldc1 and sdc1 on MIPS II and above.  */
+  if (mips_isa > 1)
+    {
+      if (FP_REG_RTX_P (dest) && GET_CODE (src) == MEM)
+       return false;
+      if (FP_REG_RTX_P (src) && GET_CODE (dest) == MEM)
+       return false;
+    }
+  return true;
+}
 
-         if (TARGET_STATS)
-           mips_count_memory_refs (op1, 1);
 
-         if (GP_REG_P (regno0))
-           {
-             /* For loads, use the mode of the memory item, instead of the
-                target, so zero/sign extend can use this code as well.  */
-             switch (GET_MODE (op1))
-               {
-               default:
-                 break;
-               case SFmode:
-                 ret = "lw\t%0,%1";
-                 break;
-               case SImode:
-               case CCmode:
-                 ret = ((unsignedp && TARGET_64BIT)
-                        ? "lwu\t%0,%1"
-                        : "lw\t%0,%1");
-                 break;
-               case HImode:
-                 ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1";
-                 break;
-               case QImode:
-                 ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1";
-                 break;
-               }
-           }
+/* Split a 64-bit move from SRC to DEST assuming that
+   mips_split_64bit_move_p holds.
 
-         else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
-           ret = "lwc1\t%0,%1";
+   Moves into and out of FPRs cause some difficulty here.  Such moves
+   will always be DFmode, since paired FPRs are not allowed to store
+   DImode values.  The most natural representation would be two separate
+   32-bit moves, such as:
 
-         else if (ALL_COP_REG_P (regno0))
-           {
-             static char retval[] = "lwc_\t%0,%1";
-             char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
-             if (cop == '0')
-               abort_with_insn (insn,
-                                "loads from memory to COP0 are illegal");
-             delay = DELAY_LOAD;
-             retval[3] = cop;
-             ret = retval;
-           }
+       (set (reg:SI $f0) (mem:SI ...))
+       (set (reg:SI $f1) (mem:SI ...))
 
-         if (ret != (char *)0 && MEM_VOLATILE_P (op1))
-           {
-             size_t i = strlen (ret);
-             if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
-               abort ();
+   However, the second insn is invalid because odd-numbered FPRs are
+   not allowed to store independent values.  Use the patterns load_df_low,
+   load_df_high and store_df_high instead.  */
 
-             sprintf (volatile_buffer, "%%{%s%%}", ret);
-             ret = volatile_buffer;
-           }
-       }
+void
+mips_split_64bit_move (dest, src)
+     rtx dest, src;
+{
+  if (FP_REG_RTX_P (dest))
+    {
+      /* Loading an FPR from memory or from GPRs.  */
+      emit_insn (gen_load_df_low (copy_rtx (dest), mips_subword (src, 0)));
+      emit_insn (gen_load_df_high (dest, mips_subword (src, 1),
+                                  copy_rtx (dest)));
+    }
+  else if (FP_REG_RTX_P (src))
+    {
+      /* Storing an FPR into memory or GPRs.  */
+      emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+      emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
+    }
+  else
+    {
+      /* The operation can be split into two normal moves.  Decide in
+        which order to do them.  */
+      rtx low_dest;
 
-      else if (code1 == CONST_INT
-              || (code1 == CONST_DOUBLE
-                  && GET_MODE (op1) == VOIDmode))
+      low_dest = mips_subword (dest, 0);
+      if (GET_CODE (low_dest) == REG
+         && reg_overlap_mentioned_p (low_dest, src))
        {
-         if (code1 == CONST_DOUBLE)
-           {
-             /* This can happen when storing constants into long long
-                 bitfields.  Just store the least significant word of
-                 the value.  */
-             operands[1] = op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
-           }
-
-         if (INTVAL (op1) == 0 && ! TARGET_MIPS16)
-           {
-             if (GP_REG_P (regno0))
-               ret = "move\t%0,%z1";
-
-             else if (FP_REG_P (regno0))
-               {
-                 delay = DELAY_LOAD;
-                 ret = "mtc1\t%z1,%0";
-               }
-
-             else if (MD_REG_P (regno0))
-               {
-                 delay = DELAY_HILO;
-                 ret = "mt%0\t%.";
-               }
-           }
-
-         else if (GP_REG_P (regno0))
-           {
-             /* Don't use X format, because that will give out of
-                range numbers for 64 bit host and 32 bit target.  */
-             if (! TARGET_MIPS16)
-               ret = "li\t%0,%1\t\t\t# %X1";
-             else
-               {
-                 if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
-                   ret = "li\t%0,%1";
-                 else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
-                   ret = "li\t%0,%n1\n\tneg\t%0";
-               }
-           }
+         emit_move_insn (mips_subword (dest, 1), mips_subword (src, 1));
+         emit_move_insn (low_dest, mips_subword (src, 0));
        }
-
-      else if (code1 == CONST_DOUBLE && mode == SFmode)
+      else
        {
-         if (op1 == CONST0_RTX (SFmode))
-           {
-             if (GP_REG_P (regno0))
-               ret = "move\t%0,%.";
-
-             else if (FP_REG_P (regno0))
-               {
-                 delay = DELAY_LOAD;
-                 ret = "mtc1\t%.,%0";
-               }
-           }
-
-         else
-           {
-             delay = DELAY_LOAD;
-             ret = "li.s\t%0,%1";
-           }
+         emit_move_insn (low_dest, mips_subword (src, 0));
+         emit_move_insn (mips_subword (dest, 1), mips_subword (src, 1));
        }
+    }
+}
+\f
+/* Return the appropriate instructions to move SRC into DEST.  Assume
+   that SRC is operand 1 and DEST is operand 0.  */
 
-      else if (code1 == PLUS)
-       {
-         rtx add_op0 = XEXP (op1, 0);
-         rtx add_op1 = XEXP (op1, 1);
+const char *
+mips_output_move (dest, src)
+     rtx dest, src;
+{
+  enum rtx_code dest_code, src_code;
+  struct mips_constant_info c;
+  bool dbl_p;
 
-         if (GET_CODE (XEXP (op1, 1)) == REG
-             && GET_CODE (XEXP (op1, 0)) == CONST_INT)
-           add_op0 = XEXP (op1, 1), add_op1 = XEXP (op1, 0);
+  dest_code = GET_CODE (dest);
+  src_code = GET_CODE (src);
+  dbl_p = (GET_MODE_SIZE (GET_MODE (dest)) == 8);
 
-         operands[2] = add_op0;
-         operands[3] = add_op1;
-         ret = "add%:\t%0,%2,%3";
-       }
+  if (dbl_p && mips_split_64bit_move_p (dest, src))
+    return "#";
 
-      else if (code1 == HIGH)
+  if ((src_code == REG && GP_REG_P (REGNO (src)))
+      || (!TARGET_MIPS16 && src == CONST0_RTX (GET_MODE (dest))))
+    {
+      if (dest_code == REG)
        {
-         operands[1] = XEXP (op1, 0);
-         ret = "lui\t%0,%%hi(%1)";
-       }
+         if (GP_REG_P (REGNO (dest)))
+           return "move\t%0,%z1";
 
-      else
-       switch (mips_classify_constant (&c, op1))
-         {
-         case CONSTANT_NONE:
-           break;
+         if (MD_REG_P (REGNO (dest)))
+           return "mt%0\t%z1";
 
-         case CONSTANT_GP:
-           ret = "move\t%0,%1";
-           break;
+         if (FP_REG_P (REGNO (dest)))
+           return (dbl_p ? "dmtc1\t%z1,%0" : "mtc1\t%z1,%0");
 
-         case CONSTANT_RELOC:
-           ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
-           break;
+         if (ALL_COP_REG_P (REGNO (dest)))
+           {
+             static char retval[] = "dmtc_\t%z1,%0";
 
-         case CONSTANT_SYMBOLIC:
-           if (TARGET_STATS)
-             mips_count_memory_refs (op1, 1);
-           ret = "la\t%0,%a1";
-           break;
-         }
+             retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (dest));
+             return (dbl_p ? retval : retval + 1);
+           }
+       }
+      if (dest_code == MEM)
+       return (dbl_p ? "sd\t%z1,%0" : "sw\t%z1,%0");
     }
-
-  else if (code0 == MEM)
+  if (dest_code == REG && GP_REG_P (REGNO (dest)))
     {
-      if (TARGET_STATS)
-       mips_count_memory_refs (op0, 1);
-
-      if (code1 == REG)
+      if (src_code == REG)
        {
-         int regno1 = REGNO (op1) + subreg_offset1;
+         if (MD_REG_P (REGNO (src)))
+           return "mf%1\t%0";
 
-         if (GP_REG_P (regno1))
-           {
-             switch (mode)
-               {
-               case SFmode: ret = "sw\t%1,%0"; break;
-               case SImode: ret = "sw\t%1,%0"; break;
-               case HImode: ret = "sh\t%1,%0"; break;
-               case QImode: ret = "sb\t%1,%0"; break;
-               default: break;
-               }
-           }
+         if (ST_REG_P (REGNO (src)) && ISA_HAS_8CC)
+           return "lui\t%0,0x3f80\n\tmovf\t%0,%.,%1";
 
-         else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
-           ret = "swc1\t%1,%0";
-         else if (ALL_COP_REG_P (regno1))
+         if (FP_REG_P (REGNO (src)))
+           return (dbl_p ? "dmfc1\t%0,%1" : "mfc1\t%0,%1");
+
+         if (ALL_COP_REG_P (REGNO (src)))
            {
-             static char retval[] = "swc_\t%1,%0";
+             static char retval[] = "dmfc_\t%0,%1";
 
-             retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
-             ret = retval;
+             retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (src));
+             return (dbl_p ? retval : retval + 1);
            }
        }
 
-      else if (code1 == CONST_INT && INTVAL (op1) == 0)
-       {
-         switch (mode)
-           {
-           case SFmode: ret = "sw\t%z1,%0"; break;
-           case SImode: ret = "sw\t%z1,%0"; break;
-           case HImode: ret = "sh\t%z1,%0"; break;
-           case QImode: ret = "sb\t%z1,%0"; break;
-           default: break;
-           }
-       }
+      if (src_code == MEM)
+       return (dbl_p ? "ld\t%0,%1" : "lw\t%0,%1");
 
-      else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode))
+      if (src_code == CONST_INT)
        {
-         switch (mode)
-           {
-           case SFmode: ret = "sw\t%.,%0"; break;
-           case SImode: ret = "sw\t%.,%0"; break;
-           case HImode: ret = "sh\t%.,%0"; break;
-           case QImode: ret = "sb\t%.,%0"; break;
-           default: break;
-           }
+         /* Don't use the X format, because that will give out of
+            range numbers for 64 bit hosts and 32 bit targets.  */
+         if (!TARGET_MIPS16)
+           return "li\t%0,%1\t\t\t# %X1";
+
+         if (INTVAL (src) >= 0 && INTVAL (src) <= 0xffff)
+           return "li\t%0,%1";
+
+         if (INTVAL (src) < 0 && INTVAL (src) >= -0xffff)
+           return "li\t%0,%n1\n\tneg\t%0";
        }
 
-      if (ret != 0 && MEM_VOLATILE_P (op0))
+      if (src_code == HIGH)
+       return "lui\t%0,%h1";
+
+      switch (mips_classify_constant (&c, src))
        {
-         size_t i = strlen (ret);
+       case CONSTANT_NONE:
+         break;
 
-         if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
-           abort ();
+       case CONSTANT_GP:
+         return "move\t%0,%1";
 
-         sprintf (volatile_buffer, "%%{%s%%}", ret);
-         ret = volatile_buffer;
+       case CONSTANT_RELOC:
+         return (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
+
+       case CONSTANT_SYMBOLIC:
+         return (dbl_p ? "dla\t%0,%a1" : "la\t%0,%a1");
        }
     }
+  if (src_code == REG && FP_REG_P (REGNO (src)))
+    {
+      if (dest_code == REG && FP_REG_P (REGNO (dest)))
+       return (dbl_p ? "mov.d\t%0,%1" : "mov.s\t%0,%1");
 
-  if (ret == 0)
+      if (dest_code == MEM)
+       return (dbl_p ? "sdc1\t%1,%0" : "swc1\t%1,%0");
+    }
+  if (dest_code == REG && FP_REG_P (REGNO (dest)))
     {
-      abort_with_insn (insn, "bad move");
-      return 0;
+      if (src_code == MEM)
+       return (dbl_p ? "ldc1\t%0,%1" : "lwc1\t%0,%1");
     }
+  if (dest_code == REG && ALL_COP_REG_P (REGNO (dest)) && src_code == MEM)
+    {
+      static char retval[] = "l_c_\t%0,%1";
 
-  if (delay != DELAY_NONE)
-    return mips_fill_delay_slot (ret, delay, operands, insn);
+      retval[1] = (dbl_p ? 'd' : 'w');
+      retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (dest));
+      return retval;
+    }
+  if (dest_code == MEM && src_code == REG && ALL_COP_REG_P (REGNO (src)))
+    {
+      static char retval[] = "s_c_\t%1,%0";
 
-  return ret;
+      retval[1] = (dbl_p ? 'd' : 'w');
+      retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (src));
+      return retval;
+    }
+  abort ();
 }
 \f
 /* Return instructions to restore the global pointer from the stack,
@@ -3354,11 +3210,11 @@ mips_move_1word (operands, insn, unsignedp)
    the GP for exception handlers.
 
    OPERANDS is an array of operands whose contents are undefined
-   on entry.  INSN is the exception_handler instruction.  */
+   on entry.  */
 
 const char *
-mips_restore_gp (operands, insn)
-     rtx *operands, insn;
+mips_restore_gp (operands)
+     rtx *operands;
 {
   rtx loc;
 
@@ -3370,464 +3226,9 @@ mips_restore_gp (operands, insn)
   loc = plus_constant (loc, cfun->machine->frame.args_size);
   operands[1] = gen_rtx_MEM (ptr_mode, loc);
 
-  return mips_move_1word (operands, insn, 0);
+  return mips_output_move (operands[0], operands[1]);
 }
 \f
-/* Return the appropriate instructions to move 2 words */
-
-const char *
-mips_move_2words (operands, insn)
-     rtx operands[];
-     rtx insn;
-{
-  const char *ret = 0;
-  rtx op0 = operands[0];
-  rtx op1 = operands[1];
-  enum rtx_code code0 = GET_CODE (operands[0]);
-  enum rtx_code code1 = GET_CODE (operands[1]);
-  int subreg_offset0 = 0;
-  int subreg_offset1 = 0;
-  enum delay_type delay = DELAY_NONE;
-  struct mips_constant_info c;
-
-  while (code0 == SUBREG)
-    {
-      subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
-                                            GET_MODE (SUBREG_REG (op0)),
-                                            SUBREG_BYTE (op0),
-                                            GET_MODE (op0));
-      op0 = SUBREG_REG (op0);
-      code0 = GET_CODE (op0);
-    }
-
-  while (code1 == SUBREG)
-    {
-      subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
-                                            GET_MODE (SUBREG_REG (op1)),
-                                            SUBREG_BYTE (op1),
-                                            GET_MODE (op1));
-      op1 = SUBREG_REG (op1);
-      code1 = GET_CODE (op1);
-    }
-
-  if (code0 == REG)
-    {
-      int regno0 = REGNO (op0) + subreg_offset0;
-
-      if (code1 == REG)
-       {
-         int regno1 = REGNO (op1) + subreg_offset1;
-
-         /* Just in case, don't do anything for assigning a register
-            to itself, unless we are filling a delay slot.  */
-         if (regno0 == regno1 && set_nomacro == 0)
-           ret = "";
-
-         else if (FP_REG_P (regno0))
-           {
-             if (FP_REG_P (regno1))
-               ret = "mov.d\t%0,%1";
-
-             else
-               {
-                 delay = DELAY_LOAD;
-                 if (TARGET_FLOAT64)
-                   {
-                     if (!TARGET_64BIT)
-                       abort_with_insn (insn, "bad move");
-
-#ifdef TARGET_FP_CALL_32
-                     if (FP_CALL_GP_REG_P (regno1))
-                       ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tdmtc1\t%1,%0";
-                     else
-#endif
-                       ret = "dmtc1\t%1,%0";
-                   }
-                 else
-                   ret = "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
-               }
-           }
-
-         else if (FP_REG_P (regno1))
-           {
-             delay = DELAY_LOAD;
-             if (TARGET_FLOAT64)
-               {
-                 if (!TARGET_64BIT)
-                   abort_with_insn (insn, "bad move");
-
-#ifdef TARGET_FP_CALL_32
-                 if (FP_CALL_GP_REG_P (regno0))
-                   ret = "dmfc1\t%0,%1\n\tmfc1\t%D0,%1\n\tdsrl\t%0,32";
-                 else
-#endif
-                   ret = "dmfc1\t%0,%1";
-               }
-             else
-               ret = "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
-           }
-
-         else if (MD_REG_P (regno0) && GP_REG_P (regno1) && !TARGET_MIPS16)
-           {
-             delay = DELAY_HILO;
-             if (TARGET_64BIT)
-               {
-                 if (regno0 != HILO_REGNUM)
-                   ret = "mt%0\t%1";
-                 else if (regno1 == 0)
-                   ret = "mtlo\t%.\n\tmthi\t%.";
-               }
-             else
-               ret = "mthi\t%M1\n\tmtlo\t%L1";
-           }
-
-         else if (GP_REG_P (regno0) && MD_REG_P (regno1))
-           {
-             delay = DELAY_HILO;
-             if (TARGET_64BIT)
-               {
-                 if (regno1 != HILO_REGNUM)
-                   ret = "mf%1\t%0";
-               }
-             else
-               ret = "mfhi\t%M0\n\tmflo\t%L0";
-           }
-         else if (GP_REG_P (regno0) && ALL_COP_REG_P (regno1)
-                  && TARGET_64BIT)
-           {
-             static char retval[] = "dmfc_\t%0,%1";
-
-             delay = DELAY_LOAD;
-             retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
-             ret = retval;
-           }
-         else if (ALL_COP_REG_P (regno0) && GP_REG_P (regno1)
-                  && TARGET_64BIT)
-           {
-             static char retval[] = "dmtc_\t%1,%0";
-             char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
-             if (cop == '0')
-               abort_with_insn (insn,
-                                "dmtc0 not supported; it disturbs virtual address translation");
-             delay = DELAY_LOAD;
-             retval[4] = cop;
-             ret = retval;
-           }
-         else if (TARGET_64BIT)
-           ret = "move\t%0,%1";
-
-         else if (regno0 != (regno1+1))
-           ret = "move\t%0,%1\n\tmove\t%D0,%D1";
-
-         else
-           ret = "move\t%D0,%D1\n\tmove\t%0,%1";
-       }
-
-      else if (code1 == CONST_DOUBLE)
-       {
-         /* Move zero from $0 unless !TARGET_64BIT and recipient
-            is 64-bit fp reg, in which case generate a constant.  */
-         if (op1 != CONST0_RTX (GET_MODE (op1))
-             || (TARGET_FLOAT64 && !TARGET_64BIT && FP_REG_P (regno0)))
-           {
-             if (GET_MODE (op1) == DFmode)
-               {
-                 delay = DELAY_LOAD;
-
-#ifdef TARGET_FP_CALL_32
-                 if (FP_CALL_GP_REG_P (regno0))
-                   {
-                     if (TARGET_FLOAT64 && !TARGET_64BIT)
-                       {
-                         split_double (op1, operands + 2, operands + 3);
-                         ret = "li\t%0,%2\n\tli\t%D0,%3";
-                       }
-                     else
-                       ret = "li.d\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32";
-                   }
-                 else
-#endif
-                   /* GNU as emits 64-bit code for li.d if the ISA is 3
-                      or higher.  For !TARGET_64BIT && gp registers we
-                      need to avoid this by using two li instructions
-                      instead.  */
-                   if (ISA_HAS_64BIT_REGS
-                       && ! TARGET_64BIT
-                       && ! FP_REG_P (regno0))
-                     {
-                       split_double (op1, operands + 2, operands + 3);
-                       ret = "li\t%0,%2\n\tli\t%D0,%3";
-                     }
-                   else
-                     ret = "li.d\t%0,%1";
-               }
-
-             else if (TARGET_64BIT)
-               {
-                 if (! TARGET_MIPS16)
-                   ret = "dli\t%0,%1";
-               }
-
-             else
-               {
-                 split_double (op1, operands + 2, operands + 3);
-                 ret = "li\t%0,%2\n\tli\t%D0,%3";
-               }
-           }
-
-         else
-           {
-             if (GP_REG_P (regno0))
-               ret = (TARGET_64BIT
-#ifdef TARGET_FP_CALL_32
-                      && ! FP_CALL_GP_REG_P (regno0)
-#endif
-                      ? "move\t%0,%."
-                      : "move\t%0,%.\n\tmove\t%D0,%.");
-
-             else if (FP_REG_P (regno0))
-               {
-                 delay = DELAY_LOAD;
-                 ret = (TARGET_64BIT
-                        ? "dmtc1\t%.,%0"
-                        : "mtc1\t%.,%0\n\tmtc1\t%.,%D0");
-               }
-           }
-       }
-
-      else if (code1 == CONST_INT && INTVAL (op1) == 0 && ! TARGET_MIPS16)
-       {
-         if (GP_REG_P (regno0))
-           ret = (TARGET_64BIT
-                  ? "move\t%0,%."
-                  : "move\t%0,%.\n\tmove\t%D0,%.");
-
-         else if (FP_REG_P (regno0))
-           {
-             delay = DELAY_LOAD;
-             ret = (TARGET_64BIT
-                    ? "dmtc1\t%.,%0"
-                    : (TARGET_FLOAT64
-                       ? "li.d\t%0,%1"
-                       : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"));
-           }
-         else if (MD_REG_P (regno0))
-           {
-             delay = DELAY_HILO;
-             ret =  (regno0 == HILO_REGNUM
-                     ? "mtlo\t%.\n\tmthi\t%."
-                     : "mt%0\t%.\n");
-           }
-       }
-
-      else if (code1 == CONST_INT && GET_MODE (op0) == DImode
-              && GP_REG_P (regno0))
-       {
-         if (TARGET_64BIT)
-           {
-             if (TARGET_MIPS16)
-               {
-                 if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
-                   ret = "li\t%0,%1";
-                 else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
-                   ret = "li\t%0,%n1\n\tneg\t%0";
-               }
-             else if (GET_CODE (operands[1]) == SIGN_EXTEND)
-               ret = "li\t%0,%1\t\t# %X1";
-             else if (HOST_BITS_PER_WIDE_INT < 64)
-               /* We can't use 'X' for negative numbers, because then we won't
-                  get the right value for the upper 32 bits.  */
-               ret = (INTVAL (op1) < 0
-                      ? "dli\t%0,%1\t\t\t# %X1"
-                      : "dli\t%0,%X1\t\t# %1");
-             else
-               /* We must use 'X', because otherwise LONG_MIN will print as
-                  a number that the assembler won't accept.  */
-               ret = "dli\t%0,%X1\t\t# %1";
-           }
-         else if (HOST_BITS_PER_WIDE_INT < 64)
-           {
-             operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1);
-             if (TARGET_MIPS16)
-               {
-                 if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
-                   ret = "li\t%M0,%2\n\tli\t%L0,%1";
-                 else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
-                   {
-                     operands[2] = GEN_INT (1);
-                     ret = "li\t%M0,%2\n\tneg\t%M0\n\tli\t%L0,%n1\n\tneg\t%L0";
-                   }
-               }
-             else
-               ret = "li\t%M0,%2\n\tli\t%L0,%1";
-           }
-         else
-           {
-             /* We use multiple shifts here, to avoid warnings about out
-                of range shifts on 32 bit hosts.  */
-             operands[2] = GEN_INT (INTVAL (operands[1]) >> 16 >> 16);
-             operands[1]
-               = GEN_INT (INTVAL (operands[1]) << 16 << 16 >> 16 >> 16);
-             if (TARGET_MIPS16)
-               {
-                 if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
-                   ret = "li\t%M0,%2\n\tli\t%L0,%1";
-                 else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
-                   {
-                     operands[2] = GEN_INT (1);
-                     ret = "li\t%M0,%2\n\tneg\t%M0\n\tli\t%L0,%n1\n\tneg\t%L0";
-                   }
-               }
-             else
-               ret = "li\t%M0,%2\n\tli\t%L0,%1";
-           }
-       }
-
-      else if (code1 == MEM)
-       {
-         delay = DELAY_LOAD;
-
-         if (TARGET_STATS)
-           mips_count_memory_refs (op1, 2);
-
-         if (FP_REG_P (regno0))
-           ret = (TARGET_64BIT ? "ldc1\t%0,%1" : "l.d\t%0,%1");
-
-         else if (ALL_COP_REG_P (regno0) && TARGET_64BIT)
-           {
-             static char retval[] = "ldc_\t%0,%1";
-             char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
-             if (cop == '0')
-               abort_with_insn (insn,
-                                "loads from memory to COP0 are illegal");
-             delay = DELAY_LOAD;
-             retval[3] = cop;
-             ret = retval;
-           }
-
-         else if (TARGET_64BIT)
-           {
-
-#ifdef TARGET_FP_CALL_32
-             if (FP_CALL_GP_REG_P (regno0))
-               ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1";
-             else
-#endif
-               ret = "ld\t%0,%1";
-           }
-
-         else
-           ret = (reg_mentioned_p (op0, op1)
-                  ? "lw\t%D0,%D1\n\tlw\t%0,%1"
-                  : "lw\t%0,%1\n\tlw\t%D0,%D1");
-
-         if (ret != 0 && MEM_VOLATILE_P (op1))
-           {
-             size_t i = strlen (ret);
-
-             if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
-               abort ();
-
-             sprintf (volatile_buffer, "%%{%s%%}", ret);
-             ret = volatile_buffer;
-           }
-       }
-      else if (code1 == HIGH)
-       {
-         operands[1] = XEXP (op1, 0);
-         ret = "lui\t%0,%%hi(%1)";
-       }
-      else
-       switch (mips_classify_constant (&c, op1))
-         {
-         case CONSTANT_NONE:
-           break;
-
-         case CONSTANT_GP:
-           ret = "move\t%0,%1";
-           break;
-
-         case CONSTANT_RELOC:
-           ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
-           break;
-
-         case CONSTANT_SYMBOLIC:
-           if (TARGET_STATS)
-             mips_count_memory_refs (op1, 2);
-           ret = "dla\t%0,%a1";
-           break;
-         }
-    }
-
-  else if (code0 == MEM)
-    {
-      if (code1 == REG)
-       {
-         int regno1 = REGNO (op1) + subreg_offset1;
-
-         if (FP_REG_P (regno1))
-           ret = (TARGET_64BIT ? "sdc1\t%1,%0" : "s.d\t%1,%0");
-
-         else if (ALL_COP_REG_P (regno1) && TARGET_64BIT)
-           {
-             static char retval[] = "sdc_\t%1,%0";
-
-             retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
-             ret = retval;
-           }
-         else if (TARGET_64BIT)
-           {
-
-#ifdef TARGET_FP_CALL_32
-             if (FP_CALL_GP_REG_P (regno1))
-               ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tsd\t%1,%0";
-             else
-#endif
-               ret = "sd\t%1,%0";
-           }
-
-         else
-           ret = "sw\t%1,%0\n\tsw\t%D1,%D0";
-       }
-
-      else if (((code1 == CONST_INT && INTVAL (op1) == 0)
-               || (code1 == CONST_DOUBLE
-                   && op1 == CONST0_RTX (GET_MODE (op1)))))
-       {
-         if (TARGET_64BIT)
-           ret = "sd\t%.,%0";
-         else
-           ret = "sw\t%.,%0\n\tsw\t%.,%D0";
-       }
-
-      if (TARGET_STATS)
-       mips_count_memory_refs (op0, 2);
-
-      if (ret != 0 && MEM_VOLATILE_P (op0))
-       {
-         size_t i = strlen (ret);
-
-         if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
-           abort ();
-
-         sprintf (volatile_buffer, "%%{%s%%}", ret);
-         ret = volatile_buffer;
-       }
-    }
-
-  if (ret == 0)
-    {
-      abort_with_insn (insn, "bad move");
-      return 0;
-    }
-
-  if (delay != DELAY_NONE)
-    return mips_fill_delay_slot (ret, delay, operands, insn);
-
-  return ret;
-}
 \f
 /* Make normal rtx_code into something we can index from an array */
 
@@ -6622,6 +6023,7 @@ mips_debugger_offset (addr, offset)
 
    'X'  X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
    'x'  X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
+   'h'  X is HIGH, prints %hi(X),
    'd'  output integer constant in decimal,
    'z' if the operand is 0, use $0 instead of normal operand.
    'D'  print second part of double-word register or memory operand.
@@ -6814,6 +6216,15 @@ print_operand (file, op, letter)
       fputc (')', file);
     }
 
+  else if (letter == 'h')
+    {
+      if (GET_CODE (op) != HIGH)
+       abort ();
+      fputs ("%hi(", file);
+      output_addr_const (file, XEXP (op, 0));
+      fputc (')', file);
+    }
+
   else if (letter == 'C')
     switch (code)
       {
@@ -6914,15 +6325,6 @@ print_operand (file, op, letter)
        output_address (XEXP (op, 0));
     }
 
-  else if (code == CONST_DOUBLE
-          && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
-    {
-      char s[60];
-
-      real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
-      fputs (s, file);
-    }
-
   else if (letter == 'x' && GET_CODE (op) == CONST_INT)
     fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL(op));
 
@@ -6932,7 +6334,7 @@ print_operand (file, op, letter)
   else if (letter == 'd' && GET_CODE(op) == CONST_INT)
     fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL(op)));
 
-  else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+  else if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
     fputs (reg_names[GP_REG_FIRST], file);
 
   else if (letter == 'd' || letter == 'x' || letter == 'X')
@@ -7815,32 +7217,32 @@ mips_add_large_offset_to_sp (offset)
   return reg;
 }
 
-/* Make INSN frame related and note that it performs the frame-related
-   operation DWARF_PATTERN.  */
+/* Make the last instruction frame related and note that it performs
+   the operation described by FRAME_PATTERN.  */
 
 static void
-mips_annotate_frame_insn (insn, dwarf_pattern)
-     rtx insn, dwarf_pattern;
+mips_set_frame_expr (frame_pattern)
+     rtx frame_pattern;
 {
+  rtx insn;
+
+  insn = get_last_insn ();
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                     dwarf_pattern,
+                                     frame_pattern,
                                      REG_NOTES (insn));
 }
 
-/* Return a frame-related rtx that stores register REGNO at (SP + OFFSET).
-   The expression should only be used to store single registers.  */
+/* Return a frame-related rtx that stores REG at (SP + OFFSET).
+   REG must be a single register.  */
 
 static rtx
-mips_frame_set (mode, regno, offset)
-     enum machine_mode mode;
-     int regno;
+mips_frame_set (reg, offset)
+     rtx reg;
      int offset;
 {
   rtx address = plus_constant (stack_pointer_rtx, offset);
-  rtx set = gen_rtx_SET (mode,
-                        gen_rtx_MEM (mode, address),
-                        gen_rtx_REG (mode, regno));
+  rtx set = gen_rtx_SET (VOIDmode, gen_rtx_MEM (GET_MODE (reg), address), reg);
   RTX_FRAME_RELATED_P (set) = 1;
   return set;
 }
@@ -7856,24 +7258,24 @@ mips_emit_frame_related_store (mem, reg, offset)
      rtx reg;
      HOST_WIDE_INT offset;
 {
-  rtx dwarf_expr;
+  if (GET_MODE (reg) == DFmode && mips_split_64bit_move_p (mem, reg))
+    mips_split_64bit_move (mem, reg);
+  else
+    emit_move_insn (mem, reg);
 
-  if (GET_MODE (reg) == DFmode && ! TARGET_FLOAT64)
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
     {
+      rtx x1, x2;
+
       /* Two registers are being stored, so the frame-related expression
-        must be a PARALLEL rtx with one SET for each register.  The
-        higher numbered register is stored in the lower address on
-        big-endian targets.  */
-      int regno1 = TARGET_BIG_ENDIAN ? REGNO (reg) + 1 : REGNO (reg);
-      int regno2 = TARGET_BIG_ENDIAN ? REGNO (reg) : REGNO (reg) + 1;
-      rtx set1 = mips_frame_set (SFmode, regno1, offset);
-      rtx set2 = mips_frame_set (SFmode, regno2, offset + UNITS_PER_FPREG);
-      dwarf_expr = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2));
+        must be a PARALLEL rtx with one SET for each register.  */
+      x1 = mips_frame_set (mips_subword (reg, TARGET_BIG_ENDIAN), offset);
+      x2 = mips_frame_set (mips_subword (reg, !TARGET_BIG_ENDIAN),
+                          offset + UNITS_PER_FPREG);
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
     }
   else
-    dwarf_expr = mips_frame_set (GET_MODE (reg), REGNO (reg), offset);
-
-  mips_annotate_frame_insn (emit_move_insn (mem, reg), dwarf_expr);
+    mips_set_frame_expr (mips_frame_set (reg, offset));
 }
 
 static void
@@ -8549,7 +7951,7 @@ mips_expand_prologue ()
       if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
          && (!TARGET_MIPS16 || tsize <= 32767))
        {
-         rtx adjustment_rtx, insn, dwarf_pattern;
+         rtx adjustment_rtx;
 
          if (tsize > 32767)
            {
@@ -8560,17 +7962,15 @@ mips_expand_prologue ()
            adjustment_rtx = tsize_rtx;
 
          if (Pmode == DImode)
-           insn = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                         adjustment_rtx));
+           emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  adjustment_rtx));
          else
-           insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                         adjustment_rtx));
-
-         dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,
-                                      plus_constant (stack_pointer_rtx,
-                                                     -tsize));
+           emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  adjustment_rtx));
 
-         mips_annotate_frame_insn (insn, dwarf_pattern);
+         mips_set_frame_expr
+           (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                         plus_constant (stack_pointer_rtx, -tsize)));
        }
 
       if (! mips_entry)
index c645f10a35ac4de1e900e40b16c99e0f7f6589f7..bef64a8a3a9d224b00e55482da5f9b7720ba1d37 100644 (file)
@@ -1935,6 +1935,8 @@ do {                                                      \
 #define ALL_COP_REG_P(REGNO) \
   ((unsigned int) ((int) (REGNO) - COP0_REG_FIRST) < ALL_COP_REG_NUM)
 
+#define FP_REG_RTX_P(X) (GET_CODE (X) == REG && FP_REG_P (REGNO (X)))
+
 /* Return coprocessor number from register number.  */
 
 #define COPNUM_AS_CHAR_FROM_REGNUM(REGNO)                              \
index a9367289d5eddafd6962cb172188f1678408d48c..876f0dbd31600c78d12ee72618f341bc59de8a44 100644 (file)
 ;; Must include new entries for fmadd in addition to existing entries.
 
 (define_constants
-  [(UNSPEC_GET_FNADDR           4)
+  [(UNSPEC_LOAD_DF_LOW          0)
+   (UNSPEC_LOAD_DF_HIGH                 1)
+   (UNSPEC_STORE_DF_HIGH        2)
+   (UNSPEC_GET_FNADDR           4)
    (UNSPEC_HILO_DELAY           5)
    (UNSPEC_BLOCKAGE             6)
    (UNSPEC_LOADGP               7)
    (clobber (match_scratch:SI 4 "=l"))
    (clobber (match_scratch:SI 5 "=a"))]
   "TARGET_MIPS4000 && !TARGET_MIPS16"
-  "*
-{
-  rtx xoperands[10];
-
-  xoperands[0] = operands[0];
-  xoperands[1] = gen_rtx_REG (SImode, LO_REGNUM);
-
-  output_asm_insn (\"mult\\t%1,%2\", operands);
-  output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
-  return \"\";
-}"
+  "mult\t%1,%2\;mflo\t%0"
   [(set_attr "type"    "imul")
    (set_attr "mode"    "SI")
-   (set_attr "length"   "12")])                ;; mult + mflo + delay
+   (set_attr "length"   "8")])
 
 ;; Multiply-accumulate patterns
 
    (clobber (match_scratch:DI 4 "=l"))
    (clobber (match_scratch:DI 5 "=a"))]
   "TARGET_64BIT && (GENERATE_MULT3_DI || TARGET_MIPS4000 || TARGET_MIPS16)"
-  "*
-{
-  if (GENERATE_MULT3_DI)
-    output_asm_insn (\"dmult\\t%0,%1,%2\", operands);
-  else
-    {
-      rtx xoperands[10];
-
-      xoperands[0] = operands[0];
-      xoperands[1] = gen_rtx_REG (DImode, LO_REGNUM);
-
-      output_asm_insn (\"dmult\\t%1,%2\", operands);
-      output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
-    }
-  return \"\";
-}"
+  {
+    if (GENERATE_MULT3_DI)
+      return "dmult\t%0,%1,%2";
+    else
+      return "dmult\t%1,%2\n\tmflo\t%0";
+  }
   [(set_attr "type"    "imul")
    (set_attr "mode"    "DI")
    (set (attr "length")
        (if_then_else (ne (symbol_ref "GENERATE_MULT3_DI") (const_int 0))
-                      (const_int 4)
-                      (const_int 12)))])       ;; mult + mflo + delay
+                     (const_int 4)
+                     (const_int 8)))])
 
 ;; ??? We could define a mulditi3 pattern when TARGET_64BIT.
 
@@ -4300,23 +4283,6 @@ move\\t%0,%z4\\n\\
    (set_attr "mode"     "DI")
    (set_attr "length"   "4,*")])
 
-;; These can be created when a paradoxical subreg operand with an implicit
-;; sign_extend operator is reloaded.  Because of the subreg, this is really
-;; a zero extend.
-;; ??? It might be possible to eliminate the need for these patterns by adding
-;; more support to reload for implicit sign_extend operators.
-(define_insn "*paradoxical_extendhidi2"
-  [(set (match_operand:DI 0 "register_operand" "=d")
-       (sign_extend:DI
-        (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)))]
-  "TARGET_64BIT"
-  "*
-{
-  return mips_move_1word (operands, insn, TRUE);
-}"
-  [(set_attr "type"    "load")
-   (set_attr "mode"    "DI")])
-
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=d")
        (zero_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
@@ -5114,11 +5080,7 @@ move\\t%0,%z4\\n\\
   [(set (match_operand:DI 0 "memory_operand" "=m")
        (reg:DI 31))]
   "TARGET_MIPS16 && TARGET_64BIT"
-  "*
-{
-  operands[1] = gen_rtx (REG, DImode, 31);
-  return mips_move_2words (operands, insn);
-}"
+  "sd\t$31,%0"
   [(set_attr "type"    "store")
    (set_attr "mode"    "DI")])
 
@@ -5130,7 +5092,7 @@ move\\t%0,%z4\\n\\
        || register_operand (operands[1], DImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
        || operands[1] == CONST0_RTX (DImode))"
-  "* return mips_move_2words (operands, insn); "
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,arith,load,store,hilo,hilo,hilo,xfer,load,xfer,store")
    (set_attr "mode"    "DI")
    (set_attr "length"   "8,16,*,*,8,8,8,8,*,8,*")])
@@ -5141,23 +5103,11 @@ move\\t%0,%z4\\n\\
   "!TARGET_64BIT && TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
-  "* return mips_move_2words (operands, insn);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,move,arith,arith,load,store,hilo")
    (set_attr "mode"    "DI")
    (set_attr "length"  "8,8,8,8,12,*,*,8")])
 
-(define_split
-  [(set (match_operand:DI 0 "register_operand" "")
-       (match_operand:DI 1 "register_operand" ""))]
-  "reload_completed && !TARGET_64BIT
-   && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
-   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
-   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
-
-  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
-   (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
-  "")
-
 (define_insn "movdi_internal2"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*d,*m")
        (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*J,*x,*d,*J,*d,*m,*B*C*D,*B*C*D"))]
@@ -5166,31 +5116,18 @@ move\\t%0,%z4\\n\\
        || register_operand (operands[1], DImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
        || operands[1] == CONST0_RTX (DImode))"
-  "* return mips_move_2words (operands, insn); "
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,const,const,load,store,move,xfer,load,xfer,store,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
    (set_attr "mode"    "DI")
    (set_attr "length"  "4,*,*,*,*,4,4,*,4,*,4,4,4,8,8,*,8,*")])
 
-;; Sign-extended operands are reloaded using this instruction, so the
-;; constraints must handle every SImode source operand X and destination
-;; register R for which:
-;;
-;;     mips_secondary_reload_class (CLASS_OF (R), DImode, true,
-;;                                 gen_rtx_SIGN_EXTEND (DImode, X))
-;;
-;; returns NO_REGS.  Also handle memory destinations, where allowed.
-;;
-;; This pattern is essentially a trimmed-down version of movdi_internal2.
-;; The main difference is that dJ -> f and f -> d are the only constraints
-;; involving float registers.  See mips_secondary_reload_class for details.
-
 (define_insn "*movdi_internal2_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m,*d")
        (match_operand:DI 1 "move_operand" "d,d,y,K,N,U,m,d,*x"))]
   "TARGET_64BIT && TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
-  "* return mips_move_2words (operands, insn);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,move,arith,arith,const,load,store,hilo")
    (set_attr "mode"    "DI")
    (set_attr_alternative "length"
@@ -5478,7 +5415,7 @@ move\\t%0,%z4\\n\\
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,const,const,load,store,move,xfer,load,xfer,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
    (set_attr "mode"    "SI")
    (set_attr "length"  "4,*,*,*,*,4,4,*,4,*,4,4,4,4,4,4,4,*,4,*")])
@@ -5489,7 +5426,7 @@ move\\t%0,%z4\\n\\
   "TARGET_MIPS16
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,move,arith,arith,const,load,store,hilo,hilo")
    (set_attr "mode"    "SI")
    (set_attr_alternative "length"
@@ -5575,7 +5512,7 @@ move\\t%0,%z4\\n\\
 }")
 
 ;; On the mips16, we can split a load of a negative constant into a
-;; load and a neg.  That's what mips_move_1word will generate anyhow.
+;; load and a neg.  That's what mips_output_move will generate anyhow.
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
@@ -5753,7 +5690,7 @@ move\\t%0,%z4\\n\\
   [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m")
        (match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))]
   "ISA_HAS_8CC && TARGET_HARD_FLOAT"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,load,store,xfer,xfer,move,load,store")
    (set_attr "mode"    "SI")
    (set_attr "length"  "8,4,*,*,4,4,4,*,*")])
@@ -5917,13 +5854,22 @@ move\\t%0,%z4\\n\\
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "movhi_internal"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
-       (match_operand:HI 1 "general_operand"       "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x,*d")
+       (match_operand:HI 1 "general_operand"       "d,IK,m,dJ,*f,*d,*f,*d,*x"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
-  "* return mips_move_1word (operands, insn, TRUE);"
+  "@
+    move\t%0,%1
+    li\t%0,%1
+    lhu\t%0,%1
+    sh\t%z1,%0
+    mfc1\t%0,%1
+    mtc1\t%1,%0
+    mov.s\t%0,%1
+    mt%0\t%1
+    mf%1\t%0"
   [(set_attr "type"    "move,arith,load,store,xfer,xfer,move,hilo,hilo")
    (set_attr "mode"    "HI")
    (set_attr "length"  "4,4,*,*,4,4,4,4,4")])
@@ -5934,7 +5880,15 @@ move\\t%0,%z4\\n\\
   "TARGET_MIPS16
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
-  "* return mips_move_1word (operands, insn, TRUE);"
+  "@
+    move\t%0,%1
+    move\t%0,%1
+    move\t%0,%1
+    li\t%0,%1
+    li\t%0,%n1\;neg\t%0
+    lhu\t%0,%1
+    sh\t%1,%0
+    mf%1\t%0"
   [(set_attr "type"    "move,move,move,arith,arith,load,store,hilo")
    (set_attr "mode"    "HI")
    (set_attr_alternative "length"
@@ -6025,13 +5979,22 @@ move\\t%0,%z4\\n\\
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "movqi_internal"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
-       (match_operand:QI 1 "general_operand"       "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x,*d")
+       (match_operand:QI 1 "general_operand"       "d,IK,m,dJ,*f,*d,*f,*d,*x"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
-  "* return mips_move_1word (operands, insn, TRUE);"
+  "@
+    move\t%0,%1
+    li\t%0,%1
+    lbu\t%0,%1
+    sb\t%z1,%0
+    mfc1\t%0,%1
+    mtc1\t%1,%0
+    mov.s\t%0,%1
+    mt%0\t%1
+    mf%1\t%0"
   [(set_attr "type"    "move,arith,load,store,xfer,xfer,move,hilo,hilo")
    (set_attr "mode"    "QI")
    (set_attr "length"  "4,4,*,*,4,4,4,4,4")])
@@ -6042,23 +6005,18 @@ move\\t%0,%z4\\n\\
   "TARGET_MIPS16
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode))"
-  "* return mips_move_1word (operands, insn, TRUE);"
+  "@
+    move\t%0,%1
+    move\t%0,%1
+    move\t%0,%1
+    li\t%0,%1
+    li\t%0,%n1\;neg\t%0
+    lbu\t%0,%1
+    sb\t%1,%0
+    mf%1\t%0"
   [(set_attr "type"    "move,move,move,arith,arith,load,store,hilo")
    (set_attr "mode"    "QI")
-   (set_attr_alternative "length"
-               [(const_int 4)
-                (const_int 4)
-                (const_int 4)
-                (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "")
-                              (const_int 4)
-                              (const_int 8))
-                (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
-                              (const_int 8)
-                              (const_int 12))
-                (const_string "*")
-                (const_string "*")
-                (const_int 4)])])
-
+   (set_attr "length"  "4,4,4,4,8,*,*,4")])
 
 ;; On the mips16, we can split lb $r,N($r) into an add and a load,
 ;; when the original load is a 4 byte instruction but the add and the
@@ -6111,7 +6069,7 @@ move\\t%0,%z4\\n\\
   "TARGET_HARD_FLOAT
    && (register_operand (operands[0], SFmode)
        || nonmemory_operand (operands[1], SFmode))"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,xfer,load,store,xfer,xfer,move,load,store")
    (set_attr "mode"    "SF")
    (set_attr "length"  "4,4,*,*,4,4,4,*,*")])
@@ -6122,7 +6080,7 @@ move\\t%0,%z4\\n\\
   "TARGET_SOFT_FLOAT && !TARGET_MIPS16
    && (register_operand (operands[0], SFmode)
        || nonmemory_operand (operands[1], SFmode))"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,load,store")
    (set_attr "mode"    "SF")
    (set_attr "length"  "4,*,*")])
@@ -6133,7 +6091,7 @@ move\\t%0,%z4\\n\\
   "TARGET_MIPS16
    && (register_operand (operands[0], SFmode)
        || register_operand (operands[1], SFmode))"
-  "* return mips_move_1word (operands, insn, FALSE);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,move,load,store")
    (set_attr "mode"    "SF")
    (set_attr "length"  "4,4,4,*,*")])
@@ -6159,10 +6117,10 @@ move\\t%0,%z4\\n\\
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_64BIT
    && (register_operand (operands[0], DFmode)
        || nonmemory_operand (operands[1], DFmode))"
-  "* return mips_move_2words (operands, insn); "
-  [(set_attr "type"    "move,move,load,store,xfer,xfer,move,load,store")
+  { return mips_output_move (operands[0], operands[1]); }
+  [(set_attr "type"    "move,xfer,load,store,xfer,xfer,move,load,store")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "4,8,*,*,4,4,4,*,*")])
+   (set_attr "length"  "4,4,*,*,4,4,4,*,*")])
 
 (define_insn "movdf_internal1b"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,*f,*d,*d,*d,*m")
@@ -6170,21 +6128,21 @@ move\\t%0,%z4\\n\\
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT
    && (register_operand (operands[0], DFmode)
        || nonmemory_operand (operands[1], DFmode))"
-  "* return mips_move_2words (operands, insn); "
-  [(set_attr "type"    "move,move,load,store,xfer,xfer,move,load,store")
+  { return mips_output_move (operands[0], operands[1]); }
+  [(set_attr "type"    "move,xfer,load,store,xfer,xfer,move,load,store")
    (set_attr "mode"    "DF")
    (set_attr "length"  "4,8,*,*,8,8,8,*,*")])
 
 (define_insn "movdf_internal2"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m,d,f,f")
-       (match_operand:DF 1 "general_operand" "dG,m,d,f,d,f"))]
+       (match_operand:DF 1 "general_operand" "dG,m,dG,f,d,f"))]
   "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16
    && (register_operand (operands[0], DFmode)
        || nonmemory_operand (operands[1], DFmode))"
-  "* return mips_move_2words (operands, insn); "
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,load,store,xfer,xfer,move")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "8,*,*,8,8,4")])
+   (set_attr "length"  "8,*,*,4,4,4")])
 
 (define_insn ""
   [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m")
@@ -6192,21 +6150,81 @@ move\\t%0,%z4\\n\\
   "TARGET_MIPS16
    && (register_operand (operands[0], DFmode)
        || register_operand (operands[1], DFmode))"
-  "* return mips_move_2words (operands, insn);"
+  { return mips_output_move (operands[0], operands[1]); }
   [(set_attr "type"    "move,move,move,load,store")
    (set_attr "mode"    "DF")
    (set_attr "length"  "8,8,8,*,*")])
 
 (define_split
-  [(set (match_operand:DF 0 "register_operand" "")
-       (match_operand:DF 1 "register_operand" ""))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
   "reload_completed && !TARGET_64BIT
-   && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
-   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
-   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
-  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
-   (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
-  "")
+   && mips_split_64bit_move_p (operands[0], operands[1])"
+  [(const_int 0)]
+  {
+    mips_split_64bit_move (operands[0], operands[1]);
+    DONE;
+  })
+
+(define_split
+  [(set (match_operand:DF 0 "nonimmediate_operand" "")
+       (match_operand:DF 1 "general_operand" ""))]
+  "reload_completed && !TARGET_64BIT
+   && mips_split_64bit_move_p (operands[0], operands[1])"
+  [(const_int 0)]
+  {
+    mips_split_64bit_move (operands[0], operands[1]);
+    DONE;
+  })
+
+;; Patterns for loading or storing part of a paired floating point
+;; register.  We need them because odd-numbered floating-point registers
+;; are not fully independent: see mips_split_64bit_move.
+
+;; Load the low word of operand 0 with operand 1.
+(define_insn "load_df_low"
+  [(set (match_operand:DF 0 "register_operand" "=f,f")
+       (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")]
+                  UNSPEC_LOAD_DF_LOW))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+  {
+    operands[0] = mips_subword (operands[0], 0);
+    return mips_output_move (operands[0], operands[1]);
+  }
+  [(set_attr "type"    "xfer,load")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "4")])
+
+;; Load the high word of operand 0 from operand 1, preserving the value
+;; in the low word.
+(define_insn "load_df_high"
+  [(set (match_operand:DF 0 "register_operand" "=f,f")
+       (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")
+                   (match_operand:DF 2 "register_operand" "0,0")]
+                  UNSPEC_LOAD_DF_HIGH))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+  {
+    operands[0] = mips_subword (operands[0], 1);
+    return mips_output_move (operands[0], operands[1]);
+  }
+  [(set_attr "type"    "xfer,load")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "4")])
+
+;; Store the high word of operand 1 in operand 0.  The corresponding
+;; low-word move is done in the normal way.
+(define_insn "store_df_high"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m")
+       (unspec:SI [(match_operand:DF 1 "register_operand" "f,f")]
+                  UNSPEC_STORE_DF_HIGH))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+  {
+    operands[1] = mips_subword (operands[1], 1);
+    return mips_output_move (operands[0], operands[1]);
+  }
+  [(set_attr "type"    "xfer,store")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "4")])
 
 ;; Instructions to load the global pointer register.
 ;; This is volatile to make sure that the scheduler won't move any symbol_ref
@@ -9808,7 +9826,7 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
 (define_insn "exception_receiver"
   [(unspec_volatile [(const_int 0)] UNSPEC_EH_RECEIVER)]
   "TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
-  "* return mips_restore_gp (operands, insn);"
+  { return mips_restore_gp (operands); }
   [(set_attr "type"   "load")
    (set_attr "length" "8")])
 \f