mips.c (mips_valid_offset_p): New function.
authorRichard Sandiford <rdsandiford@googlemail.com>
Sun, 1 Jun 2008 13:01:23 +0000 (13:01 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 1 Jun 2008 13:01:23 +0000 (13:01 +0000)
gcc/
* config/mips/mips.c (mips_valid_offset_p): New function.
(mips_valid_lo_sum_p): Likewise.
(mips_classify_address): Use them.
(mips_force_address): New function.
(mips_legitimize_address): Use it.
* config/mips/mips.md (MOVE128): New mode iterator.
(movtf): Require TARGET_64BIT.  Remove empty strings.
(*movtf_internal): Rename to...
(*movtf): ...this and require !TARGET_MIPS16.  Use "m" instead
of "R" and use {,fp}{load,store} attributes instead of "multi".
Use a separate define_split.
(*movtf_mips16): New pattern.

gcc/testsuite/
* gcc.target/mips/fpr-moves-7.c: New test.
* gcc.target/mips/fpr-moves-8.c: New test.

From-SVN: r136253

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/fpr-moves-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/fpr-moves-8.c [new file with mode: 0644]

index 624d3386f468809e063969757a08ee57427c7e06..cd13a87e68faa9bf26500d6ea7da82cb29cd7d72 100644 (file)
@@ -1,3 +1,18 @@
+2008-06-01  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * config/mips/mips.c (mips_valid_offset_p): New function.
+       (mips_valid_lo_sum_p): Likewise.
+       (mips_classify_address): Use them.
+       (mips_force_address): New function.
+       (mips_legitimize_address): Use it.
+       * config/mips/mips.md (MOVE128): New mode iterator.
+       (movtf): Require TARGET_64BIT.  Remove empty strings.
+       (*movtf_internal): Rename to...
+       (*movtf): ...this and require !TARGET_MIPS16.  Use "m" instead
+       of "R" and use {,fp}{load,store} attributes instead of "multi".
+       Use a separate define_split.
+       (*movtf_mips16): New pattern.
+
 2008-06-01  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * config/mips/mips-protos.h (mips_expand_before_return): Declare.
index 246600d8b35e3e6c8058e4a36b1fefd85404eb85..551159c9e94c78ef1ad93eda3080295f16340190 100644 (file)
@@ -1809,6 +1809,51 @@ mips_valid_base_register_p (rtx x, enum machine_mode mode, bool strict_p)
          && mips_regno_mode_ok_for_base_p (REGNO (x), mode, strict_p));
 }
 
+/* Return true if, for every base register BASE_REG, (plus BASE_REG X)
+   can address a value of mode MODE.  */
+
+static bool
+mips_valid_offset_p (rtx x, enum machine_mode mode)
+{
+  /* Check that X is a signed 16-bit number.  */
+  if (!const_arith_operand (x, Pmode))
+    return false;
+
+  /* We may need to split multiword moves, so make sure that every word
+     is accessible.  */
+  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+      && !SMALL_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode) - UNITS_PER_WORD))
+    return false;
+
+  return true;
+}
+
+/* Return true if a LO_SUM can address a value of mode MODE when the
+   LO_SUM symbol has type SYMBOL_TYPE.  */
+
+static bool
+mips_valid_lo_sum_p (enum mips_symbol_type symbol_type, enum machine_mode mode)
+{
+  /* Check that symbols of type SYMBOL_TYPE can be used to access values
+     of mode MODE.  */
+  if (mips_symbol_insns (symbol_type, mode) == 0)
+    return false;
+
+  /* Check that there is a known low-part relocation.  */
+  if (mips_lo_relocs[symbol_type] == NULL)
+    return false;
+
+  /* We may need to split multiword moves, so make sure that each word
+     can be accessed without inducing a carry.  This is mainly needed
+     for o64, which has historically only guaranteed 64-bit alignment
+     for 128-bit types.  */
+  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+      && GET_MODE_BITSIZE (mode) > GET_MODE_ALIGNMENT (mode))
+    return false;
+
+  return true;
+}
+
 /* Return true if X is a valid address for machine mode MODE.  If it is,
    fill in INFO appropriately.  STRICT_P is true if REG_OK_STRICT is in
    effect.  */
@@ -1831,7 +1876,7 @@ mips_classify_address (struct mips_address_info *info, rtx x,
       info->reg = XEXP (x, 0);
       info->offset = XEXP (x, 1);
       return (mips_valid_base_register_p (info->reg, mode, strict_p)
-             && const_arith_operand (info->offset, VOIDmode));
+             && mips_valid_offset_p (info->offset, mode));
 
     case LO_SUM:
       info->type = ADDRESS_LO_SUM;
