mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset rather than gen_lowpart to...
authorRichard Sandiford <rsandifo@nildram.co.uk>
Sun, 30 Sep 2007 22:50:02 +0000 (22:50 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 30 Sep 2007 22:50:02 +0000 (22:50 +0000)
gcc/
* config/mips/mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset
rather than gen_lowpart to change a register from DImode to DFmode.
(mips_cannot_change_mode_class): Only allow FPRs to change mode if
both FROM and TO are integer modes that are no bigger than 4 bytes.
(mips_mode_ok_for_mov_fmt_p): New function.
(mips_preferred_reload_class): Use it instead of FLOAT_MODE_P.
(mips_secondary_reload_class): Tweak formatting and comments.
Use reg_class_subset_p instead of direct comparisons with
classes.  Only allow direct FPR<->FPR moves for modes that
satisfy mips_mode_ok_for_mov_fmt_p.  Only allow loads and stores
for 4- and 8-byte types.  Handle reloads in which X is an FPR.
* config/mips/mips.md (*movdi_gp32_fp64): Remove f<-f alternative.
(*movdi_64bit): Likewise.
(*movsi_internal): Likewise.
(*movhi_internal): Likewise.
(*movqi_internal): Likewise.

From-SVN: r128894

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.md

index eef9e94799bb91791ebfb1fb430fd9a2f8322eb4..5c1fdc0566cc562248ebe29b01173a72d88e9046 100644 (file)
@@ -1,3 +1,22 @@
+2007-09-30  Richard Sandiford  <rsandifo@nildram.co.uk>
+
+       * config/mips/mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset
+       rather than gen_lowpart to change a register from DImode to DFmode.
+       (mips_cannot_change_mode_class): Only allow FPRs to change mode if
+       both FROM and TO are integer modes that are no bigger than 4 bytes.
+       (mips_mode_ok_for_mov_fmt_p): New function.
+       (mips_preferred_reload_class): Use it instead of FLOAT_MODE_P.
+       (mips_secondary_reload_class): Tweak formatting and comments.
+       Use reg_class_subset_p instead of direct comparisons with
+       classes.  Only allow direct FPR<->FPR moves for modes that
+       satisfy mips_mode_ok_for_mov_fmt_p.  Only allow loads and stores
+       for 4- and 8-byte types.  Handle reloads in which X is an FPR.
+       * config/mips/mips.md (*movdi_gp32_fp64): Remove f<-f alternative.
+       (*movdi_64bit): Likewise.
+       (*movsi_internal): Likewise.
+       (*movhi_internal): Likewise.
+       (*movqi_internal): Likewise.
+
 2007-09-30  Diego Novillo  <dnovillo@google.com>
 
        PR 33593
index dbb7149b86e892cfb6bdd67873fcb2eb34f9f68d..6ac976abe6e9a83f1b59eeeadbf160e4d6403d97 100644 (file)
@@ -3547,7 +3547,8 @@ mips_split_64bit_move (rtx dest, rtx src)
       /* Loading an FPR from memory or from GPRs.  */
       if (ISA_HAS_MXHC1)
        {
-         dest = gen_lowpart (DFmode, dest);
+         if (GET_MODE (dest) != DFmode)
+           dest = gen_rtx_REG_offset (dest, DFmode, REGNO (dest), 0);
          emit_insn (gen_load_df_low (dest, mips_subword (src, 0)));
          emit_insn (gen_mthc1 (dest, mips_subword (src, 1),
                                copy_rtx (dest)));
@@ -3565,7 +3566,8 @@ mips_split_64bit_move (rtx dest, rtx src)
       /* Storing an FPR into memory or GPRs.  */
       if (ISA_HAS_MXHC1)
        {
-         src = gen_lowpart (DFmode, src);
+         if (GET_MODE (src) != DFmode)
+           src = gen_rtx_REG_offset (src, DFmode, REGNO (src), 0);
          mips_emit_move (mips_subword (dest, 0), mips_subword (src, 0));
          emit_insn (gen_mfhc1 (mips_subword (dest, 1), src));
        }
@@ -9314,44 +9316,38 @@ mips_callee_copies (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
    to mode TO.  */
 
 bool
-mips_cannot_change_mode_class (enum machine_mode from,
-                              enum machine_mode to, enum reg_class class)
+mips_cannot_change_mode_class (enum machine_mode from ATTRIBUTE_UNUSED,
+                              enum machine_mode to ATTRIBUTE_UNUSED,
+                              enum reg_class class)
 {
-  if (MIN (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) <= UNITS_PER_WORD
-      && MAX (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) > UNITS_PER_WORD)
-    {
-      if (TARGET_BIG_ENDIAN)
-       {
-         /* When a multi-word value is stored in paired floating-point
-            registers, the first register always holds the low word.
-            We therefore can't allow FPRs to change between single-word
-            and multi-word modes.  */
-         if (MAX_FPRS_PER_FMT > 1 && reg_classes_intersect_p (FP_REGS, class))
-           return true;
-       }
-    }
+  /* There are several problems with changing the modes of values
+     in floating-point registers:
 
-  /* gcc assumes that each word of a multiword register can be accessed
-     individually using SUBREGs.  This is not true for floating-point
-     registers if they are bigger than a word.  */
-  if (UNITS_PER_FPREG > UNITS_PER_WORD
-      && GET_MODE_SIZE (from) > UNITS_PER_WORD
-      && GET_MODE_SIZE (to) < UNITS_PER_FPREG
-      && reg_classes_intersect_p (FP_REGS, class))
-    return true;
+     - When a multi-word value is stored in paired floating-point
+       registers, the first register always holds the low word.
+       We therefore can't allow FPRs to change between single-word
+       and multi-word modes on big-endian targets.
 
-  /* 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 SImode to
-     to a wider mode.  */
-  if (TARGET_64BIT
-      && TARGET_FLOAT64
-      && from == SImode
-      && GET_MODE_SIZE (to) >= UNITS_PER_WORD
-      && reg_classes_intersect_p (FP_REGS, class))
-    return true;
+     - GCC assumes that each word of a multiword register can be accessed
+       individually using SUBREGs.  This is not true for floating-point
+       registers if they are bigger than a word.
 
-  return false;
+     - 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 FPRs to change from SImode to to a wider mode on
+       64-bit targets.
+
+     - If the FPU has already interpreted a value in one format, we must
+       not ask it to treat the value as having a different format.
+
+     We therefore only allow changes between 4-byte and smaller integer
+     values, all of which have the "W" format as far as the FPU is
+     concerned.  */
+  return (reg_classes_intersect_p (FP_REGS, class)
+         && (GET_MODE_CLASS (from) != MODE_INT
+             || GET_MODE_CLASS (to) != MODE_INT
+             || GET_MODE_SIZE (from) > 4
+             || GET_MODE_SIZE (to) > 4));
 }
 
 /* Return true if X should not be moved directly into register $25.
@@ -9367,6 +9363,27 @@ mips_dangerous_for_la25_p (rtx x)
          && mips_global_symbol_p (x));
 }
 
+/* Return true if moves in mode MODE can use the FPU's mov.fmt instruction.  */
+
+static bool
+mips_mode_ok_for_mov_fmt_p (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case SFmode:
+      return TARGET_HARD_FLOAT;
+
+    case DFmode:
+      return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT;
+
+    case V2SFmode:
+      return TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT;
+
+    default:
+      return false;
+    }
+}
+
 /* Implement PREFERRED_RELOAD_CLASS.  */
 
 enum reg_class
@@ -9375,9 +9392,8 @@ mips_preferred_reload_class (rtx x, enum reg_class class)
   if (mips_dangerous_for_la25_p (x) && reg_class_subset_p (LEA_REGS, class))
     return LEA_REGS;
 
-  if (TARGET_HARD_FLOAT
-      && FLOAT_MODE_P (GET_MODE (x))
-      && reg_class_subset_p (FP_REGS, class))
+  if (reg_class_subset_p (FP_REGS, class)
+      && mips_mode_ok_for_mov_fmt_p (GET_MODE (x)))
     return FP_REGS;
 
   if (reg_class_subset_p (GR_REGS, class))
@@ -9399,110 +9415,81 @@ enum reg_class
 mips_secondary_reload_class (enum reg_class class,
                             enum machine_mode mode, rtx x, int in_p)
 {
-  enum reg_class gr_regs = TARGET_MIPS16 ? M16_REGS : GR_REGS;
-  int regno = -1;
-  int gp_reg_p;
-
-  if (REG_P (x)|| GET_CODE (x) == SUBREG)
-    regno = true_regnum (x);
-
-  gp_reg_p = TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);
+  int regno;
 
+  /* If X is a constant that cannot be loaded into $25, it must be loaded
+     into some other GPR.  No other register class allows a direct move.  */
   if (mips_dangerous_for_la25_p (x))
+    return reg_class_subset_p (class, LEA_REGS) ? NO_REGS : LEA_REGS;
+
+  regno = true_regnum (x);
+  if (TARGET_MIPS16)
     {
-      gr_regs = LEA_REGS;
-      if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], 25))
-       return gr_regs;
+      /* In MIPS16 mode, every move must involve a member of M16_REGS.  */
+      if (!reg_class_subset_p (class, M16_REGS) && !M16_REG_P (regno))
+       return M16_REGS;
+
+      /* We can't really copy to HI or LO at all in MIPS16 mode.  */
+      if (in_p ? reg_classes_intersect_p (class, ACC_REGS) : ACC_REG_P (regno))
+       return M16_REGS;
+
+      return NO_REGS;
     }
 
