diff options
author | uros <uros@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-04 18:41:59 +0000 |
---|---|---|
committer | uros <uros@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-04 18:41:59 +0000 |
commit | f89c6c9dbdd5f7b65039ebc693ca8bc41f91d11e (patch) | |
tree | 7023e428e5aab63f24b55d12fced3602b2ad7087 | |
parent | b572c3c961eadd3a7dc0fbdbf938d595816e61e2 (diff) | |
download | gcc-f89c6c9dbdd5f7b65039ebc693ca8bc41f91d11e.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@154988 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | libffi/ChangeLog | 10 | ||||
-rw-r--r-- | libffi/src/x86/ffi64.c | 88 | ||||
-rw-r--r-- | libffi/testsuite/libffi.call/cls_dbls_struct.c | 2 |
3 files changed, 82 insertions, 18 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index b2cef85eba8..7c877a1f4cc 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 116c636598d..51ada0e879f 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 fcf48b79237..660dabb883b 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" } */ |