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]

[RFC][PATCH 2/3] Complex type support (FFI_TYPE_COMPLEX)


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
>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


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