@@ -1849,8 +1894,7 @@ mips_classify_address (struct mips_address_info *info, rtx x,
       info->symbol_type
        = mips_classify_symbolic_expression (info->offset, SYMBOL_CONTEXT_MEM);
       return (mips_valid_base_register_p (info->reg, mode, strict_p)
-             && mips_symbol_insns (info->symbol_type, mode) > 0
-             && mips_lo_relocs[info->symbol_type] != 0);
+             && mips_valid_lo_sum_p (info->symbol_type, mode));
 
     case CONST_INT:
       /* Small-integer addresses don't occur very often, but they
@@ -2473,6 +2517,16 @@ mips_legitimize_tls_address (rtx loc)
   return dest;
 }
 \f
+/* If X is not a valid address for mode MODE, force it into a register.  */
+
+static rtx
+mips_force_address (rtx x, enum machine_mode mode)
+{
+  if (!mips_legitimate_address_p (mode, x, false))
+    x = force_reg (Pmode, x);
+  return x;
+}
+
 /* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
    be legitimized in a way that the generic machinery might not expect,
    put the new address in *XLOC and return true.  MODE is the mode of
@@ -2481,7 +2535,7 @@ mips_legitimize_tls_address (rtx loc)
 bool
 mips_legitimize_address (rtx *xloc, enum machine_mode mode)
 {
-  rtx base;
+  rtx base, addr;
   HOST_WIDE_INT offset;
 
   if (mips_tls_symbol_p (*xloc))
@@ -2491,8 +2545,11 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
     }
 
   /* See if the address can split into a high part and a LO_SUM.  */
-  if (mips_split_symbol (NULL, *xloc, mode, xloc))
-    return true;
+  if (mips_split_symbol (NULL, *xloc, mode, &addr))
+    {
+      *xloc = mips_force_address (addr, mode);
+      return true;
+    }
 
   /* Handle BASE + OFFSET using mips_add_offset.  */
   mips_split_plus (*xloc, &base, &offset);
@@ -2500,7 +2557,8 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
     {
       if (!mips_valid_base_register_p (base, mode, false))
        base = copy_to_mode_reg (Pmode, base);
-      *xloc = mips_add_offset (NULL, base, offset);
+      addr = mips_add_offset (NULL, base, offset);
+      *xloc = mips_force_address (addr, mode);
       return true;
     }
   return false;
