mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-18 20:55:20 +08:00
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:
parent
75e0407e01
commit
cc4c8975aa
@ -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.
|
||||
|
@ -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@)
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
148
libffi/src/powerpc/ppc_closure.S
Normal file
148
libffi/src/powerpc/ppc_closure.S
Normal 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)
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user