public inbox for libffi-discuss@sourceware.org
 help / color / mirror / Atom feed
* [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX)
@ 2014-07-22  9:27 Dominik Vogt
  2014-07-22  9:35 ` [RFC][PATCH 1/3] " Dominik Vogt
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Dominik Vogt @ 2014-07-22  9:27 UTC (permalink / raw)
  To: libffi-discuss

The following series of patches introduces a framework for C
complex types (FFI_TYPE_COMPLEX) and support for complex types on
s390/s390x.  For now, an architecture that supports complex types
has to define FFI_TARGET_HAS_COMPLEX_TYPE to activate the support.
This can be changed in the future when most architecture have
implemented it so that this is the default.  The patch does not
address complex support in java_raw_api.c (as there is no
documentation how this interface is supposed to work).

Complex support in libffi is necessary to support the complex
types with the reflection interface of the libgo of the Go
programming language (gccgo).

* Patch 1/3: Somewhat reduce the macro hell.

This is a general cleanup patch that reduces the complexity of
some preprocessor macros.  It is not strictly necessary, but it
simplifies the following patch.

* Patch 2/3: FFI_TYPE_COMPLEX framework

The patch introducing the FFI_TYPE_COMPLEX framework, including
documentation and test cases.  Note that the patch introduces
predefined ffi_types for complex float, complex double and complex
longdouble but also supports the non-standard complex types that
gcc supports (the ffi_types have to be defined manually for them).
(See documentation for details.)

* Patch 3/3: S390: Implement FFI_TYPE_COMPLEX

A simple patch that implements the s390-abi for complex types.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC][PATCH 1/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
@ 2014-07-22  9:35 ` Dominik Vogt
  2014-07-23  8:41   ` Dominik Vogt
  2014-07-22  9:36 ` [RFC][PATCH 3/3] " Dominik Vogt
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Dominik Vogt @ 2014-07-22  9:35 UTC (permalink / raw)
  To: libffi-discuss

[-- Attachment #1: Type: text/plain, Size: 689 bytes --]

ChangeLog:

--
2014-07-22  Dominik Vogt  <vogt@linux.vnet.ibm.com>

	* src/types.c (FFI_TYPEDEF, FFI_NONCONST_TYPEDEF): Merge the macros by
	adding another argument that controls whether the result is const or not
	(FFI_LDBL_CONST): Temporary macro to reduce ifdef confusion
	* src/prep_cif.c (ffi_prep_cif_core): Replace list of systems with new
	macro FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
	* src/pa/ffitarget.h (FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION):
	Define.
	* src/s390/ffitarget.h (FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION):
	Define.
	* src/x86/ffitarget.h (FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION):
	Define.
--

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

[-- Attachment #2: 0001-Somewhat-reduce-the-macro-hell.patch --]
[-- Type: text/x-diff, Size: 5086 bytes --]

From 3d67e987080a73847034d1b700c7e8bf0e717ded Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@de.ibm.com>
Date: Tue, 22 Jul 2014 09:59:35 +0100
Subject: [PATCH 1/3] Somewhat reduce the macro hell.

---
 src/pa/ffitarget.h   |  2 ++
 src/prep_cif.c       |  4 ++--
 src/s390/ffitarget.h |  1 +
 src/types.c          | 49 ++++++++++++++++++++-----------------------------
 src/x86/ffitarget.h  |  2 ++
 5 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/src/pa/ffitarget.h b/src/pa/ffitarget.h
index 5e364d3..fff4c6b 100644
--- a/src/pa/ffitarget.h
+++ b/src/pa/ffitarget.h
@@ -62,6 +62,8 @@ typedef enum ffi_abi {
 } ffi_abi;
 #endif
 
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+
 /* ---- Definitions for closures ----------------------------------------- */
 
 #define FFI_CLOSURES 1
diff --git a/src/prep_cif.c b/src/prep_cif.c
index 55ceed8..955bac1 100644
--- a/src/prep_cif.c
+++ b/src/prep_cif.c
@@ -140,7 +140,7 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
   FFI_ASSERT_VALID_TYPE(cif->rtype);
 
   /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
-#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
+#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
   /* Make space for the return structure pointer */
   if (cif->rtype->type == FFI_TYPE_STRUCT
 #ifdef SPARC
@@ -170,7 +170,7 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
 	 check after the initialization.  */
       FFI_ASSERT_VALID_TYPE(*ptr);
 
-#if !defined X86_ANY && !defined S390 && !defined PA
+#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
 #ifdef SPARC
       if (((*ptr)->type == FFI_TYPE_STRUCT
 	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
diff --git a/src/s390/ffitarget.h b/src/s390/ffitarget.h
index 97fa5c4..7700f26 100644
--- a/src/s390/ffitarget.h
+++ b/src/s390/ffitarget.h
@@ -52,6 +52,7 @@ typedef enum ffi_abi {
 } ffi_abi;
 #endif
 
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
 
 /* ---- Definitions for closures ----------------------------------------- */
 
diff --git a/src/types.c b/src/types.c
index 0de5994..e32e111 100644
--- a/src/types.c
+++ b/src/types.c
@@ -33,23 +33,12 @@
 
 /* Type definitions */
 
-#define FFI_TYPEDEF(name, type, id)		\
+#define FFI_TYPEDEF(name, type, id, maybe_const)\
 struct struct_align_##name {			\
   char c;					\
   type x;					\
 };						\
-const ffi_type ffi_type_##name = {		\
-  sizeof(type),					\
-  offsetof(struct struct_align_##name, x),	\
-  id, NULL					\
-}
-
-#define FFI_NONCONST_TYPEDEF(name, type, id)	\
-struct struct_align_##name {			\
-  char c;					\
-  type x;					\
-};						\
-ffi_type ffi_type_##name = {			\
+maybe_const ffi_type ffi_type_##name = {	\
   sizeof(type),					\
   offsetof(struct struct_align_##name, x),	\
   id, NULL					\
@@ -60,19 +49,25 @@ const ffi_type ffi_type_void = {
   1, 1, FFI_TYPE_VOID, NULL
 };
 
-FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8);
-FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8);
-FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16);
-FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16);
-FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32);
-FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32);
-FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64);
-FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64);
+FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8, const);
+FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8, const);
+FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16, const);
+FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16, const);
+FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32, const);
+FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32, const);
+FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64, const);
+FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64, const);
 
-FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER);
+FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER, const);
 
-FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
-FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
+FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT, const);
+FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const);
+
+#if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__
+#define FFI_LDBL_CONST const
+#else
+#define FFI_LDBL_CONST
+#endif
 
 #ifdef __alpha__
 /* Even if we're not configured to default to 128-bit long double, 
@@ -84,9 +79,5 @@ FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
 # endif
 const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
 #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-# if HAVE_LONG_DOUBLE_VARIANT
-FFI_NONCONST_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
-# else
-FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
-# endif
+FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE, FFI_LDBL_CONST);
 #endif
diff --git a/src/x86/ffitarget.h b/src/x86/ffitarget.h
index b2afe91..9cc53cf 100644
--- a/src/x86/ffitarget.h
+++ b/src/x86/ffitarget.h
@@ -49,6 +49,8 @@
 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
 #endif
 
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+
 /* ---- Generic type definitions ----------------------------------------- */
 
 #ifndef LIBFFI_ASM