index 55e1cd0ece3a7d8b82580b522eb81f9a32b1c0f4..3370d9958c8925253b7a0f54741d266d96897e05 100644 (file)
 (define_mode_iterator MOVE64
   [DI DF (V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")])
 
+;; 128-bit modes for which we provide move patterns on 64-bit targets.
+(define_mode_iterator MOVE128 [TF])
+
 ;; This mode iterator allows the QI and HI extension patterns to be
 ;; defined from the same template.
 (define_mode_iterator SHORT [QI HI])
 ;; 128-bit floating point moves
 
 (define_expand "movtf"
-  [(set (match_operand:TF 0 "")
-       (match_operand:TF 1 ""))]
-  ""
+  [(set (match_operand:TF 0)
+       (match_operand:TF 1))]
+  "TARGET_64BIT"
 {
   if (mips_legitimize_move (TFmode, operands[0], operands[1]))
     DONE;
 })
 
 ;; This pattern handles both hard- and soft-float cases.
-(define_insn_and_split "*movtf_internal"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=d,R,f,dR")
-       (match_operand:TF 1 "move_operand" "dGR,dG,dGR,f"))]
-  ""
+(define_insn "*movtf"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=d,d,m,f,d,f,m")
+       (match_operand:TF 1 "move_operand" "dG,m,dG,dG,f,m,f"))]
+  "TARGET_64BIT
+   && !TARGET_MIPS16
+   && (register_operand (operands[0], TFmode)
+       || reg_or_0_operand (operands[1], TFmode))"
   "#"
-  "&& reload_completed"
-  [(const_int 0)]
-{
-  mips_split_doubleword_move (operands[0], operands[1]);
-  DONE;
-}
-  [(set_attr "type" "multi")
-   (set_attr "length" "16")])
+  [(set_attr "type" "multi,load,store,multi,multi,fpload,fpstore")
+   (set_attr "length" "8,*,*,8,8,*,*")])
+
+(define_insn "*movtf_mips16"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=d,y,d,d,m")
+       (match_operand:TF 1 "move_operand" "d,d,y,m,d"))]
+  "TARGET_64BIT
+   && TARGET_MIPS16
+   && (register_operand (operands[0], TFmode)
+       || register_operand (operands[1], TFmode))"
+  "#"
+  [(set_attr "type" "multi,multi,multi,load,store")
+   (set_attr "length" "8,8,8,*,*")])
 
 (define_split
   [(set (match_operand:MOVE64 0 "nonimmediate_operand")
   DONE;
 })
 
+(define_split
+  [(set (match_operand:MOVE128 0 "nonimmediate_operand")
+       (match_operand:MOVE128 1 "move_operand"))]
+  "TARGET_64BIT && reload_completed"
+  [(const_int 0)]
+{
+  mips_split_doubleword_move (operands[0], operands[1]);
+  DONE;
+})
+
 ;; When generating mips16 code, split moves of negative constants into
 ;; a positive "li" followed by a negation.
 (define_split
index 4a3d5ca91074dab5d1a64cb474c3abd921bcc0be..a53fdd73f9e6459516734e110d63db4184e7c58c 100644 (file)
@@ -1,3 +1,8 @@
+2008-06-01  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * gcc.target/mips/fpr-moves-7.c: New test.
+       * gcc.target/mips/fpr-moves-8.c: New test.
+
 2008-05-30  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * gcc.target/bfin/mcpu-default.c: Adjust for recent changes: default
diff --git a/gcc/testsuite/gcc.target/mips/fpr-moves-7.c b/gcc/testsuite/gcc.target/mips/fpr-moves-7.c
new file mode 100644 (file)
index 0000000..4736edd
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do compile { target mips16_attribute } } */
+/* { dg-mips-options "-mabi=64 -msoft-float -O2 -EL" } */
+/* { dg-add-options mips16_attribute } */
+
+extern long double g[16];
+extern unsigned char gstuff[0x10000];
+
+NOMIPS16 long double
+foo (long double i1, long double i2, long double i3, long double i4,
+     long double *x, unsigned char *lstuff)
+{
+  g[0] = i1;
+  g[1] = i2;
+  g[2] = i3;
+  g[3] = i4;
+  x[0] = x[4];
+  x[1] = 0;
+  x[2] = 1.0;
+  x[3] = g[4];
+  x[4] = *(long double *) (lstuff + 0x7fff);
+  return *(long double *) (gstuff + 0x7fff);
+}
+
+MIPS16 long double
+bar (long double i1, long double i2, long double i3, long double i4,
+     long double *x, unsigned char *lstuff)
+{
+  g[0] = i1;
+  g[1] = i2;
+  g[2] = i3;
+  g[3] = i4;
+  x[0] = x[4];
+  x[1] = 0;
+  x[2] = 1.0;
+  x[3] = g[4];
+  x[4] = *(long double *) (lstuff + 0x7fff);
+  return *(long double *) (gstuff + 0x7fff);
+}
diff --git a/gcc/testsuite/gcc.target/mips/fpr-moves-8.c b/gcc/testsuite/gcc.target/mips/fpr-moves-8.c
new file mode 100644 (file)
index 0000000..ade9e5e
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do compile { target mips16_attribute } } */
+/* { dg-mips-options "-mabi=64 -msoft-float -O2 -EB" } */
+/* { dg-add-options mips16_attribute } */
+
+extern long double g[16];
+extern unsigned char gstuff[0x10000];
+
+NOMIPS16 long double
+foo (long double i1, long double i2, long double i3, long double i4,
+     long double *x, unsigned char *lstuff)
+{
+  g[0] = i1;
+  g[1] = i2;
+  g[2] = i3;
+  g[3] = i4;
+  x[0] = x[4];
+  x[1] = 0;
+  x[2] = 1.0;
+  x[3] = g[4];
+  x[4] = *(long double *) (lstuff + 0x7fff);
+  return *(long double *) (gstuff + 0x7fff);
+}
+
+MIPS16 long double
+bar (long double i1, long double i2, long double i3, long double i4,
+     long double *x, unsigned char *lstuff)
+{
+  g[0] = i1;
+  g[1] = i2;
+  g[2] = i3;
+  g[3] = i4;
+  x[0] = x[4];
+  x[1] = 0;
+  x[2] = 1.0;
+  x[3] = g[4];
+  x[4] = *(long double *) (lstuff + 0x7fff);
+  return *(long double *) (gstuff + 0x7fff);
+}