This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
[PATCH 5/4] s390: Inline and tidy ffi_prep_args
- From: Richard Henderson <rth at twiddle dot net>
- To: libffi-discuss at sourceware dot org
- Cc: Ulrich dot Weigand at de dot ibm dot com, vogt at linux dot vnet dot ibm dot com, krebbel at linux dot vnet dot ibm dot com, Richard Henderson <rth at redhat dot com>
- Date: Fri, 19 Dec 2014 10:43:12 -0600
- Subject: [PATCH 5/4] s390: Inline and tidy ffi_prep_args
- Authentication-results: sourceware.org; auth=none
- References: <1418938403-15836-1-git-send-email-rth at twiddle dot net>
From: Richard Henderson <rth@redhat.com>
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.
---
src/s390/ffi.c | 294 ++++++++++++++++++++++++--------------------------------
src/s390/sysv.S | 21 ++--
2 files changed, 135 insertions(+), 180 deletions(-)
diff --git a/src/s390/ffi.c b/src/s390/ffi.c
index 1189f7b..4035b6e 100644
--- a/src/s390/ffi.c
+++ b/src/s390/ffi.c
@@ -30,6 +30,7 @@
#include <ffi.h>
#include <ffi_common.h>
+#include <stdint.h>
#include "internal.h"
/*====================== End of Includes =============================*/
@@ -130,165 +131,6 @@ ffi_check_struct_type (ffi_type *arg)
/*====================================================================*/
/* */
-/* 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. */
/* */
/* Function - Perform machine dependent CIF processing. */
@@ -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);
}
diff --git a/src/s390/sysv.S b/src/s390/sysv.S
index 1869269..c4b5006 100644
--- a/src/s390/sysv.S
+++ b/src/s390/sysv.S
@@ -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
--
2.1.0