From 6078f50a123e3801db6d548dfcb5131677b3baae Mon Sep 17 00:00:00 2001 From: Uros Bizjak <ubizjak@gmail.com> Date: Fri, 4 Dec 2009 19:41:59 +0100 Subject: [PATCH] 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 --- libffi/ChangeLog | 10 +++ libffi/src/x86/ffi64.c | 88 +++++++++++++++---- .../testsuite/libffi.call/cls_dbls_struct.c | 2 +- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/libffi/ChangeLog b/libffi/ChangeLog index b2cef85eba80..7c877a1f4cca 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,13 @@ +2009-12-04 Uros Bizjak <ubizjak@gmail.com> + + 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. + 2009-12-04 David Edelsohn <edelsohn@gnu.org> * src/powerpc/ffi_darwin.c (ffi_closure_helper_DARWIN): Increment diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c index 116c636598d8..51ada0e879fa 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])) diff --git a/libffi/testsuite/libffi.call/cls_dbls_struct.c b/libffi/testsuite/libffi.call/cls_dbls_struct.c index fcf48b79237d..660dabb883b1 100644 --- a/libffi/testsuite/libffi.call/cls_dbls_struct.c +++ b/libffi/testsuite/libffi.call/cls_dbls_struct.c @@ -57,7 +57,7 @@ int main(int argc __UNUSED__, char** argv __UNUSED__) CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK); ((void*(*)(Dbls))(code))(arg); - /* { dg-output "1.0 2.0\n" { xfail x86_64-*-linux-* } } */ + /* { dg-output "1.0 2.0\n" } */ closure_test_fn(arg); /* { dg-output "1.0 2.0\n" } */ -- GitLab