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
This commit is contained in:
Alan Modra
2013-11-16 06:52:43 -05:00
committed by Anthony Green
parent 1c06515d92
commit 362851379a
4 changed files with 56 additions and 61 deletions

View File

@@ -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 */
@@ -720,35 +715,21 @@ ffi_prep_cif_machdep_core (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. */
@@ -990,30 +971,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)
{
@@ -1038,7 +1014,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);
}
}