I was wondering if someone could help me find the right GCC hooks to
implement some changes in the prologue and epilogue code for the MIPS
target.  What I am trying to do is to have a flag (call it
-mfp64-compat) that will allow me to generate code in a routine that
will use the MIPS floating point unit in fp1 mode (-mfp64, 64 bit
floating point registers) but in a way that is compatible with being
called from a routine in fp0 mode (-mfp32, 32 bit floating point
registers).

The idea is that the routine is called with the FPU in fp0 mode, then we
save all the floating point registers, because switching modes leaves
the fp registers in an unknown state, and then switch to fp1 mode.  At
the return we save the f12 return register (if needed), switch back to
fp0 mode and then restore f12 and the other floating point registers
before the return.  I'll leave out the complication of making calls to
other routines from this routine for now.

I can set TARGET_FLOAT64 at the beginning of the function to generate 
fp1 code, but my attempt to create an instruction that switches mode and
clobbers all the floating point registers and calling this from
expand_prologue does not seem to be working.  I generate the instruction
(currently just a nop stub) but it does not clobber the floating point
registers.  I think this is because expand_prologue is getting called
too late in the rtl expansion/code generation stream.  So I am wondering
where I should add this instruction into the rtl stream?  Do I need to
create a new rtl pass I could run immediately after the trees are
expanded into rtl?

I have attached a GCC patch file that I have been experimenting with
so far.  If I compile a routine with -mfp64-compat I get my nop
generated by expand_prologue but I do not get the save/restore of the
floating point registers that I was hoping for.  If I call
__builtin_mips_switch_fp_mode(0) explicitly then I do see the fp
registers get saved and restored.

Steve Ellcey
sell...@mips.com

diff --git a/gcc/config/mips/mips-ftypes.def b/gcc/config/mips/mips-ftypes.def
index 1268c53..7ccbca5 100644
--- a/gcc/config/mips/mips-ftypes.def
+++ b/gcc/config/mips/mips-ftypes.def
@@ -124,3 +124,4 @@ DEF_MIPS_FTYPE (2, (VOID, SI, CVPOINTER))
 DEF_MIPS_FTYPE (2, (VOID, SI, SI))
 DEF_MIPS_FTYPE (2, (VOID, V2HI, V2HI))
 DEF_MIPS_FTYPE (2, (VOID, V4QI, V4QI))
+DEF_MIPS_FTYPE (1, (VOID, SI))
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 5993aab..573c136 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -682,6 +682,7 @@ static const struct attribute_spec mips_attribute_table[] = {
   { "micromips",   0, 0, true,  false, false, NULL, false },
   { "nomicromips", 0, 0, true,  false, false, NULL, false },
   { "nocompression", 0, 0, true,  false, false, NULL, false },
+  { "fp64_compat", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -11224,6 +11225,12 @@ mips_expand_prologue (void)
      the call to mcount.  */
   if (crtl->profile)
     emit_insn (gen_blockage ());
+
+  if (TARGET_FP64_COMPAT)
+    {
+      emit_insn (gen_mips_switch_fp_mode (GEN_INT (0)));
+      emit_insn (gen_blockage ());
+    }
 }
 
 /* Attach all pending register saves to the previous instruction.
@@ -13620,6 +13627,7 @@ AVAIL_NON_MIPS16 (dsp_64, TARGET_64BIT && TARGET_DSP)
 AVAIL_NON_MIPS16 (dspr2_32, !TARGET_64BIT && TARGET_DSPR2)
 AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_VECTORS)
 AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
+AVAIL_NON_MIPS16 (fp, TARGET_FP64_COMPAT)
 
 /* Construct a mips_builtin_description from the given arguments.
 
@@ -14059,7 +14067,9 @@ static const struct mips_builtin_description mips_builtins[] = {
   LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI),
 
   /* Sundry other built-in functions.  */
-  DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache)
+  DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache),
+
+  DIRECT_NO_TARGET_BUILTIN (switch_fp_mode, MIPS_VOID_FTYPE_SI, fp)
 };
 
 /* Index I is the function declaration for mips_builtins[I], or null if the
@@ -16634,6 +16644,9 @@ static void
 mips_set_current_function (tree fndecl)
 {
   mips_set_compression_mode (mips_get_compress_mode (fndecl));
+  if (fndecl \
+      && lookup_attribute ("fp64_compat", DECL_ATTRIBUTES (fndecl)) != NULL)
+    target_flags |= MASK_FP64_COMPAT;
 }
 
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16761,6 +16774,12 @@ mips_option_override (void)
       target_flags_explicit |= MASK_SOFT_FLOAT_ABI;
     }
 
+  if (TARGET_FP64_COMPAT)
+    {
+      target_flags |= MASK_FLOAT64;
+      target_flags_explicit |= MASK_FLOAT64;
+    }
+
   if (TARGET_FLIP_MIPS16)
     TARGET_INTERLINK_COMPRESSED = 1;
 
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 0cda169..47b2c00 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -121,6 +121,9 @@
   UNSPEC_MIPS_CACHE
   UNSPEC_R10K_CACHE_BARRIER
 
+  ;; Switch FP modes.
+  UNSPEC_FLUSH_FP_REGS
+
   ;; Interrupt handling.
   UNSPEC_ERET
   UNSPEC_DERET
@@ -6943,6 +6946,23 @@
   DONE;
 })
 
+(define_insn "mips_switch_fp_mode"
+  [(unspec_volatile [(match_operand 0 "const_int_operand")]
+    UNSPEC_FLUSH_FP_REGS)
+   (clobber (reg:SF 32)) (clobber (reg:SF 33)) (clobber (reg:SF 34))
+   (clobber (reg:SF 35)) (clobber (reg:SF 36)) (clobber (reg:SF 37))
+   (clobber (reg:SF 38)) (clobber (reg:SF 39)) (clobber (reg:SF 40))
+   (clobber (reg:SF 41)) (clobber (reg:SF 42)) (clobber (reg:SF 43))
+   (clobber (reg:SF 44)) (clobber (reg:SF 45)) (clobber (reg:SF 46))
+   (clobber (reg:SF 47)) (clobber (reg:SF 48)) (clobber (reg:SF 49))
+   (clobber (reg:SF 50)) (clobber (reg:SF 51)) (clobber (reg:SF 52))
+   (clobber (reg:SF 53)) (clobber (reg:SF 54)) (clobber (reg:SF 55))
+   (clobber (reg:SF 56)) (clobber (reg:SF 57)) (clobber (reg:SF 58))
+   (clobber (reg:SF 59)) (clobber (reg:SF 60)) (clobber (reg:SF 61))
+   (clobber (reg:SF 62)) (clobber (reg:SF 63))]
+  ""
+  "nop"
+)
 
 ;; Synchronization instructions.
 
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 0324041..1e21d03 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -209,6 +209,10 @@ mabs=
 Target RejectNegative Joined Enum(mips_ieee_754_value) Var(mips_abs) Init(MIPS_IEEE_754_DEFAULT)
 -mabs=MODE	Select the IEEE 754 ABS/NEG instruction execution mode
 
+mfp64-compat
+Target Report Mask(FP64_COMPAT)
+Use MIPS fp64 instructions in a manner compatibile with fp32 code.
+
 mnan=
 Target RejectNegative Joined Enum(mips_ieee_754_value) Var(mips_nan) Init(MIPS_IEEE_754_DEFAULT)
 -mnan=ENCODING	Select the IEEE 754 NaN data encoding

Reply via email to