This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
Reinstate powerpc bounce buffer copying in ffi.c
- From: Alan Modra <amodra at gmail dot com>
- To: libffi-discuss at sourceware dot org
- Date: Thu, 14 Nov 2013 00:38:59 +1030
- Subject: Reinstate powerpc bounce buffer copying in ffi.c
- Authentication-results: sourceware.org; auth=none
Andreas' 2013-02-08 change reverted some breakage for struct return
values from 2011-11-12, but in so doing reintroduced string
instructions to sysv.S that are not supported on all powerpc variants.
This patch properly copies the bounce buffer to destination in C code
rather than in asm.
I have tested this on powerpc64-linux, powerpc-linux and
powerpc-freebsd. Well, the last on powerpc-linux by lying to
configure with
CC="gcc -m32 -msvr4-struct-return -mlong-double-64" \
CXX="g++ -m32 -msvr4-struct-return -mlong-double-64" \
/src/libffi-current/configure --build=powerpc-freebsd
and then
make && make CC="gcc -m32" CXX="g++ -m32" \
RUNTESTFLAGS=--target_board=unix/-m32/-msvr4-struct-return/-mlong-double-64\
check
* src/powerpc/ffi.c (ffi_prep_cif_machdep): Revert 2013-02-08
change. Do not consume an int arg when returning a small struct
for FFI_SYSV ABI.
(ffi_call): Only use bounce buffer when FLAG_RETURNS_SMST.
Properly copy bounce buffer to destination.
* src/powerpc/sysv.S: Revert 2013-02-08 change.
* src/powerpc/ppc_closure.S: Remove stray '+'.
diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c
index f2c133b..a260c74 100644
--- a/src/powerpc/ffi.c
+++ b/src/powerpc/ffi.c
@@ -48,11 +48,6 @@ enum {
FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
- FLAG_SYSV_SMST_R4 = 1 << (31-26), /* use r4 for FFI_SYSV 8 byte
- structs. */
- FLAG_SYSV_SMST_R3 = 1 << (31-25), /* use r3 for FFI_SYSV 4 byte
- structs. */
-
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
#ifndef __NO_FPRS__
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
@@ -700,35 +695,21 @@ ffi_prep_cif_machdep (ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
- if (cif->abi == FFI_SYSV)
+ /*
+ * 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.
+ *
+ * NOTE: The assembly code can safely assume that it just needs to
+ * store both r3 and r4 into a 8-byte word-aligned buffer, as
+ * we allocate a temporary buffer in ffi_call() if this flag is
+ * set.
+ */
+ if (cif->abi == FFI_SYSV && size <= 8)
{
- /* 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 |= FLAG_SYSV_SMST_R3;
- flags |= 8 * (4 - size) << 8;
- break;
- }
- /* These structs are returned in r3 and r4. See above. */
- if (size <= 8)
- {
- flags |= FLAG_SYSV_SMST_R3 | FLAG_SYSV_SMST_R4;
- flags |= 8 * (8 - size) << 8;
- break;
- }
- }
+ flags |= FLAG_RETURNS_SMST;
+ break;
}
-
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */
@@ -947,30 +928,25 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
/*
* 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
+ * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
* in memory.
*
- * Just to keep things simple for the assembly code, we will always
- * bounce-buffer struct return values less than or equal to 8 bytes.
- * This allows the ASM to handle SYSV small structures by directly
- * writing r3 and r4 to memory without worrying about struct size.
+ * We bounce-buffer SYSV small struct return values so that sysv.S
+ * can write r3 and r4 to memory without worrying about struct size.
*/
unsigned int smst_buffer[2];
extended_cif ecif;
- unsigned int rsize = 0;
ecif.cif = cif;
ecif.avalue = avalue;
- /* Ensure that we have a valid struct return value */
ecif.rvalue = rvalue;
- if (cif->rtype->type == FFI_TYPE_STRUCT) {
- rsize = cif->rtype->size;
- if (rsize <= 8)
- ecif.rvalue = smst_buffer;
- else if (!rvalue)
- ecif.rvalue = alloca(rsize);
- }
+ if ((cif->flags & FLAG_RETURNS_SMST) != 0)
+ ecif.rvalue = smst_buffer;
+ /* Ensure that we have a valid struct return value.
+ FIXME: Isn't this just papering over a user problem? */
+ else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
+ ecif.rvalue = alloca (cif->rtype->size);
switch (cif->abi)
{
@@ -995,7 +971,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* Check for a bounce-buffered return value */
if (rvalue && ecif.rvalue == smst_buffer)
- memcpy(rvalue, smst_buffer, rsize);
+ {
+ unsigned int rsize = cif->rtype->size;
+#ifndef __LITTLE_ENDIAN__
+ /* The SYSV ABI returns a structure of up to 4 bytes in size
+ left-padded in r3. */
+ if (rsize <= 4)
+ memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
+ /* The SYSV ABI returns a structure of up to 8 bytes in size
+ left-padded in r3/r4. */
+ else if (rsize <= 8)
+ memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
+ else
+#endif
+ memcpy (rvalue, smst_buffer, rsize);
+ }
}
diff --git a/src/powerpc/ppc_closure.S b/src/powerpc/ppc_closure.S
index c3349df..3eefe7e 100644
--- a/src/powerpc/ppc_closure.S
+++ b/src/powerpc/ppc_closure.S
@@ -288,7 +288,7 @@ ENTRY(ffi_closure_SYSV)
#ifdef __LITTLE_ENDIAN__
mtlr %r0
b .Lfinish
-+#else
+#else
li %r5,16
b .Lstruct567
#endif
diff --git a/src/powerpc/sysv.S b/src/powerpc/sysv.S
index 5ee3a19..675ed03 100644
--- a/src/powerpc/sysv.S
+++ b/src/powerpc/sysv.S
@@ -142,19 +142,14 @@ L(float_return_value):
#endif
L(small_struct_return_value):
- extrwi %r6,%r31,2,19 /* number of bytes padding = shift/8 */
- mtcrf 0x02,%r31 /* copy flags to cr[24:27] (cr6) */
- extrwi %r5,%r31,5,19 /* r5 <- number of bits of padding */
- subfic %r6,%r6,4 /* r6 <- number of useful bytes in r3 */
- bf- 25,L(done_return_value) /* struct in r3 ? if not, done. */
-/* smst_one_register: */
- slw %r3,%r3,%r5 /* Left-justify value in r3 */
- mtxer %r6 /* move byte count to XER ... */
- stswx %r3,0,%r30 /* ... and store that many bytes */
- bf+ 26,L(done_return_value) /* struct in r3:r4 ? */
- add %r6,%r6,%r30 /* adjust pointer */
- stswi %r4,%r6,4 /* store last four bytes */
- b L(done_return_value)
+ /*
+ * The C code always allocates a properly-aligned 8-byte bounce
+ * buffer to make this assembly code very simple. Just write out
+ * r3 and r4 to the buffer to allow the C code to handle the rest.
+ */
+ stw %r3, 0(%r30)
+ stw %r4, 4(%r30)
+ b L(done_return_value)
.LFE1:
END(ffi_call_SYSV)
--
Alan Modra
Australia Development Lab, IBM