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 /libffi/src | |
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
Diffstat (limited to 'libffi/src')
-rw-r--r-- | libffi/src/x86/ffi64.c | 88 |
1 files changed, 71 insertions, 17 deletions
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])) |