This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 6/8] sparc: Add support for complex types


---
 src/sparc/ffi.c                     |  92 +++++++++++++++++++++++++--
 src/sparc/ffi64.c                   |  48 ++++++++++++---
 src/sparc/ffitarget.h               |   1 +
 src/sparc/internal.h                |  10 +--
 src/sparc/v8.S                      | 120 ++++++++++++++++++++++++------------
 src/sparc/v9.S                      |   8 +--
 testsuite/libffi.call/call.exp      |  12 ++--
 testsuite/libffi.call/complex_int.c |   4 +-
 8 files changed, 223 insertions(+), 72 deletions(-)

diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c
index 1b8f48e..d319c03 100644
--- a/src/sparc/ffi.c
+++ b/src/sparc/ffi.c
@@ -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();
 	}
diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c
index ab3ed09..1e2d3f4 100644
--- a/src/sparc/ffi64.c
+++ b/src/sparc/ffi64.c
@@ -52,14 +52,28 @@
    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)
diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h
index ff4dc0b..f70c937 100644
--- a/src/sparc/ffitarget.h
+++ b/src/sparc/ffitarget.h
@@ -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 ----------------------------------------- */
 
diff --git a/src/sparc/internal.h b/src/sparc/internal.h
index b4494d9..f9387d4 100644
--- a/src/sparc/internal.h
+++ b/src/sparc/internal.h
@@ -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
diff --git a/src/sparc/v8.S b/src/sparc/v8.S
index 4adcf6d..e76d813 100644
--- a/src/sparc/v8.S
+++ b/src/sparc/v8.S
@@ -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
 
diff --git a/src/sparc/v9.S b/src/sparc/v9.S
index d893d2f..5c3f27b 100644
--- a/src/sparc/v9.S
+++ b/src/sparc/v9.S
@@ -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
diff --git a/testsuite/libffi.call/call.exp b/testsuite/libffi.call/call.exp
index 5177f07..f144a65 100644
--- a/testsuite/libffi.call/call.exp
+++ b/testsuite/libffi.call/call.exp
@@ -24,16 +24,14 @@ set ctlist [lsearch -inline -all -glob [lsort [glob -nocomplain -- $srcdir/$subd
 
 run-many-tests $tlist ""
 
-if { ![istarget s390*] } {
-
+# ??? We really should preprocess ffi.h and grep
+# for FFI_TARGET_HAS_COMPLEX_TYPE.
+if { [istarget s390*] || [istarget sparc*] } {
+    run-many-tests $ctlist ""
+} else {
     foreach test $ctlist {
 	unsupported "$test"
     }
-
-} else {
-
-  run-many-tests $ctlist ""
-
 }
 
 dg-finish
diff --git a/testsuite/libffi.call/complex_int.c b/testsuite/libffi.call/complex_int.c
index 4c8e864..bac3190 100644
--- a/testsuite/libffi.call/complex_int.c
+++ b/testsuite/libffi.call/complex_int.c
@@ -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;
 }
 
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]