| 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): |
| /* |