OSDN Git Service

* config/mips/mips-protos.h (mips_sign_extend): Declare.
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 17 Jul 2002 09:24:08 +0000 (09:24 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 17 Jul 2002 09:24:08 +0000 (09:24 +0000)
* config/mips/mips.h (MASK_DEBUG_H, TARGET_DEBUG_H_MODE): Remove.
(TARGET_SWITCHES): Remove debugh.
(ISA_HAS_TRUNC_W): New macro.
(CLASS_CANNOT_CHANGE_MODE): Include FP_REGS if TARGET_FLOAT64.
(PREDICATE_CODES): Remove se_nonimmediate_operand.
* config/mips/mips.c (movdi_operand): Allow sign-extensions of
any SImode move_operand.
(se_nonimmediate_operand): Remove.
(mips_sign_extend): New.
(mips_move_2words): Use it for sign-extended source operands.
(override_options): Allow integers to be put into single FPRs.
(mips_secondary_reload_class): Handle integers in float registers.
* config/mips/mips.md (extendsidi2): Turn into a define_expand.
(fix_truncsfsi2, fix_truncdfsi2): Likewise.
(fix_truncdfsi2_insn, fix_truncdfsi2_macro): New.
(fix_truncsfsi2_insn, fix_truncsfsi2_macro): New.
(fix_truncdfdi2): Provide only a single alternative, in which the
integer is in a float register.  Depend on TARGET_FLOAT64 rather
than TARGET_64BIT.
(fix_truncsfdi2, floatdidf2, floatdisf2): Likewise.
(floatsidf2, floatsisf2): Likewise, but no TARGET_FLOAT64 dependency.
(movdi_internal2): Don't allow the source operand to be sign-extended.
Add alternatives for float registers.
(*movdi_internal2_extend): New.  Version of movdi_internal2 that
allows sign-extension.
(*movdi_internal2_mips16): Name the existing mips16 movdi pattern.
(movsi_internal2): Rename to movsi_internal.  Add alternatives for
float registers.  Remove TARGET_DEBUG_H_MODE test.
(movhi_internal1): Rename to movhi_internal.  Don't check
TARGET_DEBUG_H_MODE.  Fix transposed *d and *f source constraints.
(movqi_internal1): Rename to movqi_internal and remove
TARGET_DEBUG_H_MODE dependency.
(movsi_internal1, movhi_internal2, movqi_internal2): Remove.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@55514 138bc75d-0d04-0410-961f-82ee72b054a4

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

index b3db910..b23d59d 100644 (file)
@@ -1,3 +1,40 @@
+2002-07-17  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips-protos.h (mips_sign_extend): Declare.
+       * config/mips/mips.h (MASK_DEBUG_H, TARGET_DEBUG_H_MODE): Remove.
+       (TARGET_SWITCHES): Remove debugh.
+       (ISA_HAS_TRUNC_W): New macro.
+       (CLASS_CANNOT_CHANGE_MODE): Include FP_REGS if TARGET_FLOAT64.
+       (PREDICATE_CODES): Remove se_nonimmediate_operand.
+       * config/mips/mips.c (movdi_operand): Allow sign-extensions of
+       any SImode move_operand.
+       (se_nonimmediate_operand): Remove.
+       (mips_sign_extend): New.
+       (mips_move_2words): Use it for sign-extended source operands.
+       (override_options): Allow integers to be put into single FPRs.
+       (mips_secondary_reload_class): Handle integers in float registers.
+       * config/mips/mips.md (extendsidi2): Turn into a define_expand.
+       (fix_truncsfsi2, fix_truncdfsi2): Likewise.
+       (fix_truncdfsi2_insn, fix_truncdfsi2_macro): New.
+       (fix_truncsfsi2_insn, fix_truncsfsi2_macro): New.
+       (fix_truncdfdi2): Provide only a single alternative, in which the
+       integer is in a float register.  Depend on TARGET_FLOAT64 rather
+       than TARGET_64BIT.
+       (fix_truncsfdi2, floatdidf2, floatdisf2): Likewise.
+       (floatsidf2, floatsisf2): Likewise, but no TARGET_FLOAT64 dependency.
+       (movdi_internal2): Don't allow the source operand to be sign-extended.
+       Add alternatives for float registers.
+       (*movdi_internal2_extend): New.  Version of movdi_internal2 that
+       allows sign-extension.
+       (*movdi_internal2_mips16): Name the existing mips16 movdi pattern.
+       (movsi_internal2): Rename to movsi_internal.  Add alternatives for
+       float registers.  Remove TARGET_DEBUG_H_MODE test.
+       (movhi_internal1): Rename to movhi_internal.  Don't check
+       TARGET_DEBUG_H_MODE.  Fix transposed *d and *f source constraints.
+       (movqi_internal1): Rename to movqi_internal and remove
+       TARGET_DEBUG_H_MODE dependency.
+       (movsi_internal1, movhi_internal2, movqi_internal2): Remove.
+
 2002-07-16  Jim Wilson  <wilson@redhat.com>
 
        * toplev.c (lang_dependent_init): Create function context for
index 0b585a5..01bd254 100644 (file)
@@ -98,6 +98,7 @@ extern const char      *mips_fill_delay_slot PARAMS ((const char *,
                                                      rtx));
 extern const char      *mips_move_1word PARAMS ((rtx *, rtx, int));
 extern const char      *mips_move_2words PARAMS ((rtx *, rtx));
+extern const char      *mips_sign_extend PARAMS ((rtx, rtx, rtx));
 extern const char      *mips_emit_prefetch PARAMS ((rtx *));
 extern const char      *mips_restore_gp PARAMS ((rtx *, rtx));
 extern const char      *output_block_move PARAMS ((rtx, rtx *, int,
index 64c458f..56225f4 100644 (file)
@@ -1200,9 +1200,11 @@ move_operand (op, mode)
 
 /* Return nonzero if OPERAND is valid as a source operand for movdi.
    This accepts not only general_operand, but also sign extended
-   constants and registers.  We need to accept sign extended constants
+   move_operands.  Note that we need to accept sign extended constants
    in case a sign extended register which is used in an expression,
-   and is equivalent to a constant, is spilled.  */
+   and is equivalent to a constant, is spilled.  We need to accept
+   sign-extended memory in order to reload registers from stack slots,
+   and so that we generate efficient code for extendsidi2.  */
 
 int
 movdi_operand (op, mode)
@@ -1213,11 +1215,7 @@ movdi_operand (op, mode)
       && mode == DImode
       && GET_CODE (op) == SIGN_EXTEND
       && GET_MODE (op) == DImode
-      && (GET_MODE (XEXP (op, 0)) == SImode
-         || (GET_CODE (XEXP (op, 0)) == CONST_INT
-             && GET_MODE (XEXP (op, 0)) == VOIDmode))
-      && (register_operand (XEXP (op, 0), SImode)
-         || immediate_operand (XEXP (op, 0), SImode)))
+      && move_operand (XEXP (op, 0), SImode))
     return 1;
 
   return (general_operand (op, mode)
@@ -1326,26 +1324,6 @@ se_nonmemory_operand (op, mode)
   return nonmemory_operand (op, mode);
 }
 
-/* Like nonimmediate_operand, but when in 64 bit mode also accept a
-   sign extend of a 32 bit register, since the value is known to be
-   already sign extended.  */
-
-int
-se_nonimmediate_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (TARGET_64BIT
-      && mode == DImode
-      && GET_CODE (op) == SIGN_EXTEND
-      && GET_MODE (op) == DImode
-      && GET_MODE (XEXP (op, 0)) == SImode
-      && register_operand (XEXP (op, 0), SImode))
-    return 1;
-
-  return nonimmediate_operand (op, mode);
-}
-
 /* Accept any operand that can appear in a mips16 constant table
    instruction.  We can't use any of the standard operand functions
    because for these instructions we accept values that are not
@@ -2464,6 +2442,33 @@ mips_restore_gp (operands, insn)
   return mips_move_1word (operands, insn, 0);
 }
 \f
+/* Return an instruction to sign-extend SImode value SRC and store it
+   in DImode value DEST.  INSN is the original extendsidi2-type insn.  */
+
+const char *
+mips_sign_extend (insn, dest, src)
+     rtx insn, dest, src;
+{
+  rtx operands[MAX_RECOG_OPERANDS];
+
+  if ((register_operand (src, SImode) && FP_REG_P (true_regnum (src)))
+      || memory_operand (src, SImode))
+    {
+      /* If the source is a floating-point register, we need to use a
+        32-bit move, since the float register is not kept sign-extended.
+        If the source is in memory, we need a 32-bit load.  */
+      operands[0] = gen_lowpart_SUBREG (SImode, dest);
+      operands[1] = src;
+      return mips_move_1word (operands, insn, false);
+    }
+  else
+    {
+      operands[0] = dest;
+      operands[1] = src;
+      return mips_move_2words (operands, insn);
+    }
+}
+\f
 /* Return the appropriate instructions to move 2 words */
 
 const char *
