This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Improved libffi support for s390/s390x
- From: "Ulrich Weigand" <Ulrich dot Weigand at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org, java-patches at gcc dot gnu dot org
- Cc: green at redhat dot com
- Date: Fri, 27 Sep 2002 18:47:44 +0200
- Subject: [PATCH] Improved libffi support for s390/s390x
- Sensitivity:
Hello,
this patch adds support for the 64-bit s390x-ibm-linux target to libffi,
and adds closure support for both 31-bit and 64-bit S/390 targets.
To allow for multilib builds (31-bit library build on 64-bit system),
the s390x target uses the same target directory and source files as
the s390 target; which ABI to use is decided from the predefined
preprocessor symbols (i.e. __s390x__).
The existing s390 support is also somewhat reworked to fit better to the
new code; in the process I've fixed a couple of minor corner case bugs
in the old implementation.
With this patch, libffi passes 'ffitest' (with the new closure tests
by Andreas Tobler added) on both s390-ibm-linux and s390x-ibm-linux.
Also, in combination with the separately posted boehm-gc patch for s390x,
the libjava regression test suite passes without new regressions on
s390-ibm-linux (the only existing failures are PR1343 and Array_3, which
I believe to be platform-independent bugs), and runs (for the first time)
on s390x-ibm-linux, with the same set of failures as on s390-ibm-linux.
OK to commit?
ChangeLog:
* configure.in: Add s390x-*-linux-* target.
* configure: Regenerate.
* include/ffi.h.in: Define S390X for s390x targets.
(FFI_CLOSURES): Define for s390/s390x.
(FFI_TRAMPOLINE_SIZE): Likewise.
(FFI_NATIVE_RAW_API): Likewise.
* src/prep_cif.c (ffi_prep_cif): Do not compute stack space for s390.
* src/types.c (FFI_TYPE_POINTER): Use 8-byte pointers on s390x.
* src/s390/ffi.c: Major rework of existing code. Add support for
s390x targets. Add closure support.
* src/s390/sysv.S: Likewise.
Index: libffi/configure.in
===================================================================
RCS file: /cvs/gcc/gcc/libffi/configure.in,v
retrieving revision 1.31
diff -c -p -r1.31 configure.in
*** libffi/configure.in 19 Jul 2002 15:30:58 -0000 1.31
--- libffi/configure.in 27 Sep 2002 16:30:55 -0000
*************** powerpc-*-aix*) TARGET=POWERPC_AIX; TARG
*** 70,75 ****
--- 70,76 ----
rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
s390-*-linux-*) TARGET=S390; TARGETDIR=s390;;
+ s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;;
x86_64-*-linux*) TARGET=X86_64; TARGETDIR=x86;;
sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;;
esac
Index: libffi/include/ffi.h.in
===================================================================
RCS file: /cvs/gcc/gcc/libffi/include/ffi.h.in,v
retrieving revision 1.17
diff -c -p -r1.17 ffi.h.in
*** libffi/include/ffi.h.in 19 Jul 2002 01:08:42 -0000 1.17
--- libffi/include/ffi.h.in 27 Sep 2002 16:30:56 -0000
*************** extern "C" {
*** 164,169 ****
--- 164,175 ----
#endif
#endif
+ #ifdef S390
+ #if defined (__s390x__)
+ #define S390X
+ #endif
+ #endif
+
#ifndef LIBFFI_ASM
/* ---- Generic type definitions ----------------------------------------- */
*************** struct ffi_ia64_trampoline_struct {
*** 439,444 ****
--- 445,460 ----
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24 /* see struct below */
+ #define FFI_NATIVE_RAW_API 0
+
+ #elif defined(S390)
+
+ #define FFI_CLOSURES 1
+ #ifdef S390X
+ #define FFI_TRAMPOLINE_SIZE 32
+ #else
+ #define FFI_TRAMPOLINE_SIZE 16
+ #endif
#define FFI_NATIVE_RAW_API 0
#elif defined(SH)
Index: libffi/src/prep_cif.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/prep_cif.c,v
retrieving revision 1.4
diff -c -p -r1.4 prep_cif.c
*** libffi/src/prep_cif.c 18 Jul 2002 23:08:30 -0000 1.4
--- libffi/src/prep_cif.c 27 Sep 2002 16:30:56 -0000
*************** ffi_status ffi_prep_cif(/*@out@*/ /*@par
*** 103,111 ****
/* Perform a sanity check on the return type */
FFI_ASSERT(ffi_type_test(cif->rtype));
! /* x86-64 and s390 stack space allocation is handled in prep_machdep.
! TODO: Disable this for s390 too? */
! #if !defined M68K && !defined __x86_64__
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
--- 103,110 ----
/* Perform a sanity check on the return type */
FFI_ASSERT(ffi_type_test(cif->rtype));
! /* x86-64 and s390 stack space allocation is handled in prep_machdep. */
! #if !defined M68K && !defined __x86_64__ && !defined S390
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
*************** ffi_status ffi_prep_cif(/*@out@*/ /*@par
*** 124,131 ****
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
! /* TODO: Disable this calculation for s390 too? */
! #ifndef __x86_64__
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
--- 123,129 ----
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
! #if !defined __x86_64__ && !defined S390
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
Index: libffi/src/types.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/types.c,v
retrieving revision 1.6
diff -c -p -r1.6 types.c
*** libffi/src/types.c 19 Jul 2002 01:08:43 -0000 1.6
--- libffi/src/types.c 27 Sep 2002 16:30:57 -0000
*************** FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_T
*** 42,48 ****
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
! #if defined ALPHA || defined SPARC64 || defined X86_64
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
--- 42,48 ----
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
! #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
Index: libffi/src/s390/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/s390/ffi.c,v
retrieving revision 1.1
diff -c -p -r1.1 ffi.c
*** libffi/src/s390/ffi.c 29 Apr 2002 04:14:44 -0000 1.1
--- libffi/src/s390/ffi.c 27 Sep 2002 16:30:57 -0000
***************
*** 39,88 ****
/* Defines */
/* ------- */
/*====================================================================*/
!
! #define MAX_GPRARGS 5 /* Max. no. of GPR available */
! #define MAX_FPRARGS 2 /* Max. no. of FPR available */
!
! #define STR_GPR 1 /* Structure will fit in 1 or 2 GPR */
! #define STR_FPR 2 /* Structure will fit in a FPR */
! #define STR_STACK 3 /* Structure needs to go on stack */
!
/*===================== End of Defines ===============================*/
/*====================================================================*/
- /* Types */
- /* ----- */
- /*====================================================================*/
-
- typedef struct stackLayout
- {
- int *backChain;
- int *endOfStack;
- int glue[2];
- int scratch[2];
- int gprArgs[MAX_GPRARGS];
- int notUsed;
- union
- {
- float f;
- double d;
- } fprArgs[MAX_FPRARGS];
- int unUsed[8];
- int outArgs[100];
- } stackLayout;
-
- /*======================== End of Types ==============================*/
-
- /*====================================================================*/
/* Prototypes */
/* ---------- */
/*====================================================================*/
! void ffi_prep_args(stackLayout *, extended_cif *);
! static int ffi_check_struct(ffi_type *, unsigned int *);
! static void ffi_insert_int(int, stackLayout *, int *, int *);
! static void ffi_insert_int64(long long, stackLayout *, int *, int *);
! static void ffi_insert_double(double, stackLayout *, int *, int *);
/*====================== End of Prototypes ===========================*/
--- 39,77 ----
/* Defines */
/* ------- */
/*====================================================================*/
!
! /* Maximum number of GPRs available for argument passing. */
! #define MAX_GPRARGS 5
!
! /* Maximum number of FPRs available for argument passing. */
! #ifdef __s390x__
! #define MAX_FPRARGS 4
! #else
! #define MAX_FPRARGS 2
! #endif
!
! /* Round to multiple of 16. */
! #define ROUND_SIZE(size) (((size) + 15) & ~15)
!
! /* If these values change, sysv.S must be adapted! */
! #define FFI390_RET_VOID 0
! #define FFI390_RET_STRUCT 1
! #define FFI390_RET_FLOAT 2
! #define FFI390_RET_DOUBLE 3
! #define FFI390_RET_INT32 4
! #define FFI390_RET_INT64 5
!
/*===================== End of Defines ===============================*/
/*====================================================================*/
/* Prototypes */
/* ---------- */
/*====================================================================*/
! static void ffi_prep_args (unsigned char *, extended_cif *);
! static int ffi_check_float_struct (ffi_type *);
! void ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
! unsigned long long *, unsigned long *);
/*====================== End of Prototypes ===========================*/
*************** static void ffi_insert_double(double, st
*** 91,589 ****
/* --------- */
/*====================================================================*/
! extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *),
extended_cif *,
! unsigned, unsigned,
! unsigned *,
void (*fn)());
/*====================== End of Externals ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_check_struct. */
/* */
/* Function - Determine if a structure can be passed within a */
! /* general or floating point register. */
/* */
/*====================================================================*/
! int
! ffi_check_struct(ffi_type *arg, unsigned int *strFlags)
{
! ffi_type *element;
! int i_Element;
!
! for (i_Element = 0; arg->elements[i_Element]; i_Element++) {
! element = arg->elements[i_Element];
! switch (element->type) {
! case FFI_TYPE_DOUBLE :
! *strFlags |= STR_FPR;
! break;
!
! case FFI_TYPE_STRUCT :
! *strFlags |= ffi_check_struct(element, strFlags);
! break;
!
! default :
! *strFlags |= STR_GPR;
! }
! }
! return (*strFlags);
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_insert_int. */
/* */
! /* Function - Insert an integer parameter in a register if there are */
! /* spares else on the stack. */
/* */
/*====================================================================*/
! void
! ffi_insert_int(int gprValue, stackLayout *stack,
! int *intArgC, int *outArgC)
{
! if (*intArgC < MAX_GPRARGS) {
! stack->gprArgs[*intArgC] = gprValue;
! *intArgC += 1;
! }
! else {
! stack->outArgs[*outArgC++] = gprValue;
! *outArgC += 1;
! }
! }
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_insert_int64. */
/* */
! /* Function - Insert a long long parameter in registers if there are */
! /* spares else on the stack. */
/* */
/*====================================================================*/
! void
! ffi_insert_int64(long long llngValue, stackLayout *stack,
! int *intArgC, int *outArgC)
{
! if (*intArgC < (MAX_GPRARGS-1)) {
! memcpy(&stack->gprArgs[*intArgC],
! &llngValue, sizeof(long long));
! *intArgC += 2;
! }
! else {
! memcpy(&stack->outArgs[*outArgC],
! &llngValue, sizeof(long long));
! *outArgC += 2;
! }
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_insert_double. */
/* */
! /* Function - Insert a double parameter in a FP register if there is */
! /* a spare else on the stack. */
/* */
/*====================================================================*/
void
! ffi_insert_double(double dblValue, stackLayout *stack,
! int *fprArgC, int *outArgC)
{
! if (*fprArgC < MAX_FPRARGS) {
! stack->fprArgs[*fprArgC].d = dblValue;
! *fprArgC += 1;
! }
! else {
! memcpy(&stack->outArgs[*outArgC],
! &dblValue,sizeof(double));
! *outArgC += 2;
! }
!
}
/*======================== 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. */
! /* */
! /* The stack layout we want looks like this: */
! /* *------------------------------------------------------------* */
! /* | 0 | Back chain (a 0 here signifies end of back chain) | */
! /* +--------+---------------------------------------------------+ */
! /* | 4 | EOS (end of stack, not used on Linux for S390) | */
! /* +--------+---------------------------------------------------+ */
! /* | 8 | Glue used in other linkage formats | */
! /* +--------+---------------------------------------------------+ */
! /* | 12 | Glue used in other linkage formats | */
! /* +--------+---------------------------------------------------+ */
! /* | 16 | Scratch area | */
! /* +--------+---------------------------------------------------+ */
! /* | 20 | Scratch area | */
! /* +--------+---------------------------------------------------+ */
! /* | 24 | GPR parameter register 1 | */
! /* +--------+---------------------------------------------------+ */
! /* | 28 | GPR parameter register 2 | */
! /* +--------+---------------------------------------------------+ */
! /* | 32 | GPR parameter register 3 | */
! /* +--------+---------------------------------------------------+ */
! /* | 36 | GPR parameter register 4 | */
! /* +--------+---------------------------------------------------+ */
! /* | 40 | GPR parameter register 5 | */
! /* +--------+---------------------------------------------------+ */
! /* | 44 | Unused | */
! /* +--------+---------------------------------------------------+ */
! /* | 48 | FPR parameter register 1 | */
! /* +--------+---------------------------------------------------+ */
! /* | 56 | FPR parameter register 2 | */
! /* +--------+---------------------------------------------------+ */
! /* | 64 | Unused | */
! /* +--------+---------------------------------------------------+ */
! /* | 96 | Outgoing args (length x) | */
! /* +--------+---------------------------------------------------+ */
! /* | 96+x | Copy area for structures (length y) | */
! /* +--------+---------------------------------------------------+ */
! /* | 96+x+y | Possible stack alignment | */
! /* *------------------------------------------------------------* */
/* */
/*====================================================================*/
void
! ffi_prep_args(stackLayout *stack, extended_cif *ecif)
{
! const unsigned bytes = ecif->cif->bytes;
! const unsigned flags = ecif->cif->flags;
!
! /*----------------------------------------------------------*/
! /* Pointer to the copy area on stack for structures */
! /*----------------------------------------------------------*/
! char *copySpace = (char *) stack + bytes + sizeof(stackLayout);
!
! /*----------------------------------------------------------*/
! /* Count of general and floating point register usage */
! /*----------------------------------------------------------*/
! int intArgC = 0,
! fprArgC = 0,
! outArgC = 0;
!
! int i;
ffi_type **ptr;
! void **p_argv;
! size_t structCopySize;
! unsigned gprValue, strFlags = 0;
! unsigned long long llngValue;
! double dblValue;
!
/* Now for the arguments. */
! p_argv = ecif->avalue;
!
! /*----------------------------------------------------------------------*/
! /* If we returning a structure then we set the first parameter register */
! /* to the address of where we are returning this structure */
! /*----------------------------------------------------------------------*/
! if (flags == FFI_TYPE_STRUCT)
! stack->gprArgs[intArgC++] = (int) ecif->rvalue;
!
! for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
i > 0;
! i--, ptr++, p_argv++)
{
! switch ((*ptr)->type) {
case FFI_TYPE_FLOAT:
! if (fprArgC < MAX_FPRARGS)
! stack->fprArgs[fprArgC++].f = *(float *) *p_argv;
! else
! stack->outArgs[outArgC++] = *(int *) *p_argv;
break;
!
case FFI_TYPE_DOUBLE:
! dblValue = *(double *) *p_argv;
! ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
break;
!
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
! llngValue = *(unsigned long long *) *p_argv;
! ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
break;
!
! case FFI_TYPE_UINT8:
! gprValue = *(unsigned char *)*p_argv;
! ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
!
! case FFI_TYPE_SINT8:
! gprValue = *(signed char *)*p_argv;
! ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
!
case FFI_TYPE_UINT16:
! gprValue = *(unsigned short *)*p_argv;
! ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
!
case FFI_TYPE_SINT16:
! gprValue = *(signed short *)*p_argv;
! ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
!
! case FFI_TYPE_STRUCT:
! /*--------------------------------------------------*/
! /* If structure > 8 bytes then it goes on the stack */
! /*--------------------------------------------------*/
! if (((*ptr)->size > 8) ||
! ((*ptr)->size > 4 &&
! (*ptr)->size < 8))
! strFlags = STR_STACK;
! else
! strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags);
!
! switch (strFlags) {
! /*-------------------------------------------*/
! /* Structure that will fit in one or two GPR */
! /*-------------------------------------------*/
! case STR_GPR :
! if ((*ptr)->size <= 4) {
! gprValue = *(unsigned int *) *p_argv;
! gprValue = gprValue >> ((4 - (*ptr)->size) * 8);
! ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
! }
! else {
! llngValue = *(unsigned long long *) *p_argv;
! ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
! }
! break;
!
! /*-------------------------------------------*/
! /* Structure that will fit in one FPR */
! /*-------------------------------------------*/
! case STR_FPR :
! dblValue = *(double *) *p_argv;
! ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
! break;
!
! /*-------------------------------------------*/
! /* Structure that must be copied to stack */
! /*-------------------------------------------*/
! default :
! structCopySize = (((*ptr)->size + 15) & ~0xF);
! copySpace -= structCopySize;
! memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
! gprValue = (unsigned) copySpace;
! if (intArgC < MAX_GPRARGS)
! stack->gprArgs[intArgC++] = gprValue;
! else
! stack->outArgs[outArgC++] = gprValue;
! }
! break;
!
! #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
! case FFI_TYPE_LONGDOUBLE:
! structCopySize = (((*ptr)->size + 15) & ~0xF);
! copySpace -= structCopySize;
! memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
! gprValue = (unsigned) copySpace;
! if (intArgC < MAX_GPRARGS)
! stack->gprArgs[intArgC++] = gprValue;
! else
! stack->outArgs[outArgC++] = gprValue;
break;
! #endif
!
! case FFI_TYPE_INT:
! case FFI_TYPE_UINT32:
! case FFI_TYPE_SINT32:
! case FFI_TYPE_POINTER:
! gprValue = *(unsigned *)*p_argv;
! if (intArgC < MAX_GPRARGS)
! stack->gprArgs[intArgC++] = gprValue;
! else
! stack->outArgs[outArgC++] = gprValue;
break;
!
! }
}
}
-
- /*======================== End of Routine ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_prep_cif_machdep. */
/* */
! /* Function - Perform machine dependent CIF processing. */
/* */
/*====================================================================*/
ffi_status
! ffi_prep_cif_machdep(ffi_cif *cif)
{
! int i;
! ffi_type **ptr;
! unsigned bytes;
! int fpArgC = 0,
! intArgC = 0;
! unsigned flags = 0;
! unsigned structCopySize = 0;
!
! /*-----------------------------------------------------------------*/
! /* Extra space required in stack for overflow parameters. */
! /*-----------------------------------------------------------------*/
! bytes = 0;
!
! /*--------------------------------------------------------*/
! /* Return value handling. The rules are as follows: */
! /* - 32-bit (or less) integer values are returned in gpr2 */
! /* - Structures are returned as pointers in gpr2 */
! /* - 64-bit integer values are returned in gpr2 and 3 */
! /* - Single/double FP values are returned in fpr0 */
! /*--------------------------------------------------------*/
! flags = cif->rtype->type;
!
! /*------------------------------------------------------------------------*/
! /* The first MAX_GPRARGS words of integer arguments, and the */
! /* first MAX_FPRARGS floating point arguments, go in registers; the rest */
! /* goes on the stack. Structures and long doubles (if not equivalent */
! /* to double) are passed as a pointer to a copy of the structure. */
! /* Stuff on the stack needs to keep proper alignment. */
! /*------------------------------------------------------------------------*/
! for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
! {
! switch ((*ptr)->type)
! {
! case FFI_TYPE_FLOAT:
! case FFI_TYPE_DOUBLE:
! fpArgC++;
! if (fpArgC > MAX_FPRARGS && intArgC%2 != 0)
! intArgC++;
! break;
!
! case FFI_TYPE_UINT64:
! case FFI_TYPE_SINT64:
! /*----------------------------------------------------*/
! /* 'long long' arguments are passed as two words, but */
! /* either both words must fit in registers or both go */
! /* on the stack. If they go on the stack, they must */
! /* be 8-byte-aligned. */
! /*----------------------------------------------------*/
! if ((intArgC == MAX_GPRARGS-1) ||
! (intArgC >= MAX_GPRARGS) &&
! (intArgC%2 != 0))
! intArgC++;
! intArgC += 2;
! break;
!
! case FFI_TYPE_STRUCT:
! #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
! case FFI_TYPE_LONGDOUBLE:
! #endif
! /*----------------------------------------------------*/
! /* We must allocate space for a copy of these to */
! /* enforce pass-by-value. Pad the space up to a */
! /* multiple of 16 bytes (the maximum alignment */
! /* required for anything under the SYSV ABI). */
! /*----------------------------------------------------*/
! structCopySize += ((*ptr)->size + 15) & ~0xF;
! /*----------------------------------------------------*/
! /* Fall through (allocate space for the pointer). */
! /*----------------------------------------------------*/
!
! default:
! /*----------------------------------------------------*/
! /* Everything else is passed as a 4-byte word in a */
! /* GPR either the object itself or a pointer to it. */
! /*----------------------------------------------------*/
! intArgC++;
! break;
! }
! }
!
! /*-----------------------------------------------------------------*/
! /* Stack space. */
! /*-----------------------------------------------------------------*/
! if (intArgC > MAX_GPRARGS)
! bytes += (intArgC - MAX_GPRARGS) * sizeof(int);
! if (fpArgC > MAX_FPRARGS)
! bytes += (fpArgC - MAX_FPRARGS) * sizeof(double);
!
! /*-----------------------------------------------------------------*/
! /* The stack space allocated needs to be a multiple of 16 bytes. */
! /*-----------------------------------------------------------------*/
! bytes = (bytes + 15) & ~0xF;
!
! /*-----------------------------------------------------------------*/
! /* Add in the space for the copied structures. */
! /*-----------------------------------------------------------------*/
! bytes += structCopySize;
!
! cif->flags = flags;
! cif->bytes = bytes;
return FFI_OK;
}
!
/*======================== End of Routine ============================*/
- /*====================================================================*/
- /* */
- /* Name - ffi_call. */
- /* */
- /* Function - Call the FFI routine. */
- /* */
- /*====================================================================*/
-
- 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_SYSV:
- ffi_call_SYSV(ffi_prep_args,
- &ecif, cif->bytes,
- cif->flags, ecif.rvalue, fn);
- break;
-
- default:
- FFI_ASSERT(0);
- break;
- }
- }
-
- /*======================== End of Routine ============================*/
--- 80,759 ----
/* --------- */
/*====================================================================*/
! extern void ffi_call_SYSV(unsigned,
extended_cif *,
! void (*)(unsigned char *, extended_cif *),
! unsigned,
! void *,
void (*fn)());
+
+ extern void ffi_closure_SYSV(void);
/*====================== End of Externals ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_check_struct_type. */
/* */
/* Function - Determine if a structure can be passed within a */
! /* general purpose or floating point register. */
/* */
/*====================================================================*/
! static int
! ffi_check_struct_type (ffi_type *arg)
{
! size_t size = arg->size;
!
! /* If the struct has just one element, look at that element
! to find out whether to consider the struct as floating point. */
! while (arg->type == FFI_TYPE_STRUCT
! && arg->elements[0] && !arg->elements[1])
! arg = arg->elements[0];
!
! /* Structs of size 1, 2, 4, and 8 are passed in registers,
! just like the corresponding int/float types. */
! switch (size)
! {
! case 1:
! return FFI_TYPE_UINT8;
!
! case 2:
! return FFI_TYPE_UINT16;
!
! case 4:
! if (arg->type == FFI_TYPE_FLOAT)
! return FFI_TYPE_FLOAT;
! else
! return FFI_TYPE_UINT32;
!
! case 8:
! if (arg->type == FFI_TYPE_DOUBLE)
! return FFI_TYPE_DOUBLE;
! else
! return FFI_TYPE_UINT64;
!
! default:
! break;
! }
!
! /* Other structs are passed via a pointer to the data. */
! return FFI_TYPE_POINTER;
}
/*======================== 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 (unsigned char *stack, extended_cif *ecif)
{
! /* The stack space will be filled with those areas:
!
! FPR argument register save area (highest addresses)
! GPR argument register save area
! temporary struct copies
! overflow argument area (lowest addresses)
!
! We set up the following pointers:
!
! p_fpr: bottom of the FPR area (growing upwards)
! p_gpr: bottom of the GPR area (growing upwards)
! 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. */
!
! int gpr_off = ecif->cif->bytes;
! int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
!
! unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
! unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
! unsigned char *p_struct = (unsigned char *)p_gpr;
! unsigned long *p_ov = (unsigned long *)stack;
!
! int n_fpr = 0;
! int n_gpr = 0;
! int n_ov = 0;
!
! ffi_type **ptr;
! void **p_argv = ecif->avalue;
! 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 (ecif->cif->flags == FFI390_RET_STRUCT)
! p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
!
! /* Now for the arguments. */
!
! for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
! i > 0;
! i--, ptr++, p_argv++)
! {
! void *arg = *p_argv;
! int type = (*ptr)->type;
!
! /* Check how a structure type is passed. */
! if (type == FFI_TYPE_STRUCT)
! {
! type = ffi_check_struct_type (*ptr);
!
! /* If we pass the struct via pointer, copy the data. */
! if (type == FFI_TYPE_POINTER)
! {
! p_struct -= ROUND_SIZE ((*ptr)->size);
! memcpy (p_struct, (char *)arg, (*ptr)->size);
! arg = &p_struct;
! }
! }
!
! /* Pointers are passed like UINTs of the same size. */
! if (type == FFI_TYPE_POINTER)
! #ifdef __s390x__
! type = FFI_TYPE_UINT64;
! #else
! type = FFI_TYPE_UINT32;
! #endif
!
! /* Now handle all primitive int/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++] = (long long) *(unsigned int *) arg << 32;
! else
! p_ov[n_ov++] = *(unsigned int *) 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. */
/* */
/*====================================================================*/
! ffi_status
! ffi_prep_cif_machdep(ffi_cif *cif)
{
+ size_t struct_size = 0;
+ int n_gpr = 0;
+ int n_fpr = 0;
+ int n_ov = 0;
+
+ ffi_type **ptr;
+ int i;
+
+ /* Determine return value handling. */
+
+ switch (cif->rtype->type)
+ {
+ /* Void is easy. */
+ case FFI_TYPE_VOID:
+ cif->flags = FFI390_RET_VOID;
+ break;
+
+ /* Structures are returned via a hidden pointer. */
+ case FFI_TYPE_STRUCT:
+ cif->flags = FFI390_RET_STRUCT;
+ n_gpr++; /* We need one GPR to pass the pointer. */
+ break;
+
+ /* Floating point values are returned in fpr 0. */
+ case FFI_TYPE_FLOAT:
+ cif->flags = FFI390_RET_FLOAT;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ cif->flags = FFI390_RET_DOUBLE;
+ break;
+
+ /* Integer values are returned in gpr 2 (and gpr 3
+ for 64-bit values on 31-bit machines). */
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ cif->flags = FFI390_RET_INT64;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ /* These are to be extended to word size. */
+ #ifdef __s390x__
+ cif->flags = FFI390_RET_INT64;
+ #else
+ cif->flags = FFI390_RET_INT32;
+ #endif
+ break;
! default:
! FFI_ASSERT (0);
! break;
! }
!
! /* Now for the arguments. */
!
! for (ptr = cif->arg_types, i = cif->nargs;
! i > 0;
! i--, ptr++)
! {
! int type = (*ptr)->type;
!
! /* Check how a structure type is passed. */
! if (type == FFI_TYPE_STRUCT)
! {
! type = ffi_check_struct_type (*ptr);
!
! /* If we pass the struct via pointer, we must reserve space
! to copy its data for proper call-by-value semantics. */
! if (type == FFI_TYPE_POINTER)
! struct_size += ROUND_SIZE ((*ptr)->size);
! }
!
! /* Now handle all primitive int/float data types. */
! switch (type)
! {
! /* The first MAX_FPRARGS floating point arguments
! go in FPRs, the rest overflow to the stack. */
!
! case FFI_TYPE_DOUBLE:
! if (n_fpr < MAX_FPRARGS)
! n_fpr++;
! else
! n_ov += sizeof (double) / sizeof (long);
! break;
!
! case FFI_TYPE_FLOAT:
! if (n_fpr < MAX_FPRARGS)
! n_fpr++;
! else
! n_ov++;
! break;
!
! /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
! if one is still available, or else on the stack. If only one
! register is free, skip the register (it won't be used for any
! subsequent argument either). */
!
! #ifndef __s390x__
! case FFI_TYPE_UINT64:
! case FFI_TYPE_SINT64:
! if (n_gpr == MAX_GPRARGS-1)
! n_gpr = MAX_GPRARGS;
! if (n_gpr < MAX_GPRARGS)
! n_gpr += 2;
! else
! n_ov += 2;
! break;
! #endif
!
! /* Everything else is passed in GPRs (until MAX_GPRARGS
! have been used) or overflows to the stack. */
!
! default:
! if (n_gpr < MAX_GPRARGS)
! n_gpr++;
! else
! n_ov++;
! break;
! }
! }
!
! /* Total stack space as required for overflow arguments
! and temporary structure copies. */
!
! cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
+ return FFI_OK;
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
! /* Name - ffi_call. */
/* */
! /* Function - Call the FFI routine. */
/* */
/*====================================================================*/
void
! ffi_call(ffi_cif *cif,
! void (*fn)(),
! void *rvalue,
! void **avalue)
{
+ int ret_type = cif->flags;
+ extended_cif ecif;
! ecif.cif = cif;
! ecif.avalue = avalue;
! ecif.rvalue = rvalue;
!
! /* If we don't have a return value, we need to fake one. */
! if (rvalue == NULL)
! {
! if (ret_type == FFI390_RET_STRUCT)
! ecif.rvalue = alloca (cif->rtype->size);
! else
! ret_type = FFI390_RET_VOID;
! }
!
! switch (cif->abi)
! {
! case FFI_SYSV:
! ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
! ret_type, ecif.rvalue, fn);
! break;
!
! default:
! FFI_ASSERT (0);
! break;
! }
}
/*======================== End of Routine ============================*/
!
/*====================================================================*/
/* */
! /* Name - ffi_closure_helper_SYSV. */
/* */
! /* Function - Call a FFI closure target function. */
/* */
/*====================================================================*/
void
! ffi_closure_helper_SYSV (ffi_closure *closure,
! unsigned long *p_gpr,
! unsigned long long *p_fpr,
! unsigned long *p_ov)
{
! unsigned long long ret_buffer;
!
! void *rvalue = &ret_buffer;
! void **avalue;
! void **p_arg;
!
! int n_gpr = 0;
! int n_fpr = 0;
! int n_ov = 0;
!
ffi_type **ptr;
! int i;
!
! /* Allocate buffer for argument list pointers. */
!
! p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
!
! /* If we returning a structure, pass the structure address
! directly to the target function. Otherwise, have the target
! function store the return value to the GPR save area. */
!
! if (closure->cif->flags == FFI390_RET_STRUCT)
! rvalue = (void *) p_gpr[n_gpr++];
!
/* Now for the arguments. */
!
! for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
i > 0;
! i--, p_arg++, ptr++)
{
! int deref_struct_pointer = 0;
! int type = (*ptr)->type;
!
! /* Check how a structure type is passed. */
! if (type == FFI_TYPE_STRUCT)
! {
! type = ffi_check_struct_type (*ptr);
!
! /* If we pass the struct via pointer, remember to
! retrieve the pointer later. */
! if (type == FFI_TYPE_POINTER)
! deref_struct_pointer = 1;
! }
!
! /* Pointers are passed like UINTs of the same size. */
! if (type == FFI_TYPE_POINTER)
! #ifdef __s390x__
! type = FFI_TYPE_UINT64;
! #else
! type = FFI_TYPE_UINT32;
! #endif
!
! /* Now handle all primitive int/float data types. */
! switch (type)
! {
! case FFI_TYPE_DOUBLE:
! if (n_fpr < MAX_FPRARGS)
! *p_arg = &p_fpr[n_fpr++];
! else
! *p_arg = &p_ov[n_ov],
! n_ov += sizeof (double) / sizeof (long);
! break;
!
! case FFI_TYPE_FLOAT:
! if (n_fpr < MAX_FPRARGS)
! *p_arg = &p_fpr[n_fpr++];
! else
! *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
! break;
!
! case FFI_TYPE_UINT64:
! case FFI_TYPE_SINT64:
! #ifdef __s390x__
! if (n_gpr < MAX_GPRARGS)
! *p_arg = &p_gpr[n_gpr++];
! else
! *p_arg = &p_ov[n_ov++];
! #else
! if (n_gpr == MAX_GPRARGS-1)
! n_gpr = MAX_GPRARGS;
! if (n_gpr < MAX_GPRARGS)
! *p_arg = &p_gpr[n_gpr], n_gpr += 2;
! else
! *p_arg = &p_ov[n_ov], n_ov += 2;
! #endif
! break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
+ break;
+
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
+ break;
+
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+
+ /* If this is a struct passed via pointer, we need to
+ actually retrieve that pointer. */
+ if (deref_struct_pointer)
+ *p_arg = *(void **)*p_arg;
+ }
+
+
+ /* Call the target function. */
+ (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
+
+ /* Convert the return value. */
+ switch (closure->cif->rtype->type)
+ {
+ /* Void is easy, and so is struct. */
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ break;
+
+ /* Floating point values are returned in fpr 0. */
case FFI_TYPE_FLOAT:
! p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
break;
!
case FFI_TYPE_DOUBLE:
! p_fpr[0] = *(unsigned long long *) rvalue;
break;
!
! /* Integer values are returned in gpr 2 (and gpr 3
! for 64-bit values on 31-bit machines). */
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
! #ifdef __s390x__
! p_gpr[0] = *(unsigned long *) rvalue;
! #else
! p_gpr[0] = ((unsigned long *) rvalue)[0],
! p_gpr[1] = ((unsigned long *) rvalue)[1];
! #endif
break;
!
! case FFI_TYPE_UINT32:
! p_gpr[0] = *(unsigned int *) rvalue;
break;
!
! case FFI_TYPE_INT:
! case FFI_TYPE_SINT32:
! p_gpr[0] = *(signed int *) rvalue;
break;
!
case FFI_TYPE_UINT16:
! p_gpr[0] = *(unsigned short *) rvalue;
break;
!
case FFI_TYPE_SINT16:
! p_gpr[0] = *(signed short *) rvalue;
break;
!
! case FFI_TYPE_UINT8:
! p_gpr[0] = *(unsigned char *) rvalue;
break;
!
! case FFI_TYPE_SINT8:
! p_gpr[0] = *(signed char *) rvalue;
break;
!
! default:
! FFI_ASSERT (0);
! break;
}
}
+ /*======================== End of Routine ============================*/
+
/*====================================================================*/
/* */
! /* Name - ffi_prep_closure. */
/* */
! /* Function - Prepare a FFI closure. */
/* */
/*====================================================================*/
ffi_status
! ffi_prep_closure (ffi_closure *closure,
! ffi_cif *cif,
! void (*fun) (ffi_cif *, void *, void **, void *),
! void *user_data)
{
! FFI_ASSERT (cif->abi == FFI_SYSV);
!
! #ifndef __s390x__
! *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
! *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
! *(short *)&closure->tramp [4] = 0x1006;
! *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
! *(long *)&closure->tramp [8] = (long)closure;
! *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
! #else
! *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
! *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
! *(short *)&closure->tramp [4] = 0x100e;
! *(short *)&closure->tramp [6] = 0x0004;
! *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
! *(long *)&closure->tramp[16] = (long)closure;
! *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
! #endif
!
! closure->cif = cif;
! closure->user_data = user_data;
! closure->fun = fun;
return FFI_OK;
}
!
/*======================== End of Routine ============================*/
Index: libffi/src/s390/sysv.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/s390/sysv.S,v
retrieving revision 1.2
diff -c -p -r1.2 sysv.S
*** libffi/src/s390/sysv.S 6 Jun 2002 12:51:23 -0000 1.2
--- libffi/src/s390/sysv.S 27 Sep 2002 16:30:58 -0000
***************
*** 22,171 ****
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
- #define LIBFFI_ASM
- #include <ffi.h>
- #ifdef HAVE_MACHINE_ASM_H
- #include <machine/asm.h>
- #endif
-
.text
!
! # r2: ffi_prep_args
# r3: &ecif
! # r4: cif->bytes
! # r5: fig->flags
# r6: ecif.rvalue
! # sp+0: fn
# This assumes we are using gas.
.globl ffi_call_SYSV
.type ffi_call_SYSV,%function
ffi_call_SYSV:
.LFB1:
! # Save registers
! stm %r6,%r15,24(%r15)
.LCFI0:
! l %r7,96(%r15) # Get A(fn)
! lr %r0,%r15
! ahi %r15,-128 # Make room for my args
.LCFI1:
! st %r0,0(%r15) # Set backchain
! lr %r11,%r15 # Establish my stack register
.LCFI2:
! sr %r15,%r4 # Make room for fn args
! ahi %r15,-96 # Make room for new frame
! lr %r10,%r15 # Establish stack build area
! ahi %r15,-96 # Stack for next call
! lr %r1,%r7
! stm %r2,%r7,96(%r11) # Save args on my stack
!
! #------------------------------------------------------------------
! # move first 3 parameters in registers
! #------------------------------------------------------------------
! lr %r9,%r2 # r9: &ffi_prep_args
! lr %r2,%r10 # Parm 1: &stack Parm 2: &ecif
! basr %r14,%r9 # call ffi_prep_args
!
! #------------------------------------------------------------------
! # load first 5 parameter registers
! #------------------------------------------------------------------
! lm %r2,%r6,24(%r10)
!
! #------------------------------------------------------------------
! # load fp parameter registers
! #------------------------------------------------------------------
! ld %f0,48(%r10)
! ld %f2,56(%r10)
!
! #------------------------------------------------------------------
! # call function
! #------------------------------------------------------------------
! lr %r15,%r10 # Set new stack
! l %r9,116(%r11) # Get &fn
! basr %r14,%r9 # Call function
!
! #------------------------------------------------------------------
! # On return:
! # r2: Return value (r3: Return value + 4 for long long)
! #------------------------------------------------------------------
!
! #------------------------------------------------------------------
! # If the return value pointer is NULL, assume no return value.
! #------------------------------------------------------------------
! icm %r6,15,112(%r11)
! jz .Lepilogue
!
! l %r5,108(%r11) # Get return type
! #------------------------------------------------------------------
! # return INT
! #------------------------------------------------------------------
! chi %r5,FFI_TYPE_INT
! jne .Lchk64
!
! st %r2,0(%r6)
! j .Lepilogue
!
! .Lchk64:
! #------------------------------------------------------------------
! # return LONG LONG (signed/unsigned)
! #------------------------------------------------------------------
! chi %r5,FFI_TYPE_UINT64
! je .LdoLongLong
!
! chi %r5,FFI_TYPE_SINT64
! jne .LchkFloat
!
! .LdoLongLong:
! stm %r2,%r3,0(%r6)
! j .Lepilogue
!
! .LchkFloat:
! #------------------------------------------------------------------
! # return FLOAT
! #------------------------------------------------------------------
! chi %r5,FFI_TYPE_FLOAT
! jne .LchkDouble
!
! std %f0,0(%r6)
! j .Lepilogue
!
! .LchkDouble:
! #------------------------------------------------------------------
! # return DOUBLE or LONGDOUBLE
! #------------------------------------------------------------------
! chi %r5,FFI_TYPE_DOUBLE
! jne .LchkStruct
!
! std %f0,0(%r6)
! std %f2,8(%r6)
! j .Lepilogue
!
! .LchkStruct:
! #------------------------------------------------------------------
! # Structure - rvalue already set as sent as 1st parm to routine
! #------------------------------------------------------------------
! chi %r5,FFI_TYPE_STRUCT
! je .Lepilogue
!
! .Ldefault:
! #------------------------------------------------------------------
! # return a pointer
! #------------------------------------------------------------------
! st %r2,0(%r6)
! j .Lepilogue
!
! .Lepilogue:
! l %r15,0(%r11)
! l %r4,56(%r15)
! lm %r6,%r15,24(%r15)
br %r4
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.section .eh_frame,"aw",@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
--- 22,151 ----
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
+
+ #ifndef __s390x__
.text
!
! # r2: cif->bytes
# r3: &ecif
! # r4: ffi_prep_args
! # r5: ret_type
# r6: ecif.rvalue
! # ov: fn
# This assumes we are using gas.
.globl ffi_call_SYSV
.type ffi_call_SYSV,%function
ffi_call_SYSV:
.LFB1:
! stm %r6,%r15,24(%r15) # Save registers
.LCFI0:
! basr %r13,0 # Set up base register
! .Lbase:
! lr %r11,%r15 # Set up frame pointer
.LCFI1:
! sr %r15,%r2
! ahi %r15,-96-48 # Allocate stack
! lr %r8,%r6 # Save ecif.rvalue
! sr %r9,%r9
! ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
! l %r7,96(%r11) # Load function address
! st %r11,0(%r15) # Set up back chain
! ahi %r11,-48 # Register save area
.LCFI2:
!
! la %r2,96(%r15) # Save area
! # r3 already holds &ecif
! basr %r14,%r4 # Call ffi_prep_args
!
! lm %r2,%r6,0(%r11) # Load arguments
! ld %f0,32(%r11)
! ld %f2,40(%r11)
! la %r14,0(%r13,%r9) # Set return address
! br %r7 # ... and call function
!
! .LretNone: # Return void
! l %r4,48+56(%r11)
! lm %r6,%r15,48+24(%r11)
br %r4
+ .LretFloat:
+ l %r4,48+56(%r11)
+ ste %f0,0(%r8) # Return float
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+ .LretDouble:
+ l %r4,48+56(%r11)
+ std %f0,0(%r8) # Return double
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+ .LretInt32:
+ l %r4,48+56(%r11)
+ st %r2,0(%r8) # Return int
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+ .LretInt64:
+ l %r4,48+56(%r11)
+ stm %r2,%r3,0(%r8) # Return long long
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+ .Ltable:
+ .byte .LretNone-.Lbase # FFI390_RET_VOID
+ .byte .LretNone-.Lbase # FFI390_RET_STRUCT
+ .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
+ .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
+ .byte .LretInt32-.Lbase # FFI390_RET_INT32
+ .byte .LretInt64-.Lbase # FFI390_RET_INT64
+
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+ .globl ffi_closure_SYSV
+ .type ffi_closure_SYSV,%function
+ ffi_closure_SYSV:
+ .LFB2:
+ stm %r12,%r15,48(%r15) # Save registers
+ .LCFI10:
+ basr %r13,0 # Set up base register
+ .Lcbase:
+ stm %r2,%r6,8(%r15) # Save arguments
+ std %f0,64(%r15)
+ std %f2,72(%r15)
+ lr %r1,%r15 # Set up stack frame
+ ahi %r15,-96
+ .LCFI11:
+ l %r12,.Lchelper-.Lcbase(%r13) # Get helper function
+ lr %r2,%r0 # Closure
+ la %r3,8(%r1) # GPRs
+ la %r4,64(%r1) # FPRs
+ la %r5,96(%r1) # Overflow
+ st %r1,0(%r15) # Set up back chain
+
+ bas %r14,0(%r12,%r13) # Call helper
+
+ l %r4,96+56(%r15)
+ ld %f0,96+64(%r15) # Load return registers
+ lm %r2,%r3,96+8(%r15)
+ lm %r12,%r15,96+48(%r15)
+ br %r4
+
+ .align 4
+ .Lchelper:
+ .long ffi_closure_helper_SYSV-.Lcbase
+
+ .LFE2:
+
+ .ffi_closure_SYSV_end:
+ .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
+
+
.section .eh_frame,"aw",@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
*************** ffi_call_SYSV:
*** 187,193 ****
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
.4byte .LFB1 # FDE initial location
.4byte .LFE1-.LFB1 # FDE address range
- .uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0x8f # DW_CFA_offset, column 0xf
--- 167,172 ----
*************** ffi_call_SYSV:
*** 212,223 ****
.uleb128 0x12
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
! .byte 0xe # DW_CFA_def_cfa_offset
! .uleb128 0xe0
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI2-.LCFI1
! .byte 0xd # DW_CFA_def_cfa_register
.uleb128 0xb
.align 4
.LEFDE1:
--- 191,417 ----
.uleb128 0x12
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
! .byte 0xd # DW_CFA_def_cfa_register
! .uleb128 0xb
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI2-.LCFI1
! .byte 0xe # DW_CFA_def_cfa_offset
! .uleb128 0x90
! .align 4
! .LEFDE1:
! .LSFDE2:
! .4byte .LEFDE2-.LASFDE2 # FDE Length
! .LASFDE2:
! .4byte .LASFDE2-.Lframe1 # FDE CIE offset
! .4byte .LFB2 # FDE initial location
! .4byte .LFE2-.LFB2 # FDE address range
! .byte 0x4 # DW_CFA_advance_loc4
! .4byte .LCFI10-.LFB2
! .byte 0x8f # DW_CFA_offset, column 0xf
! .uleb128 0x9
! .byte 0x8e # DW_CFA_offset, column 0xe
! .uleb128 0xa
! .byte 0x8d # DW_CFA_offset, column 0xd
.uleb128 0xb
+ .byte 0x8c # DW_CFA_offset, column 0xc
+ .uleb128 0xc
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI11-.LCFI10
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0xc0
.align 4
+ .LEFDE2:
+
+ #else
+
+ .text
+
+ # r2: cif->bytes
+ # r3: &ecif
+ # r4: ffi_prep_args
+ # r5: ret_type
+ # r6: ecif.rvalue
+ # ov: fn
+
+ # This assumes we are using gas.
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV,%function
+ ffi_call_SYSV:
+ .LFB1:
+ stmg %r6,%r15,48(%r15) # Save registers
+ .LCFI0:
+ larl %r13,.Lbase # Set up base register
+ lgr %r11,%r15 # Set up frame pointer
+ .LCFI1:
+ sgr %r15,%r2
+ aghi %r15,-160-80 # Allocate stack
+ lgr %r8,%r6 # Save ecif.rvalue
+ llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
+ lg %r7,160(%r11) # Load function address
+ stg %r11,0(%r15) # Set up back chain
+ aghi %r11,-80 # Register save area
+ .LCFI2:
+
+ la %r2,160(%r15) # Save area
+ # r3 already holds &ecif
+ basr %r14,%r4 # Call ffi_prep_args
+
+ lmg %r2,%r6,0(%r11) # Load arguments
+ ld %f0,48(%r11)
+ ld %f2,56(%r11)
+ ld %f4,64(%r11)
+ ld %f6,72(%r11)
+ la %r14,0(%r13,%r9) # Set return address
+ br %r7 # ... and call function
+
+ .Lbase:
+ .LretNone: # Return void
+ lg %r4,80+112(%r11)
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+ .LretFloat:
+ lg %r4,80+112(%r11)
+ ste %f0,0(%r8) # Return float
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+ .LretDouble:
+ lg %r4,80+112(%r11)
+ std %f0,0(%r8) # Return double
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+ .LretInt32:
+ lg %r4,80+112(%r11)
+ st %r2,0(%r8) # Return int
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+ .LretInt64:
+ lg %r4,80+112(%r11)
+ stg %r2,0(%r8) # Return long
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+ .Ltable:
+ .byte .LretNone-.Lbase # FFI390_RET_VOID
+ .byte .LretNone-.Lbase # FFI390_RET_STRUCT
+ .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
+ .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
+ .byte .LretInt32-.Lbase # FFI390_RET_INT32
+ .byte .LretInt64-.Lbase # FFI390_RET_INT64
+
+ .LFE1:
+ .ffi_call_SYSV_end:
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+
+
+ .globl ffi_closure_SYSV
+ .type ffi_closure_SYSV,%function
+ ffi_closure_SYSV:
+ .LFB2:
+ stmg %r14,%r15,112(%r15) # Save registers
+ .LCFI10:
+ stmg %r2,%r6,16(%r15) # Save arguments
+ std %f0,128(%r15)
+ std %f2,136(%r15)
+ std %f4,144(%r15)
+ std %f6,152(%r15)
+ lgr %r1,%r15 # Set up stack frame
+ aghi %r15,-160
+ .LCFI11:
+ lgr %r2,%r0 # Closure
+ la %r3,16(%r1) # GPRs
+ la %r4,128(%r1) # FPRs
+ la %r5,160(%r1) # Overflow
+ stg %r1,0(%r15) # Set up back chain
+
+ brasl %r14,ffi_closure_helper_SYSV # Call helper
+
+ lg %r14,160+112(%r15)
+ ld %f0,160+128(%r15) # Load return registers
+ lg %r2,160+16(%r15)
+ la %r15,160(%r15)
+ br %r14
+ .LFE2:
+
+ .ffi_closure_SYSV_end:
+ .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
+
+
+
+ .section .eh_frame,"aw",@progbits
+ .Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+ .LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0xe # CIE RA Column
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0xf
+ .uleb128 0xa0
+ .align 8
+ .LECIE1:
+ .LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+ .LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .8byte .LFB1 # FDE initial location
+ .8byte .LFE1-.LFB1 # FDE address range
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI0-.LFB1
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x5
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0x6
+ .byte 0x8d # DW_CFA_offset, column 0xd
+ .uleb128 0x7
+ .byte 0x8c # DW_CFA_offset, column 0xc
+ .uleb128 0x8
+ .byte 0x8b # DW_CFA_offset, column 0xb
+ .uleb128 0x9
+ .byte 0x8a # DW_CFA_offset, column 0xa
+ .uleb128 0xa
+ .byte 0x89 # DW_CFA_offset, column 0x9
+ .uleb128 0xb
+ .byte 0x88 # DW_CFA_offset, column 0x8
+ .uleb128 0xc
+ .byte 0x87 # DW_CFA_offset, column 0x7
+ .uleb128 0xd
+ .byte 0x86 # DW_CFA_offset, column 0x6
+ .uleb128 0xe
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI1-.LCFI0
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0xb
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI2-.LCFI1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0xf0
+ .align 8
.LEFDE1:
+ .LSFDE2:
+ .4byte .LEFDE2-.LASFDE2 # FDE Length
+ .LASFDE2:
+ .4byte .LASFDE2-.Lframe1 # FDE CIE offset
+ .8byte .LFB2 # FDE initial location
+ .8byte .LFE2-.LFB2 # FDE address range
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI10-.LFB2
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x5
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0x6
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI11-.LCFI10
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x140
+ .align 8
+ .LEFDE2:
+
+ #endif
Mit freundlichen Gruessen / Best Regards
Ulrich Weigand
--
Dr. Ulrich Weigand
Linux for S/390 Design & Development
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032 Boeblingen
Phone: +49-7031/16-3727 --- Email: Ulrich.Weigand@de.ibm.com