-  /* Copying from HI or LO to anywhere other than a general register
-     requires a general register.
-     This rule applies to both the original HI/LO pair and the new
-     DSP accumulators.  */
+  /* Copying from accumulator registers to anywhere other than a general
+     register requires a temporary general register.  */
   if (reg_class_subset_p (class, ACC_REGS))
-    {
-      if (TARGET_MIPS16 && in_p)
-       {
-         /* We can't really copy to HI or LO at all in mips16 mode.  */
-         return M16_REGS;
-       }
-      return gp_reg_p ? NO_REGS : gr_regs;
-    }
+    return GP_REG_P (regno) ? NO_REGS : GR_REGS;
   if (ACC_REG_P (regno))
-    {
-      if (TARGET_MIPS16 && ! in_p)
-       {
-         /* We can't really copy to HI or LO at all in mips16 mode.  */
-         return M16_REGS;
-       }
-      return class == gr_regs ? NO_REGS : gr_regs;
-    }
+    return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS;
 
   /* We can only copy a value to a condition code register from a
      floating point register, and even then we require a scratch
      floating point register.  We can only copy a value out of a
      condition code register into a general register.  */
-  if (class == ST_REGS)
+  if (reg_class_subset_p (class, ST_REGS))
     {
       if (in_p)
        return FP_REGS;
-      return gp_reg_p ? NO_REGS : gr_regs;
+      return GP_REG_P (regno) ? NO_REGS : GR_REGS;
     }
   if (ST_REG_P (regno))
     {
-      if (! in_p)
+      if (!in_p)
        return FP_REGS;
-      return class == gr_regs ? NO_REGS : gr_regs;
+      return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS;
     }
 
