sparc: Add support for complex types
authorRichard Henderson <rth@twiddle.net>
Sun, 26 Oct 2014 20:16:03 +0000 (13:16 -0700)
committerRichard Henderson <rth@twiddle.net>
Wed, 12 Nov 2014 08:36:09 +0000 (09:36 +0100)
src/sparc/ffi.c
src/sparc/ffi64.c
src/sparc/ffitarget.h
src/sparc/internal.h
src/sparc/v8.S
src/sparc/v9.S
testsuite/libffi.call/call.exp
testsuite/libffi.call/complex_int.c

index 1b8f48e..d319c03 100644 (file)
@@ -90,6 +90,40 @@ ffi_prep_cif_machdep(ffi_cif *cif)
     case FFI_TYPE_UINT64:
       flags = SPARC_RET_INT64;
       break;
+    case FFI_TYPE_COMPLEX:
+      rtt = rtype->elements[0]->type;
+      switch (rtt)
+       {
+       case FFI_TYPE_FLOAT:
+         flags = SPARC_RET_F_2;
+         break;
+       case FFI_TYPE_DOUBLE:
+         flags = SPARC_RET_F_4;
+         break;
+       case FFI_TYPE_LONGDOUBLE:
+         flags = SPARC_RET_F_8;
+         break;
+       case FFI_TYPE_SINT64:
+       case FFI_TYPE_UINT64:
+         flags = SPARC_RET_INT128;
+         break;
+       case FFI_TYPE_INT:
+       case FFI_TYPE_SINT32:
+       case FFI_TYPE_UINT32:
+         flags = SPARC_RET_INT64;
+         break;
+       case FFI_TYPE_SINT16:
+       case FFI_TYPE_UINT16:
+         flags = SP_V8_RET_CPLX16;
+         break;
+       case FFI_TYPE_SINT8:
+       case FFI_TYPE_UINT8:
+         flags = SP_V8_RET_CPLX8;
+         break;
+       default:
+         abort();
+       }
+      break;
     default:
       abort();
     }
@@ -102,11 +136,24 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       size_t z = ty->size;
       int tt = ty->type;
 
-      if (tt == FFI_TYPE_STRUCT || tt == FFI_TYPE_LONGDOUBLE)
-       /* Passed by reference.  */
-       z = 4;
-      else
-       z = ALIGN(z, 4);
+      switch (tt)
+       {
+       case FFI_TYPE_STRUCT:
+       case FFI_TYPE_LONGDOUBLE:
+       by_reference:
+         /* Passed by reference.  */
+         z = 4;
+         break;
+
+       case FFI_TYPE_COMPLEX:
+         tt = ty->elements[0]->type;
+         if (tt == FFI_TYPE_FLOAT || z > 8)
+           goto by_reference;
+         /* FALLTHRU */
+
+       default:
+         z = ALIGN(z, 4);
+       }
       bytes += z;
     }
 
