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