-  if (class == FP_REGS)
+  if (reg_class_subset_p (class, FP_REGS))
     {
-      if (MEM_P (x))
-       {
-         /* 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 || 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;
-       }
-    }
+      if (MEM_P (x)
+         && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
+       /* In this case we can use lwc1, swc1, ldc1 or sdc1.  We'll use
+          pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported.  */
+       return NO_REGS;
 
-  /* In mips16 mode, going between memory and anything but M16_REGS
-     requires an M16_REG.  */
-  if (TARGET_MIPS16)
-    {
-      if (class != M16_REGS && class != M16_NA_REGS)
+      if (GP_REG_P (regno) || x == CONST0_RTX (mode))
+       /* In this case we can use mtc1, mfc1, dmtc1 or dmfc1.  */
+       return NO_REGS;
+
+      if (mips_mode_ok_for_mov_fmt_p (mode))
        {
-         if (gp_reg_p)
+         if (CONSTANT_P (x))
+           /* We can force the constants to memory and use lwc1
+              and ldc1.  As above, we will use pairs of lwc1s if
+              ldc1 is not supported.  */
            return NO_REGS;
-         return M16_REGS;
-       }
-      if (! gp_reg_p)
-       {
-         if (class == M16_REGS || class == M16_NA_REGS)
+
+         if (FP_REG_P (regno))
+           /* In this case we can use mov.fmt.  */
            return NO_REGS;
-         return M16_REGS;
        }
+
+      /* Otherwise, we need to reload through an integer register.  */
+      return GR_REGS;
     }
+  if (FP_REG_P (regno))
+    return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS;
 
   return NO_REGS;
 }
index d687223c382fbcb0709a49ca7bdc1729d2caae8e..890cc706590a21e642a1bde8e5dd45fbb9f28efc 100644 (file)
    (set_attr "length"   "8,16,*,*,8,8,8,*,8,*")])
 
 (define_insn "*movdi_gp32_fp64"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*f,*d,*m")
-       (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*f,*J*d,*m,*f,*f"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*d,*m")
+       (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*J*d,*m,*f,*f"))]
   "!TARGET_64BIT && TARGET_FLOAT64 && !TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "type"    "multi,multi,load,store,mthilo,mfhilo,fmove,mtc,fpload,mfc,fpstore")
+  [(set_attr "type"    "multi,multi,load,store,mthilo,mfhilo,mtc,fpload,mfc,fpstore")
    (set_attr "mode"    "DI")
-   (set_attr "length"   "8,16,*,*,8,8,4,8,*,8,*")])
+   (set_attr "length"   "8,16,*,*,8,8,8,*,8,*")])
 
 (define_insn "*movdi_32bit_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
    (set_attr "length"  "8,8,8,8,12,*,*,8")])
 
 (define_insn "*movdi_64bit"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*x,*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*d,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*x,*B*C*D,*B*C*D,*d,*m")
+       (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*d,*m,*B*C*D,*B*C*D"))]
   "TARGET_64BIT && !TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "type"    "move,const,const,load,store,fmove,mtc,fpload,mfc,fpstore,mthilo,mtc,load,mfc,store")
+  [(set_attr "type"    "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mtc,load,mfc,store")
    (set_attr "mode"    "DI")
-   (set_attr "length"  "4,*,*,*,*,4,4,*,4,*,4,8,*,8,*")])
+   (set_attr "length"  "4,*,*,*,*,4,*,4,*,4,8,*,8,*")])
 
 (define_insn "*movdi_64bit_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m")
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*movsi_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-       (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+       (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], SImode)
        || reg_or_0_operand (operands[1], SImode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "type"    "move,const,const,load,store,fmove,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,load,mfc,store")
