Commit f20459f1 by Richard Earnshaw Committed by Richard Earnshaw

ffi.c (ffi_prep_cif_machdep): Handle functions that return long long values.

* src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return
long long values.  Round stack allocation to a multiple of 8 bytes
for ATPCS compatibility.
* src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register
names.  Handle returning long long types.  Add Thumb and interworking
support.  Improve soft-float code.

From-SVN: r89681
parent 5ae4c565
2004-10-27 Richard Earnshaw <rearnsha@arm.com> 2004-10-27 Richard Earnshaw <rearnsha@arm.com>
* src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return
long long values. Round stack allocation to a multiple of 8 bytes
for ATPCS compatibility.
* src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register
names. Handle returning long long types. Add Thumb and interworking
support. Improve soft-float code.
2004-10-27 Richard Earnshaw <rearnsha@arm.com>
* testsuite/lib/libffi-db.exp (load_gcc_lib): New function. * testsuite/lib/libffi-db.exp (load_gcc_lib): New function.
(libffi_exit): New function. (libffi_exit): New function.
(libffi_init): Build the testglue wrapper if needed. (libffi_init): Build the testglue wrapper if needed.
......
...@@ -108,6 +108,11 @@ void ffi_prep_args(char *stack, extended_cif *ecif) ...@@ -108,6 +108,11 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
/* Perform machine dependent cif processing */ /* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif) ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{ {
/* Round the stack up to a multiple of 8 bytes. This isn't needed
everywhere, but it is on some platforms, and it doesn't harm anything
when it isn't needed. */
cif->bytes = (cif->bytes + 7) & ~7;
/* Set the return type flag */ /* Set the return type flag */
switch (cif->rtype->type) switch (cif->rtype->type)
{ {
...@@ -118,6 +123,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) ...@@ -118,6 +123,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
cif->flags = (unsigned) cif->rtype->type; cif->flags = (unsigned) cif->rtype->type;
break; break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = (unsigned) FFI_TYPE_SINT64;
break;
default: default:
cif->flags = FFI_TYPE_INT; cif->flags = FFI_TYPE_INT;
break; break;
......
...@@ -40,87 +40,169 @@ ...@@ -40,87 +40,169 @@
#endif #endif
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
#endif #endif
#ifdef __ELF__
#define LSYM(x) .x
#else
#define LSYM(x) x
#endif
/* We need a better way of testing for this, but for now, this is all
we can do. */
@ This selects the minimum architecture level required.
#define __ARM_ARCH__ 3
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 4
#endif
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 5
#endif
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 6
#endif
#if __ARM_ARCH__ >= 5
# define call_reg(x) blx x
#elif defined (__ARM_ARCH_4T__)
# define call_reg(x) mov lr, pc ; bx x
# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
# define __INTERWORKING__
# endif
#else
# define call_reg(x) mov lr, pc ; mov pc, x
#endif
#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
.macro ARM_FUNC_START name
.text
.align 0
.thumb
.thumb_func
ENTRY(\name)
bx pc
nop
.arm
/* A hook to tell gdb that we've switched to ARM mode. Also used to call
directly from other local arm routines. */
_L__\name:
.endm
#else
.macro ARM_FUNC_START name
.text
.align 0
.arm
ENTRY(\name)
.endm
#endif
.macro RETLDM regs=, cond=, dirn=ia
#if defined (__INTERWORKING__)
.ifc "\regs",""
ldr\cond lr, [sp], #4
.else
ldm\cond\dirn sp!, {\regs, lr}
.endif
bx\cond lr
#else
.ifc "\regs",""
ldr\cond pc, [sp], #4
.else
ldm\cond\dirn sp!, {\regs, pc}
.endif
#endif
.endm
@ r0: ffi_prep_args
@ r1: &ecif
@ r2: cif->bytes
@ r3: fig->flags
@ sp+0: ecif.rvalue
@ sp+4: fn
@ This assumes we are using gas.
ARM_FUNC_START ffi_call_SYSV
@ Save registers
stmfd sp!, {r0-r3, fp, lr}
mov fp, sp
@ Make room for all of the new args.
sub sp, fp, r2
@ Place all of the ffi_prep_args in position
mov ip, r0
mov r0, sp
@ r1 already set
@ Call ffi_prep_args(stack, &ecif)
call_reg(ip)
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
@ and adjust stack
ldr ip, [fp, #8]
cmp ip, #16
movhs ip, #16
add sp, sp, ip
@ call (fn) (...)
ldr ip, [fp, #28]
call_reg(ip)
.text @ Remove the space we pushed for the args
mov sp, fp
# a1: ffi_prep_args
# a2: &ecif @ Load r2 with the pointer to storage for the return value
# a3: cif->bytes ldr r2, [sp, #24]
# a4: fig->flags
# sp+0: ecif.rvalue @ Load r3 with the return type code
# sp+4: fn ldr r3, [sp, #12]
# This assumes we are using gas. @ If the return value pointer is NULL, assume no return value.
ENTRY(ffi_call_SYSV) cmp r2, #0
# Save registers beq LSYM(Lepilogue)
stmfd sp!, {a1-a4, fp, lr}
mov fp, sp @ return INT
cmp r3, #FFI_TYPE_INT
# Make room for all of the new args.
sub sp, fp, a3
# Place all of the ffi_prep_args in position
mov ip, a1
mov a1, sp
# a2 already set
# And call
mov lr, pc
mov pc, ip
# move first 4 parameters in registers
ldr a1, [sp, #0]
ldr a2, [sp, #4]
ldr a3, [sp, #8]
ldr a4, [sp, #12]
# and adjust stack
ldr ip, [fp, #8]
cmp ip, #16
movge ip, #16
add sp, sp, ip
# call function
mov lr, pc
ldr pc, [fp, #28]
# Remove the space we pushed for the args
mov sp, fp
# Load a3 with the pointer to storage for the return value
ldr a3, [sp, #24]
# Load a4 with the return type code
ldr a4, [sp, #12]
# If the return value pointer is NULL, assume no return value.
cmp a3, #0
beq epilogue
# return INT
cmp a4, #FFI_TYPE_INT
streq a1, [a3]
beq epilogue
# return FLOAT
cmp a4, #FFI_TYPE_FLOAT
#ifdef __SOFTFP__ #ifdef __SOFTFP__
streq a1, [a3] cmpne r3, #FFI_TYPE_FLOAT
#else
stfeqs f0, [a3]
#endif #endif
beq epilogue streq r0, [r2]
beq LSYM(Lepilogue)
# return DOUBLE or LONGDOUBLE @ return INT64
cmp a4, #FFI_TYPE_DOUBLE cmp r3, #FFI_TYPE_SINT64
#ifdef __SOFTFP__ #ifdef __SOFTFP__
stmeqia a3, {a1, a2} cmpne r3, #FFI_TYPE_DOUBLE
#else #endif
stfeqd f0, [a3] stmeqia r2, {r0, r1}
#ifndef __SOFTFP__
beq LSYM(Lepilogue)
@ return FLOAT
cmp r3, #FFI_TYPE_FLOAT
stfeqs f0, [r2]
beq LSYM(Lepilogue)
@ return DOUBLE or LONGDOUBLE
cmp r3, #FFI_TYPE_DOUBLE
stfeqd f0, [r2]
#endif #endif
epilogue: LSYM(Lepilogue):
ldmfd sp!, {a1-a4, fp, pc} RETLDM "r0-r3,fp"
.ffi_call_SYSV_end: .ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment