This is the mail archive of the
libffi-discuss@sources.redhat.com
mailing list for the libffi project.
alpha closures
- To: libffi-discuss at sources dot redhat dot com
- Subject: alpha closures
- From: Richard Henderson <rth at redhat dot com>
- Date: Thu, 7 Dec 2000 11:09:31 -0800
- Cc: Anthony Green <green at redhat dot com>
Also significantly streamlines the ffi_call code paths, and
fixes an argument type promotion bug wrt unsigned int.
Also some typos in generic code.
r~
* src/raw_api.c (ffi_translate_args): Fix typo.
(ffi_prep_closure): Likewise.
* include/ffi.h.in [ALPHA]: Define FFI_CLOSURES and
FFI_TRAMPOLINE_SIZE.
* src/alpha/ffi.c (ffi_prep_cif_machdep): Adjust minimal
cif->bytes for new ffi_call_osf implementation.
(ffi_prep_args): Absorb into ...
(ffi_call): ... here. Do all stack allocation here and
avoid a callback function.
(ffi_prep_closure, ffi_closure_osf_inner): New.
* src/alpha/osf.S (ffi_call_osf): Reimplement with no callback.
(ffi_closure_osf): New.
Index: include/ffi.h.in
===================================================================
RCS file: /cvs/libffi/libffi/include/ffi.h.in,v
retrieving revision 1.4
diff -c -p -d -r1.4 ffi.h.in
*** ffi.h.in 2000/04/17 03:18:45 1.4
--- ffi.h.in 2000/12/07 18:56:10
*************** struct ffi_ia64_trampoline_struct {
*** 360,365 ****
--- 360,371 ----
};
#define FFI_NATIVE_RAW_API 0
+ #elif defined(ALPHA)
+
+ #define FFI_CLOSURES 1
+ #define FFI_TRAMPOLINE_SIZE 24
+ #define FFI_NATIVE_RAW_API 0
+
#else
#define FFI_CLOSURES 0
Index: src/raw_api.c
===================================================================
RCS file: /cvs/libffi/libffi/src/raw_api.c,v
retrieving revision 1.1
diff -c -p -d -r1.1 raw_api.c
*** raw_api.c 1999/08/04 18:02:34 1.1
--- raw_api.c 2000/12/07 18:56:10
*************** void ffi_raw_call (/*@dependent@*/ ffi_c
*** 202,208 ****
#if FFI_CLOSURES /* base system provides closures */
static void
! ffi_translate_args (ffi_cif *cif, void *ravlue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
--- 202,208 ----
#if FFI_CLOSURES /* base system provides closures */
static void
! ffi_translate_args (ffi_cif *cif, void *rvalue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
*************** ffi_prep_raw_closure (ffi_raw_closure* c
*** 226,232 ****
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
! &ffi_closure_translate,
(void*)cl);
if (status == FFI_OK)
{
--- 226,232 ----
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
! &ffi_translate_args,
(void*)cl);
if (status == FFI_OK)
{
Index: src/alpha/ffi.c
===================================================================
RCS file: /cvs/libffi/libffi/src/alpha/ffi.c,v
retrieving revision 1.1.1.1
diff -c -p -d -r1.1.1.1 ffi.c
*** ffi.c 1998/11/29 16:48:16 1.1.1.1
--- ffi.c 2000/12/07 18:56:10
***************
*** 30,199 ****
#include <stdlib.h>
! /* ffi_prep_args is called by the assembly routine once stack space
! has been allocated for the function's arguments */
- static void
- ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags)
- {
- register long i, avn;
- register void **p_argv;
- register char *argp;
- register ffi_type **p_arg;
! /* To streamline things in the assembly code, we always allocate 12
! words for loading up the int and fp argument registers. The layout
! is as when processing varargs: the 6 fp args, the 6 int args, then
! the incoming stack. ARGP points to the first int slot. */
! argp = stack + 6 * SIZEOF_ARG;
! memset (stack, 0, 12 * SIZEOF_ARG);
! if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
{
! *(void **) argp = ecif->rvalue;
! argp += sizeof(void *);
}
i = 0;
! avn = ecif->cif->nargs;
! p_arg = ecif->cif->arg_types;
! p_argv = ecif->avalue;
while (i < avn)
{
! size_t z = ALIGN((*p_arg)->size, SIZEOF_ARG);
!
! switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
! *(SINT64 *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
! *(UINT64 *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
! *(SINT64 *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
! *(UINT64 *) argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
- *(SINT64 *) argp = *(SINT32 *)(* p_argv);
- break;
-
case FFI_TYPE_UINT32:
! *(UINT64 *) argp = *(UINT32 *)(* p_argv);
break;
!
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
! *(UINT64 *) argp = *(UINT64 *)(* p_argv);
break;
case FFI_TYPE_FLOAT:
! if (argp - stack < 12 * SIZEOF_ARG)
{
/* Note the conversion -- all the fp regs are loaded as
doubles. The in-register format is the same. */
! *(double *) (argp - 6 * SIZEOF_ARG) = *(float *)(* p_argv);
}
else
! *(float *) argp = *(float *)(* p_argv);
break;
case FFI_TYPE_DOUBLE:
! if (argp - stack < 12 * SIZEOF_ARG)
! *(double *) (argp - 6 * SIZEOF_ARG) = *(double *)(* p_argv);
! else
! *(double *) argp = *(double *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
! memcpy(argp, *p_argv, (*p_arg)->size);
break;
default:
FFI_ASSERT(0);
}
! argp += z;
! i++, p_arg++, p_argv++;
}
}
! /* Perform machine dependent cif processing */
ffi_status
! ffi_prep_cif_machdep(ffi_cif *cif)
{
! /* Adjust cif->bytes. to include 12 words for the temporary register
! argument loading area. This will be removed before the call. */
!
! cif->bytes += 6*SIZEOF_ARG;
! if (cif->bytes < 12*SIZEOF_ARG)
! cif->bytes = 12*SIZEOF_ARG;
!
! /* The stack must be double word aligned, so round bytes up
! appropriately. */
! cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
! /* Set the return type flag */
! switch (cif->rtype->type)
! {
! case FFI_TYPE_VOID:
! case FFI_TYPE_STRUCT:
! cif->flags = cif->rtype->type;
! break;
! case FFI_TYPE_FLOAT:
! cif->flags = FFI_TYPE_FLOAT;
! break;
! case FFI_TYPE_DOUBLE:
! cif->flags = FFI_TYPE_DOUBLE;
! break;
- default:
- cif->flags = FFI_TYPE_INT;
- break;
- }
-
return FFI_OK;
}
-
- extern int ffi_call_osf(void (*)(char *, extended_cif *, int, int),
- extended_cif *, unsigned,
- unsigned, unsigned *, void (*)());
! void
! ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
! extended_cif ecif;
! ecif.cif = cif;
! ecif.avalue = avalue;
!
! /* If the return value is a struct and we don't have a return
! value address then we need to make one. */
! if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
! ecif.rvalue = alloca(cif->rtype->size);
! else
! ecif.rvalue = rvalue;
!
! switch (cif->abi)
{
! case FFI_OSF:
! ffi_call_osf(ffi_prep_args, &ecif, cif->bytes,
! cif->flags, rvalue, fn);
! break;
! default:
! FFI_ASSERT(0);
! break;
}
}
--- 30,249 ----
#include <stdlib.h>
! extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
! extern void ffi_closure_osf(void);
! ffi_status
! ffi_prep_cif_machdep(ffi_cif *cif)
! {
! /* Adjust cif->bytes to represent a minimum 6 words for the temporary
! register argument loading area. */
! if (cif->bytes < 6*SIZEOF_ARG)
! cif->bytes = 6*SIZEOF_ARG;
! /* Set the return type flag */
! switch (cif->rtype->type)
{
! case FFI_TYPE_STRUCT:
! case FFI_TYPE_FLOAT:
! case FFI_TYPE_DOUBLE:
! cif->flags = cif->rtype->type;
! break;
!
! default:
! cif->flags = FFI_TYPE_INT;
! break;
}
+
+ return FFI_OK;
+ }
+
+ void
+ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+ {
+ unsigned long *stack, *argp;
+ long i, avn;
+ ffi_type **arg_types;
+
+ FFI_ASSERT (cif->abi == FFI_OSF);
+
+ /* If the return value is a struct and we don't have a return
+ value address then we need to make one. */
+ if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
+ rvalue = alloca(cif->rtype->size);
+
+ /* Allocate the space for the arguments, plus 4 words of temp
+ space for ffi_call_osf. */
+ argp = stack = alloca(cif->bytes + 4*SIZEOF_ARG);
+
+ if (cif->flags == FFI_TYPE_STRUCT)
+ *(void **) argp++ = rvalue;
i = 0;
! avn = cif->nargs;
! arg_types = cif->arg_types;
!
while (i < avn)
{
! switch ((*arg_types)->type)
{
case FFI_TYPE_SINT8:
! *(SINT64 *) argp = *(SINT8 *)(* avalue);
break;
case FFI_TYPE_UINT8:
! *(SINT64 *) argp = *(UINT8 *)(* avalue);
break;
case FFI_TYPE_SINT16:
! *(SINT64 *) argp = *(SINT16 *)(* avalue);
break;
case FFI_TYPE_UINT16:
! *(SINT64 *) argp = *(UINT16 *)(* avalue);
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
! /* Note that unsigned 32-bit quantities are sign extended. */
! *(SINT64 *) argp = *(SINT32 *)(* avalue);
break;
!
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
! *(UINT64 *) argp = *(UINT64 *)(* avalue);
break;
case FFI_TYPE_FLOAT:
! if (argp - stack < 6)
{
/* Note the conversion -- all the fp regs are loaded as
doubles. The in-register format is the same. */
! *(double *) argp = *(float *)(* avalue);
}
else
! *(float *) argp = *(float *)(* avalue);
break;
case FFI_TYPE_DOUBLE:
! *(double *) argp = *(double *)(* avalue);
break;
case FFI_TYPE_STRUCT:
! memcpy(argp, *avalue, (*arg_types)->size);
break;
default:
FFI_ASSERT(0);
}
! argp += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
! i++, arg_types++, avalue++;
}
+
+ ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
}
!
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_OSF);
! tramp = (unsigned int *) &closure->tramp[0];
! tramp[0] = 0x47fb0401; /* mov $27,$1 */
! tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
! tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
! tramp[3] = 0x47ff041f; /* nop */
! *(void **) &tramp[4] = ffi_closure_osf;
! closure->cif = cif;
! closure->fun = fun;
! closure->user_data = user_data;
! /* Flush the Icache. */
! asm volatile ("imb" : : : "memory");
return FFI_OK;
}
! int
! ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
{
! ffi_cif *cif;
! void **avalue;
! ffi_type **arg_types;
! long i, avn, argn;
! cif = closure->cif;
! avalue = alloca(cif->nargs * sizeof(void *));
!
! argn = 0;
!
! /* Copy the caller's structure return address to that the closure
! returns the data directly to the caller. */
! if (cif->flags == FFI_TYPE_STRUCT)
! {
! rvalue = (void *) argp[0];
! argn = 1;
! }
!
! 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)->type)
! {
! case FFI_TYPE_SINT8:
! case FFI_TYPE_UINT8:
! case FFI_TYPE_SINT16:
! case FFI_TYPE_UINT16:
! case FFI_TYPE_SINT32:
! case FFI_TYPE_UINT32:
! case FFI_TYPE_SINT64:
! case FFI_TYPE_UINT64:
! case FFI_TYPE_POINTER:
! case FFI_TYPE_STRUCT:
! *avalue = &argp[argn];
! break;
! case FFI_TYPE_FLOAT:
! if (argn < 6)
! {
! /* Floats coming from registers need conversion from double
! back to float format. */
! *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
! *avalue = &argp[argn - 6];
! }
! else
! *avalue = &argp[argn];
! break;
!
! case FFI_TYPE_DOUBLE:
! *avalue = &argp[argn - (argn < 6 ? 6 : 0)];
! break;
!
! default:
! FFI_ASSERT(0);
! }
!
! argn += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
! i++, arg_types++, avalue++;
}
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_osf what register to put the return value in. */
+ return cif->flags;
}
Index: src/alpha/osf.S
===================================================================
RCS file: /cvs/libffi/libffi/src/alpha/osf.S,v
retrieving revision 1.1.1.1
diff -c -p -d -r1.1.1.1 osf.S
*** osf.S 1998/11/29 16:48:16 1.1.1.1
--- osf.S 2000/12/07 18:56:10
***************
*** 28,118 ****
#define LIBFFI_ASM
#include <ffi.h>
! #define callback $16
! #define ecifp $17
! #define bytes $18
! #define flags $19
! #define raddr $20
! #define fn $21
! #define flags_ofs 16
! #define raddr_ofs 24
! #define fn_ofs 32
! #define SIZEOF_FRAME (6*8)
! .text
! .align 4
.globl ffi_call_osf
.ent ffi_call_osf
-
ffi_call_osf:
! lda $30, -SIZEOF_FRAME($30)
! stq $26, 0($30)
! stq $15, 8($30)
! stq flags, flags_ofs($30)
! stq raddr, raddr_ofs($30)
! stq fn, fn_ofs($30)
! mov $30, $15
! .frame $15, SIZEOF_FRAME, $26, 0
! .mask 0x4008000, -SIZEOF_FRAME
.prologue 0
! mov callback, $27 # mov callback into place
! subq $30, bytes, $30 # allocate stack space
!
! # Call ffi_prep_args; ecif, bytes and flags are already in place.
! mov $30, $16 # push stack arg
! jsr $26, ($27), 0
# Load up all of the (potential) argument registers.
ldt $f16, 0($30)
ldt $f17, 8($30)
ldt $f18, 16($30)
ldt $f19, 24($30)
ldt $f20, 32($30)
ldt $f21, 40($30)
! ldq $16, 48($30)
! ldq $17, 56($30)
! ldq $18, 64($30)
! ldq $19, 72($30)
! ldq $20, 80($30)
! ldq $21, 88($30)
! # Get rid of the arg reg temp space and call the function.
! ldq $27, fn_ofs($15)
! lda $30, 12*8($30)
jsr $26, ($27), 0
# If the return value pointer is NULL, assume no return value.
! ldq raddr, raddr_ofs($15)
! beq raddr, $noretval
! ldq flags, flags_ofs($15)
! cmpeq flags, FFI_TYPE_INT, $1
bne $1, $retint
! cmpeq flags, FFI_TYPE_FLOAT, $2
bne $2, $retfloat
! cmpeq flags, FFI_TYPE_DOUBLE, $3
bne $3, $retdouble
! br $retstruct
!
! .align 3
$retint:
! stq $0, 0(raddr)
! br $noretval
$retfloat:
! sts $f0, 0(raddr)
! br $noretval
! $retdouble:
! stt $f0, 0(raddr)
! $retstruct:
! $noretval:
! mov $15, $30
! ldq $26, 0($15)
ldq $15, 8($15)
- lda $30, SIZEOF_FRAME($30)
ret
.end ffi_call_osf
--- 28,182 ----
#define LIBFFI_ASM
#include <ffi.h>
! .text
! /* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
! void *raddr, void (*fnaddr)());
! Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
! for this function. This has been allocated by ffi_call. We also
! deallocate some of the stack that has been alloca'd. */
! .align 3
.globl ffi_call_osf
.ent ffi_call_osf
ffi_call_osf:
! .frame $15, 32, $26, 0
! .mask 0x4008000, -32
! addq $16,$17,$1
! mov $16, $30
! stq $26, 0($1)
! stq $15, 8($1)
! stq $18, 16($1)
! mov $1, $15
.prologue 0
! stq $19, 24($1)
! mov $20, $27
# Load up all of the (potential) argument registers.
+ ldq $16, 0($30)
ldt $f16, 0($30)
ldt $f17, 8($30)
+ ldq $17, 8($30)
ldt $f18, 16($30)
+ ldq $18, 16($30)
ldt $f19, 24($30)
+ ldq $19, 24($30)
ldt $f20, 32($30)
+ ldq $20, 32($30)
ldt $f21, 40($30)
! ldq $21, 40($30)
! # Deallocate the register argument area.
! lda $30, 48($30)
!
jsr $26, ($27), 0
+ ldgp $29, 0($26)
# If the return value pointer is NULL, assume no return value.
! ldq $19, 24($15)
! ldq $18, 16($15)
! ldq $26, 0($15)
! beq $19, $noretval
! # Store the return value out in the proper type.
! cmpeq $18, FFI_TYPE_INT, $1
bne $1, $retint
! cmpeq $18, FFI_TYPE_FLOAT, $2
bne $2, $retfloat
! cmpeq $18, FFI_TYPE_DOUBLE, $3
bne $3, $retdouble
!
! $noretval:
! ldq $15, 8($15)
! ret
!
$retint:
! stq $0, 0($19)
! nop
! ldq $15, 8($15)
! ret
!
$retfloat:
! sts $f0, 0($19)
! nop
! ldq $15, 8($15)
! ret
! $retdouble:
! stt $f0, 0($19)
! nop
ldq $15, 8($15)
ret
.end ffi_call_osf
+
+ /* ffi_closure_osf(...)
+
+ Receives the closure argument in $1. */
+
+ .align 3
+ .globl ffi_closure_osf
+ .ent ffi_closure_osf
+ ffi_closure_osf:
+ .frame $30, 16*8, $26, 0
+ .mask 0x4000000, -14*8
+ ldgp $29, 0($27)
+ subq $30, 14*8, $30
+ stq $26, 0($30)
+ .prologue 1
+
+ # Store all of the potential argument registers in va_list format.
+ stt $f16, 4*8($30)
+ stt $f17, 5*8($30)
+ stt $f18, 6*8($30)
+ stt $f19, 7*8($30)
+ stt $f20, 8*8($30)
+ stt $f21, 9*8($30)
+ stq $16, 10*8($30)
+ stq $17, 11*8($30)
+ stq $18, 12*8($30)
+ stq $19, 13*8($30)
+ stq $20, 14*8($30)
+ stq $21, 15*8($30)
+
+ # Call ffi_closure_osf_inner to do the bulk of the work.
+ mov $1, $16
+ lda $17, 2*8($30)
+ lda $18, 10*8($30)
+ jsr $26, ffi_closure_osf_inner
+ ldgp $29, 0($26)
+ ldq $26, 0($30)
+
+ # Load up the return value in the proper type.
+ cmpeq $0, FFI_TYPE_INT, $1
+ bne $1, $loadint
+ cmpeq $0, FFI_TYPE_FLOAT, $2
+ bne $2, $loadfloat
+ cmpeq $18, FFI_TYPE_DOUBLE, $3
+ bne $3, $loaddouble
+
+ addq $30, 16*8, $30
+ ret
+
+ .align 3
+ $loadint:
+ ldq $0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ $loadfloat:
+ lds $f0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ $loaddouble:
+ ldt $f0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ .end ffi_closure_osf