@@ -2480,6 +2485,9 @@ mips_move_2words (operands, insn)
   int subreg_offset1 = 0;
   enum delay_type delay = DELAY_NONE;
 
+  if (code1 == SIGN_EXTEND)
+    return mips_sign_extend (insn, op0, XEXP (op1, 0));
+
   while (code0 == SUBREG)
     {
       subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
@@ -2490,12 +2498,6 @@ mips_move_2words (operands, insn)
       code0 = GET_CODE (op0);
     }
 
-  if (code1 == SIGN_EXTEND)
-    {
-      op1 = XEXP (op1, 0);
-      code1 = GET_CODE (op1);
-    }
-
   while (code1 == SUBREG)
     {
       subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
@@ -2506,17 +2508,6 @@ mips_move_2words (operands, insn)
       code1 = GET_CODE (op1);
     }
 
-  /* Sanity check.  */
-  if (GET_CODE (operands[1]) == SIGN_EXTEND
-      && code1 != REG
-      && code1 != CONST_INT
-      /* The following three can happen as the result of a questionable
-        cast.  */
-      && code1 != LABEL_REF
-      && code1 != SYMBOL_REF
-      && code1 != CONST)
-    abort ();
-
   if (code0 == REG)
     {
       int regno0 = REGNO (op0) + subreg_offset0;
@@ -5406,10 +5397,12 @@ override_options ()
                         the value, not about whether math works on the
                         register.  */
                      || (mips_abi == ABI_MEABI && size <= 4))
