Skip to content

Commit

Permalink
* src/powerpc/ppc_closure.S: New file.
Browse files Browse the repository at this point in the history
	* 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
  • Loading branch information
tromey committed Mar 24, 2001
1 parent 46da8d1 commit 384eea1
Show file tree
Hide file tree
Showing 6 changed files with 433 additions and 5 deletions.
15 changes: 15 additions & 0 deletions libffi/ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
5 changes: 3 additions & 2 deletions libffi/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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@
Expand Down Expand Up @@ -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@)
Expand Down
7 changes: 4 additions & 3 deletions libffi/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
6 changes: 6 additions & 0 deletions libffi/include/ffi.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
257 changes: 257 additions & 0 deletions libffi/src/powerpc/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

}





Loading

0 comments on commit 384eea1

Please sign in to comment.