[LLVMdev] mips16 hard float puzzle

reed kotler rkotler at mips.com
Tue Jan 8 14:20:29 PST 2013

On 01/08/2013 01:47 PM, Eli Friedman wrote:
> On Mon, Jan 7, 2013 at 4:16 PM, reed kotler <rkotler at mips.com> wrote:
>> On 01/04/2013 07:45 PM, Eli Friedman wrote:
>>> On Fri, Jan 4, 2013 at 6:28 PM, reed kotler <rkotler at mips.com> wrote:
>>>> On 01/04/2013 06:08 PM, Eli Friedman wrote:
>>>>> On Fri, Jan 4, 2013 at 4:08 PM, reed kotler <rkotler at mips.com> wrote:
>>>>>> I'm working on mips16 hard float which at a first approximation is just
>>>>>> soft
>>>>>> float but calls different library routines. Those different library
>>>>>> routines
>>>>>> are just an implementation (in mips32 mode) of soft float using mips32
>>>>>> hardware instructions. This part is already done. (mips16 mode has no
>>>>>> floating point instructions).
>>>>>> The next level of this that I am working on now is the ability to call
>>>>>> mips32 mode functions from mips16. This is needed for example to call
>>>>>> the
>>>>>> math library (sin, cos), because those library
>>>>>> routines are mips32 functions.
>>>>>> This has an interesting problem.
>>>>>> The mips16 functions do not know what they are calling when it's an
>>>>>> external
>>>>>> function; i.e. it could be a mips32 or mips16.
>>>>>> On mips32, floating point arguments, if they are argument 1 and
>>>>>> argument
>>>>>> 2,
>>>>>> are passed in floating point registers. If the return type is floating
>>>>>> point, then it is returned in a floating point register.
>>>>>> On mips 16, it is doing soft float essentially so the arguments are
>>>>>> passed
>>>>>> in integer registers.
>>>>>> The way gcc mips16 does this is to call helper functions which do the
>>>>>> actual
>>>>>> call to the external function. The helper functions copy arg 1 and 2
>>>>>> into
>>>>>> fp
>>>>>> arg 1 and fp arg 2 and then do the actual call. So whether you are
>>>>>> calling
>>>>>> mips16 or mips32 from that point on does not matter.
>>>>>> I'm simplifiying this a bit and you have to think about the mips abi to
>>>>>> understand how this all works but it does.
>>>>>> The question I have is how to find the original prototype.
>>>>>> In order to know if I need to call a helper function, and which helper
>>>>>> function to call, I need to know the return type and type of arguments
>>>>>> 1
>>>>>> and
>>>>>> 2. I need to know this pre soft float lowering.
>>>>>>    From what I can see, in the beginning of ISelLowering code, the DAG
>>>>>> will
>>>>>> still reflect the original prototype. If I do a DAG.viewGraph() there
>>>>>> in
>>>>>> the
>>>>>> debugger, it knows about the proper prototype (pre soft float
>>>>>> lowering).
>>>>>> It would have been cool to get the function class that corresponds to
>>>>>> this
>>>>>> call and get the arguments that way but I don't see how I can get it.
>>>>>> Is looking at the DAG the only (or best) way to do find the function
>>>>>> prototype?
>>>>>> I would be happy to add something to lowering calls methods but it was
>>>>>> not
>>>>>> clear how to do this too.
>>>>> You have to do this as part of call lowering: once the call is
>>>>> lowered, the type information is lost permanently.  It's not
>>>>> conceptually difficult to do as part of call lowering, though: in the
>>>>> MIPS-specific call lowering code, if you detect that a call requires
>>>>> an argument in an FP register, you just need to generate a call to the
>>>>> relevant helper rather than the function itself.
>>>>> -Eli
>>>> So just read the DAG in the beginning of MIPS-specific call lowering
>>>> before
>>>> it gets modified?
>>> Take a look at CCValAssign etc. in MipsTargetLowering::LowerCall.
>>> (The DAG node for the callee doesn't have the necessary information in
>>> the general case, even though it might appear to work in simple
>>> cases.)
>>> -Eli
>> I'm not sure if I understood you.
>> For Mips hard float, we also have the soft float option in llc.
>> Right now we pass:
>> -mips16-hard-float -soft-float
>> To llc.
>> So the call is going to get changed to use integer types but I need to be
>> able to find what is was before that change takes place.
> If you need to be able to put values into floating-point registers,
> your architecture is not soft-float.  If the call expects the operand
> in a floating-point register, the call analysis code needs to know
> that we're dealing with a floating point value, and the code that
> generates the call needs to correctly put it in that register; whether
> there is a Mips16 instruction to perform that operation is irrelevant.
>   If the CCValAssign thinks that a floating-point argument is actually
> an integer, you can't recover at that point.  (It's possible that the
> call analysis code needs to be enhanced to make this work.)
> -Eli
Mips16 is not an architecture; it's a processor mode.

The real architecture is Mips32 (or Mips64 though I don't know that 
anyone has implemented mips16 mode in mips64 but it's allowed for our 
architectural licenses to do that).

When the program is running in mips16 mode all the time, then the 
processor can be thought
to be in soft float. That flavor of llvm mips16 works now and passes 
almost 100% of test-suite.

What can get messy is when you want to have mips32 and mips16 mode code 
in the same executable. If there is no floating point in the call 
signature, mips32 and mips16 functions can call each other with no problems.

I'm starting to implement the various interoperable modes now.

There is an historical way that all of this has been done in gcc and for 
this base port, management wants it done the same way. The historical 
definition of hard-float for mips16 is a hybrid based on gcc soft float.

The first step is to allow mips16 to use a library of soft float library 
routines that are implemented in mips32 mode using mips32 floating point 
hardware instructions. This mostly will work if you just change the 
names of the normal libc soft float library routines to be the hard 
float counterparts.  These hardware floating point versions of soft 
float helper functions have the same signature as their soft float 
counterparts. The place where it does not work is with libm because the 
libm routines are mips32 functions and written without any knowledge of 
this and expect it's arguments to be in floating point registers if the 
mips 32 abi requires that. Ditto for return values.

There are two paths in this first stage; one for pic and one for non 
pic. Non pic requires some other functionality that I have to add to 
llvm which we already have discussed; that is the ability to compile 
functions in mips32 and mips16 mode in the same module.

So I am solving the pic case now.

I need to know the original (pre-lowered) return type and type of 
argument 1 and argument 2
in order to know which helper functions (if any) to call during the 

I will look into extending llvm to make this information available as 
you suggested.


More information about the llvm-dev mailing list