-                   && (class == MODE_FLOAT
-                       || class == MODE_COMPLEX_FLOAT
-                       || (TARGET_DEBUG_H_MODE && class == MODE_INT))
-                   && size <= UNITS_PER_FPVALUE);
+                   && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+                        && size <= UNITS_PER_FPVALUE)
+                       /* Allow integer modes that fit into a single
+                          register.  We need to put integers into FPRs
+                          when using instructions like cvt and trunc.  */
+                       || (class == MODE_INT && size <= UNITS_PER_FPREG)));
 
          else if (MD_REG_P (regno))
            temp = (class == MODE_INT
@@ -8319,6 +8312,18 @@ mips_secondary_reload_class (class, mode, x, in_p)
          if (GET_CODE (x) == REG)
            regno = REGNO (x) + off;
        }
+
+      /* 64-bit floating-point registers don't store 32-bit values
+        in sign-extended form.  The only way we can reload
+        (sign_extend:DI (reg:SI $f0)) is by moving $f0 into
+        an integer register using a 32-bit move.  */
+      if (FP_REG_P (regno))
+       return (class == GR_REGS ? NO_REGS : GR_REGS);
+
+      /* For the same reason, we can only reload (sign_extend:DI FOO) into
+        a floating-point register when FOO is an integer register. */
+      if (class == FP_REGS)
+       return (GP_REG_P (regno) ? NO_REGS : GR_REGS);
     }
 
   else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
