[PATCH, libffi]: Fix PR libffi/41908

Uros Bizjak ubizjak@gmail.com
Fri Dec 4 12:05:00 GMT 2009


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.



More information about the Gcc-patches mailing list