OSDN Git Service

PR libffi/41908
authoruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Dec 2009 18:41:59 +0000 (18:41 +0000)
committeruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Dec 2009 18:41:59 +0000 (18:41 +0000)
* 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

libffi/ChangeLog
libffi/src/x86/ffi64.c
libffi/testsuite/libffi.call/cls_dbls_struct.c

index b2cef85..7c877a1 100644 (file)
@@ -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
index 116c636..51ada0e 100644 (file)
@@ -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]))
index fcf48b7..660dabb 100644 (file)
@@ -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" } */