[PATCH] Improved libffi support for s390/s390x

Ulrich Weigand Ulrich.Weigand@de.ibm.com
Fri Sep 27 09:48:00 GMT 2002


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



More information about the Gcc-patches mailing list