diff options
author | Andreas Tobler <andreast@gcc.gnu.org> | 2005-07-19 23:15:36 +0200 |
---|---|---|
committer | Andreas Tobler <andreast@gcc.gnu.org> | 2005-07-19 23:15:36 +0200 |
commit | 970676420b393e14a8857887876b731552331e44 (patch) | |
tree | 21351941ab537791da38bac3a026c412d513b438 /libffi/src | |
parent | af62f6f9a440d24b135f7d5023173180566a780e (diff) | |
download | gcc-970676420b393e14a8857887876b731552331e44.zip gcc-970676420b393e14a8857887876b731552331e44.tar.gz gcc-970676420b393e14a8857887876b731552331e44.tar.bz2 |
Makefile.am (nodist_libffi_la_SOURCES): Add POWERPC_FREEBSD.
2005-07-19 Andreas Tobler <a.tobler@schweiz.ch>
* Makefile.am (nodist_libffi_la_SOURCES): Add POWERPC_FREEBSD.
* Makefile.in: Regenerate.
* include/Makefile.in: Likewise.
* testsuite/Makefile.in: Likewise.
* configure.ac: Add POWERPC_FREEBSD rules.
* configure: Regenerate.
* src/powerpc/ffitarget.h: Add POWERPC_FREEBSD rules.
(FFI_SYSV_TYPE_SMALL_STRUCT): Define.
* src/powerpc/ffi.c: Add flags to handle small structure returns
in ffi_call_SYSV.
(ffi_prep_cif_machdep): Handle small structures for SYSV 4 ABI.
Aka FFI_SYSV.
(ffi_closure_helper_SYSV): Likewise.
* src/powerpc/ppc_closure.S: Add return types for small structures.
* src/powerpc/sysv.S: Add bits to handle small structures for
final SYSV 4 ABI
From-SVN: r102174
Diffstat (limited to 'libffi/src')
-rw-r--r-- | libffi/src/powerpc/ffi.c | 55 | ||||
-rw-r--r-- | libffi/src/powerpc/ffitarget.h | 10 | ||||
-rw-r--r-- | libffi/src/powerpc/ppc_closure.S | 110 | ||||
-rw-r--r-- | libffi/src/powerpc/sysv.S | 22 |
4 files changed, 168 insertions, 29 deletions
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c index 67d945b..b337aa7 100644 --- a/libffi/src/powerpc/ffi.c +++ b/libffi/src/powerpc/ffi.c @@ -41,6 +41,7 @@ extern void hidden ffi_closure_LINUX64(void); 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 */ FLAG_RETURNS_FP = 1 << (31-29), FLAG_RETURNS_64BITS = 1 << (31-28), @@ -462,6 +463,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) unsigned flags = 0; unsigned struct_copy_size = 0; unsigned type = cif->rtype->type; + unsigned size = cif->rtype->size; if (cif->abi != FFI_LINUX64) { @@ -518,15 +520,30 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) break; case FFI_TYPE_STRUCT: - if (cif->abi != FFI_GCC_SYSV && cif->abi != FFI_LINUX64) + if (cif->abi == FFI_SYSV) { - if (cif->rtype->size <= 4) - break; - else if (cif->rtype->size <= 8) - { - flags |= FLAG_RETURNS_64BITS; + /* The final SYSV ABI says that structures smaller or equal 8 bytes + are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them + in memory. */ + + /* Treat structs with size <= 8 bytes. */ + if (size <= 8) { + flags |= FLAG_RETURNS_SMST; + /* These structs are returned in r3. We pack the type and the + precalculated shift value (needed in the sysv.S) into flags. + The same applies for the structs returned in r3/r4. */ + if (size <= 4) { + flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1 ) + | (8 * (4 - size) << 4); break; } + /* These structs are returned in r3 and r4. See above. */ + if (size <= 8) { + flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2 ) + | (8 * (8 - size) << 4); + break; + } + } } /* else fall through. */ #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE @@ -573,7 +590,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *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 - be 8-byte-aligned. + be 8-byte-aligned. Also, only certain register pairs can be used for passing long long int -- specifically (r3,r4), (r5,r6), @@ -770,7 +787,7 @@ ffi_prep_closure (ffi_closure* closure, #else unsigned int *tramp; - FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV); tramp = (unsigned int *) &closure->tramp[0]; tramp[0] = 0x7c0802a6; /* mflr r0 */ @@ -829,20 +846,27 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue, long ng; /* number of general registers already used */ ffi_cif * cif; double temp; + unsigned size; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); + size = cif->rtype->size; nf = 0; ng = 0; /* Copy the caller's structure return value address so that the closure - returns the data directly to the caller. */ + 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) { - rvalue = (void *) *pgr; - ng++; - pgr++; + if (!((cif->abi == FFI_SYSV) && (size <= 8))) { + rvalue = (void *) *pgr; + ng++; + pgr++; + } } i = 0; @@ -986,7 +1010,12 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue, (closure->fun) (cif, rvalue, avalue, closure->user_data); - /* Tell ffi_closure_SYSV how to perform return type promotions. */ + /* Tell ffi_closure_SYSV how to perform return type promotions. + Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 + we have to tell ffi_closure_SYSV how to treat them. */ + if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT + && size <= 8) + return FFI_SYSV_TYPE_SMALL_STRUCT + size; return cif->rtype->type; } diff --git a/libffi/src/powerpc/ffitarget.h b/libffi/src/powerpc/ffitarget.h index ee87152..af63796 100644 --- a/libffi/src/powerpc/ffitarget.h +++ b/libffi/src/powerpc/ffitarget.h @@ -62,6 +62,13 @@ typedef enum ffi_abi { FFI_DEFAULT_ABI = FFI_DARWIN, #endif +#ifdef POWERPC_FREEBSD + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, + FFI_DEFAULT_ABI = FFI_SYSV, +#endif + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif @@ -71,6 +78,9 @@ typedef enum ffi_abi { #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 +/* Needed for FFI_SYSV small structure returns. */ +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST) + #if defined(POWERPC64) || defined(POWERPC_AIX) #define FFI_TRAMPOLINE_SIZE 24 #else /* POWERPC || POWERPC_AIX */ diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S index c71a7ff..b45ccd6 100644 --- a/libffi/src/powerpc/ppc_closure.S +++ b/libffi/src/powerpc/ppc_closure.S @@ -63,9 +63,22 @@ ENTRY(ffi_closure_SYSV) # so use it to look up in a table # so we know how to deal with each type + # Extract the size of the return type for small structures. + # Then calculate (4 - size) and multiply the result by 8. + # This gives the value needed for the shift operation below. + # This part is only needed for FFI_SYSV and small structures. + addi %r5,%r3,-(FFI_SYSV_TYPE_SMALL_STRUCT) + cmpwi cr0,%r5,4 + ble cr0,.Lnext + addi %r5,%r5,-4 +.Lnext: + addi %r5,%r5,-4 + neg %r5,%r5 + slwi %r5,%r5,3 + # look up the proper starting point in table # by using return type as offset - addi %r5,%r1,112 # get pointer to results area + 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 @@ -94,85 +107,85 @@ ENTRY(ffi_closure_SYSV) # case FFI_TYPE_INT .Lret_type1: - lwz %r3,0(%r5) + lwz %r3,0(%r6) b .Lfinish nop nop # case FFI_TYPE_FLOAT .Lret_type2: - lfs %f1,0(%r5) + lfs %f1,0(%r6) b .Lfinish nop nop # case FFI_TYPE_DOUBLE .Lret_type3: - lfd %f1,0(%r5) + lfd %f1,0(%r6) b .Lfinish nop nop # case FFI_TYPE_LONGDOUBLE .Lret_type4: - lfd %f1,0(%r5) + lfd %f1,0(%r6) b .Lfinish nop nop # case FFI_TYPE_UINT8 .Lret_type5: - lbz %r3,3(%r5) + lbz %r3,3(%r6) b .Lfinish nop nop # case FFI_TYPE_SINT8 .Lret_type6: - lbz %r3,3(%r5) + lbz %r3,3(%r6) extsb %r3,%r3 b .Lfinish nop # case FFI_TYPE_UINT16 .Lret_type7: - lhz %r3,2(%r5) + lhz %r3,2(%r6) b .Lfinish nop nop # case FFI_TYPE_SINT16 .Lret_type8: - lha %r3,2(%r5) + lha %r3,2(%r6) b .Lfinish nop nop # case FFI_TYPE_UINT32 .Lret_type9: - lwz %r3,0(%r5) + lwz %r3,0(%r6) b .Lfinish nop nop # case FFI_TYPE_SINT32 .Lret_type10: - lwz %r3,0(%r5) + lwz %r3,0(%r6) b .Lfinish nop nop # case FFI_TYPE_UINT64 .Lret_type11: - lwz %r3,0(%r5) - lwz %r4,4(%r5) + lwz %r3,0(%r6) + lwz %r4,4(%r6) b .Lfinish nop # case FFI_TYPE_SINT64 .Lret_type12: - lwz %r3,0(%r5) - lwz %r4,4(%r5) + lwz %r3,0(%r6) + lwz %r4,4(%r6) b .Lfinish nop @@ -185,10 +198,75 @@ ENTRY(ffi_closure_SYSV) # case FFI_TYPE_POINTER .Lret_type14: - lwz %r3,0(%r5) + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# 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. + nop + nop + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. +.Lret_type16: +# fall through. + nop + nop + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. +.Lret_type17: +# fall through. + nop + nop + nop + 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) + srw %r3,%r3,%r5 b .Lfinish nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. +.Lret_type19: +# fall through. + nop + nop + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. +.Lret_type20: +# fall through. + nop nop + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. +.Lret_type21: +# fall through. + nop + nop + nop + nop + +# 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) + bl __lshrdi3 # libgcc function to shift r3/r4, shift value in r5. + b .Lfinish # case done .Lfinish: diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S index 6d8b601..eba70fbd 100644 --- a/libffi/src/powerpc/sysv.S +++ b/libffi/src/powerpc/sysv.S @@ -99,6 +99,7 @@ ENTRY(ffi_call_SYSV) /* Now, deal with the return value. */ mtcrf 0x01,%r31 + bt- 31,L(small_struct_return_value) bt- 30,L(done_return_value) bt- 29,L(fp_return_value) stw %r3,0(%r30) @@ -124,6 +125,27 @@ L(fp_return_value): L(float_return_value): stfs %f1,0(%r30) b L(done_return_value) + +L(small_struct_return_value): + mtcrf 0x10,%r31 /* cr3 */ + bt- 15,L(smst_one_register) + mtcrf 0x08,%r31 /* cr4 */ + bt- 16,L(smst_two_register) + b L(done_return_value) + +L(smst_one_register): + rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */ + slw %r3,%r3,%r5 + stw %r3,0(%r30) + b L(done_return_value) +L(smst_two_register): + rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */ + bl __ashldi3 /* libgcc function to shift r3/r4, + shift value in r5. */ + stw %r3,0(%r30) + stw %r4,4(%r30) + b L(done_return_value) + .LFE1: END(ffi_call_SYSV) |