aboutsummaryrefslogtreecommitdiff
path: root/libffi/src/powerpc
diff options
context:
space:
mode:
authorAndreas Tobler <andreast@gcc.gnu.org>2005-07-19 23:15:36 +0200
committerAndreas Tobler <andreast@gcc.gnu.org>2005-07-19 23:15:36 +0200
commit970676420b393e14a8857887876b731552331e44 (patch)
tree21351941ab537791da38bac3a026c412d513b438 /libffi/src/powerpc
parentaf62f6f9a440d24b135f7d5023173180566a780e (diff)
downloadgcc-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/powerpc')
-rw-r--r--libffi/src/powerpc/ffi.c55
-rw-r--r--libffi/src/powerpc/ffitarget.h10
-rw-r--r--libffi/src/powerpc/ppc_closure.S110
-rw-r--r--libffi/src/powerpc/sysv.S22
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)