@@ -169,11 +216,14 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
     {
       ffi_type *ty = p_arg[i];
       void *a = avalue[i];
+      int tt = ty->type;
+      size_t z;
 
-      switch (ty->type)
+      switch (tt)
        {
        case FFI_TYPE_STRUCT:
        case FFI_TYPE_LONGDOUBLE:
+       by_reference:
          *argp++ = (unsigned long)a;
          break;
 
@@ -205,6 +255,23 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
          *argp++ = *(SINT16 *)a;
          break;
 
+        case FFI_TYPE_COMPLEX:
+         tt = ty->elements[0]->type;
+         z = ty->size;
+         if (tt == FFI_TYPE_FLOAT || z > 8)
+           goto by_reference;
+         if (z < 4)
+           {
+             memcpy((char *)argp + 4 - z, a, z);
+             argp++;
+           }
+         else
+           {
+             memcpy(argp, a, z);
+             argp += z / 4;
+           }
+         break;
+
        default:
          abort();
        }
@@ -299,11 +366,13 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
       ffi_type *ty = arg_types[i];
       int tt = ty->type;
       void *a = argp;
+      size_t z;
 
       switch (tt)
        {
        case FFI_TYPE_STRUCT:
        case FFI_TYPE_LONGDOUBLE:
+       by_reference:
          /* Straight copy of invisible reference.  */
          a = (void *)*argp;
          break;
@@ -336,6 +405,17 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
          a += 3;
          break;
 
+        case FFI_TYPE_COMPLEX:
+         tt = ty->elements[0]->type;
+         z = ty->size;
+         if (tt == FFI_TYPE_FLOAT || z > 8)
+           goto by_reference;
+         if (z < 4)
+           a += 4 - z;
+         else if (z > 4)
+           argp++;
+         break;
+
        default:
          abort();
        }
index ab3ed09..1e2d3f4 100644 (file)
    and addition work correctly.  The mask is placed in the second byte.  */
 
 static int
-ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
+ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
 {
-  ffi_type **elts, *t;
+  ffi_type **elts;
+  ffi_type *t;
 
-  for (elts = struct_type->elements; (t = *elts) != NULL; elts++)
+  if (outer_type->type == FFI_TYPE_COMPLEX)
+    {
+      int m = 0, tt = outer_type->elements[0]->type;
+      size_t z = outer_type->size;
+
+      if (tt == FFI_TYPE_FLOAT
+         || tt == FFI_TYPE_DOUBLE
+         || tt == FFI_TYPE_LONGDOUBLE)
+        m = (1 << (z / 4)) - 1;
+      return (m << 8) | z;
+    }
+  FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
+
+  for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
     {
       size_t z = t->size;
-      int o, m;
+      int o, m, tt;
 
       size_mask = ALIGN(size_mask, t->alignment);
       switch (t->type)
@@ -67,6 +81,13 @@ ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
        case FFI_TYPE_STRUCT:
          size_mask = ffi_struct_float_mask (t, size_mask);
          continue;
+       case FFI_TYPE_COMPLEX:
+         tt = t->elements[0]->type;
+         if (tt != FFI_TYPE_FLOAT
+             && tt != FFI_TYPE_DOUBLE
+             && tt != FFI_TYPE_LONGDOUBLE)
+           break;
+         /* FALLTHRU */
        case FFI_TYPE_FLOAT:
        case FFI_TYPE_DOUBLE:
        case FFI_TYPE_LONGDOUBLE:
@@ -78,8 +99,8 @@ ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
       size_mask += z;
     }
 
-  size_mask = ALIGN(size_mask, struct_type->alignment);
-  FFI_ASSERT ((size_mask & 0xff) == struct_type->size);
+  size_mask = ALIGN(size_mask, outer_type->alignment);
+  FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
 
   return size_mask;
 }
@@ -162,6 +183,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       flags = SPARC_RET_F_4;
       break;
 
+    case FFI_TYPE_COMPLEX:
     case FFI_TYPE_STRUCT:
       if (rtype->size > 32)
        {
@@ -194,7 +216,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
              {
              case 1: flags = SPARC_RET_F_1; break;
              case 2: flags = SPARC_RET_F_2; break;
-             case 3: flags = SPARC_RET_F_3; break;
+             case 3: flags = SP_V9_RET_F_3; break;
              case 4: flags = SPARC_RET_F_4; break;
              /* 5 word structures skipped; handled via RET_STRUCT.  */
              case 6: flags = SPARC_RET_F_6; break;
@@ -218,7 +240,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       break;
     case FFI_TYPE_INT:
     case FFI_TYPE_SINT32:
-      flags = SPARC_RET_SINT32;
+      flags = SP_V9_RET_SINT32;
       break;
     case FFI_TYPE_UINT32:
       flags = SPARC_RET_UINT32;
@@ -242,6 +264,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 
       switch (ty->type)
        {
+       case FFI_TYPE_COMPLEX:
        case FFI_TYPE_STRUCT:
          /* Large structs passed by reference.  */
          if (z > 16)
@@ -249,7 +272,12 @@ ffi_prep_cif_machdep(ffi_cif *cif)
              a = z = 8;
              break;
            }
-         /* ??? FALLTHRU -- check for fp members in the struct.  */
+         /* Small structs may be passed in integer or fp regs or both.  */
+         if (bytes >= 16*8)
+           break;
+         if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
+           break;
+         /* FALLTHRU */
        case FFI_TYPE_FLOAT:
        case FFI_TYPE_DOUBLE:
        case FFI_TYPE_LONGDOUBLE:
@@ -351,6 +379,7 @@ ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
          break;
 
        case FFI_TYPE_LONGDOUBLE:
+       case FFI_TYPE_COMPLEX:
        case FFI_TYPE_STRUCT:
          z = ty->size;
          if (z > 16)
@@ -466,6 +495,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
       argx = argn + 1;
       switch (ty->type)
        {
+       case FFI_TYPE_COMPLEX:
        case FFI_TYPE_STRUCT:
          z = ty->size;
          if (z > 16)
index ff4dc0b..f70c937 100644 (file)
@@ -58,6 +58,7 @@ typedef enum ffi_abi {
 #endif
 
 #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#define FFI_TARGET_HAS_COMPLEX_TYPE
 
 /* ---- Definitions for closures ----------------------------------------- */
 
index b4494d9..f9387d4 100644 (file)
@@ -5,16 +5,18 @@
 #define SPARC_RET_UINT16       4
 #define SPARC_RET_SINT16       5
 #define SPARC_RET_UINT32       6
-#define SPARC_RET_SINT32       7       /* v9 only */
+#define SP_V9_RET_SINT32       7       /* v9 only */
+#define SP_V8_RET_CPLX16       7       /* v8 only */
 #define SPARC_RET_INT64                8
-#define SPARC_RET_INT128       9       /* v9 only */
+#define SPARC_RET_INT128       9
 
 /* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT.  */
 #define SPARC_RET_F_8          10
-#define SPARC_RET_F_6          11      /* v9 only */
+#define SPARC_RET_F_6          11
 #define SPARC_RET_F_4          12
 #define SPARC_RET_F_2          13
-#define SPARC_RET_F_3          14      /* v9 only */
+#define SP_V9_RET_F_3          14      /* v9 only */
+#define SP_V8_RET_CPLX8                14      /* v8 only */
 #define SPARC_RET_F_1          15
 
 #define SPARC_FLAG_RET_MASK    15
index 4adcf6d..e76d813 100644 (file)
@@ -1,8 +1,8 @@
 /* -----------------------------------------------------------------------
    v8.S - Copyright (c) 2013  The Written Word, Inc.
          Copyright (c) 1996, 1997, 2003, 2004, 2008  Red Hat, Inc.
-   
-   SPARC Foreign Function Interface 
+
+   SPARC Foreign Function Interface
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@
    DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
-#define LIBFFI_ASM     
+#define LIBFFI_ASM
 #include <fficonfig.h>
 #include <ffi.h>
 #include <ffi_cfi.h>
@@ -45,7 +45,7 @@
 
        .text
 
-#ifndef __GNUC__       
+#ifndef __GNUC__
         .align 8
        .globl  C(ffi_flush_icache)
        .type   C(ffi_flush_icache),@function
@@ -75,7 +75,7 @@ C(ffi_flush_icache):
        .globl  C(ffi_call_v8)
        .type   C(ffi_call_v8),@function
        FFI_HIDDEN(C(ffi_call_v8))
-       
+
 C(ffi_call_v8):
        cfi_startproc
        ! Allocate a stack frame sized by ffi_call.
@@ -139,26 +139,44 @@ E SPARC_RET_UINT32
 7:     st      %o0, [%i2]
        ret
         restore
-E SPARC_RET_SINT32
-       unimp
+E SP_V8_RET_CPLX16
+       sth     %o0, [%i2+2]
+       b       9f
+        srl    %o0, 16, %o0
 E SPARC_RET_INT64
-       std     %o0, [%i2]
+       st      %o0, [%i2]
+       st      %o1, [%i2+4]
        ret
         restore
 E SPARC_RET_INT128
-       unimp
+       std     %o0, [%i2]
+       std     %o2, [%i2+8]
+       ret
+        restore
 E SPARC_RET_F_8
-       unimp
+       st      %f7, [%i2+7*4]
+       nop
+       st      %f6, [%i2+6*4]
+       nop
 E SPARC_RET_F_6
-       unimp
+       st      %f5, [%i2+5*4]
+       nop
+       st      %f4, [%i2+4*4]
+       nop
 E SPARC_RET_F_4
-       unimp
+       st      %f3, [%i2+3*4]
+       nop
+       st      %f2, [%i2+2*4]
+       nop
 E SPARC_RET_F_2
-       std     %f0, [%i2]
+       st      %f1, [%i2+4]
+       st      %f0, [%i2]
        ret
         restore
-E SPARC_RET_F_3
-       unimp
+E SP_V8_RET_CPLX8
+       stb     %o0, [%i2+1]
+       b       10f
+        srl    %o0, 8, %o0
 E SPARC_RET_F_1
        st      %f0, [%i2]
        ret
@@ -172,16 +190,22 @@ E SPARC_RET_F_1
        ret
         restore
 
+       .align  8
+9:     sth     %o0, [%i2]
+       ret
+        restore
+       .align  8
+10:    stb     %o0, [%i2]
+       ret
+        restore
+
        cfi_endproc
        .size   C(ffi_call_v8),. - C(ffi_call_v8)
 
 
-#undef STACKFRAME
-#define        STACKFRAME      104     /* 16*4 register window +
-                                  1*4 struct return +  
-                                  6*4 args backing store +
-                                  2*4 return storage +
-                                  1*4 alignment */
+/* 16*4 register window + 1*4 struct return + 6*4 args backing store
+   + 8*4 return storage + 1*4 alignment.  */
+#define        STACKFRAME      (16*4 + 4 + 6*4 + 8*4 + 4)
 
 /* ffi_closure_v8(...)
 
@@ -211,7 +235,7 @@ C(ffi_closure_v8):
 
        ! Call ffi_closure_sparc_inner to do the bulk of the work.
        mov     %g2, %o0
-       add     %fp, -8, %o1
+       add     %fp, -8*4, %o1
        call    ffi_closure_sparc_inner_v8
         add    %fp,  64, %o2
 
@@ -220,8 +244,8 @@ C(ffi_closure_v8):
 1:     sll     %o0, 4, %o0     ! o0 = o0 * 16
        add     %o7, %o0, %o7   ! o7 = 0b + o0*16
        jmp     %o7+(2f-0b)
-        nop
-
+        add    %fp, -8*4, %i2
+        
        ! Note that each entry is 4 insns, enforced by the E macro.
        .align  16
 2:
@@ -232,47 +256,63 @@ E SPARC_RET_STRUCT
        jmp     %i7+12
         restore
 E SPARC_RET_UINT8
-       ldub    [%fp-8+3], %i0
+       ldub    [%i2+3], %i0
        ret
         restore
 E SPARC_RET_SINT8
-       ldsb    [%fp-8+3], %i0
+       ldsb    [%i2+3], %i0
        ret
         restore
 E SPARC_RET_UINT16
-       lduh    [%fp-8+2], %i0
+       lduh    [%i2+2], %i0
        ret
         restore
 E SPARC_RET_SINT16
-       ldsh    [%fp-8+2], %i0
+       ldsh    [%i2+2], %i0
        ret
         restore
 E SPARC_RET_UINT32
-       ld      [%fp-8], %i0
+       ld      [%i2], %i0
+       ret
+        restore
+E SP_V8_RET_CPLX16
+       ld      [%i2], %i0
        ret
         restore
-E SPARC_RET_SINT32
-       unimp
 E SPARC_RET_INT64
-       ldd     [%fp-8], %i0
+       ldd     [%i2], %i0
        ret
         restore
 E SPARC_RET_INT128
-       unimp
+       ldd     [%i2], %i0
+       ldd     [%i2+8], %i2
+       ret
+        restore
 E SPARC_RET_F_8
-       unimp
+       ld      [%i2+7*4], %f7
+       nop
+       ld      [%i2+6*4], %f6
+       nop
 E SPARC_RET_F_6
-       unimp
+       ld      [%i2+5*4], %f5
+       nop
+       ld      [%i2+4*4], %f4
+       nop
 E SPARC_RET_F_4
-       unimp
+       ld      [%i2+3*4], %f3
+       nop
+       ld      [%i2+2*4], %f2
+       nop
 E SPARC_RET_F_2
-       ldd     [%fp-8], %f0
+       ldd     [%i2], %f0
+       ret
+        restore
+E SP_V8_RET_CPLX8
+       lduh    [%i2], %i0
        ret
         restore
-E SPARC_RET_F_3
-       unimp
 E SPARC_RET_F_1
-       ld      [%fp-8], %f0
+       ld      [%i2], %f0
        ret
         restore
 
index d893d2f..5c3f27b 100644 (file)
@@ -137,7 +137,7 @@ E SPARC_RET_UINT32
        srl     %o0, 0, %i0
        return  %i7+8
         stx    %o0, [%o2]
-E SPARC_RET_SINT32
+E SP_V9_RET_SINT32
        sra     %o0, 0, %i0
        return  %i7+8
         stx    %o0, [%o2]
@@ -167,7 +167,7 @@ E SPARC_RET_F_4
 E SPARC_RET_F_2
        return  %i7+8
         std    %f0, [%o2]
-E SPARC_RET_F_3
+E SP_V9_RET_F_3
        st      %f2, [%i2+2*4]
        nop
        st      %f1, [%i2+1*4]
@@ -294,7 +294,7 @@ E SPARC_RET_UINT32
        lduw    [FP-160+4], %i0
        return  %i7+8
         nop
-E SPARC_RET_SINT32
+E SP_V9_RET_SINT32
        ldsw    [FP-160+4], %i0
        return  %i7+8
         nop
@@ -326,7 +326,7 @@ E SPARC_RET_F_2
        ldd     [FP-160], %f0
        return  %i7+8
         nop
-E SPARC_RET_F_3
+E SP_V9_RET_F_3
        ld      [FP-160+2*4], %f2
        nop
        ld      [FP-160+1*4], %f1
index 7a5c44f..982c03e 100644 (file)
@@ -31,6 +31,7 @@ if { [istarget aarch64*]
      || [istarget arm*]
      || [istarget i?86*]
      || [istarget s390*]
+     || [istarget sparc*]
      || [istarget x86_64*] } {
     run-many-tests $ctlist ""
 } else {
index 4c8e864..bac3190 100644 (file)
@@ -12,9 +12,9 @@
 
 _Complex int f_complex(_Complex int c, int x, int *py)
 {
-  c = -(2 * creal (c)) + (cimag (c) + 1)* I;
+  __real__ c = -2 * __real__ c;
+  __imag__ c = __imag__ c + 1;
   *py += x;
-
   return c;
 }