This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
Re: [PATCH, libffi]: Fix PR libffi/41908
- From: Uros Bizjak <ubizjak at gmail dot com>
- To: Andrew Haley <aph at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, libffi-discuss at sourceware dot org
- Date: Fri, 4 Dec 2009 12:28:31 +0100
- Subject: Re: [PATCH, libffi]: Fix PR libffi/41908
- References: <4B182715.60501@gmail.com> <4B18DEA3.6020002@redhat.com>
2009/12/4 Andrew Haley <aph@redhat.com>:
> Uros Bizjak wrote:
>
>> The core of the fix is the fix to this thinko:
>>
>> - Â Â/* 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;
>>
>> Without this part, libffi simply misses special handling for
>> FFI_TYPE_STRUCT with n == 2 in ffi_closure_unix64_inner.
>>
>> Other than that, I have updated classify_argument function with the copy
>> from gcc/config/i386/i386.c. As can be seen from the patch, the problems
>> were mainly in the merging of SImode and SFmode arguments and some
>> special cases when arguments are passed through memory.
>>
>>
>> 2009-12-03 ÂUros Bizjak <ubizjak@gmail.com>
>>
>> Â Â ÂPR libffi/41908
>> Â Â Â* src/x86/ffi64.c (classify_argument): Update from
>> Â Â Âgcc/config/i386/i386.c.
>>
>> 2009-12-03 ÂUros Bizjak <ubizjak@gmail.com>
>>
>> Â Â Â* testsuite/libffi.call/cls_dbls_struct.c (main): Remove xfail
>> Â Â Âfor x86_64 linux targets.
>>
>> Patch was tested on x86_64-pc-linux-gnu, where it fixes all remaining
>> failures.
>>
>> OK for mainline gcc?
>
> Yes, this looks good to me.
Actually, there _is_ another problem in ffi_closure_unix64_ffi, as
outlined in the PR. The problem is, that we can not pass two
consecutive SSE registers directly, since they are stored as 128bit
value. In testclosure.c testcase, we pass:
Breakpoint 1, 0x00002ba0aabd3984 in ffi_closure_unix64_inner (
closure=0x2ba0aadd6010, rvalue=0x7fff1e42c580, reg_args=0x7fff1e42c4d0,
argp=0x7fff1e42c5a0 " ïB\036ï\177")
at ../../../gcc-svn/trunk/libffi/src/x86/ffi64.c:197
197 if (type->size > 32)
(gdb) p reg_args
$8 = (struct register_args *) 0x7fff1e42c4d0
(gdb) p *reg_args
$9 = {gpr = {47969061400592, 140733701080576, 4196608, 0, 18937, 0}, sse = {
0x000000000000000040a0000040800000, 0x0000000000000000410000003f800000,
0x00000000000000000000000000000000, 0x00000000000000000000000000000000,
0x00000000000000000000000000000000, 0x00000000000000000000000000000000,
0x00000000000000000000000000000000, 0x00000000000000000000000000000000}}
So, even for n = 2, you can't use SSE address directly to pass i.e.
array of four floats.
Following addition to the patch then fixes failures on x86_64 for good:
@@ -528,10 +582,10 @@ ffi_closure_unix64_inner(ffi_closure *cl
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]))
Patch with the above addition was tested on x86_64-pc-linux-gnu. I
think that this part falls into obvious now ;)
Uros.