mips.h (ISA_HAS_FP4): Add MIPS32R2 + 64bit fpu combination.
authorDavid Ung <davidu@mips.com>
Thu, 23 Nov 2006 16:13:46 +0000 (16:13 +0000)
committerDavid Ung <davidu@gcc.gnu.org>
Thu, 23 Nov 2006 16:13:46 +0000 (16:13 +0000)
gcc:
* config/mips/mips.h (ISA_HAS_FP4): Add MIPS32R2 + 64bit fpu
combination.
(ISA_HAS_MXHC1): True if ISA supports mfhc1 and mthc1 opcodes.
(ASM_SPEC): Pass along -mfp32 and -mfp64.
* config/mips/mips.c (mips_split_64bit_move): Use gen_mthc1 to set
high part of FP register when in 64-bit FP register mode.  Similarly
use gen_mfhc1 to load high part of FP register.
(override_options): Allow -mgp32 and -mfp64 combination if
ISA_HAS_MXHC1 (currently for O32 only).
(mips_cannot_change_mode_class): If floating-point registers are
bigger than word size. disallow conversion of float register from a
large integer mode to a float mode smaller than the float register
size.
(mips_class_max_nregs): Handle float registers case seperately.
* config/mips/mips.md (define_constants): Add UNSPEC_MFHC1,
UNSPEC_MTHC1.
(movdi_32bit): Use !TARGET_FLOAT64 in condition pattern.
(movdf_hardfloat_32bit): Similarly.
(movdi_gp32_fp64): New DImode pattern for MIPS32R2 which optionally
support a full 64-bit fpu.
(mthc1): New pattern to generate MTHC1 instruction.
(mfhc1): New pattern to generate MFHC1 instruction.
* doc/invoke.texi (MIPS Options): Document the -mgp32 -mfp64
option for the MIPS32R2 and mention its use under O32 ABI.

gcc/testsuite:
* gcc.target/mips/mips.exp (dg-mips-options): Handle parsing of
-mfp64, allowable when ISA >= 33 and float is enabled.
* gcc.target/mips/mips32r2-mxhc1.c: New test for checking the use
of mthc1 and mfhc1 patterns.

From-SVN: r119124

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/mips.exp
gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c [new file with mode: 0644]

index fbf1652..00420be 100644 (file)
@@ -1,3 +1,30 @@
+2006-11-23  David Ung  <davidu@mips.com>
+
+       * config/mips/mips.h (ISA_HAS_FP4): Add MIPS32R2 + 64bit fpu
+       combination.
+       (ISA_HAS_MXHC1): True if ISA supports mfhc1 and mthc1 opcodes.
+       (ASM_SPEC): Pass along -mfp32 and -mfp64.
+       * config/mips/mips.c (mips_split_64bit_move): Use gen_mthc1 to set
+       high part of FP register when in 64-bit FP register mode.  Similarly
+       use gen_mfhc1 to load high part of FP register.
+       (override_options): Allow -mgp32 and -mfp64 combination if
+       ISA_HAS_MXHC1 (currently for O32 only).
+       (mips_cannot_change_mode_class): If floating-point registers are
+       bigger than word size. disallow conversion of float register from a
+       large integer mode to a float mode smaller than the float register
+       size.
+       (mips_class_max_nregs): Handle float registers case seperately.
+       * config/mips/mips.md (define_constants): Add UNSPEC_MFHC1,
+       UNSPEC_MTHC1.
+       (movdi_32bit): Use !TARGET_FLOAT64 in condition pattern.
+       (movdf_hardfloat_32bit): Similarly.
+       (movdi_gp32_fp64): New DImode pattern for MIPS32R2 which optionally
+       support a full 64-bit fpu.
+       (mthc1): New pattern to generate MTHC1 instruction.
+       (mfhc1): New pattern to generate MFHC1 instruction.
+       * doc/invoke.texi (MIPS Options): Document the -mgp32 -mfp64
+       option for the MIPS32R2 and mention its use under O32 ABI.
+
 2006-11-23  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * var-tracking.c (emit_note_insn_var_location): Take care not to