-- 
1.8.4.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC][PATCH 3/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
  2014-07-22  9:35 ` [RFC][PATCH 1/3] " Dominik Vogt
@ 2014-07-22  9:36 ` Dominik Vogt
  2014-07-22  9:36 ` [RFC][PATCH 2/3] " Dominik Vogt
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Dominik Vogt @ 2014-07-22  9:36 UTC (permalink / raw)
  To: libffi-discuss

[-- Attachment #1: Type: text/plain, Size: 388 bytes --]

ChangeLog:

--
2014-07-22  Dominik Vogt  <vogt@linux.vnet.ibm.com>

	* src/s390/ffitarget.h (FFI_TARGET_HAS_COMPLEX_TYPE): Define to provide
	FFI_TYPE_COMPLEX support.
	* src/s390/ffi.c (ffi_check_struct_type): Implement FFI_TYPE_COMPLEX
	(ffi_prep_args): Ditto.
	(ffi_prep_cif_machdep): Ditto.
	(ffi_closure_helper_SYSV): Ditto.
--

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

[-- Attachment #2: 0003-S390-Implement-FFI_TYPE_COMPLEX.patch --]
[-- Type: text/x-diff, Size: 3003 bytes --]

From 2fce72b95c240c35248df92e541d8596369ece53 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@de.ibm.com>
Date: Tue, 22 Jul 2014 10:04:41 +0100
Subject: [PATCH 3/3] S390: Implement FFI_TYPE_COMPLEX

---
 src/s390/ffi.c       | 25 ++++++++++++++++++-------
 src/s390/ffitarget.h |  1 +
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/s390/ffi.c b/src/s390/ffi.c
index 8adb5bc..520ec7c 100644
--- a/src/s390/ffi.c
+++ b/src/s390/ffi.c
@@ -215,9 +215,12 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif)
 #endif
 
       /* Check how a structure type is passed.  */
-      if (type == FFI_TYPE_STRUCT)
+      if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
 	{
-	  type = ffi_check_struct_type (*ptr);
+	  if (type == FFI_TYPE_COMPLEX)
+	    type = FFI_TYPE_POINTER;
+	  else
+	    type = ffi_check_struct_type (*ptr);
 
 	  /* If we pass the struct via pointer, copy the data.  */
 	  if (type == FFI_TYPE_POINTER)
@@ -356,8 +359,9 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 	cif->flags = FFI390_RET_VOID;
 	break;
 
-      /* Structures are returned via a hidden pointer.  */
+      /* Structures and complex are returned via a hidden pointer.  */
       case FFI_TYPE_STRUCT:
+      case FFI_TYPE_COMPLEX:
 	cif->flags = FFI390_RET_STRUCT;
 	n_gpr++;  /* We need one GPR to pass the pointer.  */
 	break; 
@@ -420,9 +424,12 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 #endif
 
       /* Check how a structure type is passed.  */
-      if (type == FFI_TYPE_STRUCT)
+      if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
 	{
-	  type = ffi_check_struct_type (*ptr);
+	  if (type == FFI_TYPE_COMPLEX)
+	    type = FFI_TYPE_POINTER;
+	  else
+	    type = ffi_check_struct_type (*ptr);
 
 	  /* If we pass the struct via pointer, we must reserve space
 	     to copy its data for proper call-by-value semantics.  */
@@ -588,9 +595,12 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
 #endif
 
       /* Check how a structure type is passed.  */
-      if (type == FFI_TYPE_STRUCT)
+      if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
 	{
-	  type = ffi_check_struct_type (*ptr);
+	  if (type == FFI_TYPE_COMPLEX)
+	    type = FFI_TYPE_POINTER;
+	  else
+	    type = ffi_check_struct_type (*ptr);
 
 	  /* If we pass the struct via pointer, remember to 
 	     retrieve the pointer later.  */
@@ -687,6 +697,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
       /* Void is easy, and so is struct.  */
       case FFI_TYPE_VOID:
       case FFI_TYPE_STRUCT:
+      case FFI_TYPE_COMPLEX:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
       case FFI_TYPE_LONGDOUBLE:
 #endif
diff --git a/src/s390/ffitarget.h b/src/s390/ffitarget.h
index 7700f26..0e4868a 100644
--- a/src/s390/ffitarget.h
+++ b/src/s390/ffitarget.h
@@ -53,6 +53,7 @@ typedef enum ffi_abi {
 #endif
 
 #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#define FFI_TARGET_HAS_COMPLEX_TYPE
 
 /* ---- Definitions for closures ----------------------------------------- */
 
-- 
1.8.4.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC][PATCH 2/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
  2014-07-22  9:35 ` [RFC][PATCH 1/3] " Dominik Vogt
  2014-07-22  9:36 ` [RFC][PATCH 3/3] " Dominik Vogt
@ 2014-07-22  9:36 ` Dominik Vogt
  2014-09-23 13:17   ` Alan Lawrence
  2014-08-20  6:57 ` [PING][RFC][PATCH 0/3] " Dominik Vogt
  2014-09-20 10:31 ` [RFC][PATCH " Anthony Green
  4 siblings, 1 reply; 9+ messages in thread
From: Dominik Vogt @ 2014-07-22  9:36 UTC (permalink / raw)
  To: libffi-discuss

[-- Attachment #1: Type: text/plain, Size: 2791 bytes --]

ChangeLog:
--
2014-07-22  Dominik Vogt  <vogt@linux.vnet.ibm.com>

	* doc/libffi.texi (Primitive Types): Document ffi_type_complex_float,
	ffi_type_complex_double and ffi_type_complex_longdouble
	(Complex Types): New subsection.
	(Complex Type Example): Ditto.
	* testsuite/libffi.call/cls_align_complex_double.c: New
	FFI_TYPE_COMPLEX test.
	* testsuite/libffi.call/cls_align_complex_float.c: Ditto.
	* testsuite/libffi.call/cls_align_complex_longdouble.c: Ditto.
	* testsuite/libffi.call/cls_complex_double.c: Ditto.
	* testsuite/libffi.call/cls_complex_float.c: Ditto.
	* testsuite/libffi.call/cls_complex_longdouble.c: Ditto.
	* testsuite/libffi.call/cls_complex_struct_double.c: Ditto.
	* testsuite/libffi.call/cls_complex_struct_float.c: Ditto.
	* testsuite/libffi.call/cls_complex_struct_longdouble.c: Ditto.
	* testsuite/libffi.call/cls_complex_va_double.c: Ditto.
	* testsuite/libffi.call/cls_complex_va_float.c: Ditto.
	* testsuite/libffi.call/cls_complex_va_longdouble.c: Ditto.
	* testsuite/libffi.call/complex_double.c: Ditto.
	* testsuite/libffi.call/complex_defs_double.c: Ditto.
	* testsuite/libffi.call/complex_float.c: Ditto.
	* testsuite/libffi.call/complex_defs_float.c: Ditto.
	* testsuite/libffi.call/complex_longdouble.c: Ditto.
	* testsuite/libffi.call/complex_defs_longdouble.c: Ditto.
	* testsuite/libffi.call/complex_int.c: Ditto.
	* testsuite/libffi.call/many_complex_double.c: Ditto.
	* testsuite/libffi.call/many_complex_float.c: Ditto.
	* testsuite/libffi.call/many_complex_longdouble.c: Ditto.
	* testsuite/libffi.call/return_complex1_double.c: Ditto.
	* testsuite/libffi.call/return_complex1_float.c: Ditto.
	* testsuite/libffi.call/return_complex1_longdouble.c: Ditto.
	* testsuite/libffi.call/return_complex2_double.c: Ditto.
	* testsuite/libffi.call/return_complex2_float.c: Ditto.
	* testsuite/libffi.call/return_complex2_longdouble.c: Ditto.
	* testsuite/libffi.call/return_complex_double.c: Ditto.
	* testsuite/libffi.call/return_complex_float.c: Ditto.
	* testsuite/libffi.call/return_complex_longdouble.c: Ditto.
	* src/raw_api.c (ffi_raw_to_ptrarray): Handle FFI_TYPE_COMPLEX
	(ffi_ptrarray_to_raw): Ditto.
	* src/prep_cif.c (ffi_prep_cif_core): Abort if FFI_TYPE_COMPLEX is not
	implemented in libffi for the target.
	* src/java_raw_api.c (ffi_java_raw_size): FFI_TYPE_COMPLEX not supported
	yet (abort).
	(ffi_java_raw_to_ptrarray): Ditto.
	(ffi_java_rvalue_to_raw): Ditto.
	(ffi_java_raw_to_rvalue):  Ditto.
	* src/debug.c (ffi_type_test): Add debug tests for complex types.
	* include/ffi.h.in (FFI_TYPE_COMPLEX): Add new FFI_TYPE_COMPLEX.
	(FFI_TYPE_LAST): Bump.
	(ffi_type_complex_float): Add new ffi_type_....
	(ffi_type_complex_double): Ditto.
	(ffi_type_complex_longdouble): Ditto.
--

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

[-- Attachment #2: 0002-FFI_TYPE_COMPLEX-framework.patch --]
[-- Type: text/x-diff, Size: 50222 bytes --]

From ac37948b28d4a62f34705df6835d8bdf539e6d62 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@de.ibm.com>
Date: Tue, 22 Jul 2014 10:02:07 +0100
Subject: [PATCH 2/3] FFI_TYPE_COMPLEX framework

---
 doc/libffi.texi                                    | 145 +++++++++++++++++++++
 include/ffi.h.in                                   |  13 +-
 src/debug.c                                        |   7 +-
 src/java_raw_api.c                                 |  18 +++
 src/prep_cif.c                                     |   8 ++
 src/raw_api.c                                      |  13 ++
 src/types.c                                        |  23 ++++
 testsuite/libffi.call/cls_align_complex.inc        |  91 +++++++++++++
 testsuite/libffi.call/cls_align_complex_double.c   |  10 ++
 testsuite/libffi.call/cls_align_complex_float.c    |  10 ++
 .../libffi.call/cls_align_complex_longdouble.c     |  10 ++
 testsuite/libffi.call/cls_complex.inc              |  42 ++++++
 testsuite/libffi.call/cls_complex_double.c         |  10 ++
 testsuite/libffi.call/cls_complex_float.c          |  10 ++
 testsuite/libffi.call/cls_complex_longdouble.c     |  10 ++
 testsuite/libffi.call/cls_complex_struct.inc       |  71 ++++++++++
 testsuite/libffi.call/cls_complex_struct_double.c  |  10 ++
 testsuite/libffi.call/cls_complex_struct_float.c   |  10 ++
 .../libffi.call/cls_complex_struct_longdouble.c    |  10 ++
 testsuite/libffi.call/cls_complex_va.inc           |  80 ++++++++++++
 testsuite/libffi.call/cls_complex_va_double.c      |  10 ++
 testsuite/libffi.call/cls_complex_va_float.c       |  10 ++
 testsuite/libffi.call/cls_complex_va_longdouble.c  |  10 ++
 testsuite/libffi.call/complex.inc                  |  51 ++++++++
 testsuite/libffi.call/complex_defs_double.inc      |   7 +
 testsuite/libffi.call/complex_defs_float.inc       |   7 +
 testsuite/libffi.call/complex_defs_longdouble.inc  |   7 +
 testsuite/libffi.call/complex_double.c             |  10 ++
 testsuite/libffi.call/complex_float.c              |  10 ++
 testsuite/libffi.call/complex_int.c                |  86 ++++++++++++
 testsuite/libffi.call/complex_longdouble.c         |  10 ++
 testsuite/libffi.call/many_complex.inc             |  78 +++++++++++
 testsuite/libffi.call/many_complex_double.c        |  10 ++
 testsuite/libffi.call/many_complex_float.c         |  10 ++
 testsuite/libffi.call/many_complex_longdouble.c    |  10 ++
 testsuite/libffi.call/return_complex.inc           |  37 ++++++
 testsuite/libffi.call/return_complex1.inc          |  41 ++++++
 testsuite/libffi.call/return_complex1_double.c     |  10 ++
 testsuite/libffi.call/return_complex1_float.c      |  10 ++
 testsuite/libffi.call/return_complex1_longdouble.c |  10 ++
 testsuite/libffi.call/return_complex2.inc          |  40 ++++++
 testsuite/libffi.call/return_complex2_double.c     |  10 ++
 testsuite/libffi.call/return_complex2_float.c      |  10 ++
 testsuite/libffi.call/return_complex2_longdouble.c |  10 ++
 testsuite/libffi.call/return_complex_double.c      |  10 ++
 testsuite/libffi.call/return_complex_float.c       |  10 ++
 testsuite/libffi.call/return_complex_longdouble.c  |  10 ++
 47 files changed, 1133 insertions(+), 2 deletions(-)
 create mode 100644 testsuite/libffi.call/cls_align_complex.inc
 create mode 100644 testsuite/libffi.call/cls_align_complex_double.c
 create mode 100644 testsuite/libffi.call/cls_align_complex_float.c
 create mode 100644 testsuite/libffi.call/cls_align_complex_longdouble.c
 create mode 100644 testsuite/libffi.call/cls_complex.inc
 create mode 100644 testsuite/libffi.call/cls_complex_double.c
 create mode 100644 testsuite/libffi.call/cls_complex_float.c
 create mode 100644 testsuite/libffi.call/cls_complex_longdouble.c
 create mode 100644 testsuite/libffi.call/cls_complex_struct.inc
 create mode 100644 testsuite/libffi.call/cls_complex_struct_double.c
 create mode 100644 testsuite/libffi.call/cls_complex_struct_float.c
 create mode 100644 testsuite/libffi.call/cls_complex_struct_longdouble.c
 create mode 100644 testsuite/libffi.call/cls_complex_va.inc
 create mode 100644 testsuite/libffi.call/cls_complex_va_double.c
 create mode 100644 testsuite/libffi.call/cls_complex_va_float.c
 create mode 100644 testsuite/libffi.call/cls_complex_va_longdouble.c
 create mode 100644 testsuite/libffi.call/complex.inc
 create mode 100644 testsuite/libffi.call/complex_defs_double.inc
 create mode 100644 testsuite/libffi.call/complex_defs_float.inc
 create mode 100644 testsuite/libffi.call/complex_defs_longdouble.inc
 create mode 100644 testsuite/libffi.call/complex_double.c
 create mode 100644 testsuite/libffi.call/complex_float.c
 create mode 100644 testsuite/libffi.call/complex_int.c
 create mode 100644 testsuite/libffi.call/complex_longdouble.c
 create mode 100644 testsuite/libffi.call/many_complex.inc
 create mode 100644 testsuite/libffi.call/many_complex_double.c
 create mode 100644 testsuite/libffi.call/many_complex_float.c
 create mode 100644 testsuite/libffi.call/many_complex_longdouble.c
 create mode 100644 testsuite/libffi.call/return_complex.inc
 create mode 100644 testsuite/libffi.call/return_complex1.inc
 create mode 100644 testsuite/libffi.call/return_complex1_double.c
 create mode 100644 testsuite/libffi.call/return_complex1_float.c
 create mode 100644 testsuite/libffi.call/return_complex1_longdouble.c
 create mode 100644 testsuite/libffi.call/return_complex2.inc
 create mode 100644 testsuite/libffi.call/return_complex2_double.c
 create mode 100644 testsuite/libffi.call/return_complex2_float.c
 create mode 100644 testsuite/libffi.call/return_complex2_longdouble.c
 create mode 100644 testsuite/libffi.call/return_complex_double.c
 create mode 100644 testsuite/libffi.call/return_complex_float.c
 create mode 100644 testsuite/libffi.call/return_complex_longdouble.c

diff --git a/doc/libffi.texi b/doc/libffi.texi
index a2b1242..b1c9bc3 100644
--- a/doc/libffi.texi
+++ b/doc/libffi.texi
@@ -247,6 +247,8 @@ int main()
 * Primitive Types::             Built-in types.
 * Structures::                  Structure types.
 * Type Example::                Structure type example.
+* Complex::                     Complex types.
+* Complex Type Example::        Complex type example.
 @end menu
 
 @node Primitive Types
@@ -345,6 +347,20 @@ On other platforms, it is not.
 @tindex ffi_type_pointer
 A generic @code{void *} pointer.  You should use this for all
 pointers, regardless of their real type.
+
+@item ffi_type_complex_float
+@tindex ffi_type_complex_float
+The C @code{_Complex float} type.
+
+@item ffi_type_complex_double
+@tindex ffi_type_complex_double
+The C @code{_Complex double} type.
+
+@item ffi_type_complex_longdouble
+@tindex ffi_type_complex_longdouble
+The C @code{_Complex long double} type.
+On platforms that have a C @code{long double} type, this is defined.
+On other platforms, it is not.
 @end table
 
 Each of these is of type @code{ffi_type}, so you must take the address
@@ -429,6 +445,135 @@ Here is the corresponding code to describe this struct to
     @}
 @end example
 
+@node Complex
+@subsection Complex Types
+
+@samp{libffi} supports the complex types defined by the C99
+standard (@code{_Complex float}, @code{_Complex double} and
+@code{_Complex long double} with the built-in type descriptors
+@code{ffi_type_complex_float}, @code{ffi_type_complex_double} and
+@code{ffi_type_complex_longdouble}.
+
+Custom complex types like @code{_Complex int} can also be used.
+An @code{ffi_type} object has to be defined to describe the
+complex type to @samp{libffi}.
+
+@tindex ffi_type
+@deftp {Data type} ffi_type
+@table @code
+@item size_t size
+This must be manually set to the size of the complex type.
+
+@item unsigned short alignment
+This must be manually set to the alignment of the complex type.
+
+@item unsigned short type
+For a complex type, this must be set to @code{FFI_TYPE_COMPLEX}.
+
+@item ffi_type **elements
+
+This is a @samp{NULL}-terminated array of pointers to
+@code{ffi_type} objects.  The first element is set to the
+@code{ffi_type} of the complex's base type.  The second element
+must be set to @code{NULL}.
+@end table
+@end deftp
+
+The section @ref{Complex Type Example} shows a way to determine
+the @code{size} and @code{alignment} members in a platform
+independent way.
+
+For platforms that have no complex support in @code{libffi} yet,
+the functions @code{ffi_prep_cif} and @code{ffi_prep_args} abort
+the program if they encounter a complex type.
+
+@node Complex Type Example
+@subsection Complex Type Example
+
+This example demonstrates how to use complex types:
+
+@example
+#include <stdio.h>
+#include <ffi.h>
+#include <complex.h>
+
+void complex_fn(_Complex float cf,
+                _Complex double cd,
+                _Complex long double cld)
+@{
+  printf("cf=%f+%fi\ncd=%f+%fi\ncld=%f+%fi\n",
+         (float)creal (cf), (float)cimag (cf),
+         (float)creal (cd), (float)cimag (cd),
+         (float)creal (cld), (float)cimag (cld));
+@}
+
+int main()
+@{
+  ffi_cif cif;
+  ffi_type *args[3];
+  void *values[3];
+  _Complex float cf;
+  _Complex double cd;
+  _Complex long double cld;
+
+  /* Initialize the argument info vectors */
+  args[0] = &ffi_type_complex_float;
+  args[1] = &ffi_type_complex_double;
+  args[2] = &ffi_type_complex_longdouble;
+  values[0] = &cf;
+  values[1] = &cd;
+  values[2] = &cld;
+
+  /* Initialize the cif */
+  if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3,
+                   &ffi_type_void, args) == FFI_OK)
+    @{
+      cf = 1.0 + 20.0 * I;
+      cd = 300.0 + 4000.0 * I;
+      cld = 50000.0 + 600000.0 * I;
+      /* Call the function */
+      ffi_call(&cif, (void (*)(void))complex_fn, 0, values);
+    @}
+
+  return 0;
+@}
+@end example
+
+This is an example for defining a custom complex type descriptor
+for compilers that support them:
+
+@example
+/*
+ * This macro can be used to define new complex type descriptors
+ * in a platform independent way.
+ *
+ * name: Name of the new descriptor is ffi_type_complex_<name>.
+ * type: The C base type of the complex type.
+ */
+#define FFI_COMPLEX_TYPEDEF(name, type, ffitype)             \
+  static ffi_type *ffi_elements_complex_##name [2] = @{      \
+    (ffi_type *)(&ffitype), NULL                             \
+  @};                                                        \
+  struct struct_align_complex_##name @{                      \
+    char c;                                                  \
+    _Complex type x;                                         \
+  @};                                                        \
+  ffi_type ffi_type_complex_##name = @{                      \
+    sizeof(_Complex type),                                   \
+    offsetof(struct struct_align_complex_##name, x),         \
+    FFI_TYPE_COMPLEX,                                        \
+    (ffi_type **)ffi_elements_complex_##name                 \
+  @}
+
+/* Define new complex type descriptors using the macro: */
+/* ffi_type_complex_sint */
+FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint);
+/* ffi_type_complex_uchar */
+FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8);
+@end example
+
+The new type descriptors can then be used like one of the built-in
+type descriptors in the previous example.
 
 @node Multiple ABIs
 @section Multiple ABIs
diff --git a/include/ffi.h.in b/include/ffi.h.in
index 70c6179..fa6963a 100644
--- a/include/ffi.h.in
+++ b/include/ffi.h.in
@@ -199,6 +199,16 @@ FFI_EXTERN ffi_type ffi_type_longdouble;
 #else
 #define ffi_type_longdouble ffi_type_double
 #endif
+
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+FFI_EXTERN ffi_type ffi_type_complex_float;
+FFI_EXTERN ffi_type ffi_type_complex_double;
+#if @HAVE_LONG_DOUBLE@
+FFI_EXTERN ffi_type ffi_type_complex_longdouble;
+#else
+#define ffi_type_complex_longdouble ffi_type_complex_double
+#endif
+#endif
 #endif /* LIBFFI_HIDE_BASIC_TYPES */
 
 typedef enum {
@@ -465,9 +475,10 @@ void ffi_call(ffi_cif *cif,
 #define FFI_TYPE_SINT64     12
 #define FFI_TYPE_STRUCT     13
 #define FFI_TYPE_POINTER    14
+#define FFI_TYPE_COMPLEX    15
 
 /* This should always refer to the last type code (for sanity checks) */
-#define FFI_TYPE_LAST       FFI_TYPE_POINTER
+#define FFI_TYPE_LAST       FFI_TYPE_COMPLEX
 
 #ifdef __cplusplus
 }
diff --git a/src/debug.c b/src/debug.c
index 51dcfcf..f3172b1 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -54,6 +54,11 @@ void ffi_type_test(ffi_type *a, char *file, int line)
   FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line);
   FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line);
   FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line);
-  FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line);
+  FFI_ASSERT_AT((a->type != FFI_TYPE_STRUCT && a->type != FFI_TYPE_COMPLEX)
+		|| a->elements != NULL, file, line);
+  FFI_ASSERT_AT(a->type != FFI_TYPE_COMPLEX
+		|| (a->elements != NULL
+		    && a->elements[0] != NULL && a->elements[1] == NULL),
+		file, line);
 
 }
diff --git a/src/java_raw_api.c b/src/java_raw_api.c
index 522c8bf..15664b4 100644
--- a/src/java_raw_api.c
+++ b/src/java_raw_api.c
@@ -60,6 +60,9 @@ ffi_java_raw_size (ffi_cif *cif)
 	case FFI_TYPE_STRUCT:
 	  /* No structure parameters in Java.	*/
 	  abort();
+	case FFI_TYPE_COMPLEX:
+	  /* Not supported yet.  */
+	  abort();
 	default:
 	  result += FFI_SIZEOF_JAVA_RAW;
       }
@@ -104,6 +107,10 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
 	  *args = (void*) &(raw++)->ptr;
 	  break;
 
+	case FFI_TYPE_COMPLEX:
+	  /* Not supported yet.  */
+	  abort();
+
 	default:
 	  *args = raw;
 	  raw +=
@@ -126,6 +133,9 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
 	  *args = (void*) raw;
 	  raw += 2;
 	  break;
+	case FFI_TYPE_COMPLEX:
+	  /* Not supported yet.  */
+	  abort();
 	default:
 	  *args = (void*) raw++;
       }
@@ -254,6 +264,10 @@ ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
       *(SINT64 *)rvalue <<= 32;
       break;
 
+    case FFI_TYPE_COMPLEX:
+      /* Not supported yet.  */
+      abort();
+
     default:
       break;
     }
@@ -279,6 +293,10 @@ ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
       *(SINT64 *)rvalue >>= 32;
       break;
 
+    case FFI_TYPE_COMPLEX:
+      /* Not supported yet.  */
+      abort();
+
     default:
       break;
     }
diff --git a/src/prep_cif.c b/src/prep_cif.c
index 955bac1..be5eae3 100644
--- a/src/prep_cif.c
+++ b/src/prep_cif.c
@@ -136,6 +136,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
   if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
     return FFI_BAD_TYPEDEF;
 
+#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
+  if (rtype->type == FFI_TYPE_COMPLEX)
+    abort();
+#endif
   /* Perform a sanity check on the return type */
   FFI_ASSERT_VALID_TYPE(cif->rtype);
 
@@ -166,6 +170,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
       if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
 	return FFI_BAD_TYPEDEF;
 
+#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
+      if ((*ptr)->type == FFI_TYPE_COMPLEX)
+	abort();
+#endif
       /* Perform a sanity check on the argument type, do this
 	 check after the initialization.  */
       FFI_ASSERT_VALID_TYPE(*ptr);
diff --git a/src/raw_api.c b/src/raw_api.c
index ce21372..276cb22 100644
--- a/src/raw_api.c
+++ b/src/raw_api.c
@@ -88,6 +88,10 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
 	  break;
 #endif
 
+	case FFI_TYPE_COMPLEX:
+	  *args = (raw++)->ptr;
+	  break;
+
 	case FFI_TYPE_POINTER:
 	  *args = (void*) &(raw++)->ptr;
 	  break;
@@ -112,6 +116,11 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
 	}
       else
 #endif
+      if ((*tp)->type == FFI_TYPE_COMPLEX)
+	{
+	  *args = (raw++)->ptr;
+	}
+      else
 	{
 	  *args = (void*) raw;
 	  raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
@@ -167,6 +176,10 @@ ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
 	  break;
 #endif
 
+	case FFI_TYPE_COMPLEX:
+	  (raw++)->ptr = *args;
+	  break;
+
 	case FFI_TYPE_POINTER:
 	  (raw++)->ptr = **(void***) args;
 	  break;
diff --git a/src/types.c b/src/types.c
index e32e111..7e80aec 100644
--- a/src/types.c
+++ b/src/types.c
@@ -44,6 +44,21 @@ maybe_const ffi_type ffi_type_##name = {	\
   id, NULL					\
 }
 
+#define FFI_COMPLEX_TYPEDEF(name, type, maybe_const)	\
+static ffi_type *ffi_elements_complex_##name [2] = {	\
+	(ffi_type *)(&ffi_type_##name), NULL		\
+};							\
+struct struct_align_complex_##name {			\
+  char c;						\
+  _Complex type x;					\
+};							\
+maybe_const ffi_type ffi_type_complex_##name = {	\
+  sizeof(_Complex type),				\
+  offsetof(struct struct_align_complex_##name, x),	\
+  FFI_TYPE_COMPLEX,					\
+  (ffi_type **)ffi_elements_complex_##name		\
+}
+
 /* Size and alignment are fake here. They must not be 0. */
 const ffi_type ffi_type_void = {
   1, 1, FFI_TYPE_VOID, NULL
@@ -81,3 +96,11 @@ const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
 #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE, FFI_LDBL_CONST);
 #endif
+
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+FFI_COMPLEX_TYPEDEF(float, float, const);
+FFI_COMPLEX_TYPEDEF(double, double, const);
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+FFI_COMPLEX_TYPEDEF(longdouble, long double, FFI_LDBL_CONST);
+#endif
+#endif
diff --git a/testsuite/libffi.call/cls_align_complex.inc b/testsuite/libffi.call/cls_align_complex.inc
new file mode 100644
index 0000000..4a812ed
--- /dev/null
+++ b/testsuite/libffi.call/cls_align_complex.inc
@@ -0,0 +1,91 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+typedef struct cls_struct_align {
+  unsigned char a;
+  _Complex T_C_TYPE b;
+  unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(
+	struct cls_struct_align a1, struct cls_struct_align a2)
+{
+  struct cls_struct_align result;
+
+  result.a = a1.a + a2.a;
+  result.b = a1.b + a2.b;
+  result.c = a1.c + a2.c;
+
+  printf("%d %f,%fi %d %d %f,%fi %d: %d %f,%fi %d\n",
+	 a1.a, T_CONV creal (a1.b), T_CONV cimag (a1.b), a1.c,
+	 a2.a, T_CONV creal (a2.b), T_CONV cimag (a2.b), a2.c,
+	 result.a, T_CONV creal (result.b), T_CONV cimag (result.b), result.c);
+
+  return  result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+		    void* userdata __UNUSED__)
+{
+
+  struct cls_struct_align a1, a2;
+
+  a1 = *(struct cls_struct_align*)(args[0]);
+  a2 = *(struct cls_struct_align*)(args[1]);
+
+  *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  void *code;
+  ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+  void* args_c[5];
+  ffi_type* cls_struct_fields[4];
+  ffi_type cls_struct_type;
+  ffi_type* c_arg_types[5];
+
+  struct cls_struct_align g_c = { 12, 4951 + 7 * I, 127 };
+  struct cls_struct_align f_c = { 1, 9320 + 1 * I, 13 };
+  struct cls_struct_align res_c;
+
+  cls_struct_type.size = 0;
+  cls_struct_type.alignment = 0;
+  cls_struct_type.type = FFI_TYPE_STRUCT;
+  cls_struct_type.elements = cls_struct_fields;
+
+  cls_struct_fields[0] = &ffi_type_uchar;
+  cls_struct_fields[1] = &T_FFI_TYPE;
+  cls_struct_fields[2] = &ffi_type_uchar;
+  cls_struct_fields[3] = NULL;
+
+  c_arg_types[0] = &cls_struct_type;
+  c_arg_types[1] = &cls_struct_type;
+  c_arg_types[2] = NULL;
+
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+		     c_arg_types) == FFI_OK);
+
+  args_c[0] = &g_c;
+  args_c[1] = &f_c;
+  args_c[2] = NULL;
+
+  ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_c, args_c);
+  /* { dg-output "12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */
+  printf("res: %d %f,%fi %d\n",
+	 res_c.a, T_CONV  creal (res_c.b), T_CONV  cimag (res_c.b), res_c.c);
+  /* { dg-output "\nres: 13 14271,8i 140" } */
+
+  CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+  res_c = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_c, f_c);
+  /* { dg-output "\n12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */
+  printf("res: %d %f,%fi %d\n",
+	 res_c.a, T_CONV  creal (res_c.b), T_CONV  cimag (res_c.b), res_c.c);
+  /* { dg-output "\nres: 13 14271,8i 140" } */
+
+  exit(0);
+}
diff --git a/testsuite/libffi.call/cls_align_complex_double.c b/testsuite/libffi.call/cls_align_complex_double.c
new file mode 100644
index 0000000..0dff23a
--- /dev/null
+++ b/testsuite/libffi.call/cls_align_complex_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check structure alignment of complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.call/cls_align_complex_float.c b/testsuite/libffi.call/cls_align_complex_float.c
new file mode 100644
index 0000000..0affbd0
--- /dev/null
+++ b/testsuite/libffi.call/cls_align_complex_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check structure alignment of complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.call/cls_align_complex_longdouble.c b/testsuite/libffi.call/cls_align_complex_longdouble.c
new file mode 100644
index 0000000..7889ba8
--- /dev/null
+++ b/testsuite/libffi.call/cls_align_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check structure alignment of complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.call/cls_complex.inc b/testsuite/libffi.call/cls_complex.inc
new file mode 100644
index 0000000..f937404
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex.inc
@@ -0,0 +1,42 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static void cls_ret_complex_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+			      void* userdata __UNUSED__)
+ {
+   _Complex T_C_TYPE *pa;
+   _Complex T_C_TYPE *pr;
+   pa = (_Complex T_C_TYPE *)args[0];
+   pr = (_Complex T_C_TYPE *)resp;
+   *pr = *pa;
+
+   printf("%.6f,%.6fi: %.6f,%.6fi\n",
+	  T_CONV creal (*pa), T_CONV cimag (*pa),
+	  T_CONV creal (*pr), T_CONV cimag (*pr));
+ }
+typedef _Complex T_C_TYPE (*cls_ret_complex)(_Complex T_C_TYPE);
+
+int main (void)
+{
+  ffi_cif cif;
+  void *code;
+  ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+  ffi_type * cl_arg_types[2];
+  _Complex T_C_TYPE res;
+
+  cl_arg_types[0] = &T_FFI_TYPE;
+  cl_arg_types[1] = NULL;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+		     &T_FFI_TYPE, cl_arg_types) == FFI_OK);
+
+  CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_complex_fn, NULL, code)  == FFI_OK);
+
+  res = (*((cls_ret_complex)code))(0.125 + 128.0 * I);
+  printf("res: %.6f,%.6fi\n", T_CONV creal (res), T_CONV cimag (res));
+  CHECK (res == (0.125 + 128.0 * I));
+
+  exit(0);
+}
diff --git a/testsuite/libffi.call/cls_complex_double.c b/testsuite/libffi.call/cls_complex_double.c
new file mode 100644
index 0000000..05e3534
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_double.c
@@ -0,0 +1,10 @@
+/* Area:	closure_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.call/cls_complex_float.c b/testsuite/libffi.call/cls_complex_float.c
new file mode 100644
index 0000000..5df7849
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_float.c
@@ -0,0 +1,10 @@
+/* Area:	closure_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.call/cls_complex_longdouble.c b/testsuite/libffi.call/cls_complex_longdouble.c
new file mode 100644
index 0000000..2b1c320
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	closure_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.call/cls_complex_struct.inc b/testsuite/libffi.call/cls_complex_struct.inc
new file mode 100644
index 0000000..df8708d
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_struct.inc
@@ -0,0 +1,71 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+typedef struct Cs {
+  _Complex T_C_TYPE x;
+  _Complex T_C_TYPE y;
+} Cs;
+
+Cs gc;
+
+void
+closure_test_fn(Cs p)
+{
+  printf("%.1f,%.1fi %.1f,%.1fi\n",
+	 T_CONV creal (p.x), T_CONV cimag (p.x),
+	 T_CONV creal (p.y), T_CONV cimag (p.y));
+  gc = p;
+}
+
+void
+closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+		void** args, void* userdata __UNUSED__)
+{
+  closure_test_fn(*(Cs*)args[0]);
+}
+
+int main(int argc __UNUSED__, char** argv __UNUSED__)
+{
+  ffi_cif cif;
+
+  void *code;
+  ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+  ffi_type *cl_arg_types[1];
+
+  ffi_type ts1_type;
+  ffi_type* ts1_type_elements[4];
+
+  Cs arg = { 1.0 + 11.0 * I, 2.0 + 22.0 * I};
+
+  ts1_type.size = 0;
+  ts1_type.alignment = 0;
+  ts1_type.type = FFI_TYPE_STRUCT;
+  ts1_type.elements = ts1_type_elements;
+
+  ts1_type_elements[0] = &T_FFI_TYPE;
+  ts1_type_elements[1] = &T_FFI_TYPE;
+  ts1_type_elements[2] = NULL;
+
+  cl_arg_types[0] = &ts1_type;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+		     &ffi_type_void, cl_arg_types) == FFI_OK);
+
+  CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK);
+
+  gc.x = 0.0 + 0.0 * I;
+  gc.y = 0.0 + 0.0 * I;
+  ((void*(*)(Cs))(code))(arg);
+  /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */
+  CHECK (gc.x == arg.x && gc.y == arg.y);
+
+  gc.x = 0.0 + 0.0 * I;
+  gc.y = 0.0 + 0.0 * I;
+  closure_test_fn(arg);
+  /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */
+  CHECK (gc.x == arg.x && gc.y == arg.y);
+
+  return 0;
+}
diff --git a/testsuite/libffi.call/cls_complex_struct_double.c b/testsuite/libffi.call/cls_complex_struct_double.c
new file mode 100644
index 0000000..ec71346
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_struct_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check complex arguments in structs.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.call/cls_complex_struct_float.c b/testsuite/libffi.call/cls_complex_struct_float.c
new file mode 100644
index 0000000..96fdf75
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_struct_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check complex arguments in structs.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.call/cls_complex_struct_longdouble.c b/testsuite/libffi.call/cls_complex_struct_longdouble.c
new file mode 100644
index 0000000..005b467
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_struct_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Check complex arguments in structs.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.call/cls_complex_va.inc b/testsuite/libffi.call/cls_complex_va.inc
new file mode 100644
index 0000000..8a3e15f
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_va.inc
@@ -0,0 +1,80 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <complex.h>
+
+static _Complex T_C_TYPE gComplexValue1 = 1 + 2 * I;
+static _Complex T_C_TYPE gComplexValue2 = 3 + 4 * I;
+
+static int cls_variadic(const char *format, ...)
+{
+  va_list ap;
+  _Complex T_C_TYPE p1, p2;
+
+  va_start (ap, format);
+  p1 = va_arg (ap, _Complex T_C_TYPE);
+  p2 = va_arg (ap, _Complex T_C_TYPE);
+  va_end (ap);
+
+  return printf(format, T_CONV creal (p1), T_CONV cimag (p1),
+		T_CONV creal (p2), T_CONV cimag (p2));
+}
+
+static void
+cls_complex_va_fn(ffi_cif* cif __UNUSED__, void* resp,
+		  void** args, void* userdata __UNUSED__)
+{
+  char*	format = *(char**)args[0];
+  gComplexValue1 = *(_Complex T_C_TYPE*)args[1];
+  gComplexValue2 = *(_Complex T_C_TYPE*)args[2];
+
+  *(ffi_arg*)resp =
+    printf(format,
+	   T_CONV creal (gComplexValue1), T_CONV cimag (gComplexValue1),
+	   T_CONV creal (gComplexValue2), T_CONV cimag (gComplexValue2));
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  void *code;
+  ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+  void* args[4];
+  ffi_type* arg_types[4];
+  char *format = "%.1f,%.1fi %.1f,%.1fi\n";
+
+  _Complex T_C_TYPE complexArg1 = 1.0 + 22.0 *I;
+  _Complex T_C_TYPE complexArg2 = 333.0 + 4444.0 *I;
+  ffi_arg res = 0;
+
+  arg_types[0] = &ffi_type_pointer;
+  arg_types[1] = &T_FFI_TYPE;
+  arg_types[2] = &T_FFI_TYPE;
+  arg_types[3] = NULL;
+
+  /* This printf call is variadic */
+  CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 3, &ffi_type_sint,
+			 arg_types) == FFI_OK);
+
+  args[0] = &format;
+  args[1] = &complexArg1;
+  args[2] = &complexArg2;
+  args[3] = NULL;
+
+  ffi_call(&cif, FFI_FN(cls_variadic), &res, args);
+  printf("res: %d\n", (int) res);
+  CHECK (res == 24);
+
+  CHECK(ffi_prep_closure_loc(pcl, &cif, cls_complex_va_fn, NULL, code)
+	== FFI_OK);
+
+  res = ((int(*)(char *, ...))(code))(format, complexArg1, complexArg2);
+  CHECK (gComplexValue1 == complexArg1);
+  CHECK (gComplexValue2 == complexArg2);
+  printf("res: %d\n", (int) res);
+  CHECK (res == 24);
+
+  exit(0);
+}
diff --git a/testsuite/libffi.call/cls_complex_va_double.c b/testsuite/libffi.call/cls_complex_va_double.c
new file mode 100644
index 0000000..879ccf3
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_va_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Test complex' passed in variable argument lists.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.call/cls_complex_va_float.c b/testsuite/libffi.call/cls_complex_va_float.c
new file mode 100644
index 0000000..0b79979
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_va_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Test complex' passed in variable argument lists.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.call/cls_complex_va_longdouble.c b/testsuite/libffi.call/cls_complex_va_longdouble.c
new file mode 100644
index 0000000..6eca965
--- /dev/null
+++ b/testsuite/libffi.call/cls_complex_va_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call, closure_call
+   Purpose:	Test complex' passed in variable argument lists.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.call/complex.inc b/testsuite/libffi.call/complex.inc
new file mode 100644
index 0000000..515ae3e
--- /dev/null
+++ b/testsuite/libffi.call/complex.inc
@@ -0,0 +1,51 @@
+/* -*-c-*-*/
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE f_complex(_Complex T_C_TYPE c, int x, int *py)
+{
+  c = -(2 * creal (c)) + (cimag (c) + 1)* I;
+  *py += x;
+
+  return c;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+
+  _Complex T_C_TYPE tc_arg;
+  _Complex T_C_TYPE tc_result;
+  int tc_int_arg_x;
+  int tc_y;
+  int *tc_ptr_arg_y = &tc_y;
+
+  args[0] = &T_FFI_TYPE;
+  args[1] = &ffi_type_sint;
+  args[2] = &ffi_type_pointer;
+  values[0] = &tc_arg;
+  values[1] = &tc_int_arg_x;
+  values[2] = &tc_ptr_arg_y;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3,
+		     &T_FFI_TYPE, args) == FFI_OK);
+
+  tc_arg = 1 + 7 * I;
+  tc_int_arg_x = 1234;
+  tc_y = 9876;
+  ffi_call(&cif, FFI_FN(f_complex), &tc_result, values);
+
+  printf ("%f,%fi %f,%fi, x %d 1234, y %d 11110\n",
+	  T_CONV creal (tc_result), T_CONV cimag (tc_result),
+	  T_CONV creal (2.0), T_CONV creal (8.0), tc_int_arg_x, tc_y);
+
+  CHECK (creal (tc_result) == -2);
+  CHECK (cimag (tc_result) == 8);
+  CHECK (tc_int_arg_x == 1234);
+  CHECK (*tc_ptr_arg_y == 11110);
+
+  exit(0);
+}
diff --git a/testsuite/libffi.call/complex_defs_double.inc b/testsuite/libffi.call/complex_defs_double.inc
new file mode 100644
index 0000000..3583e16
--- /dev/null
+++ b/testsuite/libffi.call/complex_defs_double.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type.  */
+#define T_FFI_TYPE ffi_type_complex_double
+/* C type corresponding to the base type.  */
+#define T_C_TYPE double
+/* C cast for a value of type T_C_TYPE that is passed to printf.  */
+#define T_CONV
diff --git a/testsuite/libffi.call/complex_defs_float.inc b/testsuite/libffi.call/complex_defs_float.inc
new file mode 100644
index 0000000..bbd9375
--- /dev/null
+++ b/testsuite/libffi.call/complex_defs_float.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type.  */
+#define T_FFI_TYPE ffi_type_complex_float
+/* C type corresponding to the base type.  */
+#define T_C_TYPE float
+/* C cast for a value of type T_C_TYPE that is passed to printf.  */
+#define T_CONV (double)
diff --git a/testsuite/libffi.call/complex_defs_longdouble.inc b/testsuite/libffi.call/complex_defs_longdouble.inc
new file mode 100644
index 0000000..14b9f24
--- /dev/null
+++ b/testsuite/libffi.call/complex_defs_longdouble.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type.  */
+#define T_FFI_TYPE ffi_type_complex_longdouble
+/* C type corresponding to the base type.  */
+#define T_C_TYPE long double
+/* C cast for a value of type T_C_TYPE that is passed to printf.  */
+#define T_CONV
diff --git a/testsuite/libffi.call/complex_double.c b/testsuite/libffi.call/complex_double.c
new file mode 100644
index 0000000..8a3297b
--- /dev/null
+++ b/testsuite/libffi.call/complex_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check complex types.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.call/complex_float.c b/testsuite/libffi.call/complex_float.c
new file mode 100644
index 0000000..5044ebb
--- /dev/null
+++ b/testsuite/libffi.call/complex_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check complex types.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.call/complex_int.c b/testsuite/libffi.call/complex_int.c
new file mode 100644
index 0000000..4c8e864
--- /dev/null
+++ b/testsuite/libffi.call/complex_int.c
@@ -0,0 +1,86 @@
+/* Area:	ffi_call
+   Purpose:	Check non-standard complex types.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+#include "ffi.h"
+#include <complex.h>
+
+_Complex int f_complex(_Complex int c, int x, int *py)
+{
+  c = -(2 * creal (c)) + (cimag (c) + 1)* I;
+  *py += x;
+
+  return c;
+}
+
+/*
+ * This macro can be used to define new complex type descriptors
+ * in a platform independent way.
+ *
+ * name: Name of the new descriptor is ffi_type_complex_<name>.
+ * type: The C base type of the complex type.
+ */
+#define FFI_COMPLEX_TYPEDEF(name, type, ffitype)	     \
+  static ffi_type *ffi_elements_complex_##name [2] = {	     \
+    (ffi_type *)(&ffitype), NULL			     \
+  };							     \
+  struct struct_align_complex_##name {			     \
+    char c;						     \
+    _Complex type x;					     \
+  };							     \
+  ffi_type ffi_type_complex_##name = {		     \
+    sizeof(_Complex type),				     \
+    offsetof(struct struct_align_complex_##name, x),	     \
+    FFI_TYPE_COMPLEX,					     \
+    (ffi_type **)ffi_elements_complex_##name		     \
+  }
+
+/* Define new complex type descriptors using the macro: */
+/* ffi_type_complex_sint */
+FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint);
+/* ffi_type_complex_uchar */
+FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8);
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+
+  _Complex int tc_arg;
+  _Complex int tc_result;
+  int tc_int_arg_x;
+  int tc_y;
+  int *tc_ptr_arg_y = &tc_y;
+
+  args[0] = &ffi_type_complex_sint;
+  args[1] = &ffi_type_sint;
+  args[2] = &ffi_type_pointer;
+  values[0] = &tc_arg;
+  values[1] = &tc_int_arg_x;
+  values[2] = &tc_ptr_arg_y;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &ffi_type_complex_sint, args)
+	== FFI_OK);
+
+  tc_arg = 1 + 7 * I;
+  tc_int_arg_x = 1234;
+  tc_y = 9876;
+  ffi_call(&cif, FFI_FN(f_complex), &tc_result, values);
+
+  printf ("%d,%di %d,%di, x %d 1234, y %d 11110\n",
+	  (int)tc_result, (int)(tc_result * -I), 2, 8, tc_int_arg_x, tc_y);
+  /* dg-output "-2,8i 2,8i, x 1234 1234, y 11110 11110" */
+  CHECK (creal (tc_result) == -2);
+  CHECK (cimag (tc_result) == 8);
+  CHECK (tc_int_arg_x == 1234);
+  CHECK (*tc_ptr_arg_y == 11110);
+
+  exit(0);
+}
diff --git a/testsuite/libffi.call/complex_longdouble.c b/testsuite/libffi.call/complex_longdouble.c
new file mode 100644
index 0000000..7e78366
--- /dev/null
+++ b/testsuite/libffi.call/complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check complex types.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.call/many_complex.inc b/testsuite/libffi.call/many_complex.inc
new file mode 100644
index 0000000..e37a774
--- /dev/null
+++ b/testsuite/libffi.call/many_complex.inc
@@ -0,0 +1,78 @@
+/* -*-c-*- */
+#include "ffitest.h"
+
+#include <stdlib.h>
+#include <complex.h>
+
+static _Complex T_C_TYPE many(_Complex T_C_TYPE c1,
+			      _Complex T_C_TYPE c2,
+			      _Complex T_C_TYPE c3,
+			      _Complex T_C_TYPE c4,
+			      _Complex T_C_TYPE c5,
+			      _Complex T_C_TYPE c6,
+			      _Complex T_C_TYPE c7,
+			      _Complex T_C_TYPE c8,
+			      _Complex T_C_TYPE c9,
+			      _Complex T_C_TYPE c10,
+			      _Complex T_C_TYPE c11,
+			      _Complex T_C_TYPE c12,
+			      _Complex T_C_TYPE c13)
+{
+  printf("0 :%f,%fi\n"
+	 "1 :%f,%fi\n"
+	 "2 :%f,%fi\n"
+	 "3 :%f,%fi\n"
+	 "4 :%f,%fi\n"
+	 "5 :%f,%fi\n"
+	 "6 :%f,%fi\n"
+	 "7 :%f,%fi\n"
+	 "8 :%f,%fi\n"
+	 "9 :%f,%fi\n"
+	 "10:%f,%fi\n"
+	 "11:%f,%fi\n"
+	 "12:%f,%fi\n",
+	 T_CONV creal (c1), T_CONV cimag (c1),
+	 T_CONV creal (c2), T_CONV cimag (c2),
+	 T_CONV creal (c3), T_CONV cimag (c3),
+	 T_CONV creal (c4), T_CONV cimag (c4),
+	 T_CONV creal (c5), T_CONV cimag (c5),
+	 T_CONV creal (c6), T_CONV cimag (c6),
+	 T_CONV creal (c7), T_CONV cimag (c7),
+	 T_CONV creal (c8), T_CONV cimag (c8),
+	 T_CONV creal (c9), T_CONV cimag (c9),
+	 T_CONV creal (c10), T_CONV cimag (c10),
+	 T_CONV creal (c11), T_CONV cimag (c11),
+	 T_CONV creal (c12), T_CONV cimag (c12),
+	 T_CONV creal (c13), T_CONV cimag (c13));
+
+  return (c1+c2-c3-c4+c5+c6+c7-c8-c9-c10-c11+c12+c13);
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[13];
+  void *values[13];
+  _Complex T_C_TYPE ca[13];
+  _Complex T_C_TYPE c, cc;
+  int i;
+
+  for (i = 0; i < 13; i++)
+    {
+      args[i] = &T_FFI_TYPE;
+      values[i] = &ca[i];
+      ca[i] = i + (-20 - i) * I;
+    }
+
+    /* Initialize the cif */
+    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, &T_FFI_TYPE, args) == FFI_OK);
+
+    ffi_call(&cif, FFI_FN(many), &c, values);
+
+    cc =  many(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7], ca[8],
+	       ca[9], ca[10], ca[11], ca[12]);
+    CHECK(creal (cc) == creal (c));
+    CHECK(cimag (cc) == cimag (c));
+
+    exit(0);
+}
diff --git a/testsuite/libffi.call/many_complex_double.c b/testsuite/libffi.call/many_complex_double.c
new file mode 100644
index 0000000..3fd53c3
--- /dev/null
+++ b/testsuite/libffi.call/many_complex_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex, with many arguments
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.call/many_complex_float.c b/testsuite/libffi.call/many_complex_float.c
new file mode 100644
index 0000000..c43d21c
--- /dev/null
+++ b/testsuite/libffi.call/many_complex_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex, with many arguments
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.call/many_complex_longdouble.c b/testsuite/libffi.call/many_complex_longdouble.c
new file mode 100644
index 0000000..dbab723
--- /dev/null
+++ b/testsuite/libffi.call/many_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex, with many arguments
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.call/return_complex.inc b/testsuite/libffi.call/return_complex.inc
new file mode 100644
index 0000000..8bf0c1f
--- /dev/null
+++ b/testsuite/libffi.call/return_complex.inc
@@ -0,0 +1,37 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c)
+{
+  printf ("%f,%fi\n", T_CONV creal (c), T_CONV cimag (c));
+  return 2 * c;
+}
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  _Complex T_C_TYPE c, rc, rc2;
+  T_C_TYPE cr, ci;
+
+  args[0] = &T_FFI_TYPE;
+  values[0] = &c;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+		     &T_FFI_TYPE, args) == FFI_OK);
+
+  for (cr = -127.0; cr <  127; cr++)
+    {
+      ci = 1000.0 - cr;
+      c = cr + ci * I;
+      ffi_call(&cif, FFI_FN(return_c), &rc, values);
+      rc2 = return_c(c);
+      printf ("%f,%fi vs %f,%fi\n",
+	      T_CONV creal (rc), T_CONV cimag (rc),
+	      T_CONV creal (rc2), T_CONV cimag (rc2));
+      CHECK(rc == 2 * c);
+    }
+  exit(0);
+}
diff --git a/testsuite/libffi.call/return_complex1.inc b/testsuite/libffi.call/return_complex1.inc
new file mode 100644
index 0000000..7cecc0f
--- /dev/null
+++ b/testsuite/libffi.call/return_complex1.inc
@@ -0,0 +1,41 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c1, float fl2, unsigned int in3, _Complex T_C_TYPE c4)
+{
+  return c1 + fl2 + in3 + c4;
+}
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  _Complex T_C_TYPE c1, c4, rc, rc2;
+  float fl2;
+  unsigned int in3;
+  args[0] = &T_FFI_TYPE;
+  args[1] = &ffi_type_float;
+  args[2] = &ffi_type_uint;
+  args[3] = &T_FFI_TYPE;
+  values[0] = &c1;
+  values[1] = &fl2;
+  values[2] = &in3;
+  values[3] = &c4;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+		     &T_FFI_TYPE, args) == FFI_OK);
+  c1 = 127.0 + 255.0 * I;
+  fl2 = 128.0;
+  in3 = 255;
+  c4 = 512.7 + 1024.1 * I;
+
+  ffi_call(&cif, FFI_FN(return_c), &rc, values);
+  rc2 = return_c(c1, fl2, in3, c4);
+  printf ("%f,%fi vs %f,%fi\n",
+	  T_CONV creal (rc), T_CONV cimag (rc),
+	  T_CONV creal (rc2), T_CONV cimag (rc2));
+  CHECK(rc == rc2);
+  exit(0);
+}
diff --git a/testsuite/libffi.call/return_complex1_double.c b/testsuite/libffi.call/return_complex1_double.c
new file mode 100644
index 0000000..727410d
--- /dev/null
+++ b/testsuite/libffi.call/return_complex1_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.call/return_complex1_float.c b/testsuite/libffi.call/return_complex1_float.c
new file mode 100644
index 0000000..a2aeada
--- /dev/null
+++ b/testsuite/libffi.call/return_complex1_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.call/return_complex1_longdouble.c b/testsuite/libffi.call/return_complex1_longdouble.c
new file mode 100644
index 0000000..103504b
--- /dev/null
+++ b/testsuite/libffi.call/return_complex1_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.call/return_complex2.inc b/testsuite/libffi.call/return_complex2.inc
new file mode 100644
index 0000000..dad4a0f
--- /dev/null
+++ b/testsuite/libffi.call/return_complex2.inc
@@ -0,0 +1,40 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c1, _Complex T_C_TYPE c2, unsigned int in3, _Complex T_C_TYPE c4)
+{
+  return c1 + c2 + in3 + c4;
+}
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  _Complex T_C_TYPE c1, c2, c4, rc, rc2;
+  unsigned int in3;
+  args[0] = &T_FFI_TYPE;
+  args[1] = &T_FFI_TYPE;
+  args[2] = &ffi_type_uint;
+  args[3] = &T_FFI_TYPE;
+  values[0] = &c1;
+  values[1] = &c2;
+  values[2] = &in3;
+  values[3] = &c4;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+		     &T_FFI_TYPE, args) == FFI_OK);
+  c1 = 127.0 + 255.0 * I;
+  c2 = 128.0 + 256.0;
+  in3 = 255;
+  c4 = 512.7 + 1024.1 * I;
+
+  ffi_call(&cif, FFI_FN(return_c), &rc, values);
+  rc2 = return_c(c1, c2, in3, c4);
+  printf ("%f,%fi vs %f,%fi\n",
+	  T_CONV creal (rc), T_CONV cimag (rc),
+	  T_CONV creal (rc2), T_CONV cimag (rc2));
+  CHECK(rc ==  c1 + c2 + in3 + c4);
+  exit(0);
+}
diff --git a/testsuite/libffi.call/return_complex2_double.c b/testsuite/libffi.call/return_complex2_double.c
new file mode 100644
index 0000000..ab9efac
--- /dev/null
+++ b/testsuite/libffi.call/return_complex2_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.call/return_complex2_float.c b/testsuite/libffi.call/return_complex2_float.c
new file mode 100644
index 0000000..d7f22c2
--- /dev/null
+++ b/testsuite/libffi.call/return_complex2_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.call/return_complex2_longdouble.c b/testsuite/libffi.call/return_complex2_longdouble.c
new file mode 100644
index 0000000..3edea62
--- /dev/null
+++ b/testsuite/libffi.call/return_complex2_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.call/return_complex_double.c b/testsuite/libffi.call/return_complex_double.c
new file mode 100644
index 0000000..e2497cc
--- /dev/null
+++ b/testsuite/libffi.call/return_complex_double.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex.inc"
diff --git a/testsuite/libffi.call/return_complex_float.c b/testsuite/libffi.call/return_complex_float.c
new file mode 100644
index 0000000..a35528f
--- /dev/null
+++ b/testsuite/libffi.call/return_complex_float.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex.inc"
diff --git a/testsuite/libffi.call/return_complex_longdouble.c b/testsuite/libffi.call/return_complex_longdouble.c
new file mode 100644
index 0000000..142d7be
--- /dev/null
+++ b/testsuite/libffi.call/return_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area:	ffi_call
+   Purpose:	Check return value complex.
+   Limitations:	none.
+   PR:		none.
+   Originator:	<vogt@linux.vnet.ibm.com>.  */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex.inc"
-- 
1.8.4.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC][PATCH 1/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:35 ` [RFC][PATCH 1/3] " Dominik Vogt
@ 2014-07-23  8:41   ` Dominik Vogt
  0 siblings, 0 replies; 9+ messages in thread
From: Dominik Vogt @ 2014-07-23  8:41 UTC (permalink / raw)
  To: libffi-discuss

On Tue, Jul 22, 2014 at 10:35:34AM +0100, Dominik Vogt wrote:
>    FFI_ASSERT_VALID_TYPE(cif->rtype);
> 
>    /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
> -#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
> +#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION

Just noticed that I forgot about M68K here.  The correct condition
is

  #if !defined M68K && !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION

unless ...

>        FFI_ASSERT_VALID_TYPE(*ptr);
> 
> -#if !defined X86_ANY && !defined S390 && !defined PA
> +#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION

... this condition forgets to check M68K by accident or in case it
does not matter.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PING][RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
                   ` (2 preceding siblings ...)
  2014-07-22  9:36 ` [RFC][PATCH 2/3] " Dominik Vogt
@ 2014-08-20  6:57 ` Dominik Vogt
  2014-09-20 10:31 ` [RFC][PATCH " Anthony Green
  4 siblings, 0 replies; 9+ messages in thread
From: Dominik Vogt @ 2014-08-20  6:57 UTC (permalink / raw)
  To: libffi-discuss

Ping.

On Tue, Jul 22, 2014 at 10:27:34AM +0100, Dominik Vogt wrote:
> The following series of patches introduces a framework for C
> complex types (FFI_TYPE_COMPLEX) and support for complex types on
> s390/s390x.  For now, an architecture that supports complex types
> has to define FFI_TARGET_HAS_COMPLEX_TYPE to activate the support.
> This can be changed in the future when most architecture have
> implemented it so that this is the default.  The patch does not
> address complex support in java_raw_api.c (as there is no
> documentation how this interface is supposed to work).
> 
> Complex support in libffi is necessary to support the complex
> types with the reflection interface of the libgo of the Go
> programming language (gccgo).
> 
> * Patch 1/3: Somewhat reduce the macro hell.
> 
> This is a general cleanup patch that reduces the complexity of
> some preprocessor macros.  It is not strictly necessary, but it
> simplifies the following patch.
> 
> * Patch 2/3: FFI_TYPE_COMPLEX framework
> 
> The patch introducing the FFI_TYPE_COMPLEX framework, including
> documentation and test cases.  Note that the patch introduces
> predefined ffi_types for complex float, complex double and complex
> longdouble but also supports the non-standard complex types that
> gcc supports (the ffi_types have to be defined manually for them).
> (See documentation for details.)
> 
> * Patch 3/3: S390: Implement FFI_TYPE_COMPLEX
> 
> A simple patch that implements the s390-abi for complex types.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
                   ` (3 preceding siblings ...)
  2014-08-20  6:57 ` [PING][RFC][PATCH 0/3] " Dominik Vogt
@ 2014-09-20 10:31 ` Anthony Green
  2014-09-29 10:24   ` Dominik Vogt
  4 siblings, 1 reply; 9+ messages in thread
From: Anthony Green @ 2014-09-20 10:31 UTC (permalink / raw)
  To: vogt; +Cc: libffi-discuss

Dominik Vogt <vogt@linux.vnet.ibm.com> writes:

> The following series of patches introduces a framework for C
> complex types (FFI_TYPE_COMPLEX) and support for complex types on
> s390/s390x.  For now, an architecture that supports complex types
> has to define FFI_TARGET_HAS_COMPLEX_TYPE to activate the support.
> This can be changed in the future when most architecture have
> implemented it so that this is the default.  The patch does not
> address complex support in java_raw_api.c (as there is no
> documentation how this interface is supposed to work).

Thank you for this tremendous effort, Dominik.

I'm not all that familiar with how GCC handles complex types on other
architectures, but hopefully they are as straight forward as on s390.

It would be nice if the complex test cases turned into expected failures
for platforms that don't have the back end support.

I've committed this patch to the libffi git repo.

AG

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC][PATCH 2/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-07-22  9:36 ` [RFC][PATCH 2/3] " Dominik Vogt
@ 2014-09-23 13:17   ` Alan Lawrence
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Lawrence @ 2014-09-23 13:17 UTC (permalink / raw)
  To: libffi-discuss; +Cc: Dominik Vogt

That's a lot of tests that don't pass on targets that don't yet support complex 
numbers. Is there any way to gate / XFAIL these on such targets?

Cheers, Alan

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX)
  2014-09-20 10:31 ` [RFC][PATCH " Anthony Green
@ 2014-09-29 10:24   ` Dominik Vogt
  0 siblings, 0 replies; 9+ messages in thread
From: Dominik Vogt @ 2014-09-29 10:24 UTC (permalink / raw)
  To: libffi-discuss

On Sat, Sep 20, 2014 at 06:31:21AM -0400, Anthony Green wrote:
> I'm not all that familiar with how GCC handles complex types on other
> architectures, but hopefully they are as straight forward as on s390.

I think the real issue here is the Abi.  On x86, complex types
seem to be treated exactly like structs with two elements, but on
s390[x] that is not the case (structs of size 8 are passed in a
register, but complex types are always passed on the stack).
Other than that, complex types are hopefully treated the same
inside gcc.

> It would be nice if the complex test cases turned into expected failures
> for platforms that don't have the back end support.

Sorry for the late reply, but I've had a cold.  Have you already
resolved this issue in that patch here?

  Only run the complex type tests on supported platforms.

If there's something left to do, I can look into it now.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-09-29 10:24 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-22  9:27 [RFC][PATCH 0/3] Complex type support (FFI_TYPE_COMPLEX) Dominik Vogt
2014-07-22  9:35 ` [RFC][PATCH 1/3] " Dominik Vogt
2014-07-23  8:41   ` Dominik Vogt
2014-07-22  9:36 ` [RFC][PATCH 3/3] " Dominik Vogt
2014-07-22  9:36 ` [RFC][PATCH 2/3] " Dominik Vogt
2014-09-23 13:17   ` Alan Lawrence
2014-08-20  6:57 ` [PING][RFC][PATCH 0/3] " Dominik Vogt
2014-09-20 10:31 ` [RFC][PATCH " Anthony Green
2014-09-29 10:24   ` Dominik Vogt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).