[LLVMdev] Request for merge: GHC/ARM calling convention.
Karel Gardas
karel.gardas at centrum.cz
Fri Jun 29 14:56:40 PDT 2012
On 06/29/12 11:12 PM, Renato Golin wrote:
> On 29 June 2012 17:46, Karel Gardas<karel.gardas at centrum.cz> wrote:
>> Yes and no. Shortly: original GHC/ARM/LLVM port was done by Stephen on
>> ARMv5/Qemu IIRC. I've later added whole VFP support and ARMv7 support. The
>> code in GHC is properly #ifdefed, so if there is no VFP available on pre
>> ARMv6, then it's not used. ie. GHC STG floating points regs are then
>> allocated in RAM instead of real hardware regs.
>
> That's fine. As long as you don't try to interoperate with EABI libraries... ;)
You makes me worried! Let me ask, am I wrong assuming Ubuntu
11.04/11.10/12.04 are using EABI? That's at least what I thought all the
time...
Anyway, if they are EABI, then GHC/ARM needs to interoperate well with
EABI libs as Haskell code is using them too.
For registerised GHC build there are two important functions provided in
GHC's RTS written in C (or gcc inline asm compiled by gcc still using
platform ABI) which performs important task of bridging C world ABI and
GHC own ABI. It's StgRun and StgReturn. StgRun calls Haskell (STG)
function from the C world and StgReturn return from the Haskell world
into C world again safely. They are defined in rts/StgCRun.c and the
comment from the top of the file might be more useful here than my
writing about it:
* STG-to-C glue.
*
* To run an STG function from C land, call
*
* rv = StgRun(f,BaseReg);
*
* where "f" is the STG function to call, and BaseReg is the address of the
* RegTable for this run (we might have separate RegTables if we're running
* multiple threads on an SMP machine).
*
* In the end, "f" must JMP to StgReturn (defined below), passing the
* return-value "rv" in R1, to return to the caller of StgRun returning
"rv" in
* the whatever way C returns a value.
*
* NOTE: StgRun/StgReturn do *NOT* load or store Hp or any other registers
* (other than saving the C callee-saves registers). Instead, the called
* function "f" must do that in STG land.
*
* We also initially make sure that there are @RESERVED_C_STACK_BYTES@
on the
* C-stack. This is done to reserve some space for the allocation of
* temporaries in STG code.
If you are then curious how ARM-specific StgRun implementation looks,
then here it is:
#ifdef arm_HOST_ARCH
#if defined(__thumb__)
#define THUMB_FUNC ".thumb\n\t.thumb_func\n\t"
#else
#define THUMB_FUNC
#endif
StgRegTable *
StgRun(StgFunPtr f, StgRegTable *basereg) {
StgRegTable * r;
__asm__ volatile (
/*
* save callee-saves registers on behalf of the STG code.
*/
"stmfd sp!, {r4-r10, fp, ip, lr}\n\t"
#if !defined(arm_HOST_ARCH_PRE_ARMv6)
"vstmdb sp!, {d8-d11}\n\t"
#endif
/*
* allocate some space for Stg machine's temporary storage.
* Note: RESERVER_C_STACK_BYTES has to be a round number here or
* the assembler can't assemble it.
*/
"sub sp, sp, %3\n\t"
/*
* Set BaseReg
*/
"mov r4, %2\n\t"
/*
* Jump to function argument.
*/
"bx %1\n\t"
".global " STG_RETURN "\n\t"
THUMB_FUNC
".type " STG_RETURN ", %%function\n"
STG_RETURN ":\n\t"
/*
* Free the space we allocated
*/
"add sp, sp, %3\n\t"
/*
* Return the new register table, taking it from Stg's R1
(ARM's R7).
*/
"mov %0, r7\n\t"
/*
* restore callee-saves registers.
*/
#if !defined(arm_HOST_ARCH_PRE_ARMv6)
"vldmia sp!, {d8-d11}\n\t"
#endif
"ldmfd sp!, {r4-r10, fp, ip, lr}\n\t"
: "=r" (r)
: "r" (f), "r" (basereg), "i" (RESERVED_C_STACK_BYTES)
#if !defined(__thumb__)
/* In ARM mode, r11/fp is frame-pointer and so we cannot mark
it as clobbered. If we do so, GCC complains with error. */
: "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", "%ip", "%lr"
#else
/* In Thumb mode r7 is frame-pointer and so we cannot mark it
as clobbered. On the other hand we mark as clobbered also
those regs not used in Thumb mode. Hard to judge if this is
needed, but certainly Haskell code is using them for
placing GHC's virtual registers there. See
includes/stg/MachRegs.h Please note that Haskell code is
compiled by GHC/LLVM into ARM code (not Thumb!), at least
as of February 2012 */
: "%r4", "%r5", "%r6", "%r8", "%r9", "%r10", "%fp", "%ip", "%lr"
#endif
);
return r;
}
#endif
Please see https://github.com/ghc/ghc/blob/master/rts/StgCRun.c -- if
you are interested to see implementations of that function for another
architectures (x86/amd64/ppc/...)
Honestly speaking I don't know if I'm making things more clear or more
confused with this but I hope you can somehow distill it and tell me if
there is anything wrong with our ARM/GHC support then.
Thanks a lot!
Karel
More information about the llvm-dev
mailing list