On Thu, 22 May 2014, Matthew Fortune wrote:

> I'm not confident that it would be the right thing to change this
> behaviour. While the test is slightly weird in that the compiler generates
> code that touches a -ffixed-reg this is just an ABI test.
> 
> == Taken from MIPS ABI supplement ==
> Only registers $f20.$f30 are preserved across a function call. All other 
> float-
> ing-point registers can change across a function call. However, functions
> that use any of $f20.$f30 for single-precision operations only must still save
> and restore the corresponding odd-numbered register since the odd-num-
> bered register contents are left undefined by single-precision operations
> == end == 
> 
> There are comments in the code to assert that this is behaviour is very much
> intentional as well:
> 
> == mips.c ==
> static bool
> mips_save_reg_p (unsigned int regno)
> {
>   if (mips_cfun_call_saved_reg_p (regno))
>     {
>       if (mips_cfun_might_clobber_call_saved_reg_p (regno))
>         return true;
> 
>       /* Save both registers in an FPR pair if either one is used.  This is
>          needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
>          register to be used without the even register.  */
>       if (FP_REG_P (regno)
>           && MAX_FPRS_PER_FMT == 2
>           && mips_cfun_might_clobber_call_saved_reg_p (regno + 1))
>         return true;
>     }
> 
>   /* We need to save the incoming return address if __builtin_eh_return
>      is being used to set a different return address.  */
>   if (regno == RETURN_ADDR_REGNUM && crtl->calls_eh_return)
>     return true;
> 
>   return false;
> }
> == end ==
> 
> I therefore take back my comment about the prologue/epilogue saving too much
> callee-save register state :-) It is doing exactly what is required by the
> arch. I doubt very much that any MIPS implementation would end up with
> incorrect operation if you ran the following and ended up with $f18 and $f20
> being different or undefined behaviour if $f20 were accessed as a double but 
> that is actually what the spec says.
> 
> ADD.D $f20, $f10, $f10
> MOV.D $f18, $f20
> SWC1 $f20, 0($sp)
> MTC1 $2, $f20
> LWC1 $f20, 0($sp)
> ADD.D $f16, $f18, $f20
> ($f16 should be 4*$f10)

 Neither of MTC1/LWC1 is arithmetic so a different rule applies.  This 
code will work just fine on a 32-bit FPU or with the CP0 Status.FR bit 
clear where implemented because non-arithmetic FPR 32-bit write operations 
do not change the corresponding high-order 32-bit FPR.  It will only break 
with the CP0 Status.FR bit set, where the upper half of the 64-bit FPR 
written will be left undefined, but that is actually no different to the 
current architecture definition.

 This code would break on legacy processors if you substituted MTC1 with 
an arithmetic operation e.g.:

ADD.D $f20, $f10, $f10
MOV.D $f18, $f20
SWC1 $f20, 0($sp)
CVT.S.D $f20, $f20
LWC1 $f20, 0($sp)
ADD.D $f16, $f18, $f20
($f16 should be 4*$f10)

> Presumably, to account for MIPS I then a pair of SWC1s/LWC1s are required
> by the architecture to allow the resulting even numbered register to be
> accessed as a double.
> 
> MIPS32 to my knowledge makes no re-assuring statement that accessing the
> odd numbered register with a single precision operation does not clobber
> the lower 32-bits of the double it is overlaid with.

 But the MIPS psABI also says that only MIPS I ISA instructions may be 
used in a compliant program, so by building a program for the MIPS32 or 
higher ISA you've already broken the ABI as it stands.  So I think we 
could relax the rule on FPR saving/restoration from MIPS32 ISA up, as an 
ABI extension that we already made anyway.

  Maciej

Reply via email to