Commit 6078f50a by Uros Bizjak Committed by Uros Bizjak

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
parent d0e4968c
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> 2009-12-04 David Edelsohn <edelsohn@gnu.org>
* src/powerpc/ffi_darwin.c (ffi_closure_helper_DARWIN): Increment * src/powerpc/ffi_darwin.c (ffi_closure_helper_DARWIN): Increment
......
...@@ -145,13 +145,35 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -145,13 +145,35 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
if (byte_offset + type->size <= 4) {
classes[0] = X86_64_INTEGERSI_CLASS; int size = byte_offset + type->size;
else
classes[0] = X86_64_INTEGER_CLASS; if (size <= 4)
return 1; {
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: case FFI_TYPE_FLOAT:
if (byte_offset == 0) if (!(byte_offset % 8))
classes[0] = X86_64_SSESF_CLASS; classes[0] = X86_64_SSESF_CLASS;
else else
classes[0] = X86_64_SSE_CLASS; classes[0] = X86_64_SSE_CLASS;
...@@ -171,13 +193,21 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -171,13 +193,21 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
int i; int i;
enum x86_64_reg_class subclasses[MAX_CLASSES]; enum x86_64_reg_class subclasses[MAX_CLASSES];
/* If the struct is larger than 16 bytes, pass it on the stack. */ /* If the struct is larger than 32 bytes, pass it on the stack. */
if (type->size > 16) if (type->size > 32)
return 0; return 0;
for (i = 0; i < words; i++) for (i = 0; i < words; i++)
classes[i] = X86_64_NO_CLASS; 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. */ /* Merge the fields of structure. */
for (ptr = type->elements; *ptr != NULL; ptr++) for (ptr = type->elements; *ptr != NULL; ptr++)
{ {
...@@ -198,6 +228,20 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -198,6 +228,20 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
byte_offset += (*ptr)->size; 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. */ /* Final merger cleanup. */
for (i = 0; i < words; i++) for (i = 0; i < words; i++)
{ {
...@@ -207,15 +251,25 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -207,15 +251,25 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
return 0; return 0;
/* The X86_64_SSEUP_CLASS should be always preceded by /* 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 if (classes[i] == X86_64_SSEUP_CLASS
&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) && classes[i - 1] != X86_64_SSE_CLASS
classes[i] = 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 if (classes[i] == X86_64_X87UP_CLASS
&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) && (classes[i - 1] != X86_64_X87_CLASS))
classes[i] = X86_64_SSE_CLASS; {
/* The first one should never be X86_64_X87UP_CLASS. */
FFI_ASSERT (i != 0);
return 0;
}
} }
return words; return words;
} }
...@@ -528,10 +582,10 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, ...@@ -528,10 +582,10 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
argp += arg_types[i]->size; argp += arg_types[i]->size;
} }
/* If the argument is in a single register, or two consecutive /* 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 else if (n == 1
|| (n == 2 || (n == 2 && !(SSE_CLASS_P (classes[0])
&& SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1]))) || SSE_CLASS_P (classes[1]))))
{ {
/* The argument is in a single register. */ /* The argument is in a single register. */
if (SSE_CLASS_P (classes[0])) if (SSE_CLASS_P (classes[0]))
......
...@@ -57,7 +57,7 @@ int main(int argc __UNUSED__, char** argv __UNUSED__) ...@@ -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); CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK);
((void*(*)(Dbls))(code))(arg); ((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); closure_test_fn(arg);
/* { dg-output "1.0 2.0\n" } */ /* { dg-output "1.0 2.0\n" } */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment