s390: Inline and tidy ffi_prep_args
As per discussion with Ulrich Weigand, document the restrictions on the code within ffi_call_int as we simultaneously prepare stack frames for ffi_call_SYSV and the target function.
This commit is contained in:
294
src/s390/ffi.c
294
src/s390/ffi.c
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include <stdint.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*====================== End of Includes =============================*/
|
||||
@@ -128,165 +129,6 @@ ffi_check_struct_type (ffi_type *arg)
|
||||
|
||||
/*======================== End of Routine ============================*/
|
||||
|
||||
/*====================================================================*/
|
||||
/* */
|
||||
/* Name - ffi_prep_args. */
|
||||
/* */
|
||||
/* Function - Prepare parameters for call to function. */
|
||||
/* */
|
||||
/* 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 (ffi_cif *cif, void *rvalue, void **p_argv,
|
||||
unsigned long *p_ov, struct call_frame *p_frame)
|
||||
{
|
||||
unsigned char *p_struct = (unsigned char *)p_frame;
|
||||
unsigned long *p_gpr = p_frame->gpr_args;
|
||||
unsigned long long *p_fpr = p_frame->fpr_args;
|
||||
int n_fpr = 0;
|
||||
int n_gpr = 0;
|
||||
int n_ov = 0;
|
||||
ffi_type **ptr;
|
||||
int i;
|
||||
|
||||
/* If we returning a structure then we set the first parameter register
|
||||
to the address of where we are returning this structure. */
|
||||
if (cif->flags & FFI390_RET_IN_MEM)
|
||||
p_gpr[n_gpr++] = (unsigned long) rvalue;
|
||||
|
||||
/* Now for the arguments. */
|
||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++, p_argv++)
|
||||
{
|
||||
ffi_type *ty = *ptr;
|
||||
void *arg = *p_argv;
|
||||
int type = ty->type;
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
/* 16-byte long double is passed like a struct. */
|
||||
if (type == FFI_TYPE_LONGDOUBLE)
|
||||
type = FFI_TYPE_STRUCT;
|
||||
#endif
|
||||
|
||||
/* Check how a structure type is passed. */
|
||||
if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
|
||||
{
|
||||
if (type == FFI_TYPE_COMPLEX)
|
||||
type = FFI_TYPE_POINTER;
|
||||
else
|
||||
type = ffi_check_struct_type (ty);
|
||||
|
||||
/* If we pass the struct via pointer, copy the data. */
|
||||
if (type == FFI_TYPE_POINTER)
|
||||
{
|
||||
p_struct -= ROUND_SIZE (ty->size);
|
||||
memcpy (p_struct, (char *)arg, ty->size);
|
||||
arg = &p_struct;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now handle all primitive int/pointer/float data types. */
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_DOUBLE:
|
||||
if (n_fpr < MAX_FPRARGS)
|
||||
p_fpr[n_fpr++] = *(unsigned long long *) arg;
|
||||
else
|
||||
#ifdef __s390x__
|
||||
p_ov[n_ov++] = *(unsigned long *) arg;
|
||||
#else
|
||||
p_ov[n_ov++] = ((unsigned long *) arg)[0],
|
||||
p_ov[n_ov++] = ((unsigned long *) arg)[1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (n_fpr < MAX_FPRARGS)
|
||||
p_fpr[n_fpr++] = (unsigned long long)*(unsigned int *) arg << 32;
|
||||
else
|
||||
p_ov[n_ov++] = *(unsigned int *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_POINTER:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
|
||||
else
|
||||
p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
#ifdef __s390x__
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(unsigned long *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(unsigned long *) arg;
|
||||
#else
|
||||
if (n_gpr == MAX_GPRARGS-1)
|
||||
n_gpr = MAX_GPRARGS;
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
|
||||
p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
|
||||
else
|
||||
p_ov[n_ov++] = ((unsigned long *) arg)[0],
|
||||
p_ov[n_ov++] = ((unsigned long *) arg)[1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT32:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(unsigned int *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(unsigned int *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(signed int *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(signed int *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(unsigned short *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(unsigned short *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(signed short *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(signed short *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(unsigned char *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(unsigned char *) arg;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT8:
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = *(signed char *) arg;
|
||||
else
|
||||
p_ov[n_ov++] = *(signed char *) arg;
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*======================== End of Routine ============================*/
|
||||
|
||||
/*====================================================================*/
|
||||
/* */
|
||||
/* Name - ffi_prep_cif_machdep. */
|
||||
@@ -469,8 +311,12 @@ ffi_call_int(ffi_cif *cif,
|
||||
{
|
||||
int ret_type = cif->flags;
|
||||
size_t rsize = 0, bytes = cif->bytes;
|
||||
unsigned char *stack;
|
||||
unsigned char *stack, *p_struct;
|
||||
struct call_frame *frame;
|
||||
unsigned long *p_ov, *p_gpr;
|
||||
unsigned long long *p_fpr;
|
||||
int n_fpr, n_gpr, n_ov, i, n;
|
||||
ffi_type **arg_types;
|
||||
|
||||
FFI_ASSERT (cif->abi == FFI_SYSV);
|
||||
|
||||
@@ -499,22 +345,134 @@ ffi_call_int(ffi_cif *cif,
|
||||
p_ov: bottom of the overflow area (growing upwards)
|
||||
p_struct: top of the struct copy area (growing downwards)
|
||||
|
||||
All areas are kept aligned to twice the word size. */
|
||||
All areas are kept aligned to twice the word size.
|
||||
|
||||
Note that we're going to create the stack frame for both
|
||||
ffi_call_SYSV _and_ the target function right here. This
|
||||
works because we don't make any function calls with more
|
||||
than 5 arguments (indeed only memcpy and ffi_call_SYSV),
|
||||
and thus we don't have any stacked outgoing parameters. */
|
||||
|
||||
stack = alloca (bytes + sizeof(struct call_frame) + rsize);
|
||||
frame = (struct call_frame *)(stack + bytes);
|
||||
if (rsize)
|
||||
rvalue = frame + 1;
|
||||
|
||||
/* Assuming that the current function has the standard call frame,
|
||||
we can maintain the linked list like so. */
|
||||
frame->back_chain = __builtin_dwarf_cfa() - sizeof(struct call_frame);
|
||||
|
||||
/* Pass the outgoing stack frame in the r15 save slot. */
|
||||
frame->gpr_save[8] = (unsigned long)(stack - sizeof(struct call_frame));
|
||||
/* Link the new frame back to the one from this function. */
|
||||
frame->back_chain = __builtin_frame_address (0);
|
||||
|
||||
/* Fill in all of the argument stuff. */
|
||||
ffi_prep_args (cif, rvalue, avalue, (unsigned long *)stack, frame);
|
||||
p_ov = (unsigned long *)stack;
|
||||
p_struct = (unsigned char *)frame;
|
||||
p_gpr = frame->gpr_args;
|
||||
p_fpr = frame->fpr_args;
|
||||
n_fpr = n_gpr = n_ov = 0;
|
||||
|
||||
/* If we returning a structure then we set the first parameter register
|
||||
to the address of where we are returning this structure. */
|
||||
if (cif->flags & FFI390_RET_IN_MEM)
|
||||
p_gpr[n_gpr++] = (uintptr_t) rvalue;
|
||||
|
||||
/* Now for the arguments. */
|
||||
arg_types = cif->arg_types;
|
||||
for (i = 0, n = cif->nargs; i < n; ++i)
|
||||
{
|
||||
ffi_type *ty = arg_types[i];
|
||||
void *arg = avalue[i];
|
||||
int type = ty->type;
|
||||
ffi_arg val;
|
||||
|
||||
restart:
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
val = *(SINT8 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_UINT8:
|
||||
val = *(UINT8 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_SINT16:
|
||||
val = *(SINT16 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_UINT16:
|
||||
val = *(UINT16 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
val = *(SINT32 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_UINT32:
|
||||
val = *(UINT32 *)arg;
|
||||
goto do_int;
|
||||
case FFI_TYPE_POINTER:
|
||||
val = *(uintptr_t *)arg;
|
||||
do_int:
|
||||
*(n_gpr < MAX_GPRARGS ? p_gpr + n_gpr++ : p_ov + n_ov++) = val;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
#ifdef __s390x__
|
||||
val = *(UINT64 *)arg;
|
||||
goto do_int;
|
||||
#else
|
||||
if (n_gpr == MAX_GPRARGS-1)
|
||||
n_gpr = MAX_GPRARGS;
|
||||
if (n_gpr < MAX_GPRARGS)
|
||||
p_gpr[n_gpr++] = ((UINT32 *) arg)[0],
|
||||
p_gpr[n_gpr++] = ((UINT32 *) arg)[1];
|
||||
else
|
||||
p_ov[n_ov++] = ((UINT32 *) arg)[0],
|
||||
p_ov[n_ov++] = ((UINT32 *) arg)[1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
if (n_fpr < MAX_FPRARGS)
|
||||
p_fpr[n_fpr++] = *(UINT64 *) arg;
|
||||
else
|
||||
{
|
||||
#ifdef __s390x__
|
||||
p_ov[n_ov++] = *(UINT64 *) arg;
|
||||
#else
|
||||
p_ov[n_ov++] = ((UINT32 *) arg)[0],
|
||||
p_ov[n_ov++] = ((UINT32 *) arg)[1];
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
val = *(UINT32 *)arg;
|
||||
if (n_fpr < MAX_FPRARGS)
|
||||
p_fpr[n_fpr++] = (UINT64)val << 32;
|
||||
else
|
||||
p_ov[n_ov++] = val;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
/* Check how a structure type is passed. */
|
||||
type = ffi_check_struct_type (ty);
|
||||
/* Some structures are passed via a type they contain. */
|
||||
if (type != FFI_TYPE_POINTER)
|
||||
goto restart;
|
||||
/* ... otherwise, passed by reference. fallthru. */
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* 16-byte long double is passed via reference. */
|
||||
#endif
|
||||
case FFI_TYPE_COMPLEX:
|
||||
/* Complex types are passed via reference. */
|
||||
p_struct -= ROUND_SIZE (ty->size);
|
||||
memcpy (p_struct, arg, ty->size);
|
||||
val = (uintptr_t)p_struct;
|
||||
goto do_int;
|
||||
|
||||
default:
|
||||
FFI_ASSERT (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure);
|
||||
}
|
||||
|
||||
@@ -54,26 +54,24 @@ ffi_call_SYSV:
|
||||
.cfi_rel_offset r13, 52
|
||||
.cfi_rel_offset r14, 56
|
||||
.cfi_def_cfa_register r13
|
||||
l %r15,60(%r2) # Set up outgoing stack
|
||||
#ifdef HAVE_AS_S390_ZARCH
|
||||
larl %r14,.Ltable
|
||||
#else
|
||||
basr %r14,0 # Set up base register
|
||||
.Lbase:
|
||||
#endif
|
||||
st %r2,0(%r15) # Set up back chain
|
||||
sla %r3,3 # ret_type *= 8
|
||||
lr %r12,%r4 # Save ret_addr
|
||||
lr %r1,%r5 # Save fun
|
||||
lr %r0,%r6 # Install static chain
|
||||
|
||||
# Set return address, so that there is only one indirect jump.
|
||||
#ifdef HAVE_AS_S390_ZARCH
|
||||
la %r14,0(%r14,%r3) # Set return address
|
||||
larl %r14,.Ltable
|
||||
ar %r14,%r3
|
||||
#else
|
||||
la %r14,.Ltable-.Lbase(%r14,%r3) # Set return address
|
||||
basr %r14,0
|
||||
0: la %r14,.Ltable-0b(%r14,%r3)
|
||||
#endif
|
||||
|
||||
lm %r2,%r6,8(%r13) # Load arguments
|
||||
ld %f0,64(%r13)
|
||||
ld %f2,72(%r13)
|
||||
st %r13,0(%r15) # Set up back chain
|
||||
br %r1 # ... and call function
|
||||
|
||||
.balign 8
|
||||
@@ -210,7 +208,7 @@ ffi_call_SYSV:
|
||||
.cfi_rel_offset r13, 104
|
||||
.cfi_rel_offset r14, 112
|
||||
.cfi_def_cfa_register r13
|
||||
lg %r15,120(%r2) # Set up outgoing stack
|
||||
stg %r2,0(%r15) # Set up back chain
|
||||
larl %r14,.Ltable # Set up return address
|
||||
slag %r3,%r3,3 # ret_type *= 8
|
||||
lgr %r12,%r4 # Save ret_addr
|
||||
@@ -222,7 +220,6 @@ ffi_call_SYSV:
|
||||
ld %f2,136(%r13)
|
||||
ld %f4,144(%r13)
|
||||
ld %f6,152(%r13)
|
||||
stg %r13,0(%r15) # Set up back chain
|
||||
br %r1 # ... and call function
|
||||
|
||||
.balign 8
|
||||
|
||||
Reference in New Issue
Block a user