Skip to content

Commit

Permalink
s390: Inline and tidy ffi_prep_args
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Richard Henderson committed Dec 19, 2014
1 parent f69ec6f commit 7ba30b1
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 180 deletions.
294 changes: 126 additions & 168 deletions src/s390/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <ffi.h>
#include <ffi_common.h>
#include <stdint.h>
#include "internal.h"

/*====================== End of Includes =============================*/
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
21 changes: 9 additions & 12 deletions src/s390/sysv.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 7ba30b1

Please sign in to comment.