[Vm-dev] Help: Float returns on RISCV

Eliot Miranda eliot.miranda at gmail.com
Wed Jun 29 16:17:29 UTC 2022


Hi Ken,

> On Jun 29, 2022, at 7:32 AM, Ken.Dickey at whidbey.com wrote:
> 
> Greetings,
> 
> I could use some help in how register values are passed in the FFI.
> 
> The basic situation is that on RISC-V, simple float/double values are returned in FA0 (float reg), not A0 (integer reg).

The pattern is straight-forward.  Look at the various implementations of ffiCalloutTo:SpecOnStack:in:. There are two issues, passing arguments and receiving results.

To pass register arguments the code does a call of a dummy function, loadFloatRegs, defined in platforms/Cross/plugins/SqueakFFIPrims/sqFFIPlugin.c as an empty function.  Just calling this with any floating point arguments causes the C compiler to generate the code that loads the floating point argument registers.  Because the function does nothing the values persist until the subsequent call of the real function.

Look for sends of loadFloatRegs:_:_:_: & loadFloatRegs:_:_:_:_:_:_:_: 

Then, following immediately, to collect a floating point result the point of call tests the return type and if it is floating point if casts the function pointer to one returning floating point and calls that, otherwise it casts it to one that returns an integer and calls that.


> E.g. for unit test:
> 
> =======================================
> testConstructedDoubleCall
>   "Test using generic FFI spec"
>   | result meth |
>   meth := ExternalLibraryFunction
>       name:'ffiTestDoubles' module: FFITestLibrary moduleName
>       callType: 0 returnType: ExternalType double
>       argumentTypes: ((1 to: 2) collect:[:i| ExternalType double]).
>   result := meth invokeWithArguments: (Array with: 41 with: true).
>   self assert: result = 42.0
> =======================================
> EXPORT(double) ffiTestDoubles(double d1, double d2)
> {
>   printf("The two floats are %f and %f\n", (float)d1, (float)d2);
>   return d1+d2;
> }
> 
> Looking at:
>  ThreadedARM64FFIPlugin>>ffiCalloutTo:SpecOnStack:in:
> =======================================
> 
> Stepping in GDB
> --> ffiCallArgArrayOrNilNumArgs()
> ..
> (floatRet.d = dispatchFunctionPointerwithwithwithwithwithwithwithwith(...)
> 
> At this point, I can single step to ffiTestDoubles(),
> the proper values are printed (41,1),
> 42 is placed in register FA0
> 
> But the first value in float.d is _1_ (value presumably from A0).
> 
> So I need to set GDB into asm mode and crawl through the C assign to floatRet.d,
> but some theory of operations could help me out here.
> 
> Different setup passed to #setReturnRegister:andCall:withArgsArray: ??
> 
> Thanks much for help,
> -KenD


More information about the Vm-dev mailing list