@@ -8378,6 +8383,37 @@ mips_secondary_reload_class (class, mode, x, in_p)
       return class == GR_REGS ? NO_REGS : GR_REGS;
     }
 
+  if (class == FP_REGS)
+    {
+      if (GET_CODE (x) == MEM)
+       {
+         /* In this case we can use lwc1, swc1, ldc1 or sdc1. */
+         return NO_REGS;
+       }
+      else if (CONSTANT_P (x) && GET_MODE_CLASS (mode) == MODE_FLOAT)
+       {
+         /* We can use the l.s and l.d macros to load floating-point
+            constants.  ??? For l.s, we could probably get better
+            code by returning GR_REGS here.  */
+         return NO_REGS;
+       }
+      else if (GP_REG_P (regno) || x == CONST0_RTX (mode))
+       {
+         /* In this case we can use mtc1, mfc1, dmtc1 or dmfc1.  */
+         return NO_REGS;
+       }
+      else if (FP_REG_P (regno))
+       {
+         /* In this case we can use mov.s or mov.d.  */
+         return NO_REGS;
+       }
+      else
+       {
+         /* Otherwise, we need to reload through an integer register.  */
+         return GR_REGS;
+       }
+    }
+
   /* In mips16 mode, going between memory and anything but M16_REGS
      requires an M16_REG.  */
   if (TARGET_MIPS16)
index 309ea45..238f2b7 100644 (file)
@@ -225,7 +225,6 @@ extern void         sbss_section PARAMS ((void));
 #define MASK_DEBUG_E   0               /* function_arg debug */
 #define MASK_DEBUG_F   0               /* ??? */
 #define MASK_DEBUG_G   0               /* don't support 64 bit arithmetic */
-#define MASK_DEBUG_H   0               /* allow ints in FP registers */
 #define MASK_DEBUG_I   0               /* unused */
 
                                        /* Dummy switches used only in specs */
@@ -253,7 +252,6 @@ extern void         sbss_section PARAMS ((void));
 #define TARGET_DEBUG_E_MODE    (target_flags & MASK_DEBUG_E)
 #define TARGET_DEBUG_F_MODE    (target_flags & MASK_DEBUG_F)
 #define TARGET_DEBUG_G_MODE    (target_flags & MASK_DEBUG_G)
-#define TARGET_DEBUG_H_MODE    (target_flags & MASK_DEBUG_H)
 #define TARGET_DEBUG_I_MODE    (target_flags & MASK_DEBUG_I)
 
                                        /* Reg. Naming in .s ($21 vs. $a0) */
@@ -585,8 +583,6 @@ extern void         sbss_section PARAMS ((void));
      NULL},                                                            \
   {"debugg",             MASK_DEBUG_G,                                 \
      NULL},                                                            \
-  {"debugh",             MASK_DEBUG_H,                                 \
-     NULL},                                                            \
   {"debugi",             MASK_DEBUG_I,                                 \
      NULL},                                                            \
   {"",                   (TARGET_DEFAULT                               \
@@ -783,6 +779,11 @@ extern void                sbss_section PARAMS ((void));
                                  || ISA_MIPS64)                        \
                                 && !TARGET_MIPS16)
 
