aboutsummaryrefslogtreecommitdiff
path: root/libffi/src
diff options
context:
space:
mode:
authorUros Bizjak <ubizjak@gmail.com>2009-12-04 19:41:59 +0100
committerUros Bizjak <uros@gcc.gnu.org>2009-12-04 19:41:59 +0100
commit6078f50a123e3801db6d548dfcb5131677b3baae (patch)
tree7023e428e5aab63f24b55d12fced3602b2ad7087 /libffi/src
parentd0e4968c33c257bcfa1afa4f499661c18c80e5bc (diff)
downloadgcc-6078f50a123e3801db6d548dfcb5131677b3baae.zip
gcc-6078f50a123e3801db6d548dfcb5131677b3baae.tar.gz
gcc-6078f50a123e3801db6d548dfcb5131677b3baae.tar.bz2
re PR libffi/41908 (closures fail for some structure arguments containing floats)
PR libffi/41908 * src/x86/ffi64.c (classify_argument): Update from gcc/config/i386/i386.c. (ffi_closure_unix64_inner): Do not use the address of two consecutive SSE registers directly. * testsuite/libffi.call/cls_dbls_struct.c (main): Remove xfail for x86_64 linux targets. From-SVN: r154988
Diffstat (limited to 'libffi/src')
-rw-r--r--libffi/src/x86/ffi64.c88
1 files changed, 71 insertions, 17 deletions
diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c
index 116c636..51ada0e 100644
--- a/libffi/src/x86/ffi64.c
+++ b/libffi/src/x86/ffi64.c
@@ -145,13 +145,35 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER:
- if (byte_offset + type->size <= 4)
- classes[0] = X86_64_INTEGERSI_CLASS;
- else
- classes[0] = X86_64_INTEGER_CLASS;
- return 1;
+ {
+ int size = byte_offset + type->size;
+
+ if (size <= 4)
+ {
+ classes[0] = X86_64_INTEGERSI_CLASS;
+ return 1;
+ }
+ else if (size <= 8)
+ {
+ classes[0] = X86_64_INTEGER_CLASS;
+ return 1;
+ }
+ else if (size <= 12)
+ {
+ classes[0] = X86_64_INTEGER_CLASS;
+ classes[1] = X86_64_INTEGERSI_CLASS;
+ return 2;
+ }
+ else if (size <= 16)
+ {
+ classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
+ return 2;
+ }
+ else
+ FFI_ASSERT (0);
+ }
case FFI_TYPE_FLOAT:
- if (byte_offset == 0)
+ if (!(byte_offset % 8))
classes[0] = X86_64_SSESF_CLASS;
else
classes[0] = X86_64_SSE_CLASS;
@@ -171,13 +193,21 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
int i;
enum x86_64_reg_class subclasses[MAX_CLASSES];
- /* If the struct is larger than 16 bytes, pass it on the stack. */
- if (type->size > 16)
+ /* If the struct is larger than 32 bytes, pass it on the stack. */
+ if (type->size > 32)
return 0;
for (i = 0; i < words; i++)
classes[i] = X86_64_NO_CLASS;
+ /* Zero sized arrays or structures are NO_CLASS. We return 0 to
+ signalize memory class, so handle it as special case. */
+ if (!words)
+ {
+ classes[0] = X86_64_NO_CLASS;
+ return 1;
+ }
+
/* Merge the fields of structure. */
for (ptr = type->elements; *ptr != NULL; ptr++)
{
@@ -198,6 +228,20 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
byte_offset += (*ptr)->size;
}
+ if (words > 2)
+ {
+ /* When size > 16 bytes, if the first one isn't
+ X86_64_SSE_CLASS or any other ones aren't
+ X86_64_SSEUP_CLASS, everything should be passed in
+ memory. */
+ if (classes[0] != X86_64_SSE_CLASS)
+ return 0;
+
+ for (i = 1; i < words; i++)
+ if (classes[i] != X86_64_SSEUP_CLASS)
+ return 0;
+ }
+
/* Final merger cleanup. */
for (i = 0; i < words; i++)
{
@@ -207,15 +251,25 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
return 0;
/* The X86_64_SSEUP_CLASS should be always preceded by
- X86_64_SSE_CLASS. */
+ X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
if (classes[i] == X86_64_SSEUP_CLASS
- && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
- classes[i] = X86_64_SSE_CLASS;
+ && classes[i - 1] != X86_64_SSE_CLASS
+ && classes[i - 1] != X86_64_SSEUP_CLASS)
+ {
+ /* The first one should never be X86_64_SSEUP_CLASS. */
+ FFI_ASSERT (i != 0);
+ classes[i] = X86_64_SSE_CLASS;
+ }
- /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
+ /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+ everything should be passed in memory. */
if (classes[i] == X86_64_X87UP_CLASS
- && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
- classes[i] = X86_64_SSE_CLASS;
+ && (classes[i - 1] != X86_64_X87_CLASS))
+ {
+ /* The first one should never be X86_64_X87UP_CLASS. */
+ FFI_ASSERT (i != 0);
+ return 0;
+ }
}
return words;
}
@@ -528,10 +582,10 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
argp += arg_types[i]->size;
}
/* If the argument is in a single register, or two consecutive
- registers, then we can use that address directly. */
+ integer registers, then we can use that address directly. */
else if (n == 1
- || (n == 2
- && SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1])))
+ || (n == 2 && !(SSE_CLASS_P (classes[0])
+ || SSE_CLASS_P (classes[1]))))
{
/* The argument is in a single register. */
if (SSE_CLASS_P (classes[0]))