diff options
author | Andreas Tobler <toa@pop.agri.ch> | 2002-03-07 19:24:42 +0100 |
---|---|---|
committer | David Edelsohn <dje@gcc.gnu.org> | 2002-03-07 13:24:42 -0500 |
commit | 073ae293d97f76c66767fdce57f6f6e3ef58b612 (patch) | |
tree | 2067fd3b0161aebe36726eaf4d9574b16aa6c1d3 /libffi/src/powerpc/ffi_darwin.c | |
parent | fcf742eac8e28d8867e19a17fa21999c300166db (diff) | |
download | gcc-073ae293d97f76c66767fdce57f6f6e3ef58b612.tar.gz |
Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files.
2002-03-07 Andreas Tobler <toa@pop.agri.ch>
David Edelsohn <edelsohn@gnu.org>
* Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files.
(TARGET_SRC_POWERPC_AIX): Add aix_closure.S.
(TARGET_SRC_POWERPC_DARWIN): Add darwin_closure.S.
* Makefile.in: Regenerate.
* include/ffi.h.in: Add AIX and Darwin closure definitions.
* src/powerpc/ffi_darwin.c (ffi_prep_closure): New function.
(flush_icache, flush_range): New functions.
(ffi_closure_helper_DARWIN): New function.
* src/powerpc/aix_closure.S: New file.
* src/powerpc/darwin_closure.S: New file.
Co-Authored-By: David Edelsohn <edelsohn@gnu.org>
From-SVN: r50408
Diffstat (limited to 'libffi/src/powerpc/ffi_darwin.c')
-rw-r--r-- | libffi/src/powerpc/ffi_darwin.c | 329 |
1 files changed, 328 insertions, 1 deletions
diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c index 3cf504cf150..d80f6bfc6f0 100644 --- a/libffi/src/powerpc/ffi_darwin.c +++ b/libffi/src/powerpc/ffi_darwin.c @@ -6,7 +6,7 @@ Darwin ABI support (c) 2001 John Hornkvist AIX ABI support (c) 2002 Free Software Foundation, Inc. - $Id: ffi_darwin.c,v 1.2 2002/01/17 16:04:21 dje Exp $ + $Id: ffi_darwin.c,v 1.3 2002/02/21 19:14:28 dje Exp $ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -31,6 +31,8 @@ #include <ffi_common.h> #include <stdlib.h> + +extern void ffi_closure_ASM(void); enum { /* The assembly depends on these exact flags. */ @@ -382,3 +384,328 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, break; } } + +static void flush_icache(char *); +static void flush_range(char *, int); + +/* The layout of a function descriptor. A C function pointer really */ +/* points to one of these. */ + +typedef struct aix_fd_struct { + void *code_pointer; + void *toc; +} aix_fd; + +/* here I'd like to add the stack frame layout we use in darwin_closure.S + * and aix_clsoure.S + * +/* SP previous -> +---------------------------------------+ <--- child frame + | back chain to caller 4 | + +---------------------------------------+ 4 + | saved CR 4 | + +---------------------------------------+ 8 + | saved LR 4 | + +---------------------------------------+ 12 + | reserved for compilers 4 | + +---------------------------------------+ 16 + | reserved for binders 4 | + +---------------------------------------+ 20 + | saved TOC pointer 4 | + +---------------------------------------+ 24 + | always reserved 8*4=32 (revious GPRs)| + | according to the linkage convention | + | from AIX | + +---------------------------------------+ 56 + | our FPR area 13*8=104 | + | f1 | + | . | + | f13 | + +---------------------------------------+ 160 + | result area 4 | +SP current --> +---------------------------------------+ 164 <- parent frame + | back chain to caller 4 | + +---------------------------------------+ 168 + | saved CR 4 | + +---------------------------------------+ 172 + | saved LR 4 | + +---------------------------------------+ 176 + | reserved for compilers 4 | + +---------------------------------------+ 180 + | reserved for binders 4 | + +---------------------------------------+ 184 + | saved TOC pointer 4 | + +---------------------------------------+ 188 + | always reserved 8*4=32 we store our | + | GPRs here | + | r3 | + | . | + | r10 | + +---------------------------------------+ 220 + | PST area, overflow part | + +---------------------------------------+ xxx + | ???? | + +---------------------------------------+ xxx + +*/ +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + struct ffi_aix_trampoline_struct *tramp_aix; + + switch (cif->abi) + { + case FFI_DARWIN: + + FFI_ASSERT (cif->abi == FFI_DARWIN); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x818b0000; /* lwz r12,0(r11) /* function address */ + tramp[6] = 0x7c0803a6; /* mtlr r0 */ + tramp[7] = 0x7d8903a6; /* mtctr r12 */ + tramp[8] = 0x816b0004; /* lwz r11,4(r11) /* static chain */ + tramp[9] = 0x4e800420; /* bctr */ + *(void **) &tramp[2] = (void *)ffi_closure_ASM; /* function */ + *(void **) &tramp[3] = (void *)closure; /* context */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. Only necessary on Darwin */ + flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE); + + break; + + case FFI_AIX: + + tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp); + aix_fd *fd = (aix_fd *)(void *)ffi_closure_ASM; + + FFI_ASSERT (cif->abi == FFI_AIX); + + tramp_aix->code_pointer = fd->code_pointer; + tramp_aix->toc = fd->toc; + tramp_aix->static_chain = closure; + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + default: + + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +static void +flush_icache(char *addr) +{ +#ifndef _AIX + __asm__ volatile ( + "dcbf 0,%0;" + "sync;" + "icbi 0,%0;" + "sync;" + "isync;" + : : "r"(addr) : "memory"); +#endif +} + +static void +flush_range(char * addr1, int size) +{ +#define MIN_LINE_SIZE 32 + int i; + for (i = 0; i < size; i += MIN_LINE_SIZE) + flush_icache(addr1+i); + flush_icache(addr1+size-1); +} + +int ffi_closure_helper_DARWIN (ffi_closure*, void*, unsigned long*, + unsigned long*, unsigned long*); + +/* Basically the trampoline invokes ffi_closure_ASM, and on + * entry, r11 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_ASM invokes the + * following helper function to do most of the work + */ + +int +ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, + unsigned long * pgr, unsigned long * pfr, + unsigned long * pst) +{ + /* rvalue is the pointer to space for return value in closure assembly */ + /* pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM */ + /* pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM */ + /* pst is the pointer to outgoing parameter stack in original caller */ + + void ** avalue; + ffi_type ** arg_types; + long i, avn; + long nf; /* number of floating registers already used */ + long ng; /* number of general registers already used */ + ffi_cif * cif; + double temp; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + nf = 0; + ng = 0; + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *)pgr; + ng++; + pgr++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) { + avalue[i] = (((char *)pgr)+3); + ng++; + pgr++; + } else { + avalue[i] = (((char *)pst)+3); + pst++; + } + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) { + avalue[i] = (((char *)pgr)+2); + ng++; + pgr++; + } else { + avalue[i] = (((char *)pst)+2); + pst++; + } + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + case FFI_TYPE_STRUCT: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) { + avalue[i] = pgr; + ng++; + pgr++; + } else { + avalue[i] = pst; + pst++; + } + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* long long ints are passed in two gpr's if available or in + * the pst, one place is a bit odd, when a long long passes + * the boundary between gpr and pst area we have to increment + * the pst by one. + */ + if (ng < 7) { + avalue[i] = pgr; + ng+=2; + pgr+=2; + } else if (ng == 7) { + avalue[i] = pgr; + ng++; + pgr++; + pst++; + } else { + avalue[i] = pst; + pst+=2; + } + break; + + case FFI_TYPE_FLOAT: + /* a float value consumes a GPR + * + * there are 13 64bit floating point registers + */ + + if ((ng > 7) && (nf < 13)) { + pst++; + } + if (nf < 13) { + temp = *(double*)pfr; + *(float*)pfr = (float)temp; + avalue[i] = pfr; + nf++; + pfr+=2; + ng++; + pgr++; + + } else { + avalue[i] = pst; + nf++; + pst++; + } + break; + + case FFI_TYPE_DOUBLE: + /* a double value consumes two GPRs + * + * there are 13 64bit floating point registers + */ + + if ((ng == 7) && (nf < 13)) { + pst++; /* if only one gpr is left the double steals it */ + } else if ((ng > 7) && (nf < 13)) { + pst+=2; /* a double consumes two GPRs in Darwin/AIX */ + } + if (nf < 13) { + avalue[i] = pfr; + nf++; + pfr+=2; + ng+=2; + pgr+=2; + + } else { + avalue[i] = pst; + nf++; + pst+=2; + } + break; + + default: + FFI_ASSERT(0); + + } + + i++; + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype->type; + +} |