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



New patch revision attached.


This patch adds -mfp64 for MIPS32R2 to allow the use of 64bit float insn, mfhc1/mthc1 instructions to access the high half of the FPU register.
I've restricted the -mgp32 -mfp64 to O32 only.
I've taken Richard's suggestion of retaining the modes in load_df_{low/high}.
As a consequence, I had to force the mode change (DI to DF) in mips_split_64bit_move such that the patterns would match. (Instead of creating multiple versions of load_di_{low/high} and m{f/t}hc1_{di/df})
Some problems with complex float arguments etc which will be addressed in future patches.


Re-tested on cross-compiler (mipsisa32-sde-elf, O32 abi) under GNU sim with flags "-mip32r2 -mfp64".
regressions mostly ok. (39 failures when running "-mips32r2", 42 failures with "-mip32r2 -mfp64")
Bootstrapped on linux.


Comments?

David.

    * 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_MIPS32R2 and TARGET_FLOAT64 (currently for O32 only).
    (mips_cannot_change_mode_class): Disallow implicit conversion
    to/from another non-float class when TARGET_FLOAT64.

    * config/mips/mips.md (define_constants): Add UNSPEC_MFHC1,
    UNSPEC_MTHC1.
    (movdi_32bit): Use !TARGET_FLOAT64 in condition pattern.
    (movdf_hardfloat_32bit): Similarly.
    (movdi_32bit_mips32r2_fp64): New DImode pattern for MIPS32R2 which
    optionally support a full 64-bit fpu.
    (movdf_hardfloat_mips32r2_fp64): Simlilarly, but for DFmode.
    (mthc1): New pattern to generate MTHC1 instruction.
    (mfhc1): New pattern to generate MFHC1 instruction.

    * testsuite/gcc.target/mips/mips.exp (dg-mips-options): Handle parsing
    of -mfp64, allowable when ISA >= 33 and float is enabled.
    * testsuite/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 118564)
+++ 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 118564)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2846,15 +2846,28 @@
   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)));
+      rtx d = dest;
+      if (ISA_HAS_MXHC1 && GET_MODE (d) == DImode)
+	d = gen_rtx_REG (DFmode, REGNO (d));
+      emit_insn (gen_load_df_low (copy_rtx (d), mips_subword (src, 0)));
+      if (ISA_HAS_MXHC1 && GET_CODE (src) != MEM)
+	emit_insn (gen_mthc1 (copy_rtx (d), mips_subword (src, 1),
+			      copy_rtx (d)));
+      else
+	emit_insn (gen_load_df_high (copy_rtx (d), mips_subword (src, 1),
+				     copy_rtx (d)));
     }
   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));
+      rtx s = src;
+      if (ISA_HAS_MXHC1 && GET_MODE (s) == DImode)
+	s = gen_rtx_REG (DFmode, REGNO (s));
+      emit_move_insn (mips_subword (dest, 0), mips_subword (s, 0));
+      if (ISA_HAS_MXHC1 && GET_CODE (dest) != MEM)
+	emit_insn (gen_mfhc1 (mips_subword (dest, 1), s));
+      else
+	emit_insn (gen_store_df_high (mips_subword (dest, 1), s));
     }
   else
     {
@@ -4804,7 +4817,8 @@
 	 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)
+      else if (!TARGET_64BIT && TARGET_FLOAT64 
+	       && !(ISA_MIPS32R2 && mips_abi == ABI_32))
 	error ("unsupported combination: %s", "-mgp32 -mfp64");
       else if (TARGET_SINGLE_FLOAT && TARGET_FLOAT64)
 	error ("unsupported combination: %s", "-mfp64 -msingle-float");
@@ -7639,6 +7653,10 @@
   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_FLOAT64)
+	/* Don't allow implicit conversion to/from another class that
+	   isn't float.  */
+	return reg_classes_intersect_p (FP_REGS, class);
       if (TARGET_BIG_ENDIAN)
 	{
 	  /* When a multi-word value is stored in paired floating-point
@@ -7669,6 +7687,7 @@
       && GET_MODE_SIZE (to) >= UNITS_PER_WORD
       && reg_classes_intersect_p (FP_REGS, class))
     return true;
+
   return false;
 }
 
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 118564)
+++ 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_32bit_mips32r2_fp64"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*B*C*D,*B*C*D,*d,*m,*f,*f,*f,*d,*m")
+	(match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*d,*m,*B*C*D,*B*C*D,*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,xfer,load,xfer,store,fmove,xfer,fpload,xfer,fpstore")
+   (set_attr "mode"	"DI")
+   (set_attr "length"   "8,16,*,*,8,8,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"))]
@@ -3807,7 +3820,7 @@
 (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"))]
-  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_FLOAT64
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return mips_output_move (operands[0], operands[1]); }
@@ -3815,6 +3828,17 @@
    (set_attr "mode"	"DF")
    (set_attr "length"	"4,8,*,*,*,8,8,8,*,*")])
 
+(define_insn "*movdf_hardfloat_mips32r2_fp64"
+  [(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"))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FLOAT64
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return mips_output_move (operands[0], operands[1]); }
+  [(set_attr "type"	"fmove,xfer,fpload,fpstore,store,xfer,xfer,arith,load,store")
+   (set_attr "mode"	"DF")
+   (set_attr "length"	"4,4,*,*,*,8,8,8,*,*")])
+
 (define_insn "*movdf_softfloat"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m,d,f,f")
 	(match_operand:DF 1 "move_operand" "dG,m,dG,f,d,f"))]
@@ -3985,6 +4009,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/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc/testsuite/gcc.target/mips/mips.exp	(revision 118564)
+++ 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]