+/* True if trunc.w.s and trunc.w.d are real (not synthetic)
+   instructions.  Both require TARGET_HARD_FLOAT, and trunc.w.d
+   also requires TARGET_DOUBLE_FLOAT.  */
+#define ISA_HAS_TRUNC_W                (!ISA_MIPS1)
+
 /* CC1_SPEC causes -mips3 and -mips4 to set -mfp64 and -mgp64; -mips1 or
    -mips2 sets -mfp32 and -mgp32.  This can be overridden by an explicit
    -mfp32, -mfp64, -mgp32 or -mgp64.  -mfp64 sets MASK_FLOAT64 in
@@ -2243,17 +2244,20 @@ extern enum reg_class mips_char_to_class[256];
 
 /* If defined, gives a class of registers that cannot be used as the
    operand of a SUBREG that changes the mode of the object illegally.
-   When FP regs are larger than integer regs... Er, anyone remember what
-   goes wrong?
 
    In little-endian mode, the hi-lo registers are numbered backwards,
    so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
-   word as intended.  */
+   word as intended.
+
+   Also, loading a 32-bit value into a 64-bit floating-point register
+   will not sign-extend the value, despite what LOAD_EXTEND_OP says.
+   We can't allow 64-bit float registers to change from a 32-bit
+   mode to a 64-bit mode.  */
 
 #define CLASS_CANNOT_CHANGE_MODE                                       \
   (TARGET_BIG_ENDIAN                                                   \
-   ? (TARGET_FLOAT64 && ! TARGET_64BIT ? FP_REGS : NO_REGS)            \
-   : (TARGET_FLOAT64 && ! TARGET_64BIT ? HI_AND_FP_REGS : HI_REG))
+   ? (TARGET_FLOAT64 ? FP_REGS : NO_REGS)                              \
+   : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
 
 /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */
 
@@ -3677,7 +3681,6 @@ typedef struct mips_args {
   {"se_nonmemory_operand",     { CONST_INT, CONST_DOUBLE, CONST,       \
                                  SYMBOL_REF, LABEL_REF, SUBREG,        \
                                  REG, SIGN_EXTEND }},                  \
-  {"se_nonimmediate_operand",   { SUBREG, REG, MEM, SIGN_EXTEND }},    \
   {"consttable_operand",       { LABEL_REF, SYMBOL_REF, CONST_INT,     \
                                  CONST_DOUBLE, CONST }},               \
   {"extend_operator",           { SIGN_EXTEND, ZERO_EXTEND }},          \
index 1205e52..c832878 100644 (file)
@@ -4122,16 +4122,14 @@ move\\t%0,%z4\\n\\
 ;; In 64 bit mode, 32 bit values in general registers are always
 ;; correctly sign extended.  That means that if the target is a
 ;; general register, we can sign extend from SImode to DImode just by
-;; doing a move.
+;; doing a move.  The matching define_insns are *movdi_internal2_extend
+;; and *movdi_internal2_mips16.
 
-(define_insn "extendsidi2"
-  [(set (match_operand:DI 0 "register_operand" "=d,y,d,*d,d,d")
-       (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x,R,m")))]
+(define_expand "extendsidi2"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
   "TARGET_64BIT"
-  "* return mips_move_1word (operands, insn, FALSE);"
-  [(set_attr "type"    "move,move,move,hilo,load,load")
-   (set_attr "mode"    "DI")
-   (set_attr "length"  "4,4,4,4,4,8")])
+  "")
 
 ;; These patterns originally accepted general_operands, however, slightly
 ;; better code is generated by only accepting register_operands, and then
@@ -4307,65 +4305,67 @@ move\\t%0,%z4\\n\\
 ;;
 ;;  ....................
 
-;; The SImode scratch register can not be shared with address regs used for
-;; operand zero, because then the address in the move instruction will be
-;; clobbered.  We mark the scratch register as early clobbered to prevent this.
-
-;; We need the ?X in alternative 1 so that it will be chosen only if the
-;; destination is a floating point register.  Otherwise, alternative 1 can
-;; have lower cost than alternative 0 (because there is one less loser), and
-;; can be chosen when it won't work (because integral reloads into FP
-;; registers are not supported).
-
-(define_insn "fix_truncdfsi2"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,*f,R,To")
-       (fix:SI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
-   (clobber (match_scratch:SI 2 "=d,*d,&d,&d"))
-   (clobber (match_scratch:DF 3 "=f,?*X,f,f"))]
+(define_expand "fix_truncdfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:DF 1 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
-  "*
 {
-  rtx xoperands[10];
-
-  if (which_alternative == 1)
-    return \"trunc.w.d %0,%1,%2\";
-
-  output_asm_insn (\"trunc.w.d %3,%1,%2\", operands);
+  if (!ISA_HAS_TRUNC_W)
+    {
+      emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1]));
+      DONE;
+    }
+})
 
-  xoperands[0] = operands[0];
-  xoperands[1] = operands[3];
-  output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
-  return \"\";
-}"
+(define_insn "fix_truncdfsi2_insn"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:DF 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W"
+  "trunc.w.d %0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "44,36,40,44")])
-
+   (set_attr "length"  "4")])
+
+(define_insn "fix_truncdfsi2_macro"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:DF 1 "register_operand" "f")))
+   (clobber (match_scratch:DF 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
+  "trunc.w.d %0,%1,%2"
+  [(set_attr "type"    "fcvt")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "36")])
 
