ppc_closure.S: New file.

* 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.

From-SVN: r40807
This commit is contained in:
Kevin B Hendricks 2001-03-24 03:26:28 +00:00 committed by Tom Tromey
parent 75e0407e01
commit cc4c8975aa
6 changed files with 433 additions and 5 deletions

View File

@ -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.

View File

@ -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@)

View File

@ -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 \

View File

@ -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

View File

@ -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;
}

View File

@ -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)