From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14878 invoked by alias); 19 Dec 2014 16:43:26 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 14845 invoked by uid 89); 19 Dec 2014 16:43:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qa0-f54.google.com Received: from mail-qa0-f54.google.com (HELO mail-qa0-f54.google.com) (209.85.216.54) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 19 Dec 2014 16:43:22 +0000 Received: by mail-qa0-f54.google.com with SMTP id k15so859393qaq.27 for ; Fri, 19 Dec 2014 08:43:19 -0800 (PST) X-Received: by 10.224.131.135 with SMTP id x7mr15576721qas.19.1419007399282; Fri, 19 Dec 2014 08:43:19 -0800 (PST) Received: from pike.twiddle.home.com (187-254-17-144-cable.cybercable.net.mx. [187.254.17.144]) by mx.google.com with ESMTPSA id p9sm9881774qax.8.2014.12.19.08.43.16 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Dec 2014 08:43:18 -0800 (PST) From: Richard Henderson To: libffi-discuss@sourceware.org Cc: Ulrich.Weigand@de.ibm.com, vogt@linux.vnet.ibm.com, krebbel@linux.vnet.ibm.com, Richard Henderson Subject: [PATCH 5/4] s390: Inline and tidy ffi_prep_args Date: Fri, 19 Dec 2014 16:43:00 -0000 Message-Id: <1419007392-10873-1-git-send-email-rth@twiddle.net> In-Reply-To: <1418938403-15836-1-git-send-email-rth@twiddle.net> References: <1418938403-15836-1-git-send-email-rth@twiddle.net> X-SW-Source: 2014/txt/msg00277.txt.bz2 From: Richard Henderson 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 #include +#include #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