965 lines
26 KiB
Plaintext
965 lines
26 KiB
Plaintext
Index: libffi/ChangeLog
|
|
===================================================================
|
|
--- libffi.orig/ChangeLog
|
|
+++ libffi/ChangeLog
|
|
@@ -59,6 +59,12 @@
|
|
|
|
* configure: Regenerate.
|
|
|
|
+2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
|
|
+
|
|
+ * src/powerpc/ffi.c, src/powerpc/ffitarget.h,
|
|
+ src/powerpc/ppc_closure.S, src/powerpc/sysv.S: Many changes for
|
|
+ softfloat powerpc variants.
|
|
+
|
|
2011-11-12 Petr Salinger <Petr.Salinger@seznam.cz>
|
|
|
|
* configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support.
|
|
Index: libffi/src/powerpc/ffi.c
|
|
===================================================================
|
|
--- libffi.orig/src/powerpc/ffi.c
|
|
+++ libffi/src/powerpc/ffi.c
|
|
@@ -41,27 +41,28 @@ enum {
|
|
/* The assembly depends on these exact flags. */
|
|
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
|
|
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
|
|
+#ifndef __NO_FPRS__
|
|
FLAG_RETURNS_FP = 1 << (31-29),
|
|
+#endif
|
|
FLAG_RETURNS_64BITS = 1 << (31-28),
|
|
|
|
FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
|
|
|
|
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
|
|
+#ifndef __NO_FPRS__
|
|
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
|
|
+#endif
|
|
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
|
|
FLAG_RETVAL_REFERENCE = 1 << (31- 4)
|
|
};
|
|
|
|
/* About the SYSV ABI. */
|
|
-unsigned int NUM_GPR_ARG_REGISTERS = 8;
|
|
+#define ASM_NEEDS_REGISTERS 4
|
|
+#define NUM_GPR_ARG_REGISTERS 8
|
|
#ifndef __NO_FPRS__
|
|
-unsigned int NUM_FPR_ARG_REGISTERS = 8;
|
|
-#else
|
|
-unsigned int NUM_FPR_ARG_REGISTERS = 0;
|
|
+# define NUM_FPR_ARG_REGISTERS 8
|
|
#endif
|
|
|
|
-enum { ASM_NEEDS_REGISTERS = 4 };
|
|
-
|
|
/* ffi_prep_args_SYSV is called by the assembly routine once stack space
|
|
has been allocated for the function's arguments.
|
|
|
|
@@ -110,10 +111,12 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
valp gpr_base;
|
|
int intarg_count;
|
|
|
|
+#ifndef __NO_FPRS__
|
|
/* 'fpr_base' points at the space for fpr1, and grows upwards as
|
|
we use FPR registers. */
|
|
valp fpr_base;
|
|
int fparg_count;
|
|
+#endif
|
|
|
|
/* 'copy_space' grows down as we put structures in it. It should
|
|
stay 16-byte aligned. */
|
|
@@ -122,9 +125,8 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
/* 'next_arg' grows up as we put parameters in it. */
|
|
valp next_arg;
|
|
|
|
- int i, ii MAYBE_UNUSED;
|
|
+ int i;
|
|
ffi_type **ptr;
|
|
- double double_tmp;
|
|
union {
|
|
void **v;
|
|
char **c;
|
|
@@ -140,15 +142,16 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
size_t struct_copy_size;
|
|
unsigned gprvalue;
|
|
|
|
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- NUM_FPR_ARG_REGISTERS = 0;
|
|
-
|
|
stacktop.c = (char *) stack + bytes;
|
|
gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
|
|
intarg_count = 0;
|
|
+#ifndef __NO_FPRS__
|
|
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
|
|
fparg_count = 0;
|
|
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
|
|
+#else
|
|
+ copy_space.c = gpr_base.c;
|
|
+#endif
|
|
next_arg.u = stack + 2;
|
|
|
|
/* Check that everything starts aligned properly. */
|
|
@@ -171,12 +174,28 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
i > 0;
|
|
i--, ptr++, p_argv.v++)
|
|
{
|
|
- switch ((*ptr)->type)
|
|
- {
|
|
+ unsigned short typenum = (*ptr)->type;
|
|
+
|
|
+ /* We may need to handle some values depending on ABI */
|
|
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) {
|
|
+ if (typenum == FFI_TYPE_FLOAT)
|
|
+ typenum = FFI_TYPE_UINT32;
|
|
+ if (typenum == FFI_TYPE_DOUBLE)
|
|
+ typenum = FFI_TYPE_UINT64;
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_UINT128;
|
|
+ } else if (ecif->cif->abi != FFI_LINUX) {
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_STRUCT;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ /* Now test the translated value */
|
|
+ switch (typenum) {
|
|
+#ifndef __NO_FPRS__
|
|
case FFI_TYPE_FLOAT:
|
|
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
|
|
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- goto soft_float_prep;
|
|
double_tmp = **p_argv.f;
|
|
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
|
{
|
|
@@ -215,43 +234,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
|
|
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
case FFI_TYPE_LONGDOUBLE:
|
|
- if ((ecif->cif->abi != FFI_LINUX)
|
|
- && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
|
|
- goto do_struct;
|
|
- /* The soft float ABI for long doubles works like this,
|
|
- a long double is passed in four consecutive gprs if available.
|
|
- A maximum of 2 long doubles can be passed in gprs.
|
|
- If we do not have 4 gprs left, the long double is passed on the
|
|
- stack, 4-byte aligned. */
|
|
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- {
|
|
- unsigned int int_tmp = (*p_argv.ui)[0];
|
|
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
|
|
- {
|
|
- if (intarg_count < NUM_GPR_ARG_REGISTERS)
|
|
- intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
|
|
- *next_arg.u = int_tmp;
|
|
- next_arg.u++;
|
|
- for (ii = 1; ii < 4; ii++)
|
|
- {
|
|
- int_tmp = (*p_argv.ui)[ii];
|
|
- *next_arg.u = int_tmp;
|
|
- next_arg.u++;
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- *gpr_base.u++ = int_tmp;
|
|
- for (ii = 1; ii < 4; ii++)
|
|
- {
|
|
- int_tmp = (*p_argv.ui)[ii];
|
|
- *gpr_base.u++ = int_tmp;
|
|
- }
|
|
- }
|
|
- intarg_count +=4;
|
|
- }
|
|
- else
|
|
- {
|
|
double_tmp = (*p_argv.d)[0];
|
|
|
|
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
|
|
@@ -277,13 +259,40 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
|
|
fparg_count += 2;
|
|
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
|
- }
|
|
break;
|
|
#endif
|
|
+#endif /* have FPRs */
|
|
+
|
|
+ /*
|
|
+ * The soft float ABI for long doubles works like this, a long double
|
|
+ * is passed in four consecutive GPRs if available. A maximum of 2
|
|
+ * long doubles can be passed in gprs. If we do not have 4 GPRs
|
|
+ * left, the long double is passed on the stack, 4-byte aligned.
|
|
+ */
|
|
+ case FFI_TYPE_UINT128: {
|
|
+ unsigned int int_tmp = (*p_argv.ui)[0];
|
|
+ unsigned int ii;
|
|
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) {
|
|
+ if (intarg_count < NUM_GPR_ARG_REGISTERS)
|
|
+ intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
|
|
+ *(next_arg.u++) = int_tmp;
|
|
+ for (ii = 1; ii < 4; ii++) {
|
|
+ int_tmp = (*p_argv.ui)[ii];
|
|
+ *(next_arg.u++) = int_tmp;
|
|
+ }
|
|
+ } else {
|
|
+ *(gpr_base.u++) = int_tmp;
|
|
+ for (ii = 1; ii < 4; ii++) {
|
|
+ int_tmp = (*p_argv.ui)[ii];
|
|
+ *(gpr_base.u++) = int_tmp;
|
|
+ }
|
|
+ }
|
|
+ intarg_count += 4;
|
|
+ break;
|
|
+ }
|
|
|
|
case FFI_TYPE_UINT64:
|
|
case FFI_TYPE_SINT64:
|
|
- soft_double_prep:
|
|
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
|
|
intarg_count++;
|
|
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
|
@@ -316,9 +325,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
break;
|
|
|
|
case FFI_TYPE_STRUCT:
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- do_struct:
|
|
-#endif
|
|
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
|
|
copy_space.c -= struct_copy_size;
|
|
memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
|
|
@@ -346,7 +352,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
case FFI_TYPE_UINT32:
|
|
case FFI_TYPE_SINT32:
|
|
case FFI_TYPE_POINTER:
|
|
- soft_float_prep:
|
|
|
|
gprvalue = **p_argv.ui;
|
|
|
|
@@ -363,8 +368,10 @@ ffi_prep_args_SYSV (extended_cif *ecif,
|
|
/* Check that we didn't overrun the stack... */
|
|
FFI_ASSERT (copy_space.c >= next_arg.c);
|
|
FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
|
|
+#ifndef __NO_FPRS__
|
|
FFI_ASSERT (fpr_base.u
|
|
<= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
|
|
+#endif
|
|
FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
|
|
}
|
|
|
|
@@ -601,9 +608,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
unsigned type = cif->rtype->type;
|
|
unsigned size = cif->rtype->size;
|
|
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- NUM_FPR_ARG_REGISTERS = 0;
|
|
-
|
|
if (cif->abi != FFI_LINUX64)
|
|
{
|
|
/* All the machine-independent calculation of cif->bytes will be wrong.
|
|
@@ -643,25 +647,38 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
- Single/double FP values in fpr1, long double in fpr1,fpr2.
|
|
- soft-float float/doubles are treated as UINT32/UINT64 respectivley.
|
|
- soft-float long doubles are returned in gpr3-gpr6. */
|
|
+ /* First translate for softfloat/nonlinux */
|
|
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
|
|
+ if (type == FFI_TYPE_FLOAT)
|
|
+ type = FFI_TYPE_UINT32;
|
|
+ if (type == FFI_TYPE_DOUBLE)
|
|
+ type = FFI_TYPE_UINT64;
|
|
+ if (type == FFI_TYPE_LONGDOUBLE)
|
|
+ type = FFI_TYPE_UINT128;
|
|
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ if (type == FFI_TYPE_LONGDOUBLE)
|
|
+ type = FFI_TYPE_STRUCT;
|
|
+#endif
|
|
+ }
|
|
+
|
|
switch (type)
|
|
{
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+#ifndef __NO_FPRS__
|
|
case FFI_TYPE_LONGDOUBLE:
|
|
- if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
|
|
- && cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
- goto byref;
|
|
flags |= FLAG_RETURNS_128BITS;
|
|
/* Fall through. */
|
|
-#endif
|
|
case FFI_TYPE_DOUBLE:
|
|
flags |= FLAG_RETURNS_64BITS;
|
|
/* Fall through. */
|
|
case FFI_TYPE_FLOAT:
|
|
- /* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */
|
|
- if (cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
- flags |= FLAG_RETURNS_FP;
|
|
+ flags |= FLAG_RETURNS_FP;
|
|
break;
|
|
+#endif
|
|
|
|
+ case FFI_TYPE_UINT128:
|
|
+ flags |= FLAG_RETURNS_128BITS;
|
|
+ /* Fall through. */
|
|
case FFI_TYPE_UINT64:
|
|
case FFI_TYPE_SINT64:
|
|
flags |= FLAG_RETURNS_64BITS;
|
|
@@ -680,10 +697,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
*/
|
|
if (cif->abi == FFI_SYSV && size <= 8)
|
|
flags |= FLAG_RETURNS_SMST;
|
|
-
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- byref:
|
|
-#endif
|
|
intarg_count++;
|
|
flags |= FLAG_RETVAL_REFERENCE;
|
|
/* Fall through. */
|
|
@@ -704,39 +717,36 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
Stuff on the stack needs to keep proper alignment. */
|
|
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
|
{
|
|
- switch ((*ptr)->type)
|
|
- {
|
|
+ unsigned short typenum = (*ptr)->type;
|
|
+
|
|
+ /* We may need to handle some values depending on ABI */
|
|
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
|
|
+ if (typenum == FFI_TYPE_FLOAT)
|
|
+ typenum = FFI_TYPE_UINT32;
|
|
+ if (typenum == FFI_TYPE_DOUBLE)
|
|
+ typenum = FFI_TYPE_UINT64;
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_UINT128;
|
|
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_STRUCT;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ switch (typenum) {
|
|
+#ifndef __NO_FPRS__
|
|
case FFI_TYPE_FLOAT:
|
|
- /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- goto soft_float_cif;
|
|
fparg_count++;
|
|
/* 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 && cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
- goto do_struct;
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- {
|
|
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
|
|
- || intarg_count < NUM_GPR_ARG_REGISTERS)
|
|
- /* A long double in FFI_LINUX_SOFT_FLOAT can use only
|
|
- a set of four consecutive gprs. If we have not enough,
|
|
- we have to adjust the intarg_count value. */
|
|
- intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
|
|
- intarg_count += 4;
|
|
- break;
|
|
- }
|
|
- else
|
|
- fparg_count++;
|
|
+ fparg_count++;
|
|
/* Fall thru */
|
|
#endif
|
|
case FFI_TYPE_DOUBLE:
|
|
- /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- goto soft_double_cif;
|
|
fparg_count++;
|
|
/* If this FP arg is going on the stack, it must be
|
|
8-byte-aligned. */
|
|
@@ -745,10 +755,21 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
&& intarg_count % 2 != 0)
|
|
intarg_count++;
|
|
break;
|
|
+#endif
|
|
+ case FFI_TYPE_UINT128:
|
|
+ /*
|
|
+ * A long double in FFI_LINUX_SOFT_FLOAT can use only a set
|
|
+ * of four consecutive gprs. If we do not have enough, we
|
|
+ * have to adjust the intarg_count value.
|
|
+ */
|
|
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
|
|
+ && intarg_count < NUM_GPR_ARG_REGISTERS)
|
|
+ intarg_count = NUM_GPR_ARG_REGISTERS;
|
|
+ intarg_count += 4;
|
|
+ break;
|
|
|
|
case FFI_TYPE_UINT64:
|
|
case FFI_TYPE_SINT64:
|
|
- soft_double_cif:
|
|
/* '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
|
|
@@ -765,9 +786,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
break;
|
|
|
|
case FFI_TYPE_STRUCT:
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- 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
|
|
bytes (the maximum alignment required for anything under
|
|
@@ -775,12 +793,20 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
struct_copy_size += ((*ptr)->size + 15) & ~0xF;
|
|
/* Fall through (allocate space for the pointer). */
|
|
|
|
- default:
|
|
- soft_float_cif:
|
|
+ case FFI_TYPE_POINTER:
|
|
+ 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:
|
|
/* Everything else is passed as a 4-byte word in a GPR, either
|
|
the object itself or a pointer to it. */
|
|
intarg_count++;
|
|
break;
|
|
+ default:
|
|
+ FFI_ASSERT (0);
|
|
}
|
|
}
|
|
else
|
|
@@ -809,16 +835,29 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
intarg_count += ((*ptr)->size + 7) / 8;
|
|
break;
|
|
|
|
- default:
|
|
+ case FFI_TYPE_POINTER:
|
|
+ case FFI_TYPE_UINT64:
|
|
+ case FFI_TYPE_SINT64:
|
|
+ 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:
|
|
/* Everything else is passed as a 8-byte word in a GPR, either
|
|
the object itself or a pointer to it. */
|
|
intarg_count++;
|
|
break;
|
|
+ default:
|
|
+ FFI_ASSERT (0);
|
|
}
|
|
}
|
|
|
|
+#ifndef __NO_FPRS__
|
|
if (fparg_count != 0)
|
|
flags |= FLAG_FP_ARGUMENTS;
|
|
+#endif
|
|
if (intarg_count > 4)
|
|
flags |= FLAG_4_GPR_ARGUMENTS;
|
|
if (struct_copy_size != 0)
|
|
@@ -826,21 +865,27 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|
|
|
if (cif->abi != FFI_LINUX64)
|
|
{
|
|
+#ifndef __NO_FPRS__
|
|
/* Space for the FPR registers, if needed. */
|
|
if (fparg_count != 0)
|
|
bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
|
|
+#endif
|
|
|
|
/* Stack space. */
|
|
if (intarg_count > NUM_GPR_ARG_REGISTERS)
|
|
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
|
|
+#ifndef __NO_FPRS__
|
|
if (fparg_count > NUM_FPR_ARG_REGISTERS)
|
|
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
|
|
+#endif
|
|
}
|
|
else
|
|
{
|
|
+#ifndef __NO_FPRS__
|
|
/* Space for the FPR registers, if needed. */
|
|
if (fparg_count != 0)
|
|
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
|
|
+#endif
|
|
|
|
/* Stack space. */
|
|
if (intarg_count > NUM_GPR_ARG_REGISTERS64)
|
|
@@ -898,9 +943,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
|
|
switch (cif->abi)
|
|
{
|
|
#ifndef POWERPC64
|
|
+# ifndef __NO_FPRS__
|
|
case FFI_SYSV:
|
|
case FFI_GCC_SYSV:
|
|
case FFI_LINUX:
|
|
+# endif
|
|
case FFI_LINUX_SOFT_FLOAT:
|
|
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
|
|
break;
|
|
@@ -1013,32 +1060,38 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
void ** avalue;
|
|
ffi_type ** arg_types;
|
|
long i, avn;
|
|
- long nf; /* number of floating registers already used */
|
|
- long ng; /* number of general registers already used */
|
|
- ffi_cif * cif;
|
|
- double temp;
|
|
- unsigned size;
|
|
+#ifndef __NO_FPRS__
|
|
+ long nf = 0; /* number of floating registers already used */
|
|
+#endif
|
|
+ long ng = 0; /* number of general registers already used */
|
|
+
|
|
+ ffi_cif *cif = closure->cif;
|
|
+ unsigned size = cif->rtype->size;
|
|
+ unsigned short rtypenum = cif->rtype->type;
|
|
|
|
- cif = closure->cif;
|
|
avalue = alloca (cif->nargs * sizeof (void *));
|
|
- size = cif->rtype->size;
|
|
|
|
- nf = 0;
|
|
- ng = 0;
|
|
+ /* First translate for softfloat/nonlinux */
|
|
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
|
|
+ if (rtypenum == FFI_TYPE_FLOAT)
|
|
+ rtypenum = FFI_TYPE_UINT32;
|
|
+ if (rtypenum == FFI_TYPE_DOUBLE)
|
|
+ rtypenum = FFI_TYPE_UINT64;
|
|
+ if (rtypenum == FFI_TYPE_LONGDOUBLE)
|
|
+ rtypenum = FFI_TYPE_UINT128;
|
|
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ if (rtypenum == FFI_TYPE_LONGDOUBLE)
|
|
+ rtypenum = FFI_TYPE_STRUCT;
|
|
+#endif
|
|
+ }
|
|
+
|
|
|
|
/* Copy the caller's structure return value address so that the closure
|
|
returns the data directly to the caller.
|
|
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
|
|
- && !((cif->abi == FFI_SYSV) && (size <= 8)))
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
|
|
- && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
-#endif
|
|
- )
|
|
- {
|
|
+ if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) {
|
|
rvalue = (void *) *pgr;
|
|
ng++;
|
|
pgr++;
|
|
@@ -1049,10 +1102,109 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
arg_types = cif->arg_types;
|
|
|
|
/* Grab the addresses of the arguments from the stack frame. */
|
|
- while (i < avn)
|
|
- {
|
|
- switch (arg_types[i]->type)
|
|
- {
|
|
+ while (i < avn) {
|
|
+ unsigned short typenum = arg_types[i]->type;
|
|
+
|
|
+ /* We may need to handle some values depending on ABI */
|
|
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
|
|
+ if (typenum == FFI_TYPE_FLOAT)
|
|
+ typenum = FFI_TYPE_UINT32;
|
|
+ if (typenum == FFI_TYPE_DOUBLE)
|
|
+ typenum = FFI_TYPE_UINT64;
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_UINT128;
|
|
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ if (typenum == FFI_TYPE_LONGDOUBLE)
|
|
+ typenum = FFI_TYPE_STRUCT;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ switch (typenum) {
|
|
+#ifndef __NO_FPRS__
|
|
+ case FFI_TYPE_FLOAT:
|
|
+ /* unfortunately float values are stored as doubles
|
|
+ * in the ffi_closure_SYSV code (since we don't check
|
|
+ * the type in that routine).
|
|
+ */
|
|
+
|
|
+ /* there are 8 64bit floating point registers */
|
|
+
|
|
+ if (nf < 8)
|
|
+ {
|
|
+ temp = pfr->d;
|
|
+ pfr->f = (float) temp;
|
|
+ avalue[i] = pfr;
|
|
+ nf++;
|
|
+ pfr++;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* FIXME? here we are really changing the values
|
|
+ * stored in the original calling routines outgoing
|
|
+ * parameter stack. This is probably a really
|
|
+ * naughty thing to do but...
|
|
+ */
|
|
+ avalue[i] = pst;
|
|
+ pst += 1;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case FFI_TYPE_DOUBLE:
|
|
+ /* On the outgoing stack all values are aligned to 8 */
|
|
+ /* there are 8 64bit floating point registers */
|
|
+
|
|
+ if (nf < 8)
|
|
+ {
|
|
+ avalue[i] = pfr;
|
|
+ nf++;
|
|
+ pfr++;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (((long) pst) & 4)
|
|
+ pst++;
|
|
+ avalue[i] = pst;
|
|
+ pst += 2;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
+ case FFI_TYPE_LONGDOUBLE:
|
|
+ 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
|
|
+#endif /* have FPRS */
|
|
+
|
|
+ case FFI_TYPE_UINT128:
|
|
+ /*
|
|
+ * Test if for the whole long double, 4 gprs are available.
|
|
+ * otherwise the stuff ends up on the stack.
|
|
+ */
|
|
+ if (ng < 5) {
|
|
+ avalue[i] = pgr;
|
|
+ pgr += 4;
|
|
+ ng += 4;
|
|
+ } else {
|
|
+ avalue[i] = pst;
|
|
+ pst += 4;
|
|
+ ng = 8+4;
|
|
+ }
|
|
+ break;
|
|
+
|
|
case FFI_TYPE_SINT8:
|
|
case FFI_TYPE_UINT8:
|
|
/* there are 8 gpr registers used to pass values */
|
|
@@ -1088,7 +1240,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
case FFI_TYPE_SINT32:
|
|
case FFI_TYPE_UINT32:
|
|
case FFI_TYPE_POINTER:
|
|
- soft_float_closure:
|
|
/* there are 8 gpr registers used to pass values */
|
|
if (ng < 8)
|
|
{
|
|
@@ -1104,9 +1255,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
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)
|
|
@@ -1124,7 +1272,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
|
|
case FFI_TYPE_SINT64:
|
|
case FFI_TYPE_UINT64:
|
|
- soft_double_closure:
|
|
/* passing long long ints are complex, they must
|
|
* be passed in suitable register pairs such as
|
|
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
|
|
@@ -1156,99 +1303,8 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
}
|
|
break;
|
|
|
|
- case FFI_TYPE_FLOAT:
|
|
- /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- goto soft_float_closure;
|
|
- /* unfortunately float values are stored as doubles
|
|
- * in the ffi_closure_SYSV code (since we don't check
|
|
- * the type in that routine).
|
|
- */
|
|
-
|
|
- /* there are 8 64bit floating point registers */
|
|
-
|
|
- if (nf < 8)
|
|
- {
|
|
- temp = pfr->d;
|
|
- pfr->f = (float) temp;
|
|
- avalue[i] = pfr;
|
|
- nf++;
|
|
- pfr++;
|
|
- }
|
|
- else
|
|
- {
|
|
- /* FIXME? here we are really changing the values
|
|
- * stored in the original calling routines outgoing
|
|
- * parameter stack. This is probably a really
|
|
- * naughty thing to do but...
|
|
- */
|
|
- avalue[i] = pst;
|
|
- pst += 1;
|
|
- }
|
|
- break;
|
|
-
|
|
- case FFI_TYPE_DOUBLE:
|
|
- /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- goto soft_double_closure;
|
|
- /* On the outgoing stack all values are aligned to 8 */
|
|
- /* there are 8 64bit floating point registers */
|
|
-
|
|
- if (nf < 8)
|
|
- {
|
|
- avalue[i] = pfr;
|
|
- nf++;
|
|
- pfr++;
|
|
- }
|
|
- else
|
|
- {
|
|
- if (((long) pst) & 4)
|
|
- pst++;
|
|
- avalue[i] = pst;
|
|
- pst += 2;
|
|
- }
|
|
- break;
|
|
-
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- case FFI_TYPE_LONGDOUBLE:
|
|
- if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
- goto do_struct;
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- { /* Test if for the whole long double, 4 gprs are available.
|
|
- otherwise the stuff ends up on the stack. */
|
|
- if (ng < 5)
|
|
- {
|
|
- avalue[i] = pgr;
|
|
- pgr += 4;
|
|
- ng += 4;
|
|
- }
|
|
- else
|
|
- {
|
|
- avalue[i] = pst;
|
|
- pst += 4;
|
|
- ng = 8;
|
|
- }
|
|
- break;
|
|
- }
|
|
- 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);
|
|
+ FFI_ASSERT (0);
|
|
}
|
|
|
|
i++;
|
|
@@ -1265,39 +1321,9 @@ ffi_closure_helper_SYSV (ffi_closure *cl
|
|
already used and we never have a struct with size zero. That is the reason
|
|
for the subtraction of 1. See the comment in ffitarget.h about ordering.
|
|
*/
|
|
- if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
|
|
- && size <= 8)
|
|
+ if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8)
|
|
return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size;
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
|
|
- && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
|
|
- return FFI_TYPE_STRUCT;
|
|
-#endif
|
|
- /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
|
|
- respectivley UINT64. */
|
|
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
|
|
- {
|
|
- switch (cif->rtype->type)
|
|
- {
|
|
- case FFI_TYPE_FLOAT:
|
|
- return FFI_TYPE_UINT32;
|
|
- break;
|
|
- case FFI_TYPE_DOUBLE:
|
|
- return FFI_TYPE_UINT64;
|
|
- break;
|
|
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
- case FFI_TYPE_LONGDOUBLE:
|
|
- return FFI_TYPE_UINT128;
|
|
- break;
|
|
-#endif
|
|
- default:
|
|
- return cif->rtype->type;
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- return cif->rtype->type;
|
|
- }
|
|
+ return rtypenum;
|
|
}
|
|
|
|
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
|
|
Index: libffi/src/powerpc/ffitarget.h
|
|
===================================================================
|
|
--- libffi.orig/src/powerpc/ffitarget.h
|
|
+++ libffi/src/powerpc/ffitarget.h
|
|
@@ -60,18 +60,14 @@ typedef enum ffi_abi {
|
|
FFI_LINUX64,
|
|
FFI_LINUX,
|
|
FFI_LINUX_SOFT_FLOAT,
|
|
-# ifdef POWERPC64
|
|
+# if defined(POWERPC64)
|
|
FFI_DEFAULT_ABI = FFI_LINUX64,
|
|
-# else
|
|
-# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
|
|
- FFI_DEFAULT_ABI = FFI_LINUX,
|
|
-# else
|
|
-# ifdef __NO_FPRS__
|
|
+# elif defined(__NO_FPRS__)
|
|
FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
|
|
-# else
|
|
+# elif (__LDBL_MANT_DIG__ == 106)
|
|
+ FFI_DEFAULT_ABI = FFI_LINUX,
|
|
+# else
|
|
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
|
|
-# endif
|
|
-# endif
|
|
# endif
|
|
#endif
|
|
|
|
Index: libffi/src/powerpc/ppc_closure.S
|
|
===================================================================
|
|
--- libffi.orig/src/powerpc/ppc_closure.S
|
|
+++ libffi/src/powerpc/ppc_closure.S
|
|
@@ -122,22 +122,41 @@ ENTRY(ffi_closure_SYSV)
|
|
blr
|
|
|
|
# case FFI_TYPE_FLOAT
|
|
+#ifndef __NO_FPRS__
|
|
lfs %f1,112+0(%r1)
|
|
mtlr %r0
|
|
addi %r1,%r1,144
|
|
+#else
|
|
+ nop
|
|
+ nop
|
|
+ nop
|
|
+#endif
|
|
blr
|
|
|
|
# case FFI_TYPE_DOUBLE
|
|
+#ifndef __NO_FPRS__
|
|
lfd %f1,112+0(%r1)
|
|
mtlr %r0
|
|
addi %r1,%r1,144
|
|
+#else
|
|
+ nop
|
|
+ nop
|
|
+ nop
|
|
+#endif
|
|
blr
|
|
|
|
# case FFI_TYPE_LONGDOUBLE
|
|
+#ifndef __NO_FPRS__
|
|
lfd %f1,112+0(%r1)
|
|
lfd %f2,112+8(%r1)
|
|
mtlr %r0
|
|
b .Lfinish
|
|
+#else
|
|
+ nop
|
|
+ nop
|
|
+ nop
|
|
+ blr
|
|
+#endif
|
|
|
|
# case FFI_TYPE_UINT8
|
|
lbz %r3,112+3(%r1)
|
|
Index: libffi/src/powerpc/sysv.S
|
|
===================================================================
|
|
--- libffi.orig/src/powerpc/sysv.S
|
|
+++ libffi/src/powerpc/sysv.S
|
|
@@ -83,6 +83,7 @@ ENTRY(ffi_call_SYSV)
|
|
nop
|
|
1:
|
|
|
|
+#ifndef __NO_FPRS__
|
|
/* Load all the FP registers. */
|
|
bf- 6,2f
|
|
lfd %f1,-16-(8*4)-(8*8)(%r28)
|
|
@@ -94,6 +95,7 @@ ENTRY(ffi_call_SYSV)
|
|
lfd %f6,-16-(8*4)-(3*8)(%r28)
|
|
lfd %f7,-16-(8*4)-(2*8)(%r28)
|
|
lfd %f8,-16-(8*4)-(1*8)(%r28)
|
|
+#endif
|
|
2:
|
|
|
|
/* Make the call. */
|
|
@@ -103,7 +105,9 @@ ENTRY(ffi_call_SYSV)
|
|
mtcrf 0x01,%r31 /* cr7 */
|
|
bt- 31,L(small_struct_return_value)
|
|
bt- 30,L(done_return_value)
|
|
+#ifndef __NO_FPRS__
|
|
bt- 29,L(fp_return_value)
|
|
+#endif
|
|
stw %r3,0(%r30)
|
|
bf+ 28,L(done_return_value)
|
|
stw %r4,4(%r30)
|
|
@@ -124,6 +128,7 @@ L(done_return_value):
|
|
lwz %r1,0(%r1)
|
|
blr
|
|
|
|
+#ifndef __NO_FPRS__
|
|
L(fp_return_value):
|
|
bf 28,L(float_return_value)
|
|
stfd %f1,0(%r30)
|
|
@@ -134,6 +139,7 @@ L(fp_return_value):
|
|
L(float_return_value):
|
|
stfs %f1,0(%r30)
|
|
b L(done_return_value)
|
|
+#endif
|
|
|
|
L(small_struct_return_value):
|
|
/*
|