s390: Reorganize assembly

Avoid using ffi_prep_args as a callback; do all the work setting
up the frame within ffi_call_int directly.  Save fewer registers
in ffi_closure_SYSV.
This commit is contained in:
Richard Henderson
2014-12-18 16:01:59 -05:00
parent 97512ded05
commit 2f530de168
3 changed files with 285 additions and 455 deletions

View File

@@ -30,9 +30,7 @@
#include <ffi.h> #include <ffi.h>
#include <ffi_common.h> #include <ffi_common.h>
#include "internal.h"
#include <stdlib.h>
#include <stdio.h>
/*====================== End of Includes =============================*/ /*====================== End of Includes =============================*/
@@ -54,14 +52,6 @@
/* Round to multiple of 16. */ /* Round to multiple of 16. */
#define ROUND_SIZE(size) (((size) + 15) & ~15) #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 ===============================*/ /*===================== End of Defines ===============================*/
/*====================================================================*/ /*====================================================================*/
@@ -69,12 +59,17 @@
/* --------- */ /* --------- */
/*====================================================================*/ /*====================================================================*/
extern void ffi_call_SYSV(unsigned, struct call_frame
extended_cif *, {
void (*)(unsigned char *, extended_cif *), void *back_chain;
unsigned, void *eos;
void *, unsigned long gpr_args[5];
void (*fn)(void), void *); unsigned long gpr_save[9];
unsigned long long fpr_args[4];
};
extern void FFI_HIDDEN ffi_call_SYSV(struct call_frame *, unsigned, void *,
void (*fn)(void), void *);
extern void ffi_closure_SYSV(void); extern void ffi_closure_SYSV(void);
extern void ffi_go_closure_SYSV(void); extern void ffi_go_closure_SYSV(void);
@@ -145,54 +140,29 @@ ffi_check_struct_type (ffi_type *arg)
/*====================================================================*/ /*====================================================================*/
static void static void
ffi_prep_args (unsigned char *stack, extended_cif *ecif) ffi_prep_args (ffi_cif *cif, void *rvalue, void **p_argv,
unsigned long *p_ov, struct call_frame *p_frame)
{ {
/* The stack space will be filled with those areas: unsigned char *p_struct = (unsigned char *)p_frame;
unsigned long *p_gpr = p_frame->gpr_args;
FPR argument register save area (highest addresses) unsigned long long *p_fpr = p_frame->fpr_args;
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_fpr = 0;
int n_gpr = 0; int n_gpr = 0;
int n_ov = 0; int n_ov = 0;
ffi_type **ptr; ffi_type **ptr;
void **p_argv = ecif->avalue;
int i; int i;
/* If we returning a structure then we set the first parameter register /* If we returning a structure then we set the first parameter register
to the address of where we are returning this structure. */ to the address of where we are returning this structure. */
if (cif->flags & FFI390_RET_IN_MEM)
if (ecif->cif->flags == FFI390_RET_STRUCT) p_gpr[n_gpr++] = (unsigned long) rvalue;
p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
/* Now for the arguments. */ /* Now for the arguments. */
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++, p_argv++)
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
i > 0;
i--, ptr++, p_argv++)
{ {
ffi_type *ty = *ptr;
void *arg = *p_argv; void *arg = *p_argv;
int type = (*ptr)->type; int type = ty->type;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
/* 16-byte long double is passed like a struct. */ /* 16-byte long double is passed like a struct. */
@@ -206,13 +176,13 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif)
if (type == FFI_TYPE_COMPLEX) if (type == FFI_TYPE_COMPLEX)
type = FFI_TYPE_POINTER; type = FFI_TYPE_POINTER;
else else
type = ffi_check_struct_type (*ptr); type = ffi_check_struct_type (ty);
/* If we pass the struct via pointer, copy the data. */ /* If we pass the struct via pointer, copy the data. */
if (type == FFI_TYPE_POINTER) if (type == FFI_TYPE_POINTER)
{ {
p_struct -= ROUND_SIZE ((*ptr)->size); p_struct -= ROUND_SIZE (ty->size);
memcpy (p_struct, (char *)arg, (*ptr)->size); memcpy (p_struct, (char *)arg, ty->size);
arg = &p_struct; arg = &p_struct;
} }
} }
@@ -234,7 +204,7 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif)
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS) if (n_fpr < MAX_FPRARGS)
p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32; p_fpr[n_fpr++] = (unsigned long long)*(unsigned int *) arg << 32;
else else
p_ov[n_ov++] = *(unsigned int *) arg; p_ov[n_ov++] = *(unsigned int *) arg;
break; break;
@@ -325,7 +295,7 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif)
/* */ /* */
/*====================================================================*/ /*====================================================================*/
ffi_status ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif) ffi_prep_cif_machdep(ffi_cif *cif)
{ {
size_t struct_size = 0; size_t struct_size = 0;
@@ -498,32 +468,55 @@ ffi_call_int(ffi_cif *cif,
void *closure) void *closure)
{ {
int ret_type = cif->flags; int ret_type = cif->flags;
extended_cif ecif; size_t rsize = 0, bytes = cif->bytes;
unsigned char *stack;
struct call_frame *frame;
ecif.cif = cif; FFI_ASSERT (cif->abi == FFI_SYSV);
ecif.avalue = avalue;
ecif.rvalue = rvalue;
/* If we don't have a return value, we need to fake one. */ /* If we don't have a return value, we need to fake one. */
if (rvalue == NULL) if (rvalue == NULL)
{ {
if (ret_type == FFI390_RET_STRUCT) if (ret_type & FFI390_RET_IN_MEM)
ecif.rvalue = alloca (cif->rtype->size); rsize = cif->rtype->size;
else else
ret_type = FFI390_RET_VOID; ret_type = FFI390_RET_VOID;
} }
switch (cif->abi) /* The stack space will be filled with those areas:
{
case FFI_SYSV:
ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
ret_type, ecif.rvalue, fn, closure);
break;
default: dummy structure return (highest addresses)
FFI_ASSERT (0); FPR argument register save area
break; GPR argument register save area
} stack frame for ffi_call_SYSV
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. */
stack = alloca (bytes + sizeof(struct call_frame) + rsize);
frame = (struct call_frame *)(stack + bytes);
if (rsize)
rvalue = frame + 1;
/* Assuming that the current function has the standard call frame,
we can maintain the linked list like so. */
frame->back_chain = __builtin_dwarf_cfa() - sizeof(struct call_frame);
/* Pass the outgoing stack frame in the r15 save slot. */
frame->gpr_save[8] = (unsigned long)(stack - sizeof(struct call_frame));
/* Fill in all of the argument stuff. */
ffi_prep_args (cif, rvalue, avalue, (unsigned long *)stack, frame);
ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure);
} }
void void
@@ -549,8 +542,7 @@ ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
/* */ /* */
/*====================================================================*/ /*====================================================================*/
FFI_HIDDEN void FFI_HIDDEN
void
ffi_closure_helper_SYSV (ffi_cif *cif, ffi_closure_helper_SYSV (ffi_cif *cif,
void (*fun)(ffi_cif*,void*,void**,void*), void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data, void *user_data,
@@ -572,18 +564,15 @@ ffi_closure_helper_SYSV (ffi_cif *cif,
int i; int i;
/* Allocate buffer for argument list pointers. */ /* Allocate buffer for argument list pointers. */
p_arg = avalue = alloca (cif->nargs * sizeof (void *)); p_arg = avalue = alloca (cif->nargs * sizeof (void *));
/* If we returning a structure, pass the structure address /* If we returning a structure, pass the structure address
directly to the target function. Otherwise, have the target directly to the target function. Otherwise, have the target
function store the return value to the GPR save area. */ function store the return value to the GPR save area. */
if (cif->flags & FFI390_RET_IN_MEM)
if (cif->flags == FFI390_RET_STRUCT)
rvalue = (void *) p_gpr[n_gpr++]; rvalue = (void *) p_gpr[n_gpr++];
/* Now for the arguments. */ /* Now for the arguments. */
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, p_arg++, ptr++) for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, p_arg++, ptr++)
{ {
int deref_struct_pointer = 0; int deref_struct_pointer = 0;
@@ -611,11 +600,13 @@ ffi_closure_helper_SYSV (ffi_cif *cif,
/* Pointers are passed like UINTs of the same size. */ /* Pointers are passed like UINTs of the same size. */
if (type == FFI_TYPE_POINTER) if (type == FFI_TYPE_POINTER)
{
#ifdef __s390x__ #ifdef __s390x__
type = FFI_TYPE_UINT64; type = FFI_TYPE_UINT64;
#else #else
type = FFI_TYPE_UINT32; type = FFI_TYPE_UINT32;
#endif #endif
}
/* Now handle all primitive int/float data types. */ /* Now handle all primitive int/float data types. */
switch (type) switch (type)

11
src/s390/internal.h Normal file
View File

@@ -0,0 +1,11 @@
/* If these values change, sysv.S must be adapted! */
#define FFI390_RET_DOUBLE 0
#define FFI390_RET_FLOAT 1
#define FFI390_RET_INT64 2
#define FFI390_RET_INT32 3
#define FFI390_RET_VOID 4
#define FFI360_RET_MASK 7
#define FFI390_RET_IN_MEM 8
#define FFI390_RET_STRUCT (FFI390_RET_VOID | FFI390_RET_IN_MEM)

View File

@@ -29,221 +29,140 @@
#include <fficonfig.h> #include <fficonfig.h>
#include <ffi.h> #include <ffi.h>
.text
#ifndef __s390x__ #ifndef __s390x__
.text # r2: frame
# r3: ret_type
# r2: cif->bytes # r4: ret_addr
# r3: &ecif # r5: fun
# r4: ffi_prep_args # r6: closure
# r5: ret_type
# r6: ecif.rvalue
# ov: fn
# ov+8: closure
# This assumes we are using gas. # This assumes we are using gas.
.balign 8
.globl ffi_call_SYSV .globl ffi_call_SYSV
FFI_HIDDEN(ffi_call_SYSV) FFI_HIDDEN(ffi_call_SYSV)
.type ffi_call_SYSV,%function .type ffi_call_SYSV,%function
ffi_call_SYSV: ffi_call_SYSV:
.cfi_startproc .cfi_startproc
stm %r6,%r15,24(%r15) # Save registers st %r6,44(%r2) # Save registers
.cfi_offset r6, -72 stm %r12,%r14,48(%r2)
.cfi_offset r7, -68 lr %r13,%r2 # Install frame pointer
.cfi_offset r8, -64 .cfi_rel_offset r6, 44
.cfi_offset r9, -60 .cfi_rel_offset r12, 48
.cfi_offset r10, -56 .cfi_rel_offset r13, 52
.cfi_offset r11, -52 .cfi_rel_offset r14, 56
.cfi_offset r12, -48 .cfi_def_cfa_register r13
.cfi_offset r13, -44 l %r15,60(%r2) # Set up outgoing stack
.cfi_offset r14, -40 basr %r14,0 # Set up base register
.cfi_offset r15, -36
basr %r13,0 # Set up base register
.Lbase: .Lbase:
lr %r11,%r15 # Set up frame pointer sla %r3,3 # ret_type *= 8
.cfi_def_cfa_register r11 lr %r12,%r4 # Save ret_addr
sr %r15,%r2 lr %r1,%r5 # Save fun
ahi %r15,-96-48 # Allocate stack lr %r0,%r6 # Install static chain
lr %r8,%r6 # Save ecif.rvalue la %r14,.Ltable-.Lbase(%r14,%r3) # Set return address
sr %r9,%r9 lm %r2,%r6,8(%r13) # Load arguments
ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address ld %f0,64(%r13)
l %r7,96(%r11) # Load function address ld %f2,72(%r13)
st %r11,0(%r15) # Set up back chain st %r13,0(%r15) # Set up back chain
ahi %r11,-48 # Register save area br %r1 # ... and call function
.cfi_adjust_cfa_offset 48
la %r2,96(%r15) # Save area .balign 8
# r3 already holds &ecif .Ltable:
basr %r14,%r4 # Call ffi_prep_args # FFI390_RET_DOUBLE
std %f0,0(%r12)
j .Ldone
l %r0,96+48+4(%r11) # Go closure -> static chain .balign 8
lm %r2,%r6,0(%r11) # Load arguments # FFI390_RET_FLOAT
ld %f0,32(%r11) ste %f0,0(%r12)
ld %f2,40(%r11) j .Ldone
la %r14,0(%r13,%r9) # Set return address
br %r7 # ... and call function
.LretNone: # Return void .balign 8
l %r4,48+56(%r11) # FFI390_RET_INT64
lm %r6,%r15,48+24(%r11) st %r3,4(%r12)
.cfi_remember_state nop
.cfi_restore 15 # fallthru
.balign 8
# FFI390_RET_INT32
st %r2,0(%r12)
nop
# fallthru
.balign 8
# FFI390_RET_VOID
.Ldone:
l %r14,56(%r13)
l %r12,48(%r13)
l %r6,44(%r13)
l %r13,52(%r13)
.cfi_restore 14 .cfi_restore 14
.cfi_restore 13 .cfi_restore 13
.cfi_restore 12 .cfi_restore 12
.cfi_restore 11
.cfi_restore 10
.cfi_restore 9
.cfi_restore 8
.cfi_restore 7
.cfi_restore 6 .cfi_restore 6
.cfi_def_cfa r15, 96 .cfi_def_cfa r15, 96
br %r4 br %r14
.cfi_restore_state .cfi_endproc
# This nopr is necessary so that the .cfi instructions between the br .size ffi_call_SYSV,.-ffi_call_SYSV
# above and the label below get executed. See execute_cfa_program() in
# the Gcc source code, libgcc/unwind-dw2.c.
nopr
.LretFloat:
l %r4,48+56(%r11)
ste %f0,0(%r8) # Return float
lm %r6,%r15,48+24(%r11)
.cfi_remember_state
.cfi_restore 15
.cfi_restore 14
.cfi_restore 13
.cfi_restore 12
.cfi_restore 11
.cfi_restore 10
.cfi_restore 9
.cfi_restore 8
.cfi_restore 7
.cfi_restore 6
.cfi_def_cfa r15, 96
br %r4
.cfi_restore_state
# See comment on the nopr above.
nopr
.LretDouble: .balign 8
l %r4,48+56(%r11) .globl ffi_go_closure_SYSV
std %f0,0(%r8) # Return double FFI_HIDDEN(ffi_go_closure_SYSV)
lm %r6,%r15,48+24(%r11) .type ffi_go_closure_SYSV,%function
.cfi_remember_state ffi_go_closure_SYSV:
.cfi_restore 15 .cfi_startproc
.cfi_restore 14 stm %r2,%r6,8(%r15) # Save arguments
.cfi_restore 13 lr %r4,%r0 # Load closure -> user_data
.cfi_restore 12 l %r2,4(%r4) # ->cif
.cfi_restore 11 l %r3,8(%r4) # ->fun
.cfi_restore 10 j .Ldoclosure
.cfi_restore 9
.cfi_restore 8
.cfi_restore 7
.cfi_restore 6
.cfi_def_cfa r15, 96
br %r4
.cfi_restore_state
# See comment on the nopr above.
nopr
.LretInt32:
l %r4,48+56(%r11)
st %r2,0(%r8) # Return int
lm %r6,%r15,48+24(%r11)
.cfi_remember_state
.cfi_restore 15
.cfi_restore 14
.cfi_restore 13
.cfi_restore 12
.cfi_restore 11
.cfi_restore 10
.cfi_restore 9
.cfi_restore 8
.cfi_restore 7
.cfi_restore 6
.cfi_def_cfa r15, 96
br %r4
.cfi_restore_state
# See comment on the nopr above.
nopr
.LretInt64:
l %r4,48+56(%r11)
stm %r2,%r3,0(%r8) # Return long long
lm %r6,%r15,48+24(%r11)
.cfi_remember_state
.cfi_restore 15
.cfi_restore 14
.cfi_restore 13
.cfi_restore 12
.cfi_restore 11
.cfi_restore 10
.cfi_restore 9
.cfi_restore 8
.cfi_restore 7
.cfi_restore 6
.cfi_def_cfa r15, 96
br %r4
.cfi_endproc .cfi_endproc
.Ltable: .balign 8
.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
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.globl ffi_closure_SYSV .globl ffi_closure_SYSV
FFI_HIDDEN(ffi_closure_SYSV) FFI_HIDDEN(ffi_closure_SYSV)
.type ffi_closure_SYSV,%function .type ffi_closure_SYSV,%function
ffi_closure_SYSV: ffi_closure_SYSV:
.cfi_startproc .cfi_startproc
stm %r2,%r6,8(%r15) # Save arguments stm %r2,%r6,8(%r15) # Save arguments
.cfi_offset r6, -72
lr %r4,%r0 # Closure lr %r4,%r0 # Closure
l %r2,16(%r4) # ->cif l %r2,16(%r4) # ->cif
l %r3,20(%r4) # ->fun l %r3,20(%r4) # ->fun
l %r4,24(%r4) # ->user_data l %r4,24(%r4) # ->user_data
.Ldoclosure: .Ldoclosure:
stm %r12,%r15,48(%r15) # Save registers stm %r12,%r15,48(%r15) # Save registers
.cfi_offset r12, -48 lr %r12,%r15
.cfi_offset r13, -44 .cfi_def_cfa_register r12
.cfi_offset r14, -40 .cfi_rel_offset r6, 24
.cfi_offset r15, -36 .cfi_rel_offset r12, 48
.cfi_rel_offset r13, 52
.cfi_rel_offset r14, 56
.cfi_rel_offset r15, 60
basr %r13,0 # Set up base register basr %r13,0 # Set up base register
.Lcbase: .Lcbase:
std %f0,64(%r15) ahi %r15,-96-8 # Set up stack frame
std %f2,72(%r15) l %r1,.Lchelper-.Lcbase(%r13) # Get helper function
lr %r1,%r15 # Set up stack frame st %r12,0(%r15) # Set up back chain
ahi %r15,-104
.cfi_adjust_cfa_offset 104
l %r12,.Lchelper-.Lcbase(%r13) # Get helper function
la %r5,96(%r1)
st %r5,96(%r15) # Overflow
la %r5,8(%r1) # GPRs
la %r6,64(%r1) # FPRs
st %r1,0(%r15) # Set up back chain
bas %r14,0(%r12,%r13) # Call helper std %f0,64(%r12) # Save fp arguments
std %f2,72(%r12)
l %r4,104+56(%r15) la %r5,96(%r12) # Overflow
ld %f0,104+64(%r15) # Load return registers st %r5,96(%r15)
lm %r2,%r3,104+8(%r15) la %r6,64(%r12) # FPRs
l %r6,104+24(%r15) # Restore saved registers la %r5,8(%r12) # GPRs
.cfi_restore r6 bas %r14,0(%r1,%r13) # Call helper
lm %r12,%r15,104+48(%r15)
.cfi_adjust_cfa_offset -104 lr %r15,%r12
.cfi_restore r12 .cfi_def_cfa_register r15
.cfi_restore r13 lm %r12,%r14,48(%r12) # Restore saved registers
.cfi_restore r14 l %r6,24(%r15)
.cfi_restore r15 ld %f0,64(%r15) # Load return registers
br %r4 lm %r2,%r3,8(%r15)
br %r14
.cfi_endproc .cfi_endproc
.align 4 .align 4
@@ -251,234 +170,143 @@ ffi_closure_SYSV:
.long ffi_closure_helper_SYSV-.Lcbase .long ffi_closure_helper_SYSV-.Lcbase
.ffi_closure_SYSV_end: .size ffi_closure_SYSV,.-ffi_closure_SYSV
.size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
.globl ffi_go_closure_SYSV
FFI_HIDDEN(ffi_go_closure_SYSV)
.type ffi_go_closure_SYSV,%function
ffi_go_closure_SYSV:
.cfi_startproc
stm %r2,%r6,8(%r15) # Save arguments
.cfi_offset r6, -72
lr %r4,%r0 # Load closure -> user_data
l %r2,4(%r4) # ->cif
l %r3,8(%r4) # ->fun
j .Ldoclosure
.cfi_endproc
#else #else
.text # r2: frame
# r3: ret_type
# r2: cif->bytes # r4: ret_addr
# r3: &ecif # r5: fun
# r4: ffi_prep_args # r6: closure
# r5: ret_type
# r6: ecif.rvalue
# ov: fn
# ov+8: closure
# This assumes we are using gas. # This assumes we are using gas.
.balign 8
.globl ffi_call_SYSV .globl ffi_call_SYSV
FFI_HIDDEN(ffi_call_SYSV) FFI_HIDDEN(ffi_call_SYSV)
.type ffi_call_SYSV,%function .type ffi_call_SYSV,%function
ffi_call_SYSV: ffi_call_SYSV:
.cfi_startproc .cfi_startproc
stmg %r6,%r15,48(%r15) # Save registers stg %r6,88(%r2) # Save registers
.cfi_offset r6, -112 stmg %r12,%r14,96(%r2)
.cfi_offset r7, -104 lgr %r13,%r2 # Install frame pointer
.cfi_offset r8, -96 .cfi_rel_offset r6, 88
.cfi_offset r9, -88 .cfi_rel_offset r12, 96
.cfi_offset r10, -80 .cfi_rel_offset r13, 104
.cfi_offset r11, -72 .cfi_rel_offset r14, 112
.cfi_offset r12, -64 .cfi_def_cfa_register r13
.cfi_offset r13, -56 lg %r15,120(%r2) # Set up outgoing stack
.cfi_offset r14, -48 larl %r14,.Ltable # Set up return address
.cfi_offset r15, -40 slag %r3,%r3,3 # ret_type *= 8
larl %r13,.Lbase # Set up base register lgr %r12,%r4 # Save ret_addr
lgr %r11,%r15 # Set up frame pointer lgr %r1,%r5 # Save fun
.cfi_def_cfa_register r11 lgr %r0,%r6 # Install static chain
sgr %r15,%r2 agr %r14,%r3
aghi %r15,-160-80 # Allocate stack lmg %r2,%r6,16(%r13) # Load arguments
lgr %r8,%r6 # Save ecif.rvalue ld %f0,128(%r13)
llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address ld %f2,136(%r13)
lg %r7,160(%r11) # Load function address ld %f4,144(%r13)
stg %r11,0(%r15) # Set up back chain ld %f6,152(%r13)
aghi %r11,-80 # Register save area stg %r13,0(%r15) # Set up back chain
.cfi_adjust_cfa_offset 80 br %r1 # ... and call function
la %r2,160(%r15) # Save area
# r3 already holds &ecif
basr %r14,%r4 # Call ffi_prep_args
lg %r0,160+80+8(%r11) # Go closure -> static chain
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)
.cfi_remember_state
.cfi_restore r15
.cfi_restore r14
.cfi_restore r13
.cfi_restore r12
.cfi_restore r11
.cfi_restore r10
.cfi_restore r9
.cfi_restore r8
.cfi_restore r7
.cfi_restore r6
.cfi_def_cfa r15, 160
br %r4
.cfi_restore_state
# This nopr is necessary so that the .cfi instructions between the br
# above and the label below get executed. See execute_cfa_program() in
# the Gcc source code, libgcc/unwind-dw2.c.
nopr
.LretFloat:
lg %r4,80+112(%r11)
ste %f0,0(%r8) # Return float
lmg %r6,%r15,80+48(%r11)
.cfi_remember_state
.cfi_restore r6
.cfi_restore r7
.cfi_restore r8
.cfi_restore r9
.cfi_restore r10
.cfi_restore r11
.cfi_restore r12
.cfi_restore r13
.cfi_restore r14
.cfi_restore r15
.cfi_def_cfa r15, 160
br %r4
.cfi_restore_state
# See comment on the nopr above.
nopr
.LretDouble:
lg %r4,80+112(%r11)
std %f0,0(%r8) # Return double
lmg %r6,%r15,80+48(%r11)
.cfi_remember_state
.cfi_restore r15
.cfi_restore r14
.cfi_restore r13
.cfi_restore r12
.cfi_restore r11
.cfi_restore r10
.cfi_restore r9
.cfi_restore r8
.cfi_restore r7
.cfi_restore r6
.cfi_def_cfa r15, 160
br %r4
.cfi_restore_state
# See comment on the nopr above.
nopr
.LretInt64:
lg %r4,80+112(%r11)
stg %r2,0(%r8) # Return long
lmg %r6,%r15,80+48(%r11)
.cfi_restore r15
.cfi_restore r14
.cfi_restore r13
.cfi_restore r12
.cfi_restore r11
.cfi_restore r10
.cfi_restore r9
.cfi_restore r8
.cfi_restore r7
.cfi_restore r6
.cfi_def_cfa r15, 160
br %r4
.cfi_endproc
.balign 8
.Ltable: .Ltable:
.byte .LretNone-.Lbase # FFI390_RET_VOID # FFI390_RET_DOUBLE
.byte .LretNone-.Lbase # FFI390_RET_STRUCT std %f0,0(%r12)
.byte .LretFloat-.Lbase # FFI390_RET_FLOAT j .Ldone
.byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
.byte 0 # int32 retval not supported
.byte .LretInt64-.Lbase # FFI390_RET_INT64
.ffi_call_SYSV_end: .balign 8
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV # FFI390_RET_DOUBLE
ste %f0,0(%r12)
j .Ldone
.balign 8
# FFI390_RET_INT64
stg %r2,0(%r12)
.balign 8
# FFI390_RET_INT32
# Never used, as we always store type ffi_arg.
# But the stg above is 6 bytes and we cannot
# jump around this case, so fall through.
nop
nop
.balign 8
# FFI390_RET_VOID
.Ldone:
lg %r14,112(%r13)
lg %r12,96(%r13)
lg %r6,88(%r13)
lg %r13,104(%r13)
.cfi_restore r14
.cfi_restore r13
.cfi_restore r12
.cfi_restore r6
.cfi_def_cfa r15, 160
br %r14
.cfi_endproc
.size ffi_call_SYSV,.-ffi_call_SYSV
.balign 8
.globl ffi_go_closure_SYSV
FFI_HIDDEN(ffi_go_closure_SYSV)
.type ffi_go_closure_SYSV,%function
ffi_go_closure_SYSV:
.cfi_startproc
stmg %r2,%r6,16(%r15) # Save arguments
lgr %r4,%r0 # Load closure -> user_data
lg %r2,8(%r4) # ->cif
lg %r3,16(%r4) # ->fun
j .Ldoclosure
.cfi_endproc
.size ffi_go_closure_SYSV,.-ffi_go_closure_SYSV
.balign 8
.globl ffi_closure_SYSV .globl ffi_closure_SYSV
FFI_HIDDEN(ffi_closure_SYSV) FFI_HIDDEN(ffi_closure_SYSV)
.type ffi_closure_SYSV,%function .type ffi_closure_SYSV,%function
ffi_closure_SYSV: ffi_closure_SYSV:
.cfi_startproc .cfi_startproc
stmg %r2,%r6,16(%r15) # Save arguments stmg %r2,%r6,16(%r15) # Save arguments
.cfi_offset r6, -112
lgr %r4,%r0 # Load closure lgr %r4,%r0 # Load closure
lg %r2,32(%r4) # ->cif lg %r2,32(%r4) # ->cif
lg %r3,40(%r4) # ->fun lg %r3,40(%r4) # ->fun
lg %r4,48(%r4) # ->user_data lg %r4,48(%r4) # ->user_data
.Ldoclosure: .Ldoclosure:
stmg %r14,%r15,112(%r15) # Save registers stmg %r13,%r15,104(%r15) # Save registers
.cfi_offset r14, -48 lgr %r13,%r15
.cfi_offset r15, -40 .cfi_def_cfa_register r13
std %f0,128(%r15) # Save arguments .cfi_rel_offset r6, 48
std %f2,136(%r15) .cfi_rel_offset r13, 104
std %f4,144(%r15) .cfi_rel_offset r14, 112
std %f6,152(%r15) .cfi_rel_offset r15, 120
lgr %r1,%r15 # Set up stack frame aghi %r15,-160-16 # Set up stack frame
aghi %r15,-168 stg %r13,0(%r15) # Set up back chain
.cfi_adjust_cfa_offset 168
la %r5,160(%r1)
stg %r5,160(%r15) # Overflow
la %r5,16(%r1) # GPRs
la %r6,128(%r1) # FPRs
stg %r1,0(%r15) # Set up back chain
std %f0,128(%r13) # Save fp arguments
std %f2,136(%r13)
std %f4,144(%r13)
std %f6,152(%r13)
la %r5,160(%r13) # Overflow
stg %r5,160(%r15)
la %r6,128(%r13) # FPRs
la %r5,16(%r13) # GPRs
brasl %r14,ffi_closure_helper_SYSV # Call helper brasl %r14,ffi_closure_helper_SYSV # Call helper
ld %f0,168+128(%r15) # Load return registers lgr %r15,%r13
lg %r2,168+16(%r15) .cfi_def_cfa_register r15
lg %r6,168+48(%r15) # Restore saved registers lmg %r13,%r14,104(%r13) # Restore saved registers
.cfi_restore r6 lg %r6,48(%r15)
lmg %r14,%r15,168+112(%r15) ld %f0,128(%r15) # Load return registers
.cfi_restore r14 lg %r2,16(%r15)
.cfi_restore r15
.cfi_adjust_cfa_offset -168
br %r14 br %r14
.cfi_endproc .cfi_endproc
.size ffi_closure_SYSV,.-ffi_closure_SYSV
.ffi_closure_SYSV_end: #endif /* !s390x */
.size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
.globl ffi_go_closure_SYSV
FFI_HIDDEN(ffi_go_closure_SYSV)
.type ffi_go_closure_SYSV,%function
ffi_go_closure_SYSV:
.cfi_startproc
stmg %r2,%r6,16(%r15) # Save arguments
.cfi_offset r6, -112
lgr %r4,%r0 # Load closure -> user_data
lg %r2,8(%r4) # ->cif
lg %r3,16(%r4) # ->fun
j .Ldoclosure
.cfi_endproc
.ffi_go_closure_SYSV_end:
.size ffi_go_closure_SYSV,.ffi_go_closure_SYSV_end-ffi_go_closure_SYSV
#endif
#if defined __ELF__ && defined __linux__ #if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits .section .note.GNU-stack,"",@progbits