index 52e2aab..63c19ab 100644 (file)
@@ -2846,15 +2846,35 @@ mips_split_64bit_move (rtx dest, rtx 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)));
+      if (ISA_HAS_MXHC1)
+       {
+         dest = gen_lowpart (DFmode, dest);
+         emit_insn (gen_load_df_low (dest, mips_subword (src, 0)));
+         emit_insn (gen_mthc1 (dest, mips_subword (src, 1),
+                               copy_rtx (dest)));
+       }
+      else
+       {
+         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));
+      if (ISA_HAS_MXHC1)
+       {
+         src = gen_lowpart (DFmode, src);
+         emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+         emit_insn (gen_mfhc1 (mips_subword (dest, 1), src));
+       }
+      else
+       {
+         emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+         emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
+       }
     }
   else
     {
@@ -4804,8 +4824,10 @@ override_options (void)
         only one right answer here.  */
       if (TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_FLOAT64)
        error ("unsupported combination: %s", "-mgp64 -mfp32 -mdouble-float");
-      else if (!TARGET_64BIT && TARGET_FLOAT64)
-       error ("unsupported combination: %s", "-mgp32 -mfp64");
+      else if (!TARGET_64BIT && TARGET_FLOAT64 
+              && !(ISA_HAS_MXHC1 && mips_abi == ABI_32))
+       error ("-mgp32 and -mfp64 can only be combined if the target"
+              " supports the mfhc1 and mthc1 instructions");
       else if (TARGET_SINGLE_FLOAT && TARGET_FLOAT64)
        error ("unsupported combination: %s", "-mfp64 -msingle-float");
     }
@@ -7660,15 +7682,27 @@ mips_cannot_change_mode_class (enum machine_mode from,
            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.  */  
+  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;
+
   /* 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_FLOAT64
+  if (TARGET_64BIT
+      && TARGET_FLOAT64
       && from == SImode
       && GET_MODE_SIZE (to) >= UNITS_PER_WORD
       && reg_classes_intersect_p (FP_REGS, class))
     return true;
+
   return false;
 }
 
@@ -7830,14 +7864,17 @@ mips_secondary_reload_class (enum reg_class class,
 
 /* Implement CLASS_MAX_NREGS.
 
-   Usually all registers are word-sized.  The only supported exception
-   is -mgp64 -msingle-float, which has 64-bit words but 32-bit float
-   registers.  A word-based calculation is correct even in that case,
-   since -msingle-float disallows multi-FPR values.
+   - UNITS_PER_FPREG controls the number of registers needed by FP_REGS.
+
+   - ST_REGS are always hold CCmode values, and CCmode values are
+     considered to be 4 bytes wide.
 
-   The FP status registers are an exception to this rule.  They are always
-   4 bytes wide as they only hold condition code modes, and CCmode is always
-   considered to be 4 bytes wide.  */
+   All other register classes are covered by UNITS_PER_WORD.  Note that
+   this is true even for unions of integer and float registers when the
+   latter are smaller than the former.  The only supported combination
+   in which case this occurs is -mgp64 -msingle-float, which has 64-bit
+   words but 32-bit float registers.  A word-based calculation is correct
+   in that case since -msingle-float disallows multi-FPR values.  */
 
 int
 mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,
@@ -7845,6 +7882,8 @@ mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,
 {
   if (class == ST_REGS)
     return (GET_MODE_SIZE (mode) + 3) / 4;
+  else if (class == FP_REGS)
+    return (GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG;
   else
     return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 }
index ddcc81b..00f7ca8 100644 (file)
@@ -607,6 +607,7 @@ extern const struct mips_rtx_cost_data *mips_cost;
    FP madd and msub instructions, and the FP recip and recip sqrt
    instructions.  */
 #define ISA_HAS_FP4            ((ISA_MIPS4                             \
+                                 || (ISA_MIPS32R2 && TARGET_FLOAT64)   \
                                  || ISA_MIPS64)                        \
                                 && !TARGET_MIPS16)
 
@@ -703,6 +704,9 @@ extern const struct mips_rtx_cost_data *mips_cost;
 #define ISA_HAS_EXT_INS                (ISA_MIPS32R2                           \
                                 && !TARGET_MIPS16)
 
+/* ISA has instructions for accessing top part of 64 bit fp regs */
+#define ISA_HAS_MXHC1          (TARGET_FLOAT64 && ISA_MIPS32R2)
+
 /* True if the result of a load is not available to the next instruction.
    A nop will then be needed between instructions like "lw $4,..."
    and "addiu $4,$4,1".  */
@@ -821,6 +825,7 @@ extern const struct mips_rtx_cost_data *mips_cost;
 %(subtarget_asm_debugging_spec) \
 %{mabi=*} %{!mabi*: %(asm_abi_default_spec)} \
 %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \
+%{mfp32} %{mfp64} \
 %{mshared} %{mno-shared} \
 %{msym32} %{mno-sym32} \
 %{mtune=*} %{v} \
index dfa82f1..b175fb3 100644 (file)
@@ -47,6 +47,8 @@
    (UNSPEC_MFHILO              26)
    (UNSPEC_TLS_LDM             27)
    (UNSPEC_TLS_GET_TP          28)
