aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libffi/ChangeLog23
-rw-r--r--libffi/src/powerpc/ffi.c123
-rw-r--r--libffi/src/powerpc/ffitarget.h7
-rw-r--r--libffi/src/powerpc/linux64.S5
-rw-r--r--libffi/src/powerpc/ppc_closure.S222
-rw-r--r--libffi/src/powerpc/sysv.S2
6 files changed, 219 insertions, 163 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index 0622223c04e..1d8b23899dd 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,26 @@
+2006-03-24 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX. Default
+ for 32-bit using IBM extended double format. Fix FFI_LAST_ABI.
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
+ FFI_TYPE_LONGDOUBLE.
+ (ffi_prep_args64): Assert using IBM extended double.
+ (ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
+ Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
+ (ffi_call): Handle FFI_LINUX.
+ (ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
+ gpr3 return pointer as for struct return. Handle FFI_LINUX
+ FFI_TYPE_LONGDOUBLE return and args. Don't increment "nf"
+ unnecessarily.
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
+ for FFI_TYPE_LONGDOUBLE. Move epilogue insns into case table.
+ Don't use r6 as pointer to results, instead use sp offset. Don't
+ make a special call to load lr with case table address, instead
+ use offset from previous call.
+ * src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
+ return.
+
2006-03-15 Kaz Kojima <kkojima@gcc.gnu.org>
* src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c
index bfd7ab67688..39460d1b05a 100644
--- a/libffi/src/powerpc/ffi.c
+++ b/libffi/src/powerpc/ffi.c
@@ -197,6 +197,38 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (ecif->cif->abi != FFI_LINUX)
+ goto do_struct;
+ double_tmp = (*p_argv.d)[0];
+
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
+ {
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS
+ && intarg_count % 2 != 0)
+ {
+ intarg_count++;
+ next_arg.u++;
+ }
+ *next_arg.d = double_tmp;
+ next_arg.u += 2;
+ double_tmp = (*p_argv.d)[1];
+ *next_arg.d = double_tmp;
+ next_arg.u += 2;
+ }
+ else
+ {
+ *fpr_base.d++ = double_tmp;
+ double_tmp = (*p_argv.d)[1];
+ *fpr_base.d++ = double_tmp;
+ }
+
+ fparg_count += 2;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+#endif
+
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
@@ -232,7 +264,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
+ do_struct:
#endif
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
copy_space.c -= struct_copy_size;
@@ -433,6 +465,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
if (fparg_count < NUM_FPR_ARG_REGISTERS64)
*fpr_base.d++ = double_tmp;
fparg_count++;
+ FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
#endif
@@ -536,11 +569,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
/* Space for the mandatory parm save area and general registers. */
bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- if (type == FFI_TYPE_LONGDOUBLE)
- type = FFI_TYPE_DOUBLE;
-#endif
}
/* Return value handling. The rules for SYSV are as follows:
@@ -549,14 +577,24 @@ ffi_prep_cif_machdep (ffi_cif *cif)
- 64-bit integer values and structures between 5 and 8 bytes are returned
in gpr3 and gpr4;
- Single/double FP values are returned in fpr1;
- - Larger structures and long double (if not equivalent to double) values
- are allocated space and a pointer is passed as the first argument.
+ - Larger structures are allocated space and a pointer is passed as
+ the first argument.
+ - long doubles (if not equivalent to double) are returned in
+ fpr1,fpr2 for Linux and as for large structs for SysV.
For LINUX64:
- integer values in gpr3;
- Structures/Unions by reference;
- Single/double FP values in fpr1, long double in fpr1,fpr2. */
switch (type)
{
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64)
+ goto byref;
+
+ flags |= FLAG_RETURNS_128BITS;
+ /* Fall through. */
+#endif
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
@@ -598,15 +636,8 @@ ffi_prep_cif_machdep (ffi_cif *cif)
}
}
}
- /* else fall through. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
- if (type == FFI_TYPE_LONGDOUBLE && cif->abi == FFI_LINUX64)
- {
- flags |= FLAG_RETURNS_128BITS;
- flags |= FLAG_RETURNS_FP;
- break;
- }
+ byref:
#endif
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
@@ -635,6 +666,13 @@ ffi_prep_cif_machdep (ffi_cif *cif)
/* floating singles are not 8-aligned on stack */
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX)
+ goto do_struct;
+ fparg_count++;
+ /* Fall thru */
+#endif
case FFI_TYPE_DOUBLE:
fparg_count++;
/* If this FP arg is going on the stack, it must be
@@ -664,7 +702,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
+ do_struct:
#endif
/* We must allocate space for a copy of these to enforce
pass-by-value. Pad the space up to a multiple of 16
@@ -793,6 +831,7 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
#ifndef POWERPC64
case FFI_SYSV:
case FFI_GCC_SYSV:
+ case FFI_LINUX:
/*@-usedef@*/
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
@@ -920,14 +959,17 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
For FFI_SYSV the result is passed in r3/r4 if the struct size is less
or equal 8 bytes. */
- if (cif->rtype->type == FFI_TYPE_STRUCT)
+ if ((cif->rtype->type == FFI_TYPE_STRUCT
+ && !((cif->abi == FFI_SYSV) && (size <= 8)))
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+ && cif->abi != FFI_LINUX)
+#endif
+ )
{
- if (!((cif->abi == FFI_SYSV) && (size <= 8)))
- {
- rvalue = (void *) *pgr;
- ng++;
- pgr++;
- }
+ rvalue = (void *) *pgr;
+ ng++;
+ pgr++;
}
i = 0;
@@ -989,6 +1031,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
break;
case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ do_struct:
+#endif
/* Structs are passed by reference. The address will appear in a
gpr if it is one of the first 8 arguments. */
if (ng < 8)
@@ -1060,7 +1105,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
* naughty thing to do but...
*/
avalue[i] = pst;
- nf++;
pst += 1;
}
break;
@@ -1080,11 +1124,32 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
- nf++;
pst += 2;
}
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX)
+ goto do_struct;
+
+ if (nf < 7)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ nf += 2;
+ }
+ else
+ {
+ if (((long) pst) & 4)
+ pst++;
+ avalue[i] = pst;
+ pst += 4;
+ nf = 8;
+ }
+ break;
+#endif
+
default:
FFI_ASSERT (0);
}
@@ -1101,8 +1166,12 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
&& size <= 8)
return FFI_SYSV_TYPE_SMALL_STRUCT + size;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+ && cif->abi != FFI_LINUX)
+ return FFI_TYPE_STRUCT;
+#endif
return cif->rtype->type;
-
}
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
diff --git a/libffi/src/powerpc/ffitarget.h b/libffi/src/powerpc/ffitarget.h
index af63796c77c..e7f62950371 100644
--- a/libffi/src/powerpc/ffitarget.h
+++ b/libffi/src/powerpc/ffitarget.h
@@ -43,10 +43,15 @@ typedef enum ffi_abi {
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
+ FFI_LINUX,
# ifdef POWERPC64
FFI_DEFAULT_ABI = FFI_LINUX64,
# else
+# if __LDBL_MANT_DIG__ == 106
+ FFI_DEFAULT_ABI = FFI_LINUX,
+# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+# endif
# endif
#endif
@@ -69,7 +74,7 @@ typedef enum ffi_abi {
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
- FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+ FFI_LAST_ABI
} ffi_abi;
#endif
diff --git a/libffi/src/powerpc/linux64.S b/libffi/src/powerpc/linux64.S
index 25b2c4f455b..d72912da1ed 100644
--- a/libffi/src/powerpc/linux64.S
+++ b/libffi/src/powerpc/linux64.S
@@ -120,12 +120,9 @@ ffi_call_LINUX64:
blr
.Lfp_return_value:
- bt 27, .Lfd_return_value
bf 28, .Lfloat_return_value
stfd %f1, 0(%r30)
- b .Ldone_return_value
-.Lfd_return_value:
- stfd %f1, 0(%r30)
+ bf 27, .Ldone_return_value
stfd %f2, 8(%r30)
b .Ldone_return_value
.Lfloat_return_value:
diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S
index 370381378f9..356a0e32620 100644
--- a/libffi/src/powerpc/ppc_closure.S
+++ b/libffi/src/powerpc/ppc_closure.S
@@ -58,218 +58,178 @@ ENTRY(ffi_closure_SYSV)
# make the call
bl ffi_closure_helper_SYSV@local
-
+.Lret:
# now r3 contains the return type
# so use it to look up in a table
# so we know how to deal with each type
# look up the proper starting point in table
# by using return type as offset
- addi %r6,%r1,112 # get pointer to results area
- bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
- mflr %r4 # move to r4
- slwi %r3,%r3,4 # now multiply return type by 16
- add %r3,%r3,%r4 # add contents of table to table address
+
+ mflr %r4 # move address of .Lret to r4
+ slwi %r3,%r3,4 # now multiply return type by 16
+ addi %r4, %r4, .Lret_type0 - .Lret
+ lwz %r0,148(%r1)
+ add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
- bctr # jump to it
+ bctr # jump to it
.LFE1:
# Each of the ret_typeX code fragments has to be exactly 16 bytes long
# (4 instructions). For cache effectiveness we align to a 16 byte boundary
# first.
.align 4
-
- nop
- nop
- nop
-.Lget_ret_type0_addr:
- blrl
-
# case FFI_TYPE_VOID
.Lret_type0:
- b .Lfinish
- nop
- nop
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
nop
# case FFI_TYPE_INT
-.Lret_type1:
- lwz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+.Lfinish:
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_FLOAT
-.Lret_type2:
- lfs %f1,0(%r6)
- b .Lfinish
- nop
- nop
+ lfs %f1,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_DOUBLE
-.Lret_type3:
- lfd %f1,0(%r6)
- b .Lfinish
- nop
- nop
+ lfd %f1,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_LONGDOUBLE
-.Lret_type4:
- lfd %f1,0(%r6)
+ lfd %f1,112+0(%r1)
+ lfd %f2,112+8(%r1)
+ mtlr %r0
b .Lfinish
- nop
- nop
# case FFI_TYPE_UINT8
-.Lret_type5:
- lbz %r3,3(%r6)
- b .Lfinish
- nop
- nop
+ lbz %r3,112+3(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_SINT8
-.Lret_type6:
- lbz %r3,3(%r6)
+ lbz %r3,112+3(%r1)
extsb %r3,%r3
+ mtlr %r0
b .Lfinish
- nop
# case FFI_TYPE_UINT16
-.Lret_type7:
- lhz %r3,2(%r6)
- b .Lfinish
- nop
- nop
+ lhz %r3,112+2(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_SINT16
-.Lret_type8:
- lha %r3,2(%r6)
- b .Lfinish
- nop
- nop
+ lha %r3,112+2(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_UINT32
-.Lret_type9:
- lwz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_SINT32
-.Lret_type10:
- lwz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_TYPE_UINT64
-.Lret_type11:
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
b .Lfinish
- nop
# case FFI_TYPE_SINT64
-.Lret_type12:
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
b .Lfinish
- nop
# case FFI_TYPE_STRUCT
-.Lret_type13:
- b .Lfinish
- nop
- nop
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
nop
# case FFI_TYPE_POINTER
-.Lret_type14:
- lwz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
-.Lret_type15:
-# fall through.
- lbz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lbz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
-.Lret_type16:
-# fall through.
- lhz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lhz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
-.Lret_type17:
-# fall through.
- lwz %r3,0(%r6)
+ lwz %r3,112+0(%r1)
srwi %r3,%r3,8
+ mtlr %r0
b .Lfinish
- nop
# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
-.Lret_type18:
-# this one handles the structs from above too.
- lwz %r3,0(%r6)
- b .Lfinish
- nop
- nop
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
-.Lret_type19:
-# fall through.
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
li %r5,24
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
-.Lret_type20:
-# fall through.
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
li %r5,16
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
-.Lret_type21:
-# fall through.
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
li %r5,8
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
-.Lret_type22:
-# this one handles the above unhandled structs.
- lwz %r3,0(%r6)
- lwz %r4,4(%r6)
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
b .Lfinish
- nop
-# case done
-.Lfinish:
-
- lwz %r0,148(%r1)
+.Lstruct567:
+ subfic %r6,%r5,32
+ srw %r4,%r4,%r5
+ slw %r6,%r3,%r6
+ srw %r3,%r3,%r5
+ or %r4,%r6,%r4
mtlr %r0
addi %r1,%r1,144
blr
-.Lstruct567:
- subfic %r0,%r5,32
- srw %r4,%r4,%r5
- slw %r0,%r3,%r0
- srw %r3,%r3,%r5
- or %r4,%r0,%r4
- b .Lfinish
END(ffi_closure_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S
index 6d5a707ec03..9a9a109d1ae 100644
--- a/libffi/src/powerpc/sysv.S
+++ b/libffi/src/powerpc/sysv.S
@@ -121,6 +121,8 @@ L(done_return_value):
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
+ bf 27,L(done_return_value)
+ stfd %f2,8(%r30)
b L(done_return_value)
L(float_return_value):
stfs %f1,0(%r30)