[RFC] Introducing MIPS O32 ABI Extension for FR0 and FR1 Interlinking

Matthew Fortune Matthew.Fortune@imgtec.com
Mon Feb 24 14:14:00 GMT 2014


Richard Sandiford <rdsandiford@googlemail.com> writes
> Matthew Fortune <Matthew.Fortune@imgtec.com> writes:
> > All,
> >
> > Imagination Technologies would like to introduce the design of an O32
> > ABI extension for MIPS to allow it to be used in conjunction with MIPS
> > FPUs having 64-bit floating-point registers. This is a wide-reaching
> > design that involves changes to all components of the MIPS toolchain
> > it is being posted to GCC first and will progress on to other tools.
> > This ABI extension is compatible with the existing O32 ABI definition
> > and will not require the introduction of new build variants
> (multilibs).
> >
> > The design document is relatively large and has been placed on the
> > MIPS Compiler Team wiki to facilitate review:
> >
> > http://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinkin
> > g
> 
> Looks good to me.  It'll be interesting to see whether making the odd-
> numbered call-saved-in-fr0 registers available for frx pays off or
> whether it ends up being better to avoid them.

Indeed, I suspect they should be avoided except for leaf functions. You would have to be pretty desperate for a register if you use the caller-and-callee save registers!

> I understand the need to deprecate the current -mgp32 -mfp64 behaviour.
> I don't think we should deprecate -mfp64 itself though.  Instead, why
> not keep -mfp32 as meaning FR0, -mfp64 meaning FR1 and add -mfpxx for
> modeless?  So rather than deprecating the -mgp32 -mfp64 combination and
> adding -mfr, we'd just make -mgp32 -mfp64 generate the new FR1 form in
> which the odd-numbered registers are call-clobbered rather than the old
> form in which they were call-saved.

Extreme caution is the only reason why the design avoided changing fp64 behaviour (basically in case anyone had serious objection). If you would be happy with a change of behaviour for -mgp32 -mfp64 then that is a great start.
 
> AIUI the old form never really worked reliably due to things like
> newlib's setjmp not preserving the odd-numbered registers, so it doesn't
> seem worth keeping around.  Also, the old form is identified by the GNU
> attribute (4, 4) so it'd be easy for the linker to reject links between
> the old and the new form.

That is true. You will have noticed a number of changes over recent months to start fixing fp64 as currently defined but having found this new solution then such fixes are no longer important. The lack of support for gp32 fp64 in linux is further reason to permit redefining it. Would you be happy to retain the same builtin defines for FP64 if changing its behaviour (i.e. __mips_fpr=64)?
 
> The corresponding asm would then be ".set fp=xx".
> 
> Either way, a new .set option would be better than a specific .fr
> directive because it gives you access to the option stack (".set
> push"/".set pop").
> 
> I'm not sure about:
> 
>   If an assembly directive is seen prior to the start of the text
>   section then this modifies the default mode for the module.
> 
> This isn't how any of the existing options work and I think the
> inconsistency would be confusing.  It also means that if the first
> function in a file happens to force a local mode (e.g.
> because it's an ifunc implementation) then you'd have to remember to
> write:
> 
> 	.fr x
> 	.fr 1
> 
> so that the first sets the mode for the module and the second sets it
> for the first function.  The different treatment of the two lines
> wouldn't be obvious at first glance.
> 
> How about instead having a separate directive that explicitly sets the
> global value of an option?  I.e. something like ".module", taking the
> same options as ".set".  Better names welcome. :-)

Use of a different directive to actually affect the overall mode of a module sounds like a good plan and it avoids the weird behaviour. The only thing specifically needed is that the assembly file records the mode it was written for. Getting the wrong command line option would otherwise lead to unusual runtime failures. We have been/are still discussing this point so it's no surprise you have commented on it too. I'll wait for any further comments on this area and update accordingly.
 
> The scheme allows an ifunc to request a mode and effectively gives the
> choice to the firstcomer.  Every other ifunc then has to live with the
> choice.  I don't think that's a good idea, since the order that ifuncs
> are called isn't well-defined or under direct user control.
> 
> Since ifuncs would have to live with a choice made by other ifuncs, in
> practice they must all be prepared to deal with FR=1 if linked into a
> fully-modeless or FR1 program, and to deal with FR=0 if linked into a
> fully-modeless or FR0 program.  So IMO the dynamic linker should simply
> set FR=1 for modeless programs if the hardware supports it and set it to
> 0 for modeless programs otherwise, like you say in the first paragraph
> of 9.4.

The ifunc interaction should possibly be moved to a different proposal. We could reduce this down to a simple statement that interaction with ifunc needs to be considered when finalising MIPS ifunc support in general.

> You allow the mode to be changed midexecution if a new FR0 or FR1 object
> is loaded.  Is it really worth supporting that though?
> It has the same problem as the ifuncs: once you've dlopen()ed an object,
> you fix the mode for the whole program, even after the dlclose().
> Unless we know of specific cases where this is needed, maybe it would be
> safer to fix the mode before execution based on DT_NEEDED libraries and
> allow the mode of modeless programs to be overridden by an environment
> variable.

Scanning the entire set of DT_NEEDED libraries would achieve most of what full dynamic mode switching gives us, it is essentially the first stage of the dynamic mode switching described in the proposal anyway. However, I am concerned about excluding dlopen()ed objects from mode selection though (not so worried about excluding ifunc, that could just fix the mode before resolving the first one). One specific concern is for Android where I believe we have the situation where native applications are loaded as (a form of) shared library. This means a mode requirement can be introduced late on. In an Android environment it is unlikely to be acceptable to have to do something special to load an application that happens to have a specific mode requirement so dynamic selection is useful. This is more of a transitional problem than anything but making it a smooth process is quite important. I'm also not sure that there is much more effort required for a dynamic linker to take account of dlopen()ed objects in addition to DT_NEEDED, changes are needed in this code regardless.

The exact level of dynamic mode switching supported by any given dynamic linker could be left to the implementer I suppose but the fact that there is a solution for switching at runtime is important to explain at least.

> If we do end up using ELF flags then maybe adding two new EF_MIPS_ABI
> enums would be better.  It's more likely to be trapped by old loaders
> and avoids eating up those precious remaining bits.

Sound's reasonable but I'm still trying to determine how this information can be propagated from loader to dynamic loader.

> You didn't say specifically how a static program's crt code would know
> whether it was linked as modeless or in a specific FR mode.
> Maybe the linker could define a special hidden symbol?

Why do you say crt rather than dlopen? The mode requirement should only matter if you want to change it and dlopen should be able to access information in the same way that a dynamic linker would. It may seem redundant but perhaps we end up having to mark an executable with mode requirements in two ways. The primary one being the ELF flag and the secondary one being a processor specific program header. The ELF flags are easy to use/already used for the program loader and when scanning the needs of an object being loaded, but the program header is something that is easy to inspect for an already-loaded object. Overall though, a new program header would be sufficient in all cases, with a few modifications here and there.

Regards,
Matthew



More information about the Gcc mailing list