diff options
author | Alan Modra <amodra@bigpond.net.au> | 2006-03-23 23:15:46 +0000 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2006-03-24 09:45:46 +1030 |
commit | 75b8b1becb9b60cde357635e9eb66ece6f7d5148 (patch) | |
tree | 4ab557369299e8f713970f1befc75244eeb8c26a | |
parent | 5b314bb3ef9460b06abf33d911e1e361c2e37197 (diff) | |
download | gcc-75b8b1becb9b60cde357635e9eb66ece6f7d5148.zip gcc-75b8b1becb9b60cde357635e9eb66ece6f7d5148.tar.gz gcc-75b8b1becb9b60cde357635e9eb66ece6f7d5148.tar.bz2 |
ffitarget.h (enum ffi_abi): Add FFI_LINUX.
* 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.
From-SVN: r112340
-rw-r--r-- | libffi/ChangeLog | 23 | ||||
-rw-r--r-- | libffi/src/powerpc/ffi.c | 123 | ||||
-rw-r--r-- | libffi/src/powerpc/ffitarget.h | 7 | ||||
-rw-r--r-- | libffi/src/powerpc/linux64.S | 5 | ||||
-rw-r--r-- | libffi/src/powerpc/ppc_closure.S | 222 | ||||
-rw-r--r-- | libffi/src/powerpc/sysv.S | 2 |
6 files changed, 219 insertions, 163 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 0622223c..1d8b238 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 bfd7ab6..39460d1 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 af63796..e7f6295 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 25b2c4f..d72912d 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 3703813..356a0e3 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 6d5a707..9a9a109 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) |