diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-03-24 03:26:28 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-03-24 03:26:28 +0000 |
commit | 384eea1fc8299ebaac0f4986fc31e16a57ece2ad (patch) | |
tree | ed1fbe0280cc5d220154b3aa521122d435ce370e /libffi | |
parent | 46da8d1dc657ba92789bca6785a52fe3d5c80db8 (diff) | |
download | gcc-384eea1fc8299ebaac0f4986fc31e16a57ece2ad.tar.gz |
* src/powerpc/ppc_closure.S: New file.
* src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug
involving long long and register pairs.
(ffi_prep_closure): New function.
(flush_icache): Likewise.
(ffi_closure_helper_SYSV): Likewise.
* include/ffi.h.in (FFI_CLOSURES): Define on PPC.
(FFI_TRAMPOLINE_SIZE): Likewise.
(FFI_NATIVE_RAW_API): Likewise.
* Makefile.in: Rebuilt.
* Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S.
(TARGET_SRC_POWERPC): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@40807 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libffi')
-rw-r--r-- | libffi/ChangeLog | 15 | ||||
-rw-r--r-- | libffi/Makefile.am | 5 | ||||
-rw-r--r-- | libffi/Makefile.in | 7 | ||||
-rw-r--r-- | libffi/include/ffi.h.in | 6 | ||||
-rw-r--r-- | libffi/src/powerpc/ffi.c | 257 | ||||
-rw-r--r-- | libffi/src/powerpc/ppc_closure.S | 148 |
6 files changed, 433 insertions, 5 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 2110d5b227f..0e92ba64f85 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,18 @@ +2001-03-23 Tom Tromey <tromey@redhat.com> + + * src/powerpc/ppc_closure.S: New file. + * src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug + involving long long and register pairs. + (ffi_prep_closure): New function. + (flush_icache): Likewise. + (ffi_closure_helper_SYSV): Likewise. + * include/ffi.h.in (FFI_CLOSURES): Define on PPC. + (FFI_TRAMPOLINE_SIZE): Likewise. + (FFI_NATIVE_RAW_API): Likewise. + * Makefile.in: Rebuilt. + * Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S. + (TARGET_SRC_POWERPC): Likewise. + 2001-03-19 Tom Tromey <tromey@redhat.com> * Makefile.in: Rebuilt. diff --git a/libffi/Makefile.am b/libffi/Makefile.am index 44b169b2a98..8d2eb537486 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -10,7 +10,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ src/x86/ffi.c src/x86/sysv.S \ src/alpha/ffi.c src/alpha/osf.S \ src/m68k/ffi.c src/m68k/sysv.S \ - src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/asm.h \ + src/powerpc/ffi.c src/powerpc/sysv.S \ + src/powerpc/ppc_closure.S src/powerpc/asm.h \ src/arm/ffi.c src/arm/sysv.S VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@ @@ -93,7 +94,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S -TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S +TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@) diff --git a/libffi/Makefile.in b/libffi/Makefile.in index a9cdfb26fc1..a064a32662e 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -86,7 +86,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ src/x86/ffi.c src/x86/sysv.S \ src/alpha/ffi.c src/alpha/osf.S \ src/m68k/ffi.c src/m68k/sysv.S \ - src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/asm.h \ + src/powerpc/ffi.c src/powerpc/sysv.S \ + src/powerpc/asm.h src/powerpc/ppc_closure.S \ src/arm/ffi.c src/arm/sysv.S @@ -159,7 +160,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S -TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S +TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \ @@ -206,7 +207,7 @@ libffi_la_LIBADD = @MIPS_SGI_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \ @MIPS_SGI_TRUE@raw_api.lo java_raw_api.lo ffi.lo o32.lo n32.lo @POWERPC_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \ -@POWERPC_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo +@POWERPC_TRUE@raw_api.lo java_raw_api.lo ffi.lo sysv.lo ppc_closure.lo @SPARC_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \ @SPARC_TRUE@raw_api.lo java_raw_api.lo ffi.lo v8.lo v9.lo @X86_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \ diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in index 17c383d3167..7161e51e92a 100644 --- a/libffi/include/ffi.h.in +++ b/libffi/include/ffi.h.in @@ -372,6 +372,12 @@ struct ffi_ia64_trampoline_struct { #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 +#elif defined(POWERPC) + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 40 +#define FFI_NATIVE_RAW_API 0 + #else #define FFI_CLOSURES 0 diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c index 6d12d653baa..c93aec0ed87 100644 --- a/libffi/src/powerpc/ffi.c +++ b/libffi/src/powerpc/ffi.c @@ -29,6 +29,9 @@ #include <ffi_common.h> #include <stdlib.h> +#include <stdio.h> + +extern void ffi_closure_SYSV(void); enum { /* The assembly depends on these exact flags. */ @@ -172,6 +175,18 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack) } else { + /* whoops: abi states only certain register pairs + * can be used for passing long long int + * specifically (r3,r4), (r5,r6), (r7,r8), + * (r9,r10) and if next arg is long long but + * not correct starting register of pair then skip + * until the proper starting register + */ + if (intarg_count%2 != 0) + { + intarg_count ++; + gpr_base++; + } *(long long *)gpr_base = *(long long *)*p_argv; gpr_base += 2; } @@ -421,3 +436,245 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, break; } } + + +static void flush_icache(char *, int); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + + 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] = 0x7c0803a6; /* mtlr r0 */ + tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ + tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ + tramp[8] = 0x7c0903a6; /* mtctr r0 */ + tramp[9] = 0x4e800420; /* bctr */ + *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */ + *(void **) &tramp[3] = (void *)closure; /* context */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. */ + flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE); + + return FFI_OK; +} + + +#define MIN_CACHE_LINE_SIZE 8 + +static void flush_icache(char * addr1, int size) +{ + int i; + char * addr; + for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) { + addr = addr1 + i; + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory"); + } + addr = addr1 + size - 1; + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory"); +} + + +int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*, + unsigned long*, unsigned long*); + +/* Basically the trampoline invokes ffi_closure_SYSV, 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_SYSV invokes the + * following helper function to do most of the work + */ + +int +ffi_closure_helper_SYSV (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_SYSV */ + /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ + /* 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 = *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: + /* passing long long ints are complex, they must + * be passed in suitable register pairs such as + * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) + * and if the entire pair aren't available then the outgoing + * parameter stack is used for both but an alignment of 8 + * must will be kept. So we must either look in pgr + * or pst to find the correct address for this type + * of parameter. + */ + if (ng < 7) { + if (ng & 0x01) { + /* skip r4, r6, r8 as starting points */ + ng++; + pgr++; + } + avalue[i] = pgr; + ng+=2; + pgr+=2; + } else { + if (((long)pst) & 4) pst++; + avalue[i] = pst; + pst+=2; + } + break; + + case FFI_TYPE_FLOAT: + /* unfortunately float values are stored as doubles + * in the ffi_closure_SYSV code (since we don't check + * the type in that routine). This is also true + * of floats passed on the outgoing parameter stack. + * Also, on the outgoing stack all values are aligned + * to 8 + * + * Don't you just love the simplicity of this ABI! + */ + + /* there are 8 64bit floating point registers */ + + if (nf < 8) { + temp = *(double*)pfr; + *(float*)pfr = (float)temp; + avalue[i] = pfr; + nf++; + pfr+=2; + } else { + /* FIXME? here we are really changing the values + * stored in the original calling routines outgoing + * parameter stack. This is probably a really + * naughty thing to do but... + */ + if (((long)pst) & 4) pst++; + temp = *(double*)pst; + *(float*)pst = (float)temp; + avalue[i] = pst; + nf++; + pst+=2; + } + break; + + case FFI_TYPE_DOUBLE: + /* On the outgoing stack all values are aligned to 8 */ + /* there are 8 64bit floating point registers */ + + if (nf < 8) { + avalue[i] = pfr; + nf++; + pfr+=2; + } else { + if (((long)pst) & 4) pst++; + avalue[i] = pst; + nf++; + pst+=2; + } + break; + + default: + FFI_ASSERT(0); + } + + i++; + } + + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_osf how to perform return type promotions. */ + return cif->rtype->type; + +} + + + + + diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S new file mode 100644 index 00000000000..311857724cc --- /dev/null +++ b/libffi/src/powerpc/ppc_closure.S @@ -0,0 +1,148 @@ +#define LIBFFI_ASM +#include <powerpc/asm.h> + +.globl ffi_closure_helper_SYSV + +ENTRY(ffi_closure_SYSV) + stwu %r1,-144(%r1) + mflr %r0 + stw %r31,140(%r1) + stw %r0,148(%r1) + +# we want to build up an areas for the parameters passed +# in registers (both floating point and integer) + + # so first save gpr 3 to gpr 10 (aligned to 4) + stw %r3, 16(%r1) + stw %r4, 20(%r1) + stw %r5, 24(%r1) + stw %r6, 28(%r1) + stw %r7, 32(%r1) + stw %r8, 36(%r1) + stw %r9, 40(%r1) + stw %r10,44(%r1) + + # next save fpr 1 to fpr 8 (aligned to 8) + stfd %f1, 48(%r1) + stfd %f2, 56(%r1) + stfd %f3, 64(%r1) + stfd %f4, 72(%r1) + stfd %f5, 80(%r1) + stfd %f6, 88(%r1) + stfd %f7, 96(%r1) + stfd %f8, 104(%r1) + + # set up registers for the routine that actually does the work + # get the context pointer from the trampoline + mr %r3,%r11 + + # now load up the pointer to the result storage + addi %r4,%r1,112 + + # now load up the pointer to the saved gpr registers + addi %r5,%r1,16 + + # now load up the pointer to the saved fpr registers */ + addi %r6,%r1,48 + + # now load up the pointer to the outgoing parameter + # stack in the previous frame + # i.e. the previous frame pointer + 8 + addi %r7,%r1,152 + + # make the call + bl JUMPTARGET(ffi_closure_helper_SYSV) + + # now r3 contains the return type + # so use it to look up in a table + # so we know how to deal with each type + + # look up the proper starting point in table + # by using return type as offset + addi %r5,%r1,112 # get pointer to results area + addis %r4,0,.L60@ha # get address of jump table + addi %r4,%r4,.L60@l + slwi %r3,%r3,2 # now multiply return type by 4 + lwzx %r3,%r4,%r3 # get the contents of that table value + add %r3,%r3,%r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it + .align 2 +.L60: + .long .L44-.L60 # FFI_TYPE_VOID + .long .L50-.L60 # FFI_TYPE_INT + .long .L47-.L60 # FFI_TYPE_FLOAT + .long .L46-.L60 # FFI_TYPE_DOUBLE + .long .L46-.L60 # FFI_TYPE_LONGDOUBLE + .long .L56-.L60 # FFI_TYPE_UINT8 + .long .L55-.L60 # FFI_TYPE_SINT8 + .long .L58-.L60 # FFI_TYPE_UINT16 + .long .L57-.L60 # FFI_TYPE_SINT16 + .long .L50-.L60 # FFI_TYPE_UINT32 + .long .L50-.L60 # FFI_TYPE_SINT32 + .long .L48-.L60 # FFI_TYPE_UINT64 + .long .L48-.L60 # FFI_TYPE_SINT64 + .long .L44-.L60 # FFI_TYPE_STRUCT + .long .L50-.L60 # FFI_TYPE_POINTER + + +# case double +.L46: + lfd %f1,0(%r5) + b .L44 + +# case float +.L47: + lfs %f1,0(%r5) + b .L44 + +# case long long +.L48: + lwz %r3,0(%r5) + lwz %r4,4(%r5) + b .L44 + +# case default / int32 / pointer +.L50: + lwz %r3,0(%r5) + b .L44 + +# case signed int8 +.L55: + addi %r5,%r5,3 + lbz %r3,0(%r5) + extsb %r3,%r3 + b .L44 + +# case unsigned int8 +.L56: + addi %r5,%r5,3 + lbz %r3,0(%r5) + b .L44 + +# case signed int16 +.L57: + addi %r5,%r5,2 + lhz %r3,0(%r5) + extsh %r3,%r3 + b .L44 + +#case unsigned int16 +.L58: + addi %r5,%r5,2 + lhz %r3,0(%r5) + +# case void / done +.L44: + + lwz %r11,0(%r1) + lwz %r0,4(%r11) + mtlr %r0 + lwz %r31,-4(%r11) + mr %r1,%r11 + blr +END(ffi_closure_SYSV) + + + + |