-(define_insn "fix_truncsfsi2"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,*f,R,To")
-       (fix:SI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
-   (clobber (match_scratch:SI 2 "=d,*d,&d,&d"))
-   (clobber (match_scratch:SF 3 "=f,?*X,f,f"))]
+(define_expand "fix_truncsfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:SF 1 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
-  "*
 {
-  rtx xoperands[10];
-
-  if (which_alternative == 1)
-    return \"trunc.w.s %0,%1,%2\";
-
-  output_asm_insn (\"trunc.w.s %3,%1,%2\", operands);
+  if (!ISA_HAS_TRUNC_W)
+    {
+      emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1]));
+      DONE;
+    }
+})
 
-  xoperands[0] = operands[0];
-  xoperands[1] = operands[3];
-  output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
-  return \"\";
-}"
+(define_insn "fix_truncsfsi2_insn"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W"
+  "trunc.w.s %0,%1"
   [(set_attr "type"    "fcvt")
-   (set_attr "mode"    "SF")
-   (set_attr "length"  "44,36,40,44")])
-
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "4")])
+
+(define_insn "fix_truncsfsi2_macro"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (match_operand:SF 1 "register_operand" "f")))
+   (clobber (match_scratch:SF 2 "=d"))]
+  "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
+  "trunc.w.s %0,%1,%2"
+  [(set_attr "type"    "fcvt")
+   (set_attr "mode"    "DF")
+   (set_attr "length"  "36")])
 
 ;;; ??? trunc.l.d is mentioned in the appendix of the 1993 r4000/r4600 manuals
 ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
