This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] MIPS: 64bit floating point support for MIPS32R2


Richard Sandiford wrote:

These changes don't need a full retest.  Just make sure that cc1
builds and the new error message is sensible.  Also run "make dvi"
and "make info" and check that the modified documentation works OK.

OK with those changes. (Could you post the final patch for reference?)


now comitted.


David.

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.

Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 119120)
+++ gcc/config/mips/mips.h	(working copy)
@@ -607,6 +607,7 @@
    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 @@
 #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 @@
 %(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: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 119120)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2846,15 +2846,35 @@
   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 @@
 	 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 @@
 	    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,21 +7864,26 @@
 
 /* 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.
 
-   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.  */
+   - ST_REGS are always hold CCmode values, and CCmode values are
+     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,
 		      enum machine_mode mode)
 {
   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: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 119120)
+++ gcc/config/mips/mips.md	(working copy)
@@ -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)
 
@@ -3255,7 +3257,7 @@
 (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]); }
@@ -3263,6 +3265,17 @@
    (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"))]
@@ -3804,6 +3817,7 @@
    (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"))]
@@ -3985,6 +3999,29 @@
   [(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: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 119120)
+++ gcc/doc/invoke.texi	(working copy)
@@ -10657,6 +10657,19 @@
 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: gcc/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc/testsuite/gcc.target/mips/mips.exp	(revision 119120)
+++ gcc/testsuite/gcc.target/mips/mips.exp	(working copy)
@@ -158,6 +158,10 @@
 	    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
Index: gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c
===================================================================
/* { 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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]