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
This commit is contained in:
parent
5ae4c56561
commit
f20459f1b2
|
@ -1,3 +1,12 @@
|
|||
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.
|
||||
|
|
|
@ -108,6 +108,11 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
/* Perform machine dependent cif processing */
|
||||
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 */
|
||||
switch (cif->rtype->type)
|
||||
{
|
||||
|
@ -118,6 +123,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
cif->flags = (unsigned) cif->rtype->type;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
cif->flags = (unsigned) FFI_TYPE_SINT64;
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
break;
|
||||
|
|
|
@ -41,86 +41,168 @@
|
|||
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
|
||||
#endif
|
||||
|
||||
.text
|
||||
|
||||
# a1: ffi_prep_args
|
||||
# a2: &ecif
|
||||
# a3: cif->bytes
|
||||
# a4: fig->flags
|
||||
# sp+0: ecif.rvalue
|
||||
# sp+4: fn
|
||||
|
||||
# This assumes we are using gas.
|
||||
ENTRY(ffi_call_SYSV)
|
||||
# Save registers
|
||||
stmfd sp!, {a1-a4, fp, lr}
|
||||
mov fp, sp
|
||||
|
||||
# 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__
|
||||
streq a1, [a3]
|
||||
#ifdef __ELF__
|
||||
#define LSYM(x) .x
|
||||
#else
|
||||
stfeqs f0, [a3]
|
||||
#endif
|
||||
beq epilogue
|
||||
|
||||
# return DOUBLE or LONGDOUBLE
|
||||
cmp a4, #FFI_TYPE_DOUBLE
|
||||
#ifdef __SOFTFP__
|
||||
stmeqia a3, {a1, a2}
|
||||
#else
|
||||
stfeqd f0, [a3]
|
||||
#define LSYM(x) x
|
||||
#endif
|
||||
|
||||
epilogue:
|
||||
ldmfd sp!, {a1-a4, fp, pc}
|
||||
/* 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)
|
||||
|
||||
@ Remove the space we pushed for the args
|
||||
mov sp, fp
|
||||
|
||||
@ Load r2 with the pointer to storage for the return value
|
||||
ldr r2, [sp, #24]
|
||||
|
||||
@ Load r3 with the return type code
|
||||
ldr r3, [sp, #12]
|
||||
|
||||
@ If the return value pointer is NULL, assume no return value.
|
||||
cmp r2, #0
|
||||
beq LSYM(Lepilogue)
|
||||
|
||||
@ return INT
|
||||
cmp r3, #FFI_TYPE_INT
|
||||
#ifdef __SOFTFP__
|
||||
cmpne r3, #FFI_TYPE_FLOAT
|
||||
#endif
|
||||
streq r0, [r2]
|
||||
beq LSYM(Lepilogue)
|
||||
|
||||
@ return INT64
|
||||
cmp r3, #FFI_TYPE_SINT64
|
||||
#ifdef __SOFTFP__
|
||||
cmpne r3, #FFI_TYPE_DOUBLE
|
||||
#endif
|
||||
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
|
||||
|
||||
LSYM(Lepilogue):
|
||||
RETLDM "r0-r3,fp"
|
||||
|
||||
.ffi_call_SYSV_end:
|
||||
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
||||
|
|
Loading…
Reference in New Issue