@@ -4377,122 +4377,66 @@ move\\t%0,%z4\\n\\
 ;;; If this is disabled, then fixuns_truncdfdi2 must be disabled also.
 
 (define_insn "fix_truncdfdi2"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,*f,R,To")
-       (fix:DI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
-   (clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
-  "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  rtx xoperands[10];
-
-  if (which_alternative == 1)
-    return \"trunc.l.d %0,%1\";
-
-  output_asm_insn (\"trunc.l.d %2,%1\", operands);
-
-  xoperands[0] = operands[0];
-  xoperands[1] = operands[2];
-  output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
-  return \"\";
-}"
+  [(set (match_operand:DI 0 "register_operand" "=f")
+       (fix:DI (match_operand:DF 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
+  "trunc.l.d %0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "8,4,8,12")])
+   (set_attr "length"  "4")])
 
 
 ;;; ??? trunc.l.s is mentioned in the appendix of the 1993 r4000/r4600 manuals
 ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
 ;;; in the 1991 manuals.  The r4000 at Cygnus does not have this instruction.
 (define_insn "fix_truncsfdi2"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,*f,R,To")
-       (fix:DI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
-   (clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
-  "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  rtx xoperands[10];
-
-  if (which_alternative == 1)
-    return \"trunc.l.s %0,%1\";
-
-  output_asm_insn (\"trunc.l.s %2,%1\", operands);
-
-  xoperands[0] = operands[0];
-  xoperands[1] = operands[2];
-  output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
-  return \"\";
-}"
+  [(set (match_operand:DI 0 "register_operand" "=f")
+       (fix:DI (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
+  "trunc.l.s %0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "SF")
-   (set_attr "length"  "8,4,8,12")])
+   (set_attr "length"  "4")])
 
 
 (define_insn "floatsidf2"
-  [(set (match_operand:DF 0 "register_operand" "=f,f,f")
-       (float:DF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (float:DF (match_operand:SI 1 "register_operand" "f")))]
   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  dslots_load_total++;
-  if (GET_CODE (operands[1]) == MEM)
-    return \"l.s\\t%0,%1%#\;cvt.d.w\\t%0,%0\";
-
-  return \"mtc1\\t%1,%0%#\;cvt.d.w\\t%0,%0\";
-}"
+  "cvt.d.w\\t%0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "12,16,12")])
+   (set_attr "length"  "4")])
 
 
 (define_insn "floatdidf2"
-  [(set (match_operand:DF 0 "register_operand" "=f,f,f")
-       (float:DF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
-  "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  dslots_load_total++;
-  if (GET_CODE (operands[1]) == MEM)
-    return \"l.d\\t%0,%1%#\;cvt.d.l\\t%0,%0\";
-
-  return \"dmtc1\\t%1,%0%#\;cvt.d.l\\t%0,%0\";
-}"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (float:DF (match_operand:DI 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
+  "cvt.d.l\\t%0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "DF")
-   (set_attr "length"  "12,16,12")])
+   (set_attr "length"  "4")])
 
 
 (define_insn "floatsisf2"
-  [(set (match_operand:SF 0 "register_operand" "=f,f,f")
-       (float:SF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (float:SF (match_operand:SI 1 "register_operand" "f")))]
   "TARGET_HARD_FLOAT"
-  "*
-{
-  dslots_load_total++;
-  if (GET_CODE (operands[1]) == MEM)
-    return \"l.s\\t%0,%1%#\;cvt.s.w\\t%0,%0\";
-
-  return \"mtc1\\t%1,%0%#\;cvt.s.w\\t%0,%0\";
-}"
+  "cvt.s.w\\t%0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "SF")
-   (set_attr "length"  "12,16,12")])
+   (set_attr "length"  "4")])
 
 
 (define_insn "floatdisf2"
-  [(set (match_operand:SF 0 "register_operand" "=f,f,f")
-       (float:SF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
-  "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
-  "*
-{
-  dslots_load_total++;
-  if (GET_CODE (operands[1]) == MEM)
-    return \"l.d\\t%0,%1%#\;cvt.s.l\\t%0,%0\";
-
-  return \"dmtc1\\t%1,%0%#\;cvt.s.l\\t%0,%0\";
-}"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (float:SF (match_operand:DI 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
+  "cvt.s.l\\t%0,%1"
   [(set_attr "type"    "fcvt")
    (set_attr "mode"    "SF")
-   (set_attr "length"  "12,16,12")])
+   (set_attr "length"  "4")])
 
 
 (define_expand "fixuns_truncdfsi2"
@@ -5140,19 +5084,44 @@ move\\t%0,%z4\\n\\
   "")
 
 (define_insn "movdi_internal2"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
-       (match_operand:DI 1 "movdi_operand" "d,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,*f,*d,*R,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
+       (match_operand:DI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
   "TARGET_64BIT && !TARGET_MIPS16
    && (register_operand (operands[0], DImode)
-       || se_register_operand (operands[1], DImode)
+       || 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); "
-  [(set_attr "type"    "move,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+  [(set_attr "type"    "move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
    (set_attr "mode"    "DI")
-   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,8,8,8,8,8,8,8")])
+   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,8,8,8,8,8,8,8")])
 
-(define_insn ""
+;; 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_extend"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
+       (sign_extend:DI (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D")))]
+  "TARGET_64BIT && !TARGET_MIPS16
+   && (register_operand (operands[0], DImode)
+       || register_operand (operands[1], DImode)
+       || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+       || operands[1] == CONST0_RTX (DImode))"
+  "* return mips_sign_extend (insn, operands[0], operands[1]);"
+  [(set_attr "type"    "move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+   (set_attr "mode"    "DI")
+   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,4,4,8,8,8,8,8,8,8")])
+
+(define_insn "*movdi_internal2_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d")
        (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,*x"))]
   "TARGET_64BIT && TARGET_MIPS16
@@ -5535,29 +5504,17 @@ move\\t%0,%z4\\n\\
 ;; The difference between these two is whether or not ints are allowed
 ;; in FP registers (off by default, use -mdebugh to enable).
 
-(define_insn "movsi_internal1"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
-       (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
-  "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
-   && (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);"
-  [(set_attr "type"    "move,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
-   (set_attr "mode"    "SI")
-   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4,4,4,8,4,4,8")])
-
-(define_insn "movsi_internal2"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
-       (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
-  "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16
+(define_insn "movsi_internal"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,?*f,*d,*R,*m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
+       (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
+  "!TARGET_MIPS16
    && (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);"
-  [(set_attr "type"    "move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
+  [(set_attr "type"    "move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
    (set_attr "mode"    "SI")
-   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])
+   (set_attr "length"  "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])
 
 ;; This is the mips16 movsi instruction.  We accept a small integer as
 ;; the source if the destination is a GP memory reference.  This is
@@ -6041,10 +5998,10 @@ move\\t%0,%z4\\n\\
 ;; The difference between these two is whether or not ints are allowed
 ;; in FP registers (off by default, use -mdebugh to enable).
 
-(define_insn "movhi_internal1"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f,*f*z,*x,*d")
+(define_insn "movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
        (match_operand:HI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
-  "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
+  "!TARGET_MIPS16
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
@@ -6053,18 +6010,6 @@ move\\t%0,%z4\\n\\
    (set_attr "mode"    "HI")
    (set_attr "length"  "4,4,4,8,4,8,4,4,4,4,4")])
 
-(define_insn "movhi_internal2"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
-       (match_operand:HI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
-  "!TARGET_DEBUG_H_MODE && !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);"
-  [(set_attr "type"    "move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
-   (set_attr "mode"    "HI")
-   (set_attr "length"  "4,4,4,8,4,8,4,4,4,4")])
-
 (define_insn ""
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
        (match_operand:HI 1 "general_operand"      "d,d,y,K,N,R,m,d,d,*x"))]
@@ -6163,10 +6108,10 @@ move\\t%0,%z4\\n\\
 ;; The difference between these two is whether or not ints are allowed
 ;; in FP registers (off by default, use -mdebugh to enable).
 
-(define_insn "movqi_internal1"
+(define_insn "movqi_internal"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
        (match_operand:QI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
-  "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
+  "!TARGET_MIPS16
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode)
        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
@@ -6175,18 +6120,6 @@ move\\t%0,%z4\\n\\
    (set_attr "mode"    "QI")
    (set_attr "length"  "4,4,4,8,4,8,4,4,4,4,4")])
 
-(define_insn "movqi_internal2"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
-       (match_operand:QI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
-  "!TARGET_DEBUG_H_MODE && !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);"
-  [(set_attr "type"    "move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
-   (set_attr "mode"    "QI")
-   (set_attr "length"  "4,4,4,8,4,8,4,4,4,4")])
-
 (define_insn ""
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
        (match_operand:QI 1 "general_operand"      "d,d,y,K,N,R,m,d,d,*x"))]