+  [(set_attr "type"    "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,load,mfc,store")
    (set_attr "mode"    "SI")
-   (set_attr "length"  "4,*,*,*,*,4,4,*,4,*,4,4,4,4,4,*,4,*")])
+   (set_attr "length"  "4,*,*,*,*,4,*,4,*,4,4,4,4,4,*,4,*")])
 
 (define_insn "*movsi_mips16"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m")
 })
 
 (define_insn "*movhi_internal"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x")
-       (match_operand:HI 1 "move_operand"         "d,I,m,dJ,*f,*d,*f,*d"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*x")
+       (match_operand:HI 1 "move_operand"         "d,I,m,dJ,*f,*d,*d"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], HImode)
        || reg_or_0_operand (operands[1], HImode))"
     sh\t%z1,%0
     mfc1\t%0,%1
     mtc1\t%1,%0
-    mov.s\t%0,%1
     mt%0\t%1"
-  [(set_attr "type"    "move,arith,load,store,mfc,mtc,fmove,mthilo")
+  [(set_attr "type"    "move,arith,load,store,mfc,mtc,mthilo")
    (set_attr "mode"    "HI")
-   (set_attr "length"  "4,4,*,*,4,4,4,4")])
+   (set_attr "length"  "4,4,*,*,4,4,4")])
 
 (define_insn "*movhi_mips16"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m")
 })
 
 (define_insn "*movqi_internal"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x")
-       (match_operand:QI 1 "move_operand"         "d,I,m,dJ,*f,*d,*f,*d"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*x")
+       (match_operand:QI 1 "move_operand"         "d,I,m,dJ,*f,*d,*d"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], QImode)
        || reg_or_0_operand (operands[1], QImode))"
     sb\t%z1,%0
     mfc1\t%0,%1
     mtc1\t%1,%0
-    mov.s\t%0,%1
     mt%0\t%1"
-  [(set_attr "type"    "move,arith,load,store,mfc,mtc,fmove,mthilo")
+  [(set_attr "type"    "move,arith,load,store,mfc,mtc,mthilo")
    (set_attr "mode"    "QI")
-   (set_attr "length"  "4,4,*,*,4,4,4,4")])
+   (set_attr "length"  "4,4,*,*,4,4,4")])
 
 (define_insn "*movqi_mips16"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m")