+   (UNSPEC_MFHC1               31)
+   (UNSPEC_MTHC1               32)
 
    (UNSPEC_ADDRESS_FIRST       100)
 
 (define_insn "*movdi_32bit"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*B*C*D,*B*C*D,*d,*m")
        (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
-  "!TARGET_64BIT && !TARGET_MIPS16
+  "!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 "mode"    "DI")
    (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"))]
+  "!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"    "arith,arith,load,store,mthilo,mfhilo,fmove,xfer,fpload,xfer,fpstore")
+   (set_attr "mode"    "DI")
+   (set_attr "length"   "8,16,*,*,8,8,4,8,*,8,*")])
+
 (define_insn "*movdi_32bit_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
        (match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))]
    (set_attr "mode"    "DF")
    (set_attr "length"  "4,4,*,*,*,4,4,4,*,*")])
 
+;; This pattern applies to both !TARGET_FLOAT64 and TARGET_FLOAT64.
 (define_insn "*movdf_hardfloat_32bit"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
        (match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))]
   [(set_attr "type"    "xfer,fpstore")
    (set_attr "mode"    "SF")])
 
+;; Move operand 1 to the high word of operand 0 using mthc1, preserving the
+;; value in the low word.
+(define_insn "mthc1"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (unspec:DF [(match_operand:SI 1 "general_operand" "dJ")
+                   (match_operand:DF 2 "register_operand" "0")]
+                   UNSPEC_MTHC1))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && ISA_HAS_MXHC1"
+  "mthc1\t%z1,%0"
+  [(set_attr "type"    "xfer")
+   (set_attr "mode"    "SF")])
+
+;; Move high word of operand 1 to operand 0 using mfhc1.  The corresponding
+;; low-word move is done in the normal way.
+(define_insn "mfhc1"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (unspec:SI [(match_operand:DF 1 "register_operand" "f")]
+                   UNSPEC_MFHC1))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && ISA_HAS_MXHC1"
+  "mfhc1\t%0,%1"
+  [(set_attr "type"    "xfer")
+   (set_attr "mode"    "SF")])
+
 ;; Insn to initialize $gp for n32/n64 abicalls.  Operand 0 is the offset
 ;; of _gp from the start of this function.  Operand 1 is the incoming
 ;; function address.
index 045c5fd..2cef7e6 100644 (file)
@@ -10657,6 +10657,19 @@ can use @option{-mgp32} to get 32-bit code instead.
 For information about the O64 ABI, see
 @w{@uref{http://gcc.gnu.org/projects/mipso64-abi.html}}.
 
+GCC supports a variant of the o32 ABI in which floating-point registers
+are 64 rather than 32 bits wide.  You can select this combination with
+@option{-mabi=32} @option{-mfp64}.  This ABI relies on the @samp{mthc1}
+and @samp{mfhc1} instructions and is therefore only supported for
+MIPS32R2 processors.
+
+The register assignments for arguments and return values remain the
+same, but each scalar value is passed in a single 64-bit register
+rather than a pair of 32-bit registers.  For example, scalar
+floating-point values are returned in @samp{$f0} only, not a
+@samp{$f0}/@samp{$f1} pair.  The set of call-saved registers also
+remains the same, but all 64 bits are saved.
+
 @item -mabicalls
 @itemx -mno-abicalls
 @opindex mabicalls
index f8dc647..cec51b1 100644 (file)
@@ -1,3 +1,10 @@
+2006-11-23  David Ung <davidu@mips.com>
+       
+       * gcc.target/mips/mips.exp (dg-mips-options): Handle parsing of
+       -mfp64, allowable when ISA >= 33 and float is enabled.
+       * gcc.target/mips/mips32r2-mxhc1.c: New test for checking the use
+       of mthc1 and mfhc1 patterns.
+       
 2006-11-23  Zdenek Dvorak <dvorakz@suse.cz>
 
        PR tree-optimization/29921
index d88a867..af5b0fb 100644 (file)
@@ -158,6 +158,10 @@ proc dg-mips-options {args} {
            if {$mips_mips16} {
                set matches 0
            }
+       } elseif {$flag == "-mfp64"} {
+           if {$mips_isa < 33 || $mips_float != "hard"} {
+               set matches 0
+           }
        } elseif {[regexp -- {^-march=(.*)} $flag dummy arch]} {
            if {$mips_mips16 || ($arch != $mips_arch && $mips_forced_isa)} {
                set matches 0
diff --git a/gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c b/gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c
new file mode 100644 (file)
index 0000000..7a3b12d
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -march=mips32r2 -mabi=32 -mfp64" } */
+/* { dg-final { scan-assembler "mthc1" } } */
+/* { dg-final { scan-assembler "mfhc1" } } */
+
+double func1 (long long a)
+{
+  return a;
+}
+
+long long func2 (double b)
+{
+  return b;
+}