public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2] jit: Complex types and loong constants
@ 2021-10-21 13:02 Petter Tomner
  2021-10-21 13:07 ` [PATCH 1/2] " Petter Tomner
  2021-10-21 13:13 ` [PATCH 2/2] " Petter Tomner
  0 siblings, 2 replies; 6+ messages in thread
From: Petter Tomner @ 2021-10-21 13:02 UTC (permalink / raw)
  To: jit, gcc-patches

Hi,

These two patches fixes support for complex types and adds the possibility to make
long long, long double and complex long double constants.

Please see follow up mails.

Regards,

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

* [PATCH 1/2] jit: Complex types and loong constants
  2021-10-21 13:02 [PATCH 0/2] jit: Complex types and loong constants Petter Tomner
@ 2021-10-21 13:07 ` Petter Tomner
  2021-10-21 13:13 ` [PATCH 2/2] " Petter Tomner
  1 sibling, 0 replies; 6+ messages in thread
From: Petter Tomner @ 2021-10-21 13:07 UTC (permalink / raw)
  To: gcc-patches, jit

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

This patch fixes support for complex types.

It adds the entrypoints:
gcc_jit_context_new_rvalue_from_complex_double
gcc_jit_context_set_bool_enable_complex_types

Aswell as the binary operator GCC_JIT_BINARY_OP_COMPLEX, to make
complex numbers from two real number rvalues.

Note that the complex types already are in the type enum, so I thought the
cleanest solution is to enable them, rather than to have a "get_complex_type"
function.

See attachement.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Complex.patch --]
[-- Type: text/x-patch; name="0001-Complex.patch", Size: 91361 bytes --]

From 6d5d7ce40f9bb84a7943e5113c8954ae4b941905 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Fri, 15 Oct 2021 20:16:54 +0200
Subject: [PATCH 1/3] Complex

Fix support for complex types

The patch adds support of complex floating point types to libgccjit.
A new binary operator 'COMPLEX' is added to create complex values
from real values. Aswell as a function to create a complex double
literal.

To notify users if a binary linking to libgccjit depends on complex
types, complex type support most be enabled with a new option function
since they allready are in the types enum.

Signed-off-by:
2021-10-21	Petter Tomner	<tomner@kth.se>

gcc/jit/
	* jit-common.h : (INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES): New
	* jit-playback.c : Create imaginary literals, conversions
	  (complex_real_to_real) : New
	  (new_rvalue_from_const<...>) : Also build complex constants
	  (new_rvalue_from_const <_Complex double>) : New
	  (new_binary_op) : Add COMPLEX operator
	  (build_cast) : Casts to complex
	  (memento_of_new_rvalue_from_const <_Complex double>) : New
	  (binary_op::make_debug_string) : Handle complex operator
	* jit-recording.c : Reproducer, debug strings, forwarding
	* jit-recording.h :
	  (float_size_qual) : Poll size qualifier of float types
	  (is_complex) : Poll if type is complex
	* libgccjit++.h : New entrypoints, see below
	* libgccjit.c : Implementation of new entry points, see .h
	  (gcc_jit_context_get_type) : Extend range check, validation
	  (valid_binary_op_p) : Extend range check
	  (gcc_jit_context_new_binary_op) : Validation
	  (gcc_jit_context_new_unary_op) : Validation
	  (gcc_jit_context_new_comparison) : Validation
	* libgccjit.h :
	  (gcc_jit_context_new_rvalue_from_complex_double) : New
	  (GCC_JIT_BINARY_OP_COMPLEX) : New
	  (LIBGCCJIT_HAVE_COMPLEX) : New
	  (gcc_jit_context_set_bool_enable_complex_types) : New
	* libgccjit.map : Added new entrypoints
	  (LIBGCCJIT_ABI_16) : New

gcc/testsuite/
	* jit.dg/test-complex-builtins.c : New
	* jit.dg/test-complex-literals.c : New
	* jit.dg/test-complex-misc.c : New
	* jit.dg/test-complex-operators.c : New
	* jit.dg/test-complex-types.c : New
	* jit.dg/test-error-complex-noenable.c : New

gcc/jit/docs/topics/
	* contexts.rst : Update docs
	* expressions.rst
	* types.rst
---
 gcc/jit/docs/topics/contexts.rst              |  20 +
 gcc/jit/docs/topics/expressions.rst           |  89 ++-
 gcc/jit/docs/topics/types.rst                 |  12 +-
 gcc/jit/jit-common.h                          |   1 +
 gcc/jit/jit-playback.c                        | 165 ++++-
 gcc/jit/jit-recording.c                       | 126 +++-
 gcc/jit/jit-recording.h                       |  28 +
 gcc/jit/libgccjit++.h                         |  21 +
 gcc/jit/libgccjit.c                           |  97 ++-
 gcc/jit/libgccjit.h                           |  44 +-
 gcc/jit/libgccjit.map                         |   6 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |  30 +
 gcc/testsuite/jit.dg/test-complex-builtins.c  | 217 ++++++
 gcc/testsuite/jit.dg/test-complex-literals.c  | 145 ++++
 gcc/testsuite/jit.dg/test-complex-misc.c      | 204 ++++++
 gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++
 gcc/testsuite/jit.dg/test-complex-types.c     | 677 ++++++++++++++++++
 .../jit.dg/test-error-complex-noenable.c      |  31 +
 18 files changed, 2221 insertions(+), 45 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-complex-builtins.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-literals.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-misc.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-operators.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-types.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-complex-noenable.c

diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index 00fb17e155d..d8689407cc6 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -489,6 +489,26 @@ Boolean options
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
 
+.. function:: void\
+              gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,\
+                                                             int bool_value);
+
+   This option can enable complex type support in libgccjit. By default,
+   no complex types can be used.
+
+   If you use complex types, it is recommended to use builtin functions
+   `creal`, `cimag` and `conj` etc. with the correct type suffix, since
+   those are inlined into the code, rather then imported functions from
+   the math lib which are not. See :ref:`gcc_jit_context_get_builtin_function`.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
+
+
 Integer options
 ***************
 
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 396259ef07e..a98f35572b4 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -98,6 +98,15 @@ Simple expressions
    Given a numeric type (integer or floating point), build an rvalue for
    the given constant :c:type:`double` value.
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \
+                                                              gcc_jit_type *numeric_type, \
+                                                              _Complex double value)
+
+   Given a floating point type, build an rvalue for
+   the given constant :c:type:`_Complex double`. When the result type is
+   non-complex, the imaginary part is discarded.
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
                                                    gcc_jit_type *pointer_type, \
@@ -168,14 +177,14 @@ Unary Operations
 
 The available unary operations are:
 
-==========================================  ============
-Unary Operation                             C equivalent
-==========================================  ============
-:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`
-:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`
-:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`
-:c:macro:`GCC_JIT_UNARY_OP_ABS`             `abs (EXPR)`
-==========================================  ============
+==========================================  ============  ======================
+Unary Operation                             C equivalent  Supported types
+==========================================  ============  ======================
+:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`     integer, real, complex
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_ABS`             `abs (EXPR)`  integer, real
+==========================================  ============  ======================
 
 .. c:macro:: GCC_JIT_UNARY_OP_MINUS
 
@@ -235,22 +244,23 @@ Binary Operations
 
 The available binary operations are:
 
-========================================  ============
-Binary Operation                          C equivalent
-========================================  ============
-:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`
-:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`
-:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`
-:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`
-:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`
-:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`
-:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`
-:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`
-:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`
-:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`
-:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`
-:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`
-========================================  ============
+========================================  ============    =======================
+Binary Operation                          C equivalent    Supported operand types
+========================================  ============    =======================
+:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_COMPLEX`      `CMPLX (r, i)`  real
+========================================  =============== =======================
 
 .. c:macro:: GCC_JIT_BINARY_OP_PLUS
 
@@ -378,6 +388,25 @@ Binary Operation                          C equivalent
 
    in C.
 
+.. c:macro:: GCC_JIT_BINARY_OP_COMPLEX
+
+   Create a complex floating point value from
+   two real floating point values with the same
+   size qualifier as the complex result type.
+   I.e two floats for a _Complex float, etc.
+
+   Analogous to:
+     CMPLX (real,imag)
+   in C.
+
+   The first operand is the real part, the other
+   the imaginary. Negative zeroes are preserved
+   and Inf:s do not lead to NaNs.
+
+   This operator  was added in LIBGCCJIT_ABI_16;
+   you can test for its presence using
+       `#ifdef LIBGCCJIT_HAVE_COMPLEX`
+
 Comparisons
 ***********
 
@@ -402,6 +431,7 @@ Comparison                               C equivalent
 :c:macro:`GCC_JIT_COMPARISON_GE`         `x >= y`
 =======================================  ============
 
+   Note: Only `==` and `!=` are defined for complex types.
 
 Function calls
 **************
@@ -504,10 +534,17 @@ Type-coercion
 
    Currently only a limited set of conversions are possible:
 
-     * int <-> float
-     * int <-> bool
+     * integer <-> integer
+     * floating point <-> floating point
+     * integer <-> floating point
+     * integer <-> bool
      * P*  <-> Q*, for pointer types P and Q
 
+   Note: "floating point" includes complex types.
+
+   When a complex type is converted to a non-complex type, the
+   imaginary part is discarded.
+
 Lvalues
 -------
 
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index 831f11b679a..5b5ba050658 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -82,11 +82,17 @@ Standard types
    :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`       C type: ``(const char *)``
    :c:data:`GCC_JIT_TYPE_SIZE_T`               C's ``size_t`` type
    :c:data:`GCC_JIT_TYPE_FILE_PTR`             C type: ``(FILE *)``
-   :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT`        C99's ``_Complex float``
-   :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE`       C99's ``_Complex double``
-   :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE`  C99's ``_Complex long double``
+   :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT`        C99's ``_Complex float``, ABI 16
+   :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE`       C99's ``_Complex double``, ABI 16
+   :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE`  C99's ``_Complex long double``, ABI 16
    ==========================================  ================================
 
+   The complex types are available from :ref:`LIBGCCJIT_ABI_16` after
+   setting :ref:`gcc_jit_context_set_bool_enable_complex_types`.
+
+   You can test for complex types support with the define
+   `#ifdef LIBGCCJIT_HAVE_COMPLEX`.
+
 .. function:: gcc_jit_type *\
               gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
                                             int num_bytes, int is_signed)
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index f88e6755b00..bc0453fba05 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -198,6 +198,7 @@ enum inner_bool_option
 {
   INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS,
   INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER,
+  INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
 
   NUM_INNER_BOOL_OPTIONS
 };
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 59399dee251..8b1cb818b90 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc.h"
 #include "diagnostic.h"
 #include "stmt.h"
+#include "complex.h"
 
 #include <pthread.h>
 
@@ -78,6 +79,8 @@ convert (tree dst_type, tree expr)
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
       return fold (convert_to_integer (dst_type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (dst_type, expr));
 
     default:
       gcc_assert (gcc::jit::active_playback_ctxt);
@@ -679,6 +682,24 @@ new_global_initialized (location *loc,
 namespace playback
 {
 
+/* Return the corrensponding not complex float type of a
+   float type. I.e. complex float -> float */
+static tree
+complex_real_to_real (tree complex_type)
+{
+  if (TYPE_CANONICAL (complex_type) ==
+      TYPE_CANONICAL (complex_float_type_node))
+    return float_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_double_type_node))
+    return double_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_long_double_type_node))
+    return long_double_type_node;
+  else
+    gcc_unreachable();
+}
+
 /* Specialization of making an rvalue from a const, for host <int>.  */
 
 template <>
@@ -694,6 +715,25 @@ new_rvalue_from_const <int> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -718,6 +758,25 @@ new_rvalue_from_const <long> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -743,19 +802,104 @@ new_rvalue_from_const <double> (type *type,
      real.c:real_from_target appears to require the representation to be
      split into 32-bit values, and then sent as an pair of host long
      ints.  */
+
+  union
+  {
+    double as_double;
+    uint32_t as_uint32s[2];
+  } u_real, u_imag;
+
+  u_real.as_double = value;
+  long int as_long_ints[2];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
   REAL_VALUE_TYPE real_value;
+  real_from_target (&real_value, as_long_ints, DFmode);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int zero_as_long_ints[2];
+      u_imag.as_double = 0.;
+      zero_as_long_ints[0] = u_imag.as_uint32s[0];
+      zero_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, zero_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
+/* Specialization of making an rvalue from a const,
+   for host <double _Complex>. */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <_Complex double> (type *type,
+					 _Complex double  value)
+{
+  tree inner_type = type->as_tree ();
+
   union
   {
     double as_double;
     uint32_t as_uint32s[2];
-  } u;
-  u.as_double = value;
+  } u_real, u_imag;
+
+  u_real.as_double = creal(value);
   long int as_long_ints[2];
-  as_long_ints[0] = u.as_uint32s[0];
-  as_long_ints[1] = u.as_uint32s[1];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
+  REAL_VALUE_TYPE real_value;
   real_from_target (&real_value, as_long_ints, DFmode);
-  tree inner = build_real (inner_type, real_value);
-  return new rvalue (this, inner);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int value_as_long_ints[2];
+      u_imag.as_double = cimag(value);
+      value_as_long_ints[0] = u_imag.as_uint32s[0];
+      value_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, value_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
 }
 
 /* Specialization of making an rvalue from a const, for host <void *>.  */
@@ -985,6 +1129,11 @@ new_binary_op (location *loc,
     case GCC_JIT_BINARY_OP_RSHIFT:
       inner_op = RSHIFT_EXPR;
       break;
+
+    /* Create complex value from two real values */
+    case GCC_JIT_BINARY_OP_COMPLEX:
+      inner_op = COMPLEX_EXPR;
+      break;
     }
 
   tree inner_expr = build2 (inner_op,
@@ -1163,6 +1312,10 @@ playback::context::build_cast (playback::location *loc,
 		      build_int_cst (TREE_TYPE (t_expr), 0));
       goto maybe_fold;
 
+    case COMPLEX_TYPE:
+      t_ret = convert_to_complex (t_dst_type, t_expr);
+      goto maybe_fold;
+
     case REAL_TYPE:
       t_ret = convert_to_real (t_dst_type, t_expr);
       goto maybe_fold;
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 117ff70114c..b3bb6acfeb9 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 
 #include <pthread.h>
+#include <complex.h>
 
 #include "jit-builtins.h"
 #include "jit-recording.h"
@@ -1609,7 +1610,8 @@ static const char * const
 static const char * const
  inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = {
   "gcc_jit_context_set_bool_allow_unreachable_blocks",
-  "gcc_jit_context_set_bool_use_external_driver"
+  "gcc_jit_context_set_bool_use_external_driver",
+  "gcc_jit_context_set_bool_enable_complex_types"
 };
 
 /* Write the current value of all options to the log file (if any).  */
@@ -2423,6 +2425,59 @@ recording::memento_of_get_type::is_float () const
     }
 }
 
+/* Implementation of pure virtual hook recording::type::is_complex for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_complex () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return true;
+    }
+}
+
 /* Implementation of pure virtual hook recording::type::is_bool for
    recording::memento_of_get_type.  */
 
@@ -4704,6 +4759,7 @@ recording::global::write_reproducer (reproducer &r)
 template class recording::memento_of_new_rvalue_from_const <int>;
 template class recording::memento_of_new_rvalue_from_const <long>;
 template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <_Complex double>;
 template class recording::memento_of_new_rvalue_from_const <void *>;
 
 /* Implementation of the pure virtual hook recording::memento::replay_into
@@ -4881,6 +4937,53 @@ recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproduc
     m_value);
 }
 
+/* The make_debug_string specialization for <double complex>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(complex float)(42.0+42.0j)".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <_Complex double>::make_debug_string ()
+{
+  double real = creal(m_value);
+  double imag = cimag(m_value);
+  return string::from_printf (m_ctxt,
+			      "(%s)(%g%+gj)",
+			      m_type->get_debug_string (),
+			      real, imag);
+}
+
+/* The get_wide_int specialization for <double complex>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <_Complex double>::
+get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* The write_reproducer specialization for <double>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <_Complex double>::
+write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  double real = creal(m_value);
+  double imag = cimag(m_value);
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n"
+    "                                            %s, /* gcc_jit_type *numeric_type */\n"
+    "                                            %f+%fj); /* double value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    real, imag);
+}
+
 /* The make_debug_string specialization for <void *>, rendering it as
      (TARGET_TYPE)HEX
    e.g.
@@ -5178,17 +5281,24 @@ static const char * const binary_op_strings[] = {
   "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
   ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+  "", /* GCC_JIT_BINARY_OP_COMPLEX - dummy not used */
 };
 
 recording::string *
 recording::binary_op::make_debug_string ()
 {
   enum precedence prec = get_precedence ();
-  return string::from_printf (m_ctxt,
-			      "%s %s %s",
-			      m_a->get_debug_string_parens (prec),
-			      binary_op_strings[m_op],
-			      m_b->get_debug_string_parens (prec));
+  if (m_op == GCC_JIT_BINARY_OP_COMPLEX)
+    return string::from_printf (m_ctxt,
+				"(%s + %s * _Imaginary_I)",
+				m_a->get_debug_string_parens (prec),
+				m_b->get_debug_string_parens (prec));
+  else
+    return string::from_printf (m_ctxt,
+				"%s %s %s",
+				m_a->get_debug_string_parens (prec),
+				binary_op_strings[m_op],
+				m_b->get_debug_string_parens (prec));
 }
 
 const char * const binary_op_reproducer_strings[] = {
@@ -5203,7 +5313,8 @@ const char * const binary_op_reproducer_strings[] = {
   "GCC_JIT_BINARY_OP_LOGICAL_AND",
   "GCC_JIT_BINARY_OP_LOGICAL_OR",
   "GCC_JIT_BINARY_OP_LSHIFT",
-  "GCC_JIT_BINARY_OP_RSHIFT"
+  "GCC_JIT_BINARY_OP_RSHIFT",
+  "GCC_JIT_BINARY_OP_COMPLEX",
 };
 
 /* Implementation of recording::memento::write_reproducer for binary ops.  */
@@ -5244,6 +5355,7 @@ static const enum precedence binary_op_precedence[] = {
   PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */
+  PRECEDENCE_CAST, /* GCC_JIT_BINARY_OP_COMPLEX */
 };
 } /* namespace recording */
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 03fa1160cf0..d5e0c359a48 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -544,10 +544,14 @@ public:
   virtual bool is_int () const = 0;
   virtual bool is_float () const = 0;
   virtual bool is_bool () const = 0;
+  virtual bool is_complex () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_array () = 0;
   virtual bool is_void () const { return false; }
   virtual bool has_known_size () const { return true; }
+  /* Used to pair complex float types with real float type
+     of the same "base type". */
+  virtual int float_size_qual () const { return 0; }
 
   bool is_numeric () const
   {
@@ -598,9 +602,28 @@ public:
     return type::accepts_writes_from (rtype);
   }
 
+  int float_size_qual () const FINAL OVERRIDE
+  {
+    switch (m_kind)
+      {
+      default:
+	return 0;
+      case GCC_JIT_TYPE_FLOAT:
+      case GCC_JIT_TYPE_COMPLEX_FLOAT:
+	return 1;
+      case GCC_JIT_TYPE_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+	return 2;
+      case GCC_JIT_TYPE_LONG_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+	return 3;
+      }
+  }
+
   bool is_int () const FINAL OVERRIDE;
   bool is_float () const FINAL OVERRIDE;
   bool is_bool () const FINAL OVERRIDE;
+  bool is_complex () const FINAL OVERRIDE;
   type *is_pointer () FINAL OVERRIDE { return dereference (); }
   type *is_array () FINAL OVERRIDE { return NULL; }
   bool is_void () const FINAL OVERRIDE { return m_kind == GCC_JIT_TYPE_VOID; }
@@ -635,6 +658,7 @@ public:
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
+  bool is_complex () const FINAL OVERRIDE { return false; }
   type *is_pointer () FINAL OVERRIDE { return m_other_type; }
   type *is_array () FINAL OVERRIDE { return NULL; }
 
@@ -661,6 +685,7 @@ public:
   bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); }
   bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); }
   bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); }
+  bool is_complex () const FINAL OVERRIDE { return m_other_type->is_complex (); }
   type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); }
   type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); }
 
@@ -771,6 +796,7 @@ class array_type : public type
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
+  bool is_complex () const FINAL OVERRIDE { return false; }
   type *is_pointer () FINAL OVERRIDE { return NULL; }
   type *is_array () FINAL OVERRIDE { return m_element_type; }
   int num_elements () { return m_num_elements; }
@@ -805,6 +831,7 @@ public:
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
+  bool is_complex () const FINAL OVERRIDE { return false; }
   type *is_pointer () FINAL OVERRIDE { return NULL; }
   type *is_array () FINAL OVERRIDE { return NULL; }
 
@@ -918,6 +945,7 @@ public:
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
+  bool is_complex () const FINAL OVERRIDE { return false; }
   type *is_pointer () FINAL OVERRIDE { return NULL; }
   type *is_array () FINAL OVERRIDE { return NULL; }
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 82831ff5da0..c97aeb82812 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -128,6 +128,7 @@ namespace gccjit
 
     void set_bool_allow_unreachable_blocks (int bool_value);
     void set_bool_use_external_driver (int bool_value);
+    void set_bool_enable_complex_types (int bool_value);
 
     void add_command_line_option (const char *optname);
     void add_driver_option (const char *optname);
@@ -191,6 +192,8 @@ namespace gccjit
     rvalue one (type numeric_type) const;
     rvalue new_rvalue (type numeric_type,
 		       double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       _Complex double value) const;
     rvalue new_rvalue (type pointer_type,
 		       void *value) const;
     rvalue new_rvalue (const std::string &value) const;
@@ -732,6 +735,13 @@ context::set_bool_use_external_driver (int bool_value)
 						bool_value);
 }
 
+inline void
+context::set_bool_enable_complex_types (int bool_value)
+{
+  gcc_jit_context_set_bool_enable_complex_types (m_inner_ctxt,
+						 bool_value);
+}
+
 inline void
 context::add_command_line_option (const char *optname)
 {
@@ -950,6 +960,17 @@ context::new_rvalue (type numeric_type,
 					    value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     _Complex double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_complex_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
 inline rvalue
 context::new_rvalue (type pointer_type,
 		     void *value) const
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 7fa948007ad..64630b810f4 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -448,9 +448,17 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt,
   JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_PRINTF1 (
     (type >= GCC_JIT_TYPE_VOID
-     && type <= GCC_JIT_TYPE_FILE_PTR),
+     && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE),
     ctxt, NULL,
     "unrecognized value for enum gcc_jit_types: %i", type);
+  if (type >= GCC_JIT_TYPE_COMPLEX_FLOAT
+      && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE)
+    RETURN_NULL_IF_FAIL (
+      ctxt->get_inner_bool_option(
+	gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES),
+      ctxt, NULL,
+      "complex types are only available after enabling them with"
+      " gcc_jit_context_set_bool_enable_complex_types()");
 
   return (gcc_jit_type *)ctxt->get_type (type);
 }
@@ -1320,6 +1328,26 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 	  ->new_rvalue_from_const <double> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						double _Complex value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    numeric_type->is_float (),
+    ctxt, NULL,
+    "not a floating point type (type: %s)",
+    numeric_type->get_debug_string ());
+
+  return ((gcc_jit_rvalue *)ctxt
+	   ->new_rvalue_from_const <double _Complex> (numeric_type, value));
+}
+
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -1415,6 +1443,14 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
     result_type->get_debug_string ());
   RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
 
+  if (rvalue->get_type ()->is_complex ())
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      op == GCC_JIT_UNARY_OP_MINUS,
+      ctxt, loc,
+      "only unary minus defined for complex types: %s (type: %s)",
+      rvalue->get_debug_string (),
+      rvalue->get_type ()->get_debug_string ());
+
   return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
 }
 
@@ -1426,7 +1462,7 @@ static bool
 valid_binary_op_p (enum gcc_jit_binary_op op)
 {
   return (op >= GCC_JIT_BINARY_OP_PLUS
-	  && op <= GCC_JIT_BINARY_OP_RSHIFT);
+	  && op <= GCC_JIT_BINARY_OP_COMPLEX);
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -1470,6 +1506,38 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
     a->get_debug_string (), b->get_debug_string (),
     result_type->get_debug_string ());
 
+  if (op == GCC_JIT_BINARY_OP_COMPLEX)
+    {
+      RETURN_NULL_IF_FAIL (
+	result_type->is_complex (),
+	ctxt, loc,
+       "return type is not complex");
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!a->get_type ()->is_complex () &&
+	a->get_type ()->is_float (),
+	ctxt, loc,
+	"first operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	a->get_debug_string (),
+	a->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!b->get_type ()->is_complex () &&
+	b->get_type ()->is_float (),
+	ctxt, loc,
+	"2nd operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	b->get_debug_string (),
+	b->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	a->get_type ()-> float_size_qual () ==
+	result_type->float_size_qual (),
+	ctxt, loc,
+	"size qualifiers of complex operand's not the same as the result:"
+	" operands: %s, result:  %s",
+	a->get_type ()->get_debug_string (),
+	result_type->get_debug_string ());
+    }
+
   return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
 }
 
@@ -1506,6 +1574,14 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
     b->get_debug_string (),
     b->get_type ()->get_debug_string ());
 
+  if (a->get_type ()->is_complex())
+    RETURN_NULL_IF_FAIL_PRINTF1 (
+      (op == GCC_JIT_COMPARISON_EQ
+       || op == GCC_JIT_COMPARISON_NE),
+      ctxt, loc,
+      "invalid enum gcc_jit_comparison for complex operands: %i",
+      op);
+
   return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
 }
 
@@ -2735,6 +2811,23 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt,
     bool_value);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::set_inner_bool_option method in
+   jit-recording.c. */
+
+void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  ctxt->set_inner_bool_option (
+    gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
+    bool_value);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 5c722c2c57f..d4b10fc0644 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -848,6 +848,16 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					gcc_jit_type *numeric_type,
 					double value);
 
+/* Complex floating-point constants.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						_Complex double value);
+
 /* Pointers.  */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
@@ -959,7 +969,26 @@ enum gcc_jit_binary_op
   /* Right shift; analogous to:
        (EXPR_A) >> (EXPR_B)
      in C.  */
-  GCC_JIT_BINARY_OP_RSHIFT
+  GCC_JIT_BINARY_OP_RSHIFT,
+
+  /* Create a complex floating point value from
+     two real floating point values. The operands
+     and the result need to have the same size
+     qualifier.
+
+     Analogous to:
+       CMPLX (real,imag)
+     in C.
+
+     The first operand is the real part, the other
+     the imaginary. Negative zeroes are preserved
+     and Inf:s do not lead to NaNs.
+
+     This operator  was added in LIBGCCJIT_ABI_16;
+     you can test for its presence using
+       #ifdef LIBGCCJIT_HAVE_COMPLEX
+  */
+  GCC_JIT_BINARY_OP_COMPLEX
 };
 
 extern gcc_jit_rvalue *
@@ -1434,6 +1463,19 @@ gcc_jit_timer_print (gcc_jit_timer *timer,
 		     FILE *f_out);
 
 
+#define LIBGCCJIT_HAVE_COMPLEX
+
+/* Enables complex type support in libgccjit.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX
+*/
+
+extern void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value);
+
 #define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
 
 /* Mark/clear a call as needing tail-call optimization.
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 337ea6c7fe4..c9b044dc8f5 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -205,3 +205,9 @@ LIBGCCJIT_ABI_15 {
     gcc_jit_extended_asm_add_clobber;
     gcc_jit_context_add_top_level_asm;
 } LIBGCCJIT_ABI_14;
+
+LIBGCCJIT_ABI_16 {
+  global:
+    gcc_jit_context_new_rvalue_from_complex_double;
+    gcc_jit_context_set_bool_enable_complex_types;
+} LIBGCCJIT_ABI_15;
\ No newline at end of file
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 84ef54a0386..7b45acd4b9c 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -105,6 +105,36 @@
 #undef create_code
 #undef verify_code
 
+/* test-complex-builtins.c */
+#define create_code create_code_complex_builtins
+#define verify_code verify_code_complex_builtins
+#include "test-complex-builtins.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-literals.c */
+#define create_code create_code_complex_literals
+#define verify_code verify_code_complex_literals
+#include "test-complex-literals.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-misc.c */
+#define create_code create_code_complex_misc
+#define verify_code verify_code_complex_misc
+#include "test-complex-misc.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-operators.c */
+#define create_code create_code_complex_operators
+#define verify_code verify_code_complex_operators
+#include "test-complex-operators.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-types.c: Quite long, don't include here */
+
 /* test-compound-assignment.c */
 #define create_code create_code_compound_assignment
 #define verify_code verify_code_compound_assignment
diff --git a/gcc/testsuite/jit.dg/test-complex-builtins.c b/gcc/testsuite/jit.dg/test-complex-builtins.c
new file mode 100644
index 00000000000..fce2c9b2d09
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-builtins.c
@@ -0,0 +1,217 @@
+/*
+  This test just checks that the builtins cimag, creal and
+  conj are usable.
+
+  Also, they should be inlined, which can be checked by
+  disassembling the object file manually.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+static void
+make_code_unop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type_return,
+		 int type_arg,
+		 gcc_jit_function *fn)
+{ 
+  gcc_jit_block *block;
+
+  gcc_jit_type *tr = gcc_jit_context_get_type (ctxt, type_return);
+  gcc_jit_type *ta = gcc_jit_context_get_type (ctxt, type_arg);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, ta, "f1");
+
+  gcc_jit_param *params[] = {param1};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 1, params, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1)
+  };
+  
+  /* return fn(f1); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, fn,
+     1,
+     args);
+  
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+static void
+make_code_binop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 gcc_jit_function *builtin)
+{
+  gcc_jit_block *block;
+  
+  gcc_jit_type *t1 = gcc_jit_context_get_type (ctxt, type1);
+  gcc_jit_type *t2 = gcc_jit_context_get_type (ctxt, type2);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, t1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, t2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    t1, fn_name, 2, params, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 1));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1),
+    gcc_jit_lvalue_as_rvalue (f2)
+  };
+  
+  /* return builtin(f1,f2); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, builtin,
+     2,
+     args);
+  
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+  
+  gcc_jit_function *fn_cpow = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cpow");
+
+  make_code_binop_builtins (ctxt, "cpow_builtin",
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   fn_cpow);
+
+  gcc_jit_function *fn_conj = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_conj");
+  
+  /* In a good world conj should be inlined */
+  make_code_unop_builtins (ctxt, "conj_inlined",
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_conj);
+
+  gcc_jit_function *fn_creal = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creal");
+  gcc_jit_function *fn_crealf = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_crealf");
+  gcc_jit_function *fn_creall = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creall");
+  gcc_jit_function *fn_cimag = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cimag");
+
+  /* These should be inlined too */
+  make_code_unop_builtins (ctxt, "creal_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_creal);
+  make_code_unop_builtins (ctxt, "cimag_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_cimag);
+
+  make_code_unop_builtins (ctxt, "crealf_inlined",
+		  GCC_JIT_TYPE_FLOAT,
+		  GCC_JIT_TYPE_COMPLEX_FLOAT,
+		  fn_crealf);
+  make_code_unop_builtins (ctxt, "creall_inlined",
+		  GCC_JIT_TYPE_LONG_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		  fn_creall);
+  
+  /* Use to inspect code manually and assure conj, creal, cimag
+     are inlined. At the time of writing they are on my x64 machine */
+  #if 0
+  gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+				   "test-complex-builtins.o");
+  #endif
+}
+
+typedef _Complex double (*cd_cdcd)(_Complex double, _Complex double);
+typedef _Complex double (*cd_cd)(_Complex double);
+typedef double (*d_cd)(_Complex double);
+typedef float (*f_cf)(_Complex float);
+typedef long double (*ld_cld)(_Complex long double);
+
+/* We need this to fool GCC into not precomputing the built-in ...
+   precomputing seems like a feuture libgccjit misses. */
+volatile _Complex double half = 0.5;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test binary builtins */
+    {
+       cd_cdcd fn =
+	gcc_jit_result_get_code (result, "cpow_builtin");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (2, 2), 4.);
+       _Complex double ans = fn (-1., 0.5);
+       _Complex double key = __builtin_cpow (-1., half);
+
+       /* This test fails if libgccjit can precompute builtins */
+       CHECK_VALUE (ans, key); /* Almost 1.j */
+    }
+  }
+  {/* Test unary builtins */
+    { /* conj */
+      cd_cd fn = gcc_jit_result_get_code (result, "conj_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE( fn (1. - 1.j), 1. + 1.j);
+    }
+    { /* creal */
+      d_cd fn = gcc_jit_result_get_code (result, "creal_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1. - 1.j), 1.);
+    }
+    { /* cimag */
+      d_cd fn = gcc_jit_result_get_code (result, "cimag_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1. - 1.j), -1.);
+    }
+    { /* crealf */
+      f_cf fn = gcc_jit_result_get_code (result, "crealf_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f - 1.fj), 1.f);
+    }
+    { /* creall */
+      ld_cld fn = gcc_jit_result_get_code (result, "creall_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.L - 1.Lj), 1.L);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-literals.c b/gcc/testsuite/jit.dg/test-complex-literals.c
new file mode 100644
index 00000000000..422cff1048d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-literals.c
@@ -0,0 +1,145 @@
+/*
+  Test the new 'gcc_jit_context_new_rvalue_from_complex_double()'
+  aswell as test that the old '_from_int ... _from_double"
+  can produce complex values.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code (gcc_jit_context *ctxt,
+	   const char *fn_name,
+	   int type,
+	   _Complex double local_val,
+	   int lit_type)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  if (lit_type == 'c')
+    r1 = gcc_jit_context_new_rvalue_from_complex_double (ctxt, tt, local_val);
+  else if (lit_type == 'd')
+    r1 = gcc_jit_context_new_rvalue_from_double (ctxt, tt, creal(local_val));
+  else if (lit_type == 'l')
+    r1 = gcc_jit_context_new_rvalue_from_long (ctxt, tt, creal(local_val));
+  else if (lit_type == 'i')
+    r1 = gcc_jit_context_new_rvalue_from_int (ctxt, tt, creal(local_val));
+    
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+  
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code (ctxt, "complex_float_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_FLOAT,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "complex_double_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "complex_long_double_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "float_clit_1c1",
+	       GCC_JIT_TYPE_FLOAT,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "double_clit_1c1",
+	       GCC_JIT_TYPE_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "long_double_clit_1c1",
+	       GCC_JIT_TYPE_LONG_DOUBLE,
+	       1.1 + 2.2j, 'c');
+
+  /* Make complex from "from_double", "from_long","from_int" */
+  make_code (ctxt, "complex_float_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_FLOAT,
+	       1.1, 'd');
+  make_code (ctxt, "complex_double_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       1.1, 'd');
+  make_code (ctxt, "complex_long_double_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	       1.1, 'd');
+  make_code (ctxt, "complex_double_llit_2",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       2, 'l');
+  make_code (ctxt, "complex_double_ilit_3",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       3, 'i');
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test literals */
+    {
+      _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_clit_1c1_2c2j");
+
+      CHECK_VALUE(f (), 1.1f + 2.2fj);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_clit_1c1_2c2j");
+      CHECK_VALUE(f (), 1.1 + 2.2j);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_clit_1c1_2c2j");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (),1.1 + 2.2j);
+    }
+    {
+      float (*f)() = gcc_jit_result_get_code (result, "float_clit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      double (*f)() = gcc_jit_result_get_code (result, "double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      long double (*f)() = gcc_jit_result_get_code (result, "long_double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      float (*f)() = gcc_jit_result_get_code (result, "complex_float_dlit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_dlit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_dlit_1c1");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_llit_2");
+      CHECK_VALUE(f (), 2);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_ilit_3");
+      CHECK_VALUE(f (), 3);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-misc.c b/gcc/testsuite/jit.dg/test-complex-misc.c
new file mode 100644
index 00000000000..fe0cdade927
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-misc.c
@@ -0,0 +1,204 @@
+/*
+  This test checks wether complex types work with structs, unions
+  and pointers.
+
+  Aswell as const and volatile, but only in the sense that having
+  those qualifiers doesn't crash gcc.
+
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_type *type_int =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *type_cd =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE);
+
+  gcc_jit_lvalue *cd_gbl = gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    type_cd,
+    "a_complex_global_double_2");
+
+  /* These globals are not used for anything */
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_volatile (type_cd),
+    "a_volatile_complex_double");
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_const (type_cd),
+    "a_const_complex_double");
+
+  gcc_jit_type *arr_type =
+    gcc_jit_context_new_array_type (ctxt,
+      0, type_cd, 10);
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    arr_type,
+    "a_const_complex_double_array");  
+
+  {/* Make a function returning union with 3.14 + 1516.j in it */
+    gcc_jit_field *cd_field = 
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field = 
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi =
+      gcc_jit_context_new_union_type (ctxt,
+				      0,
+				      "cdi",
+				      2,
+				      fields);
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi, "a_uniony_fn_returning_union", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi, "union_local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field
+      (local, 0, cd_field);
+    gcc_jit_block_add_assignment
+      (block, 0, lv_field,
+       gcc_jit_context_new_rvalue_from_complex_double (
+         ctxt, type_cd, 3.14 + 1592.j));
+
+    /* Note: Writes to global here */
+    gcc_jit_block_add_assignment (
+      block, 0, cd_gbl,
+      gcc_jit_context_new_rvalue_from_complex_double (
+         ctxt, type_cd, 6535 + 9.j));
+    
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function returning a complexy struct */
+    gcc_jit_field *cd_field = 
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field = 
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi_struct =
+      gcc_jit_struct_as_type(
+	gcc_jit_context_new_struct_type (ctxt,
+					0,
+					"cdi_struct",
+					2,
+					fields));
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi_struct, "a_structy_fn_returning_struct", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi_struct, "local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field (
+      local, 0, cd_field);
+    gcc_jit_block_add_assignment (
+       block, 0, lv_field,
+       /* Note: Reads from global here */
+       gcc_jit_lvalue_as_rvalue(cd_gbl));
+    
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function taking a pointer to a complex double,
+      add 1+1.j to it, and return the pointer */
+      gcc_jit_type *type_return =
+	gcc_jit_type_get_pointer (type_cd);
+      
+      gcc_jit_param *param = gcc_jit_context_new_param (
+	ctxt, 0, gcc_jit_type_get_pointer (type_cd), "pcd");
+      
+      gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+	GCC_JIT_FUNCTION_EXPORTED,
+	type_return,
+	"a_pointy_fn_returning_points", 1, &param, 0);
+      gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+      
+      gcc_jit_rvalue *param_rv = gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0));
+
+      gcc_jit_rvalue *rval = gcc_jit_context_new_binary_op (
+	ctxt, 0, GCC_JIT_BINARY_OP_PLUS, type_cd,
+	gcc_jit_context_new_rvalue_from_complex_double (
+	  ctxt, type_cd, 1 + 1.j),
+	gcc_jit_lvalue_as_rvalue (
+	  gcc_jit_rvalue_dereference (
+	    param_rv, 0)));
+      gcc_jit_block_add_assignment (block, 0,
+        gcc_jit_rvalue_dereference (
+	    param_rv, 0),
+	rval);
+
+      gcc_jit_block_end_with_return (
+	block, 0, param_rv);
+  }
+}
+
+typedef union {
+  _Complex double cd;
+  int i;
+} complex_test_union;
+
+typedef struct {
+  _Complex double cd;
+  int i;
+} complex_test_struct;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    complex_test_union (*fn)() = gcc_jit_result_get_code (result, "a_uniony_fn_returning_union");
+    CHECK_NON_NULL (fn);
+
+    complex_test_union u = fn();
+    CHECK_VALUE (u.cd, 3.14 + 1592.j);
+  }
+  {
+    complex_test_struct (*fn)() = gcc_jit_result_get_code (result, "a_structy_fn_returning_struct");
+    CHECK_NON_NULL (fn);
+
+    complex_test_struct s = fn();
+    CHECK_VALUE (s.cd, 6535 + 9.j);
+  }
+  {
+    _Complex double *
+    (*fn)(_Complex double *) = gcc_jit_result_get_code (result, "a_pointy_fn_returning_points");
+    CHECK_NON_NULL (fn);
+
+    _Complex double s = 2. + 3.i;
+    _Complex double *p = fn(&s);
+    CHECK_VALUE (p, &s);
+    CHECK_VALUE (s, 3. + 4.i);
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-operators.c b/gcc/testsuite/jit.dg/test-complex-operators.c
new file mode 100644
index 00000000000..091b56fb4d2
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-operators.c
@@ -0,0 +1,353 @@
+/*
+  Test ==, !=, the create-complex-from-reals-operator,
+  unary minus and *-/+
+ */
+
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code_compop (gcc_jit_context *ctxt,
+		  const char *fn_name,
+		  int type,
+		  enum gcc_jit_comparison op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, tt, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, tt, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    bool_type, fn_name, 2, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 1));
+ 
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rcompop = gcc_jit_context_new_comparison
+    (ctxt, 0, op,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+  
+  gcc_jit_block_end_with_return (block, 0, rcompop);
+}
+
+static void
+make_code_binop (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 int return_type,
+		 enum gcc_jit_binary_op op)
+{
+  gcc_jit_type *tt1 = gcc_jit_context_get_type(ctxt, type1);
+  gcc_jit_type *tt2 = gcc_jit_context_get_type(ctxt, type2);
+  gcc_jit_type *tr = gcc_jit_context_get_type(ctxt, return_type);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param(ctxt, 0, tt2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 2, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 1));
+ 
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_binary_op
+    (ctxt, 0, op, tr,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+  
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+static void
+make_code_unop (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int type1,
+	    enum gcc_jit_unary_op op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type(ctxt, type1);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt, "f1");
+
+  gcc_jit_param *params[] = {param1};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+ 
+  /* return op f1; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_unary_op
+    (ctxt, 0, op, tt,
+     gcc_jit_lvalue_as_rvalue (f1));
+  
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code_binop (ctxt, "plus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_PLUS);
+  make_code_binop (ctxt, "minus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MINUS);
+  make_code_binop (ctxt, "div_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_DIVIDE);
+  make_code_binop (ctxt, "mul_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MULT);
+
+  make_code_binop (ctxt, "cmplx_float_float",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_binop (ctxt, "should_not_work",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+#endif
+
+  make_code_binop (ctxt, "cmplx_double_double",
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  make_code_binop (ctxt, "cmplx_long_double_long_double",
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+  
+  make_code_unop (ctxt, "minus_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_UNARY_OP_MINUS);
+
+  make_code_compop (ctxt, "equal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_compop (ctxt, "qweasdzxc",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_GE);
+#endif
+
+}
+
+typedef _Complex float (*cf_cfcf)(_Complex float, _Complex float);
+typedef _Complex float (*cf_cf)(_Complex float);
+typedef _Bool (*b_cfcf)(_Complex float, _Complex float);
+typedef _Bool (*b_cdcd)(_Complex double, _Complex double);
+typedef _Bool (*b_cldcld)(_Complex long double, _Complex long double);
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  (void) ctxt;
+  CHECK_NON_NULL (result);
+
+  {/* Test binary operators */
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "plus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) + (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) - (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "div_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)/(3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "mul_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)*(3.f + 4.fj));
+    }
+    {
+      _Complex float (*fn)(float, float) =
+	gcc_jit_result_get_code (result, "cmplx_float_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1.f + 2.fi);
+      /* Note that the real answer is 0 not nan as it would have been by
+	 multiplying INF * 1.fi */
+      CHECK_VALUE (fn (0, INFINITY), CMPLXF (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXF (0, -INFINITY));
+
+      CHECK_VALUE (crealf (fn (0, NAN)), crealf (CMPLXF (0, NAN)));
+      CHECK (isnanf (cimagf (fn (0, NAN))));
+      
+      /* -0 need be preserved */
+      _Complex float f = fn (0, -0.);
+      CHECK (signbit ( cimagf (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.)); 
+    }
+    {
+      _Complex double (*fn)(double, double) =
+        gcc_jit_result_get_code (result, "cmplx_double_double");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1. + 2.i);
+      CHECK_VALUE (fn (0, INFINITY), CMPLX (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLX (0, -INFINITY));
+      
+      CHECK_VALUE (creal (fn (0, NAN)), creal (CMPLX (0, NAN)));
+      CHECK (isnan (cimag (fn (0, NAN))));      
+      
+      _Complex double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.)); 
+    }
+    {
+      _Complex long double (*fn)(long double, long double) =
+	gcc_jit_result_get_code (result, "cmplx_long_double_long_double");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1.L + 2.Li);
+      CHECK_VALUE (fn (0, INFINITY), CMPLXL (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXL (0, -INFINITY));
+
+      CHECK_VALUE (creall (fn (0, NAN)), creall (CMPLXL (0, NAN)));
+      CHECK (isnanl (cimagl (fn (0, NAN))));      
+
+      _Complex long double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXL (0, -0.)); 
+    }
+  }
+
+  {/* Test unary ops */
+    {
+       cf_cf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj), -(1.f + 2.fj));
+    }
+  }
+  {/* Test comp ops */
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "equal_complex_float");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 1);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 0);
+    }
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "nequal_complex_float");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 0);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 1);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "equal_complex_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "nequal_complex_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "equal_complex_long_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "nequal_complex_long_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-types.c b/gcc/testsuite/jit.dg/test-complex-types.c
new file mode 100644
index 00000000000..c555133367b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-types.c
@@ -0,0 +1,677 @@
+/*
+  Test cast from all complex types to all primitive types
+  except bool and amongst the complex types them self.
+
+  Also test some cast from non-complex to complex.
+
+  Also call a mathlib complex function and create a
+  complex global.
+ */
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+/*
+  Make code 1: (check that function calls works)
+   complex float csqrtf(complex float f);
+
+   complex float complex_float_foo(complex float f)
+   {
+     return csqrtf( f * (complex float)2.);
+   }
+
+  Make code 2: (check casts)
+   int float complex_float_to_int (complex float f)
+   {
+     return f;
+   }
+   
+  with different types and function names.
+ */
+
+
+static void
+make_code1(gcc_jit_context* ctxt,
+	   const char *fn_name,
+	   const char *sqrt_fn,
+	   int type)
+{
+  gcc_jit_rvalue *rval1, *rval2;
+  gcc_jit_block *block;
+
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *func = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_IMPORTED,
+    ct, sqrt_fn, 1, &param, 0);
+
+  param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    ct, fn_name, 1, &param, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+  
+  rval1 = gcc_jit_context_new_binary_op (ctxt, 0, GCC_JIT_BINARY_OP_MULT, ct,
+    gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0)),
+    gcc_jit_context_new_rvalue_from_double (ctxt, ct, 2.));
+  
+  rval2 = gcc_jit_context_new_call (ctxt, 0, func, 1, &rval1);
+  
+  gcc_jit_block_end_with_return (block, 0, rval2);
+}
+
+static void
+make_code2 (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int complex_type,
+	    int target_type)
+{
+  gcc_jit_block *block;
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, target_type);
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, complex_type);
+  
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, &param, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_block_end_with_return (block, 0,
+    gcc_jit_context_new_cast (ctxt, 0,
+      gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0)), tt));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE),
+    "a_complex_global_double");
+  
+  make_code1 (ctxt, "complex_float_foo", "csqrtf", GCC_JIT_TYPE_COMPLEX_FLOAT);
+  make_code1 (ctxt, "complex_double_foo", "csqrt", GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  make_code1 (ctxt, "complex_long_double_foo", "csqrtl", GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
+
+#define MAKE_CODE_2(name ,complex_type, target_type)\
+  make_code2 (ctxt, #name, GCC_JIT_TYPE_ ## complex_type, GCC_JIT_TYPE_ ## target_type);
+
+#define MAKE_CODE_2_OUTER(name, type)\
+  MAKE_CODE_2(name ## _to_char, type, CHAR)\
+  MAKE_CODE_2(name ## _to_long_double, type, LONG_DOUBLE)\
+  MAKE_CODE_2(name ## _to_double, type, DOUBLE)\
+  MAKE_CODE_2(name ## _to_float, type, FLOAT)\
+  MAKE_CODE_2(name ## _to_signed_char, type, SIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_short, type, SHORT)\
+  MAKE_CODE_2(name ## _to_int, type, INT)\
+  MAKE_CODE_2(name ## _to_long, type, LONG)\
+  MAKE_CODE_2(name ## _to_long_long, type, LONG_LONG)\
+  MAKE_CODE_2(name ## _to_u_char, type, UNSIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_u_short, type, UNSIGNED_SHORT)\
+  MAKE_CODE_2(name ## _to_u_int, type, UNSIGNED_INT)\
+  MAKE_CODE_2(name ## _to_u_long, type, UNSIGNED_LONG)\
+  MAKE_CODE_2(name ## _to_u_long_long, type, UNSIGNED_LONG_LONG)\
+  MAKE_CODE_2(name ## _to_complex_float, type, COMPLEX_FLOAT)\
+  MAKE_CODE_2(name ## _to_complex_double, type, COMPLEX_DOUBLE)\
+  MAKE_CODE_2(name ## _to_complex_long_double, type, COMPLEX_LONG_DOUBLE)
+
+  /* Test all these casts */
+  MAKE_CODE_2_OUTER (complex_float, COMPLEX_FLOAT)
+  MAKE_CODE_2_OUTER (complex_double, COMPLEX_DOUBLE)
+  MAKE_CODE_2_OUTER (complex_long_double, COMPLEX_LONG_DOUBLE)    
+
+  /* Test some of these casts */
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(float, FLOAT)
+  MAKE_CODE_2_OUTER(int, INT)
+
+  /* Writing the reproducer takes annoyingly long time with all these
+     functions bellow, so #if them out. */
+#if 0
+  MAKE_CODE_2_OUTER(long_double,LONG_DOUBLE)
+  MAKE_CODE_2_OUTER(double, DOUBLE)
+  MAKE_CODE_2_OUTER(long_long, LONG_LONG)
+  MAKE_CODE_2_OUTER(long, LONG)
+  MAKE_CODE_2_OUTER(short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(signed_char, SIGNED_CHAR)
+  MAKE_CODE_2_OUTER(unsigned_long_long, UNSIGNED_LONG_LONG)
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(unsigned_int, UNSIGNED_INT)
+  MAKE_CODE_2_OUTER(unsigned_short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(unsigned_char, UNSIGNED_CHAR)
+
+  MAKE_CODE_2_OUTER(char, CHAR)
+  /* Note: No bool */
+#endif
+    
+#undef MAKE_CODE_2
+#undef MAKE_CODE_2_OUTER
+}
+
+typedef complex long double (*ld_foop)();
+typedef complex double (*d_foop)();
+typedef complex float (*f_foop)();
+
+#define FOO_to_BAR(foo, foo_txt) \
+typedef long long (* foo_txt ## _to_ll)(_Complex foo);\
+typedef long (* foo_txt ## _to_l)(_Complex foo);\
+typedef int (* foo_txt ## _to_i)(_Complex foo);\
+typedef short (* foo_txt ## _to_h)(_Complex foo);\
+typedef signed char (* foo_txt ## _to_sc)(_Complex foo);\
+typedef char (* foo_txt ## _to_c)(_Complex foo);\
+typedef unsigned long long (* foo_txt ## _to_ull)(_Complex foo);\
+typedef unsigned long (* foo_txt ## _to_ul)(_Complex foo);\
+typedef unsigned int (* foo_txt ## _to_ui)(_Complex foo);\
+typedef unsigned short (* foo_txt ## _to_uh)(_Complex foo);\
+typedef unsigned char (* foo_txt ## _to_uc)(_Complex foo);\
+typedef double (* foo_txt ## _to_d)(_Complex foo);\
+typedef float (* foo_txt ## _to_f)(_Complex foo);\
+typedef long double (* foo_txt ## _to_ld)(_Complex foo);\
+typedef _Complex double (* foo_txt ## _to_cd)(_Complex foo);\
+typedef _Complex float (* foo_txt ## _to_cf)(_Complex foo);\
+typedef _Complex long double (* foo_txt ## _to_cld)(_Complex foo);\
+typedef _Bool (* foo_txt ## _to_b)(_Complex foo);
+ 
+FOO_to_BAR (float, cf)
+FOO_to_BAR (double, cd)
+FOO_to_BAR (long double, cld)
+     
+#undef FOO_to_BAR
+  
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+   {/* Just check that we can get the global. */
+     _Complex double *d = gcc_jit_result_get_global (result, "a_complex_global_double");
+     CHECK_NON_NULL (d);
+   }
+  }
+  {/* Check the square rooty thing. */
+   { 
+     d_foop d_foop = gcc_jit_result_get_code (result, "complex_double_foo");
+     CHECK_NON_NULL (d_foop);
+
+     complex double q = 2. + 2.i;
+     complex double ref = csqrt (q * 2.);
+     complex double ans = d_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+   {
+     f_foop f_foop = gcc_jit_result_get_code (result, "complex_float_foo");
+     CHECK_NON_NULL (f_foop);
+
+     complex float q = 2.f + 2.fi;
+     complex float ref = csqrtf (q * 2.f);
+     complex float ans = f_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+   {
+     ld_foop ld_foop = gcc_jit_result_get_code (result, "complex_long_double_foo");
+     CHECK_NON_NULL (ld_foop);
+
+     complex long double q = 2.L + 2.Li;
+     complex long double ref = csqrtl (q * 2.L);
+     complex long double ans = ld_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+  }
+  /* With the power of M-w C-y */
+
+  {/* Cast hither and thither */
+   {
+     cf_to_ld fn = gcc_jit_result_get_code (result, "complex_float_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_d fn = gcc_jit_result_get_code (result, "complex_float_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_f fn = gcc_jit_result_get_code (result, "complex_float_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1.1f);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0.f);
+   }
+   {
+     cf_to_ll fn = gcc_jit_result_get_code (result, "complex_float_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_l fn = gcc_jit_result_get_code (result, "complex_float_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_i fn = gcc_jit_result_get_code (result, "complex_float_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_h fn = gcc_jit_result_get_code (result, "complex_float_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_sc fn = gcc_jit_result_get_code (result, "complex_float_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_c fn = gcc_jit_result_get_code (result, "complex_float_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ull fn = gcc_jit_result_get_code (result, "complex_float_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ul fn = gcc_jit_result_get_code (result, "complex_float_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ui fn = gcc_jit_result_get_code (result, "complex_float_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uh fn = gcc_jit_result_get_code (result, "complex_float_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uc fn = gcc_jit_result_get_code (result, "complex_float_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+  }
+  
+  {/* complex double to ... */
+   {
+     cd_to_ld fn = gcc_jit_result_get_code (result, "complex_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.);
+   }
+   {
+     cd_to_d fn = gcc_jit_result_get_code (result, "complex_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_f fn = gcc_jit_result_get_code (result, "complex_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_ll fn = gcc_jit_result_get_code (result, "complex_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_l fn = gcc_jit_result_get_code (result, "complex_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_i fn = gcc_jit_result_get_code (result, "complex_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_h fn = gcc_jit_result_get_code (result, "complex_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_sc fn = gcc_jit_result_get_code (result, "complex_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_c fn = gcc_jit_result_get_code (result, "complex_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ull fn = gcc_jit_result_get_code (result, "complex_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ul fn = gcc_jit_result_get_code (result, "complex_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ui fn = gcc_jit_result_get_code (result, "complex_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uh fn = gcc_jit_result_get_code (result, "complex_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uc fn = gcc_jit_result_get_code (result, "complex_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  {/* complex long double to ... */
+   {
+     cld_to_ld fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_d fn = gcc_jit_result_get_code (result, "complex_long_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_f fn = gcc_jit_result_get_code (result, "complex_long_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }    
+   {
+     cld_to_ll fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_l fn = gcc_jit_result_get_code (result, "complex_long_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_i fn = gcc_jit_result_get_code (result, "complex_long_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_h fn = gcc_jit_result_get_code (result, "complex_long_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_sc fn = gcc_jit_result_get_code (result, "complex_long_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_c fn = gcc_jit_result_get_code (result, "complex_long_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ull fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ul fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ui fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uh fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uc fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  { /* Try casting complex types to complex types */
+   {
+     cld_to_cld fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L + 2.2Li);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L + 0.0Li);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0L + 2.2Li);
+   }
+   {
+     cld_to_cd fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0 + 2.2i);
+   }
+   {
+     cld_to_cf fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0f + 2.2fi);
+   }
+   {
+     cd_to_cld fn = gcc_jit_result_get_code (result, "complex_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cd fn = gcc_jit_result_get_code (result, "complex_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cf fn = gcc_jit_result_get_code (result, "complex_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cld fn = gcc_jit_result_get_code (result, "complex_float_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cd fn = gcc_jit_result_get_code (result, "complex_float_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cf fn = gcc_jit_result_get_code (result, "complex_float_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+  }
+
+  {/* Test some of the non-complex to non-complex/complex casts  */
+    {
+      _Complex float(*fn)(float) = gcc_jit_result_get_code (result, "float_to_complex_float");
+      CHECK_VALUE ( fn(3.f), 3.f);
+    }
+    {
+      _Complex float(*fn)(int) = gcc_jit_result_get_code (result, "int_to_complex_float");
+      CHECK_VALUE ( fn(-3), -3.f);
+    }
+    {
+      _Complex double(*fn)(unsigned long) = gcc_jit_result_get_code (result, "unsigned_long_to_complex_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      double(*fn)(int) = gcc_jit_result_get_code (result, "int_to_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      int(*fn)(float) = gcc_jit_result_get_code (result, "float_to_int");
+      CHECK_VALUE ( fn(3.), 3);
+    }
+  } 
+}
diff --git a/gcc/testsuite/jit.dg/test-error-complex-noenable.c b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
new file mode 100644
index 00000000000..0a7ba131f28
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
@@ -0,0 +1,31 @@
+/*
+  Test that we can't get a complex type without enabling them first
+  with
+    gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+*/
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt,
+					       GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  CHECK_VALUE (tt, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Verify that the diagnostic led to the context failing... */
+  CHECK_VALUE (result, NULL);
+
+  /* ...and that the message was captured by the API.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_get_type: complex types are only "
+		      "available after enabling them with "
+		      "gcc_jit_context_set_bool_enable_complex_types()");
+}
-- 
2.30.2


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

* [PATCH 2/2] jit: Complex types and loong constants
  2021-10-21 13:02 [PATCH 0/2] jit: Complex types and loong constants Petter Tomner
  2021-10-21 13:07 ` [PATCH 1/2] " Petter Tomner
@ 2021-10-21 13:13 ` Petter Tomner
  1 sibling, 0 replies; 6+ messages in thread
From: Petter Tomner @ 2021-10-21 13:13 UTC (permalink / raw)
  To: gcc-patches, jit

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

This patch adds the possibility to make the following constants:
* long long
* long double
* complex long double

The long long one is needed for 32bit systems.

The new entrypoints are:
gcc_jit_context_new_rvalue_from_long_long
gcc_jit_context_new_rvalue_from_long_double
gcc_jit_context_new_rvalue_from_complex_long_double

The patch also fixes a issue with the reproducer's debug 
c-file writer, which does not handle floating point numbers
very well. I.e. infs, NaN and losing precision on doubles.

make check-jit runs fine with the patch series on Debian 64x.

See attachment.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-long-long.patch --]
[-- Type: text/x-patch; name="0002-long-long.patch", Size: 42834 bytes --]

From f49cea6830b08a019958ef3f6a1ced1e416f80b3 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Sat, 16 Oct 2021 21:55:20 +0200
Subject: [PATCH 2/3] long long

Add long long, long double and complex long double constants

This patch adds entrypoints to make constants (literals) for long long,
long double and complex long double types.

Also, it fixes problems with all floating point numbers in write_reproducer.
I.e. support NAN and INF values, aswell as proper precision for double
and long double. Which is needed for testing this patch.

Signed-off-by:
2021-10-21	Petter Tomner	<tomner@kth.se>

gcc/jit/
	* jit-playback.c :
	(new_rvalue_from_const <long long>): New
	(new_rvalue_from_const <long>): Uses long long instead
	(new_rvalue_from_const <long double>): New
	(new_rvalue_from_const <_Complex long double>) : New
	* jit-recording.c :
	(dump_reproducer_to_file) : Type punning NANs
	(reproducer_write_arr) : arr -> "char array literal"-string
	(memento_of_new_rvalue_from_const <long long>) : New
	(memento_of_new_rvalue_from_const <long double>) : New
	(memento_of_new_rvalue_from_const <_Complex long double>) : New
	(memento_of_new_rvalue_from_const <double>::make_debug_string):
	%g instead of %f
	(memento_of_new_rvalue_from_const <double>::write_reproducer):
	%a instead of %f, handle NAN and INF
	(memento_of_new_rvalue_from_const <_Complex double>::write_reproducer):
	%a instead of %f, handle NAN and INF. Use CMPLX macro.
	* libgccjit.c :
	* libgccjit.h :
	(LIBGCCJIT_HAVE_LONGLONG_CONSTANTS) : New
	(gcc_jit_context_new_rvalue_from_long_long) : New
	(gcc_jit_context_new_rvalue_from_long_double) : New
	(gcc_jit_context_new_rvalue_from_complex_long_double) : New
	* libgccjit++.h : New entrypoints
	* libgccjit.map: New entrypoints added to ABI 16

gcc/testsuite/
	* jit.dg/all-non-failing-tests.h: Added test-long-literals.c
	* jit.dg/test-long-literals.c: New

gcc/jit/docs/topics/
	* expressions.rst : Updated docks
---
 gcc/jit/docs/topics/expressions.rst          |  43 +-
 gcc/jit/jit-playback.c                       | 143 +++++-
 gcc/jit/jit-recording.c                      | 442 ++++++++++++++++++-
 gcc/jit/libgccjit++.h                        |  39 ++
 gcc/jit/libgccjit.c                          |  46 ++
 gcc/jit/libgccjit.h                          |  33 +-
 gcc/jit/libgccjit.map                        |   3 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h |   7 +
 gcc/testsuite/jit.dg/test-long-literals.c    | 283 ++++++++++++
 9 files changed, 1017 insertions(+), 22 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-long-literals.c

diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index a98f35572b4..30a3b9780f9 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -70,6 +70,18 @@ Simple expressions
    Given a numeric type (integer or floating point), build an rvalue for
    the given constant :c:type:`long` value.
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, \
+                                                         gcc_jit_type *numeric_type, \
+                                                         long long value)
+
+   Given a numeric type (integer or floating point), build an rvalue for
+   the given constant :c:type:`long long` value.
+
+   This function was added in :ref:`LIBGCCJIT_ABI_16`;
+   you can test for its presence using
+       `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS`
+
 .. function::  gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
                                                      gcc_jit_type *numeric_type)
 
@@ -98,6 +110,18 @@ Simple expressions
    Given a numeric type (integer or floating point), build an rvalue for
    the given constant :c:type:`double` value.
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, \
+                                                           gcc_jit_type *numeric_type, \
+                                                           long double value)
+
+   Given a floating point type, build an rvalue for
+   the given constant :c:type:`long double`.
+
+   This function was added in :ref:`LIBGCCJIT_ABI_16`;
+   you can test for its presence using
+       `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS`
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \
                                                               gcc_jit_type *numeric_type, \
@@ -107,6 +131,23 @@ Simple expressions
    the given constant :c:type:`_Complex double`. When the result type is
    non-complex, the imaginary part is discarded.
 
+   This function was added in :ref:`LIBGCCJIT_ABI_16`;
+   you can test for its presence using
+       `#ifdef LIBGCCJIT_HAVE_COMPLEX`
+
+.. function:: extern gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_complex_long_double (gcc_jit_context *ctxt,\
+                                                                   gcc_jit_type *numeric_type,\
+                                                                   _Complex long double value);
+
+   Given a floating point type, build an rvalue for
+   the given constant :c:type:`_Complex long double`. When the result type is
+   non-complex, the imaginary part is discarded.
+
+   This function was added in :ref:`LIBGCCJIT_ABI_16`;
+   you can test for its presence using
+       `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS`
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
                                                    gcc_jit_type *pointer_type, \
@@ -403,7 +444,7 @@ Binary Operation                          C equivalent    Supported operand type
    the imaginary. Negative zeroes are preserved
    and Inf:s do not lead to NaNs.
 
-   This operator  was added in LIBGCCJIT_ABI_16;
+   This operator  was added in :ref:`LIBGCCJIT_ABI_16`;
    you can test for its presence using
        `#ifdef LIBGCCJIT_HAVE_COMPLEX`
 
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 8b1cb818b90..1f4dc31a1c1 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -61,6 +61,13 @@ along with GCC; see the file COPYING3.  If not see
 #define SET_DECL_JIT_BIT_FIELD(NODE) \
   (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
 
+/* "There are always [atleast] 32 bits in each long, no matter the
+    size of the hosts long.  We handle floating point representations
+    with up to 192 bits", says native_interpret_real() in fold-const.c.
+    That means 6 longs to store a long double. We'll make it 8 to
+    be safe with padding. */
+#define N_LONGS_LDOUBLE 8
+
 /* gcc::jit::playback::context::build_cast uses the convert.h API,
    which in turn requires the frontend to provide a "convert"
    function, apparently as a fallback for casts that can be simplified
@@ -743,15 +750,14 @@ new_rvalue_from_const <int> (type *type,
     }
 }
 
-/* Specialization of making an rvalue from a const, for host <long>.  */
+/* Specialization of making an rvalue from a const, for host <long long>. */
 
 template <>
 rvalue *
 context::
-new_rvalue_from_const <long> (type *type,
-			      long value)
+new_rvalue_from_const <long long> (type *type,
+				   long long value)
 {
-  // FIXME: type-checking, or coercion?
   tree inner_type = type->as_tree ();
   if (INTEGRAL_TYPE_P (inner_type))
     {
@@ -786,6 +792,17 @@ new_rvalue_from_const <long> (type *type,
     }
 }
 
+/* Specialization of making an rvalue from a const, for host <long>.  */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <long> (type *type,
+			      long value)
+{
+  return new_rvalue_from_const <long long> (type, value);
+}
+
 /* Specialization of making an rvalue from a const, for host <double>.  */
 
 template <>
@@ -847,6 +864,65 @@ new_rvalue_from_const <double> (type *type,
     }
 }
 
+/* Specialization of making an rvalue from a const, for host <long double>.  */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <long double> (type *type,
+				     long double value)
+{
+  tree inner_type = type->as_tree ();
+
+  scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node);
+
+  union
+  {
+    long double as_long_double;
+    uint32_t as_uint32s[N_LONGS_LDOUBLE];
+  } u_real, u_imag;
+
+  u_real.as_long_double = value;
+
+  long int as_long_ints[N_LONGS_LDOUBLE];
+
+  for (int i = 0; i < N_LONGS_LDOUBLE; i++)
+    as_long_ints[i] = u_real.as_uint32s[i];
+
+  REAL_VALUE_TYPE real_value;
+  real_from_target (&real_value, as_long_ints, mode);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int zero_as_long_ints[N_LONGS_LDOUBLE];
+      u_imag.as_long_double = 0.;
+
+      for (int i = 0; i < N_LONGS_LDOUBLE; i++)
+	zero_as_long_ints[i] = u_imag.as_uint32s[i];
+
+      real_from_target (&imag_value, zero_as_long_ints, mode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
 /* Specialization of making an rvalue from a const,
    for host <double _Complex>. */
 
@@ -902,6 +978,65 @@ new_rvalue_from_const <_Complex double> (type *type,
     }
 }
 
+/* Specialization of making an rvalue from a const,
+   for host <_Complex long double>. */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <_Complex long double> (type *type,
+					      _Complex long double value)
+{
+  tree inner_type = type->as_tree ();
+
+  scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node);
+
+  union
+  {
+    long double as_long_double;
+    uint32_t as_uint32s[N_LONGS_LDOUBLE];
+  } u_real, u_imag;
+
+  u_real.as_long_double = creall(value);
+  long int as_long_ints[N_LONGS_LDOUBLE];
+
+  for (int i = 0; i < N_LONGS_LDOUBLE; i++)
+    as_long_ints[i] = u_real.as_uint32s[i];
+
+  REAL_VALUE_TYPE real_value;
+  real_from_target (&real_value, as_long_ints, mode);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int value_as_long_ints[N_LONGS_LDOUBLE];
+      u_imag.as_long_double = cimagl(value);
+
+      for (int i = 0; i < N_LONGS_LDOUBLE; i++)
+	value_as_long_ints[i] = u_imag.as_uint32s[i];
+
+      real_from_target (&imag_value, value_as_long_ints, mode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
 /* Specialization of making an rvalue from a const, for host <void *>.  */
 
 template <>
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index b3bb6acfeb9..8d34956fc67 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <pthread.h>
 #include <complex.h>
+#include <float.h>
 
 #include "jit-builtins.h"
 #include "jit-recording.h"
@@ -1734,8 +1735,48 @@ recording::context::dump_reproducer_to_file (const char *path)
 	   " gcc_jit_context_dump_reproducer_to_file.\n\n");
   print_version (r.get_file (), "  ", false);
   r.write ("*/\n");
-  r.write ("#include <libgccjit.h>\n\n");
-  r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n\n");
+  r.write (
+    "#include <libgccjit.h>\n"
+    "#include <math.h>\n"
+    "#include <complex.h>\n"
+    "#include <string.h>\n\n");
+  r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n");
+  r.write ("#pragma GCC diagnostic ignored \"-Wunused-function\"\n\n");
+  /* Type punning unions */
+  r.write ("union dull { double d; unsigned long long ull; };\n\n");
+  r.write (
+    "union ldarr { long double ld; unsigned arr[sizeof (long double)];};\n\n");
+
+  /* Functions for type punning nan:s, keeping bit representation */
+  r.write (
+    "/* Convert type punned uint 64 to double NaN.\n"
+    "   Might lose/corrupt payload between architectures. */\n"
+    "static double\n"
+    "ull_to_d (unsigned long long ull)\n"
+    "{\n"
+    "  union dull u; u.ull = ull;\n"
+    "  /* Paranoia check for foreign NaN representation. */\n"
+    "  if (!isnan (u.d)) return NAN;\n"
+    "  return u.d;\n"
+    "}\n\n");
+  r.write (
+    "/* Convert array to long double NaN.\n"
+    "   Might lose/corrupt payload between architectures. */\n"
+    "static long double\n"
+    "arr_to_ld (unsigned char *arr, int len)\n"
+    "{\n"
+    "  union ldarr u;\n"
+    /* Since long double sizes can vary between architectures,
+       we need to handle that. */
+    "  /* For foreign long double sizes */\n"
+    "  if (sizeof u.arr != len) return NAN;\n"
+    "  memcpy (u.arr, arr, len);\n"
+    /* The size might fool us becouse of padding, so check it is a nan. */
+    "  /* Handle foreign representations that is not NaN on this machine. */\n"
+    "  if (!isnan (u.ld)) return NAN;\n"
+    "  return u.ld;\n"
+    "}\n\n");
+
   r.write ("static void\nset_options (");
   r.write_params (contexts);
   r.write (");\n\n");
@@ -4758,8 +4799,11 @@ recording::global::write_reproducer (reproducer &r)
 /* Explicit specialization of the various mementos we're interested in.  */
 template class recording::memento_of_new_rvalue_from_const <int>;
 template class recording::memento_of_new_rvalue_from_const <long>;
+template class recording::memento_of_new_rvalue_from_const <long long>;
 template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <long double>;
 template class recording::memento_of_new_rvalue_from_const <_Complex double>;
+template class recording::memento_of_new_rvalue_from_const <_Complex long double>;
 template class recording::memento_of_new_rvalue_from_const <void *>;
 
 /* Implementation of the pure virtual hook recording::memento::replay_into
@@ -4896,6 +4940,70 @@ recording::memento_of_new_rvalue_from_const <long>::write_reproducer (reproducer
 	   m_value);
 	   }
 
+/* The make_debug_string specialization for <long long>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(long long)42". */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <long long>::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%lli",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The get_wide_int specialization for <long long>. */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <long long>::get_wide_int (wide_int *out) const
+{
+  *out = wi::shwi (m_value, sizeof (m_value) * 8);
+  return true;
+}
+
+/* The write_reproducer specialization for <long long>. */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <long long>::
+write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+
+  /* Same special case as in long */
+  if (m_value == LONG_LONG_MIN)
+    {
+      r.write (
+	"  gcc_jit_rvalue *%s =\n"
+	"    gcc_jit_context_new_rvalue_from_long_long (\n"
+	"      %s, /* gcc_jit_context *ctxt */\n"
+	"      %s, /* gcc_jit_type *numeric_type */\n"
+	"      %lldLL - 1); /* long long value */\n",
+	id,
+	r.get_identifier (get_context ()),
+	r.get_identifier_as_type (m_type),
+	m_value + 1);
+      return;
+    }
+
+  r.write (
+    "  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_long_long (\n"
+    "      %s, /* gcc_jit_context *ctxt */\n"
+    "      %s, /* gcc_jit_type *numeric_type */\n"
+    "      %lldLL); /* long long value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    m_value);
+}
+
+
+
 /* The make_debug_string specialization for <double>, rendering it as
      (TARGET_TYPE)LITERAL
    e.g.
@@ -4906,7 +5014,7 @@ string *
 memento_of_new_rvalue_from_const <double>::make_debug_string ()
 {
   return string::from_printf (m_ctxt,
-			      "(%s)%f",
+			      "(%s)%g",
 			      m_type->get_debug_string (),
 			      m_value);
 }
@@ -4920,6 +5028,18 @@ memento_of_new_rvalue_from_const <double>::get_wide_int (wide_int *) const
   return false;
 }
 
+/* For typepruning NaNs. */
+union dull {
+  double d;
+  unsigned long long ull;
+};
+
+union ldarr {
+  long double ld;
+  unsigned char arr[sizeof(long double)];
+};
+
+
 /* The write_reproducer specialization for <double>.  */
 
 template <>
@@ -4927,14 +5047,154 @@ void
 recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproducer &r)
 {
   const char *id = r.make_identifier (this, "rvalue");
-  r.write ("  gcc_jit_rvalue *%s =\n"
-    "    gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
-    "                                            %s, /* gcc_jit_type *numeric_type */\n"
-    "                                            %f); /* double value */\n",
-    id,
-    r.get_identifier (get_context ()),
-    r.get_identifier_as_type (m_type),
-    m_value);
+
+  if (std::isfinite (m_value))
+    r.write ("  gcc_jit_rvalue *%s =\n"
+      "    gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
+      "                                            %s, /* gcc_jit_type *numeric_type */\n"
+      "                                            /* %.9g */\n"
+      "                                            %a);\n",
+      id,
+      r.get_identifier (get_context ()),
+      r.get_identifier_as_type (m_type),
+      m_value, m_value);
+   else if (std::isinf (m_value))
+     {
+       const char *sign = "";
+       if (m_value < 0)
+	 sign = "-";
+
+       r.write ("  gcc_jit_rvalue *%s =\n"
+	 "    gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
+	 "                                            %s, /* gcc_jit_type *numeric_type */\n"
+	 "                                            /* inf */\n"
+	 "                                            %sINFINITY);\n",
+	 id,
+	 r.get_identifier (get_context ()),
+	 r.get_identifier_as_type (m_type),
+	 sign);
+      }
+    else if (std::isnan (m_value)) {
+      union dull u;
+      u.d = m_value;
+      r.write ("  gcc_jit_rvalue *%s =\n"
+	"    gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
+	"                                            %s, /* gcc_jit_type *numeric_type */\n"
+	"                                            /* NaN */\n"
+	"                                            ull_to_d(%#llx));\n",
+	id,
+	r.get_identifier (get_context ()),
+	r.get_identifier_as_type (m_type),
+	u.ull);
+
+    }
+}
+
+/* The make_debug_string specialization for <long double>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(float)42.0".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <long double>::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%Lg",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The get_wide_int specialization for <double>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <long double>::get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* Helper function for write_reproducer()
+
+   Write an array of unsigned chars to the reproducer, like:
+   {0x12, 0x34, ... } */
+static void
+reproducer_write_arr (reproducer &r, unsigned char *arr, int len)
+{
+  if (len == 0)
+    return;
+
+  r.write ("{");
+  for (int i = 0; i < len - 1; i++)
+    r.write ("%#x , ", arr[i]);
+  r.write ("%#x }", arr[len - 1]);
+}
+
+/* The write_reproducer specialization for <double>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <long double>::
+write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+
+  if (std::isfinite (m_value))
+    r.write (
+      "  gcc_jit_rvalue *%s =\n"
+      "    gcc_jit_context_new_rvalue_from_long_double (\n"
+      "      %s, /* gcc_jit_context *ctxt */\n"
+      "      %s, /* gcc_jit_type *numeric_type */\n"
+      "      /* %.9Lg */\n"
+      "      %LaL); /* long double value */\n",
+      id,
+      r.get_identifier (get_context ()),
+      r.get_identifier_as_type (m_type),
+      m_value, m_value);
+  else if (std::isinf (m_value))
+    {
+      const char *sign = "";
+      if (m_value < 0)
+	sign = "-";
+      r.write (
+      "  gcc_jit_rvalue *%s =\n"
+      "    gcc_jit_context_new_rvalue_from_long_double (\n"
+      "      %s, /* gcc_jit_context *ctxt */\n"
+      "      %s, /* gcc_jit_type *numeric_type */\n"
+      "      /* inf */\n"
+      "      %sINFINITY);\n",
+      id,
+      r.get_identifier (get_context ()),
+      r.get_identifier_as_type (m_type),
+      sign);
+    }
+  else
+    {
+      union ldarr u; /* For type punning to array */
+      u.ld = m_value;
+
+      r.write ("  gcc_jit_rvalue *%s;\n", id);
+      /* Scope for local */
+      r.write ("  { /* long double NaN stored in char arr */\n");
+      /* Write an char arr of the bytes of the NaN */
+      r.write ("    unsigned char arr[] = ");
+      reproducer_write_arr (r, u.arr, sizeof u.arr);
+      r.write (";\n");
+
+      r.write (
+      "    %s =\n"
+      "      gcc_jit_context_new_rvalue_from_long_double (\n"
+      "        %s, /* gcc_jit_context *ctxt */\n"
+      "        %s, /* gcc_jit_type *numeric_type */\n"
+      "        /* %Lg */\n"
+      "        arr_to_ld (arr, sizeof arr));\n",
+      id,
+      r.get_identifier (get_context ()),
+      r.get_identifier_as_type (m_type),
+      m_value);
+
+      r.write ("  }\n"); /* Close scope */
+    }
 }
 
 /* The make_debug_string specialization for <double complex>, rendering it as
@@ -4964,7 +5224,7 @@ get_wide_int (wide_int *) const
   return false;
 }
 
-/* The write_reproducer specialization for <double>.  */
+/* The write_reproducer specialization for <_Complex double>.  */
 
 template <>
 void
@@ -4974,14 +5234,164 @@ write_reproducer (reproducer &r)
   const char *id = r.make_identifier (this, "rvalue");
   double real = creal(m_value);
   double imag = cimag(m_value);
-  r.write ("  gcc_jit_rvalue *%s =\n"
-    "    gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n"
-    "                                            %s, /* gcc_jit_type *numeric_type */\n"
-    "                                            %f+%fj); /* double value */\n",
+
+  r.write (
+    "  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_complex_double (\n"
+    "      %s, /* gcc_jit_context *ctxt */\n"
+    "      %s, /* gcc_jit_type *numeric_type */\n"
+    "      /* %.9g + %.9gj */\n"
+    "      CMPLX (",/* ... real, imag)); */
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    real, imag);
+
+  if (std::isfinite (real))
+    r.write("%a,", real);
+  else if (std::isinf (real))
+    {
+      if (real < 0)
+	r.write ("-INFINITY,");
+      else
+	r.write ("INFINITY,");
+    }
+  else /* NaN */
+    {
+      /* Store the NaN as a unsigned long long literal.
+	 ull_to_d() will convert it back to double */
+      union dull u;
+      u.d = real;
+      r.write ("ull_to_d (%#llx),", u.ull);
+    }
+
+  if (std::isfinite (imag))
+    r.write("%a)", imag);
+  else if (std::isinf (imag))
+    {
+      if (real < 0)
+	r.write ("-INFINITY)");
+      else
+	r.write ("INFINITY)");
+    }
+  else /* NaN */
+    {
+      union dull u;
+      u.d = imag;
+      r.write ("ull_to_d (%#llx))", u.ull);
+    }
+
+  r.write (");\n\n"); /* Close the function call */
+}
+
+template <>
+string *
+memento_of_new_rvalue_from_const <_Complex long double>::make_debug_string ()
+{
+  long double real = creall(m_value);
+  long double imag = cimagl(m_value);
+  return string::from_printf (m_ctxt,
+			      "(%s)(%Lg%+Lgj)",
+			      m_type->get_debug_string (),
+			      real, imag);
+}
+
+/* The get_wide_int specialization for <_Complex long double>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <_Complex long double>::
+get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* The write_reproducer specialization for <_Complex long double>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <_Complex long double>::
+write_reproducer (reproducer &r)
+{
+  union ldarr ureal, uimag;
+  const char *id = r.make_identifier (this, "rvalue");
+  long double real = creall(m_value);
+  long double imag = cimagl(m_value);
+
+  int has_nan = std::isnan (real) || std::isnan (imag);
+
+  if (has_nan)
+    {
+      r.write ("  gcc_jit_rvalue *%s;\n", id);
+      /* Scope for multiple "NaN-arrays" in the source file  to not clash */
+      r.write ("  {\n");
+    }
+  if (std::isnan (real))
+    {
+      /* Write the raw bytes of the long double as an char array
+	 to store it in the source code.
+	 I.e. unsigned char arr[] = {0x1, 0x2, 0x3 ... }; */
+      ureal.ld = real;
+      r.write ("    unsigned char arr_real[] = ");
+      reproducer_write_arr (r, ureal.arr, sizeof ureal.arr);
+      r.write (";\n");
+    }
+  if (std::isnan (imag))
+    {
+      uimag.ld = imag;
+      r.write ("    unsigned char arr_imag[] = ");
+      reproducer_write_arr (r, uimag.arr, sizeof uimag.arr);
+      r.write (";\n");
+    }
+
+  if (has_nan)
+    r.write ("  "); /* Definition is outside the scope for NaNs */
+  else
+    r.write ("  gcc_jit_rvalue *");
+
+  r.write ("%s =\n"
+    "    gcc_jit_context_new_rvalue_from_complex_long_double (\n"
+    "      %s, /* gcc_jit_context *ctxt */\n"
+    "      %s, /* gcc_jit_type *numeric_type */\n"
+    "      /* %.9Lg + i*%.9Lg */\n"
+    "      CMPLXL (",
     id,
     r.get_identifier (get_context ()),
     r.get_identifier_as_type (m_type),
     real, imag);
+
+  if (std::isfinite (real))
+    r.write ("%LaL, ", real);
+  else if (std::isinf (real))
+    {
+      if (real < 0)
+	r.write ("-INFINITY, ");
+      else
+	r.write ("INFINITY, ");
+    }
+  else if (std::isnan (real))
+    {
+      /* Convert the char array written above, to a long double */
+      r.write ("arr_to_ld (arr_real, sizeof arr_real), ");
+    }
+
+  if (std::isfinite (imag))
+    r.write ("%LaL)", imag);
+  else if (std::isinf (imag))
+    {
+      if (imag < 0)
+	r.write ("-INFINITY)");
+      else
+	r.write ("INFINITY)");
+    }
+  else if (std::isnan (imag))
+    {
+      r.write ("arr_to_ld (arr_imag, sizeof arr_imag))");
+    }
+  r.write(");\n\n"); /* Close function call */
+
+  if (has_nan)
+    r.write ("  }\n"); /* Close NaN-array scope */
 }
 
 /* The make_debug_string specialization for <void *>, rendering it as
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index c97aeb82812..b94cdc85c8e 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -188,12 +188,18 @@ namespace gccjit
 		       int value) const;
     rvalue new_rvalue (type numeric_type,
 		       long value) const;
+    rvalue new_rvalue (type numeric_type,
+		       long long value) const;
     rvalue zero (type numeric_type) const;
     rvalue one (type numeric_type) const;
     rvalue new_rvalue (type numeric_type,
 		       double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       long double value) const;
     rvalue new_rvalue (type numeric_type,
 		       _Complex double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       _Complex long double value) const;
     rvalue new_rvalue (type pointer_type,
 		       void *value) const;
     rvalue new_rvalue (const std::string &value) const;
@@ -936,6 +942,17 @@ context::new_rvalue (type numeric_type,
 					  value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     long long value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_long_long (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
 inline rvalue
 context::zero (type numeric_type) const
 {
@@ -960,6 +977,17 @@ context::new_rvalue (type numeric_type,
 					    value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     long double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_long_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
 inline rvalue
 context::new_rvalue (type numeric_type,
 		     _Complex double value) const
@@ -971,6 +999,17 @@ context::new_rvalue (type numeric_type,
       value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     _Complex long double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_complex_long_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
 inline rvalue
 context::new_rvalue (type pointer_type,
 		     void *value) const
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 64630b810f4..97c5aba643e 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -1275,6 +1275,19 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt,
 	  ->new_rvalue_from_const <long> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt,
+					   gcc_jit_type *numeric_type,
+					   long long value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return ((gcc_jit_rvalue *)ctxt
+	  ->new_rvalue_from_const <long long> (numeric_type, value));
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    This is essentially equivalent to:
@@ -1328,6 +1341,19 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 	  ->new_rvalue_from_const <double> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt,
+					     gcc_jit_type *numeric_type,
+					     long double value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return ((gcc_jit_rvalue *)ctxt
+	  ->new_rvalue_from_const <long double> (numeric_type, value));
+}
+
 gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
 						gcc_jit_type *numeric_type,
@@ -1347,6 +1373,26 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
 	   ->new_rvalue_from_const <double _Complex> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_long_double (
+  gcc_jit_context *ctxt,
+  gcc_jit_type *numeric_type,
+  _Complex long double value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    numeric_type->is_float (),
+    ctxt, NULL,
+    "not a floating point type (type: %s)",
+    numeric_type->get_debug_string ());
+
+  return ((gcc_jit_rvalue *)ctxt
+      ->new_rvalue_from_const <_Complex long double> (numeric_type, value));
+}
+
 
 /* Public entrypoint.  See description in libgccjit.h.
 
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index d4b10fc0644..c510c5cc902 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -834,6 +834,16 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt,
 				      gcc_jit_type *numeric_type,
 				      long value);
 
+#define LIBGCCJIT_HAVE_LONGLONG_CONSTANTS
+/* Get a constant from a long long.
+
+   This function was added in LIBGCCJIT_ABI_16. You can test for
+   its presens with:
+     #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt,
+					   gcc_jit_type *numeric_type,
+					   long long value);
 extern gcc_jit_rvalue *
 gcc_jit_context_zero (gcc_jit_context *ctxt,
 		      gcc_jit_type *numeric_type);
@@ -848,7 +858,17 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					gcc_jit_type *numeric_type,
 					double value);
 
-/* Complex floating-point constants.
+/* Get a constant from a long double.
+
+   This function was added in LIBGCCJIT_ABI_16. You can test for
+   its presence with:
+     #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt,
+					     gcc_jit_type *numeric_type,
+					     long double value);
+
+/* Get a constant from a complex double.
 
    This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
    presence using
@@ -858,6 +878,17 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
 						gcc_jit_type *numeric_type,
 						_Complex double value);
 
+/* Get a constant from a complex long double.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_long_double (
+  gcc_jit_context *ctxt,
+  gcc_jit_type *numeric_type,
+  _Complex long double value);
+
 /* Pointers.  */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index c9b044dc8f5..4022dbb6fbc 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -209,5 +209,8 @@ LIBGCCJIT_ABI_15 {
 LIBGCCJIT_ABI_16 {
   global:
     gcc_jit_context_new_rvalue_from_complex_double;
+    gcc_jit_context_new_rvalue_from_complex_long_double;
     gcc_jit_context_set_bool_enable_complex_types;
+    gcc_jit_context_new_rvalue_from_long_double;
+    gcc_jit_context_new_rvalue_from_long_long;
 } LIBGCCJIT_ABI_15;
\ No newline at end of file
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 7b45acd4b9c..8416b312bad 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -239,6 +239,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-long-literals.c */
+#define create_code create_code_long_literals
+#define verify_code verify_code_long_literals
+#include "test-long-literals.c"
+#undef create_code
+#undef verify_code
+
 /* test-long-string-literal.c */
 #define create_code create_code_long_string_literal
 #define verify_code verify_code_long_string_literal
diff --git a/gcc/testsuite/jit.dg/test-long-literals.c b/gcc/testsuite/jit.dg/test-long-literals.c
new file mode 100644
index 00000000000..a83af8b0eb1
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-long-literals.c
@@ -0,0 +1,283 @@
+/* Test long literals.
+
+   I.e. long long, long double and long complex doubles.
+
+   Also test NaN:s and inf:s with double. */
+
+
+#include <complex.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+int compare_nans(double d1, double d2)
+{
+  union {double d; unsigned long long ull;} u1, u2;
+
+  u1.d = d1;
+  u2.d = d2;
+
+  return u1.ull == u2.ull;
+}
+
+int compare_nansl(long double d1, long double d2)
+{
+  union { long double ld; unsigned char arr[sizeof (long double)];}
+    u1 = {.arr = {0}},
+    u2 = {.arr = {0}};
+  /* Zero the arrs. I don't know if long double zeroes all its size
+     since some of it is padding. */
+
+  u1.ld = d1;
+  u2.ld = d2;
+
+  return memcmp (u1.arr, u2.arr, sizeof u1.arr) == 0;
+}
+
+static void
+make_code_lit_cld(gcc_jit_context *ctxt,
+                  const char *fn_name,
+                  int type,
+                  _Complex long double local_val,
+                  int lit_type)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  if (lit_type == 'L')
+    r1 = gcc_jit_context_new_rvalue_from_long_double (
+      ctxt, tt, creall(local_val));
+  else if (lit_type == 'C')
+    r1 = gcc_jit_context_new_rvalue_from_complex_long_double (
+      ctxt, tt, local_val);
+
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1));
+}
+
+static void
+make_code_lit_d (gcc_jit_context *ctxt,
+                 const char *fn_name,
+                 int type,
+                 _Complex  double local_val,
+                int lit_type)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  if (lit_type == 'd')
+    r1 = gcc_jit_context_new_rvalue_from_double (
+      ctxt, tt, local_val);
+  else if (lit_type == 'c')
+    r1 = gcc_jit_context_new_rvalue_from_complex_double (
+      ctxt, tt, local_val);
+
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1));
+}
+
+static void
+make_code_lit_ll (gcc_jit_context *ctxt,
+                  const char *fn_name,
+                  int type,
+                  long long local_val)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  r1 = gcc_jit_context_new_rvalue_from_long_long (
+    ctxt, tt, creall(local_val));
+
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1));
+}
+
+
+union uu { double d; long long l; } u;
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code_lit_cld (ctxt, "long_double_ldlit_1c1",
+    GCC_JIT_TYPE_LONG_DOUBLE,
+    -1.1L, 'L');
+  make_code_lit_cld (ctxt, "long_double_ldlit_1Ldiv3L",
+    GCC_JIT_TYPE_LONG_DOUBLE,
+    1/3.L, 'L');
+  make_code_lit_cld (ctxt, "long_double_ldlit_inf",
+    GCC_JIT_TYPE_LONG_DOUBLE,
+    INFINITY, 'L');
+  make_code_lit_cld (ctxt, "long_double_ldlit_minf",
+    GCC_JIT_TYPE_LONG_DOUBLE,
+    -INFINITY, 'L');
+  make_code_lit_cld (ctxt, "long_double_ldlit_nan1",
+    GCC_JIT_TYPE_LONG_DOUBLE,
+    nanl("1"), 'L');
+
+  make_code_lit_cld (ctxt, "complex_long_double_cldlit_1div3_2div3j",
+    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+    1/3.L + 2.Lj/3, 'C');
+
+  make_code_lit_cld (ctxt, "complex_long_double_cldlit_inf_infj",
+    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+    CMPLXL (INFINITY, INFINITY), 'C');
+  make_code_lit_cld (ctxt, "complex_long_double_cldlit_minf_minfj",
+    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+    CMPLXL (-INFINITY, -INFINITY), 'C');
+  make_code_lit_cld (ctxt, "complex_long_double_cldlit_nan1_nan2j",
+    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+    CMPLXL (nanl ("1"), nanl ("2")), 'C');
+
+  make_code_lit_ll (ctxt, "long_long_lllit_2",
+    GCC_JIT_TYPE_LONG_LONG,
+    2);
+
+  make_code_lit_ll (ctxt, "long_long_lllit_min",
+    GCC_JIT_TYPE_LONG_LONG,
+    LLONG_MIN);
+
+  make_code_lit_ll (ctxt, "long_long_lllit_max",
+    GCC_JIT_TYPE_LONG_LONG,
+    LLONG_MAX);
+
+  make_code_lit_ll (ctxt, "ulong_long_lllit_max",
+    GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+    ULLONG_MAX);
+
+  make_code_lit_d (ctxt, "double_nan1",
+    GCC_JIT_TYPE_DOUBLE,
+    nan("1"), 'd');
+  make_code_lit_d (ctxt, "double_inf",
+    GCC_JIT_TYPE_DOUBLE,
+    INFINITY, 'd');
+  make_code_lit_d (ctxt, "double_minf",
+    GCC_JIT_TYPE_DOUBLE,
+    -INFINITY, 'd');
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+  {
+    double (*f)() = gcc_jit_result_get_code (
+      result, "double_nan1");
+
+    CHECK(compare_nans (f(), nan("1")));
+  }
+  {
+    double (*f)() = gcc_jit_result_get_code (
+      result, "double_inf");
+
+    CHECK_VALUE (f(), INFINITY);
+  }
+  {
+    double (*f)() = gcc_jit_result_get_code (
+      result, "double_minf");
+
+    CHECK_VALUE (f(), -INFINITY);
+  }
+  {
+    long double (*f)() = gcc_jit_result_get_code (
+      result, "long_double_ldlit_1c1");
+
+    CHECK_VALUE(f (), -1.1L);
+  }
+  {
+    long double (*f)() = gcc_jit_result_get_code (
+      result, "long_double_ldlit_1Ldiv3L");
+
+    CHECK_VALUE(f (), 1.L/3.L);
+  }
+  {
+    _Complex long double (*f)() = gcc_jit_result_get_code (
+      result, "complex_long_double_cldlit_1div3_2div3j");
+
+    CHECK_VALUE (f(), 1/3.L + 2.Lj/3);
+  }
+  {
+    _Complex long double (*f)() = gcc_jit_result_get_code (
+      result, "complex_long_double_cldlit_inf_infj");
+
+    CHECK_VALUE (f(),CMPLXL (INFINITY, INFINITY));
+  }
+  {
+    _Complex long double (*f)() = gcc_jit_result_get_code (
+      result, "complex_long_double_cldlit_minf_minfj");
+
+    CHECK_VALUE (f(),CMPLXL (-INFINITY, -INFINITY));
+  }
+  {
+    _Complex long double (*f)() = gcc_jit_result_get_code (
+      result, "complex_long_double_cldlit_nan1_nan2j");
+    _Complex double key = CMPLXL (nanl ("1"), nanl ("2"));
+    _Complex double ans = f();
+
+    CHECK (compare_nansl (creall (key), creall (ans)));
+    CHECK (compare_nansl (cimagl (key), cimagl (ans)));
+  }
+  {
+    long long (*f)() = gcc_jit_result_get_code (
+      result, "long_long_lllit_2");
+
+    CHECK_VALUE (f(), 2);
+  }
+  {
+    long long (*f)() = gcc_jit_result_get_code (
+      result, "long_long_lllit_min");
+
+    CHECK_VALUE (f(), LLONG_MIN);
+  }
+  {
+    long long (*f)() = gcc_jit_result_get_code (
+      result, "long_long_lllit_max");
+
+    CHECK_VALUE (f(), LLONG_MAX);
+  }
+  {
+    unsigned long long (*f)() = gcc_jit_result_get_code (
+      result, "ulong_long_lllit_max");
+
+    CHECK_VALUE (f(), ULLONG_MAX);
+  }
+}
-- 
2.30.2


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

* Re: [PATCH 1/2] jit: Complex types and loong constants
  2023-11-21 14:43   ` David Malcolm
@ 2023-11-26 23:15     ` Petter Tomner
  0 siblings, 0 replies; 6+ messages in thread
From: Petter Tomner @ 2023-11-26 23:15 UTC (permalink / raw)
  To: David Malcolm, jit

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

> The patch adds usage of "_Complex" to libgccjit.h.  ... "C99 or later"
> preprocessor guard. ... Also, this needs to be includeable from C++; I'm not sure what the
> precise requirements there are.

I did some thinking and I think it is impossible to mix std::complex and _Complex in the
same entry point. I did split up the _Complex parameters in the entrypoints to one real
and one imaginary part instead. That way is standard agnostic too.

+ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+                                                 gcc_jit_type *numeric_type,
+                                                 double real, double imag)

> so presumably it should also guard
> gcc_jit_context_new_binary_op with op == GCC_JIT_BINARY_OP_COMPLEX.

+  if (op == GCC_JIT_BINARY_OP_COMPLEX)
+    {
+      RETURN_NULL_IF_FAIL (
+	ctxt->get_inner_bool_option (gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES),
+	ctxt, NULL,
+	"the complex operator is only available after enabling it with"
+	" gcc_jit_context_set_bool_enable_complex_types()");

> though I'm
> nervous about all the tests that are comparing floating point values
> for equality; do we always get the precise expected value, on every
> target?  Floating point equality comparisons tend to be a nightmare in
> unit tests.

+     CHECK (cabs (ref - ans) < 0.0001);

+       CHECK_DOUBLE_VALUE (creal (ans), creal (key));
+       CHECK_DOUBLE_VALUE (cimag (ans), cimag (key));

I changed the comparisons that involve csqrt() and cpow () to be range checks instead.
I guess libgccjit and the test exe could maybe end up with different math-libs or something
and those are approximations. Also I removed the bytewise long double nan compare since I
realized the padding bytes changed when the optimization level is set to non-zero, and I
think getting the non-padding bytes might be hard in a platform independent way.

I think that the constant folds in the test exe and the compilation in libgccjit should
always end up with the same bit exact floating point number. Otherwise the host is really
strange and the user is probably happy to know that the calculations might differ. Like,
the operation order is the same and there should be no associativity errors (unless I messed
up the order in the key result and the libgccjit compilation).

Some old Intel processors with use the x87 FPU didn't adhere to IEEE floating point behavior, and
constant folding and runtime calculations would lead to different results on those. I have run
make check-jit in a 32 bit Debian VM though, so I think I got the tests right with that in mind.

E.g.:

#include <stdio.h>

main ()
{
     volatile double pi = 3.1416;
     double foo = pi * 6.28;

     double pi2 = 3.1416;
     double foo2 = pi2 * 6.28;

     printf ("Runtime: %g, ", foo - 3.1416 * 6.28);
     printf ("%d ", foo == 3.1416 * 6.28);
     printf ("Folded: %g, ", foo2 - 3.1416 * 6.28);
     printf ("%d\n", foo2 == 3.1416 * 6.28);

     // -m32 -mfpmath=387 -O0 => Runtime: 0, 1 Folded: 0, 1
     // -m32 -mfpmath=387 -O2 => Runtime: -1.43982e-15, 1 Folded: 0, 1
     // -m32 -mfpmath=sse -O2 => Runtime: 0, 1 Folded: 0, 1
}

[-- Attachment #2: 0001-Complex.patch --]
[-- Type: text/x-patch, Size: 95565 bytes --]

From adc8d6e9d3ec48d045fbb9ec197f141ed5744ac9 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@bahnhof.se>
Date: Fri, 15 Oct 2021 20:16:54 +0200
Subject: [PATCH 1/2] Complex

JIT: Fix support for complex types

The patch adds support of complex floating point types to libgccjit.
A new binary operator 'COMPLEX' is added to create complex values
from real values. Aswell as a function to create a complex double
literal.

To notify users if a binary linking to libgccjit depends on complex
types, complex type support most be enabled with a new option function
since they allready are in the types enum.

Signed-off-by:
2021-10-21  Petter Tomner  <tomner@bahnhof.se>

gcc/jit/
	* jit-common.h : (INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES): New
	* jit-playback.c : Create imaginary literals, conversions
	  (complex_real_to_real) : New
	  (new_rvalue_from_const <host_pair<double>>) : New
	  (new_binary_op) : Add COMPLEX operator
	  (build_cast) : Casts to complex
	  (memento_of_new_rvalue_from_const <host_pair<double>>) : New
	  (binary_op::make_debug_string) : Handle complex operator
	* jit-recording.c : Reproducer, debug strings, forwarding
	* jit-recording.h :
	  (float_size_qual) : Poll size qualifier of float types
	  (is_complex) : Poll if type is complex
	  (host_pair<HOST_TYPE>) : struct of pair values
	* libgccjit++.h : New entrypoints, see below
	* libgccjit.c : Implementation of new entry points, see .h
	  (gcc_jit_context_get_type) : Extend range check, validation
	  (valid_binary_op_p) : Extend range check
	  (gcc_jit_context_new_binary_op) : Validation
	  (gcc_jit_context_new_unary_op) : Validation
	  (gcc_jit_context_new_comparison) : Validation
	* libgccjit.h :
	  (gcc_jit_context_new_rvalue_from_complex_double) : New
	  (GCC_JIT_BINARY_OP_COMPLEX) : New
	  (LIBGCCJIT_HAVE_COMPLEX) : New
	  (gcc_jit_context_set_bool_enable_complex_types) : New
	* libgccjit.map : Added new entrypoints
	  (LIBGCCJIT_ABI_26) : New

gcc/testsuite/
	* jit.dg/test-complex-builtins.c : New
	* jit.dg/test-complex-literals.c : New
	* jit.dg/test-complex-misc.c : New
	* jit.dg/test-complex-operators.c : New
	* jit.dg/test-complex-types.c : New
	* jit.dg/test-error-complex-noenable.c : New

gcc/jit/docs/topics/
	* compatibility.rst : Update docs
	* contexts.rst
	* expressions.rst
	* types.rst
---
 gcc/jit/docs/topics/compatibility.rst         |  16 +
 gcc/jit/docs/topics/contexts.rst              |  21 +-
 gcc/jit/docs/topics/expressions.rst           | 124 ++--
 gcc/jit/docs/topics/types.rst                 |  12 +-
 gcc/jit/jit-common.h                          |   2 +-
 gcc/jit/jit-playback.cc                       | 165 ++++-
 gcc/jit/jit-recording.cc                      | 179 ++++-
 gcc/jit/jit-recording.h                       |  46 ++
 gcc/jit/libgccjit++.h                         |  36 +
 gcc/jit/libgccjit.cc                          |  96 ++-
 gcc/jit/libgccjit.h                           |  61 +-
 gcc/jit/libgccjit.map                         |   6 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |  30 +
 gcc/testsuite/jit.dg/test-complex-builtins.c  | 213 ++++++
 gcc/testsuite/jit.dg/test-complex-literals.c  | 146 ++++
 gcc/testsuite/jit.dg/test-complex-misc.c      | 241 +++++++
 gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++
 gcc/testsuite/jit.dg/test-complex-types.c     | 677 ++++++++++++++++++
 .../jit.dg/test-error-complex-noenable.c      |  31 +
 19 files changed, 2390 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-complex-builtins.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-literals.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-misc.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-operators.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-types.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-complex-noenable.c

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index ebede440ee4..6922a2f67e9 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -378,3 +378,19 @@ alignment of a variable:
 --------------------
 ``LIBGCCJIT_ABI_25`` covers the addition of
 :func:`gcc_jit_type_get_restrict`
+
+.. _LIBGCCJIT_ABI_26:
+
+``LIBGCCJIT_ABI_26``
+--------------------
+``LIBGCCJIT_ABI_26`` covers the addition of support for complex types,
+literals for complex types as well as the
+complex binary operator.
+
+Note that :c:macro:`GCC_JIT_TYPE_COMPLEX_FLOAT` etc. existed in earlier
+ABI:s, but were not functional.
+
+  *  :func:`gcc_jit_context_new_rvalue_from_complex_double`
+  *  :func:`gcc_jit_context_set_bool_enable_complex_types`
+  *  :c:macro:`GCC_JIT_BINARY_OP_COMPLEX`
+
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index b22eb2aa983..2561b2bafa7 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -502,7 +502,26 @@ Boolean options
 
    .. code-block:: c
 
-      #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_print_errors_to_stderr
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_print_errors_to_stderr
+
+.. function:: void\
+              gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,\
+                                                             int bool_value);
+
+   This option can enable complex type support in libgccjit. By default,
+   no complex types can be used.
+
+   If you use complex types, it is recommended to use builtin functions
+   `creal`, `cimag` and `conj` etc. with the correct type suffix, since
+   those are inlined into the code, rather then imported functions from
+   the math lib which are not. See :ref:`gcc_jit_context_get_builtin_function`.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
 
 Integer options
 ***************
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 42cfee36302..89c99ec2f10 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -98,6 +98,22 @@ Simple expressions
    Given a numeric type (integer or floating point), build an rvalue for
    the given constant :expr:`double` value.
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \
+                                                              gcc_jit_type *numeric_type, \
+                                                              double real, double imag)
+
+   Given a floating point type, build an rvalue for
+   the given constant :expr:`_Complex double` split into its real and imaginary parts. When the result type is
+   non-complex, the imaginary part is discarded.
+
+   This function was added in :ref:`LIBGCCJIT_ABI_26`;
+   you can test for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
                                                    gcc_jit_type *pointer_type, \
@@ -313,20 +329,14 @@ Unary Operations
 
 The available unary operations are:
 
-.. list-table::
-   :header-rows: 1
-
-   * - Unary Operation
-     - C equivalent
-
-   * - :c:macro:`GCC_JIT_UNARY_OP_MINUS`
-     - `-(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`
-     - `~(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`
-     - `!(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_ABS`
-     - `abs (EXPR)`
+==========================================  ============  ======================
+Unary Operation                             C equivalent  Supported types
+==========================================  ============  ======================
+:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`     integer, real, complex
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_ABS`             `abs (EXPR)`  integer, real
+==========================================  ============  ======================
 
 .. c:macro:: GCC_JIT_UNARY_OP_MINUS
 
@@ -386,36 +396,23 @@ Binary Operations
 
 The available binary operations are:
 
-.. list-table::
-   :header-rows: 1
-
-   * - Binary Operation
-     - C equivalent
-
-   * - :c:macro:`GCC_JIT_BINARY_OP_PLUS`
-     - `x + y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MINUS`
-     - `x - y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MULT`
-     - `x * y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_DIVIDE`
-     - `x / y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MODULO`
-     - `x % y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`
-     - `x & y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`
-     - `x ^ y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`
-     - `x | y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`
-     - `x && y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`
-     - `x || y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LSHIFT`
-     - `x << y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_RSHIFT`
-     - `x >> y`
+========================================  =============== =======================
+Binary Operation                          C equivalent    Supported operand types
+========================================  =============== =======================
+:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_COMPLEX`      `CMPLX (r, i)`  real
+========================================  =============== =======================
 
 .. c:macro:: GCC_JIT_BINARY_OP_PLUS
 
@@ -543,6 +540,31 @@ The available binary operations are:
 
    in C.
 
+.. c:macro:: GCC_JIT_BINARY_OP_COMPLEX
+
+   Create a complex floating point value from
+   two real floating point values with the same
+   size qualifier as the complex result type.
+   I.e two floats for a _Complex float, etc.
+
+   Analogous to:
+
+   .. code-block:: c
+     CMPLX (real,imag)
+
+   in C.
+
+   The first operand is the real part, the other
+   the imaginary. Negative zeroes are preserved
+   and Inf:s do not lead to NaNs.
+
+   This operator  was added in LIBGCCJIT_ABI_26;
+   you can test for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
+
 Comparisons
 ***********
 
@@ -575,6 +597,9 @@ Comparisons
    * - :c:macro:`GCC_JIT_COMPARISON_GE`
      - `x >= y`
 
+
+Note: Only `==` and `!=` are defined for complex types.
+
 Function calls
 **************
 .. function:: gcc_jit_rvalue *\
@@ -676,10 +701,17 @@ Type-coercion
 
    Currently only a limited set of conversions are possible:
 
-     * int <-> float
-     * int <-> bool
+     * integer <-> integer
+     * floating point <-> floating point
+     * integer <-> floating point
+     * integer <-> bool
      * P*  <-> Q*, for pointer types P and Q
 
+   Note: "floating point" includes complex types.
+
+   When a complex type is converted to a non-complex type, the
+   imaginary part is discarded.
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,\
                                            gcc_jit_location *loc,\
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index d8c1d15d69d..45816403eb1 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -124,11 +124,17 @@ Standard types
      * - :c:data:`GCC_JIT_TYPE_FILE_PTR`
        - C type: ``(FILE *)``
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT`
-       - C99's ``_Complex float``
+       - C99's ``_Complex float``, ABI 26
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE`
-       - C99's ``_Complex double``
+       - C99's ``_Complex double``, ABI 26
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE`
-       - C99's ``_Complex long double``
+       - C99's ``_Complex long double``, ABI 26
+
+   The complex types are available from :ref:`LIBGCCJIT_ABI_26` after
+   setting :ref:`gcc_jit_context_set_bool_enable_complex_types`.
+
+   You can test for complex types support with the define
+   `#ifdef LIBGCCJIT_HAVE_COMPLEX`.
 
 .. function:: gcc_jit_type *\
               gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 80c1618da96..af085b2671b 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -199,7 +199,7 @@ enum inner_bool_option
   INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS,
   INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER,
   INNER_BOOL_OPTION_PRINT_ERRORS_TO_STDERR,
-
+  INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
   NUM_INNER_BOOL_OPTIONS
 };
 
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 18cc4da25b8..6c4c8ed5e39 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc.h"
 #include "diagnostic.h"
 #include "stmt.h"
+#include "complex.h"
 
 #include "jit-playback.h"
 #include "jit-result.h"
@@ -77,6 +78,8 @@ convert (tree dst_type, tree expr)
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
       return fold (convert_to_integer (dst_type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (dst_type, expr));
 
     default:
       gcc_assert (gcc::jit::active_playback_ctxt);
@@ -873,6 +876,24 @@ new_global_initialized (location *loc,
 namespace playback
 {
 
+/* Return the corrensponding not complex float type of a
+   float type. I.e. complex float -> float */
+static tree
+complex_real_to_real (tree complex_type)
+{
+  if (TYPE_CANONICAL (complex_type) ==
+      TYPE_CANONICAL (complex_float_type_node))
+    return float_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_double_type_node))
+    return double_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_long_double_type_node))
+    return long_double_type_node;
+  else
+    gcc_unreachable();
+}
+
 /* Specialization of making an rvalue from a const, for host <int>.  */
 
 template <>
@@ -888,6 +909,25 @@ new_rvalue_from_const <int> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -912,6 +952,25 @@ new_rvalue_from_const <long> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -937,19 +996,104 @@ new_rvalue_from_const <double> (type *type,
      real.cc:real_from_target appears to require the representation to be
      split into 32-bit values, and then sent as an pair of host long
      ints.  */
+
+  union
+  {
+    double as_double;
+    uint32_t as_uint32s[2];
+  } u_real, u_imag;
+
+  u_real.as_double = value;
+  long int as_long_ints[2];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
   REAL_VALUE_TYPE real_value;
+  real_from_target (&real_value, as_long_ints, DFmode);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int zero_as_long_ints[2];
+      u_imag.as_double = 0.;
+      zero_as_long_ints[0] = u_imag.as_uint32s[0];
+      zero_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, zero_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
+/* Specialization of making an rvalue from a const,
+   for host complex double. */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <host_pair<double>> (type *type,
+					   host_pair<double> value)
+{
+  tree inner_type = type->as_tree ();
+
   union
   {
     double as_double;
     uint32_t as_uint32s[2];
-  } u;
-  u.as_double = value;
+  } u_real, u_imag;
+
+  u_real.as_double = value.m_a;
   long int as_long_ints[2];
-  as_long_ints[0] = u.as_uint32s[0];
-  as_long_ints[1] = u.as_uint32s[1];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
+  REAL_VALUE_TYPE real_value;
   real_from_target (&real_value, as_long_ints, DFmode);
-  tree inner = build_real (inner_type, real_value);
-  return new rvalue (this, inner);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int value_as_long_ints[2];
+      u_imag.as_double = value.m_b;
+      value_as_long_ints[0] = u_imag.as_uint32s[0];
+      value_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, value_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
 }
 
 /* Specialization of making an rvalue from a const, for host <void *>.  */
@@ -1190,6 +1334,11 @@ new_binary_op (location *loc,
     case GCC_JIT_BINARY_OP_RSHIFT:
       inner_op = RSHIFT_EXPR;
       break;
+
+    /* Create complex value from two real values */
+    case GCC_JIT_BINARY_OP_COMPLEX:
+      inner_op = COMPLEX_EXPR;
+      break;
     }
 
   tree inner_expr = build2 (inner_op,
@@ -1400,6 +1549,10 @@ playback::context::build_cast (playback::location *loc,
 		      build_int_cst (TREE_TYPE (t_expr), 0));
       goto maybe_fold;
 
+    case COMPLEX_TYPE:
+      t_ret = convert_to_complex (t_dst_type, t_expr);
+      goto maybe_fold;
+
     case REAL_TYPE:
       t_ret = convert_to_real (t_dst_type, t_expr);
       goto maybe_fold;
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 9b5b8005ebe..aa11ed5171a 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "pretty-print.h"
 #include "toplev.h"
 
+#include <math.h>
 
 #include "jit-builtins.h"
 #include "jit-recording.h"
@@ -1712,6 +1713,7 @@ static const char * const
   "gcc_jit_context_set_bool_allow_unreachable_blocks",
   "gcc_jit_context_set_bool_use_external_driver",
   "gcc_jit_context_set_bool_print_errors_to_stderr",
+  "gcc_jit_context_set_bool_enable_complex_types"
 };
 
 /* Write the current value of all options to the log file (if any).  */
@@ -2645,6 +2647,69 @@ recording::memento_of_get_type::is_float () const
     }
 }
 
+/* Implementation of pure virtual hook recording::type::is_complex for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_complex () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+    case GCC_JIT_TYPE_UINT8_T:
+    case GCC_JIT_TYPE_UINT16_T:
+    case GCC_JIT_TYPE_UINT32_T:
+    case GCC_JIT_TYPE_UINT64_T:
+    case GCC_JIT_TYPE_UINT128_T:
+    case GCC_JIT_TYPE_INT8_T:
+    case GCC_JIT_TYPE_INT16_T:
+    case GCC_JIT_TYPE_INT32_T:
+    case GCC_JIT_TYPE_INT64_T:
+    case GCC_JIT_TYPE_INT128_T:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return true;
+    }
+}
+
 /* Implementation of pure virtual hook recording::type::is_bool for
    recording::memento_of_get_type.  */
 
@@ -5071,6 +5136,10 @@ recording::global::write_reproducer (reproducer &r)
 template class recording::memento_of_new_rvalue_from_const <int>;
 template class recording::memento_of_new_rvalue_from_const <long>;
 template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <long double>;
+template class recording::memento_of_new_rvalue_from_const <host_pair<double>>;
+template class
+recording::memento_of_new_rvalue_from_const <long double[2]>;
 template class recording::memento_of_new_rvalue_from_const <void *>;
 
 /* Implementation of the pure virtual hook recording::memento::replay_into
@@ -5248,6 +5317,95 @@ recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproduc
     m_value);
 }
 
+/* The make_debug_string specialization for complex double, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(complex float)(42.0+42.0j)".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <host_pair<double>>::make_debug_string ()
+{
+  double real = m_value.m_a;
+  double imag = m_value.m_b;
+  return string::from_printf (m_ctxt,
+			      "(%s)(%g%+gj)",
+			      m_type->get_debug_string (),
+			      real, imag);
+}
+
+/* The get_wide_int specialization for complex double. */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <host_pair<double>>::
+get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* The write_reproducer specialization for complex double.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <host_pair<double>>::
+write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  double real = m_value.m_a;
+  double imag = m_value.m_b;
+
+  r.write (
+    "  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_complex_double (\n"
+    "      %s, /* gcc_jit_context *ctxt */\n"
+    "      %s, /* gcc_jit_type *numeric_type */\n"
+    "      /* %.9g + %.9gj */\n"
+    "      ",/* real, imag); */
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    real, imag);
+
+  if (isfinite (real))
+    r.write("%a,", real);
+  else if (isinf (real))
+    {
+      if (real < 0)
+	r.write ("-INFINITY,");
+      else
+	r.write ("INFINITY,");
+    }
+  else /* NaN */
+    {
+      /* Store the NaN as a unsigned long long literal.
+	 ull_to_d() will convert it back to double */
+      union dull u;
+      u.d = real;
+      r.write ("ull_to_d (%#llx),", u.ull);
+    }
+
+  if (isfinite (imag))
+    r.write("%a", imag);
+  else if (isinf (imag))
+    {
+      if (real < 0)
+	r.write ("-INFINITY");
+      else
+	r.write ("INFINITY");
+    }
+  else /* NaN */
+    {
+      union dull u;
+      u.d = imag;
+      r.write ("ull_to_d (%#llx)", u.ull);
+    }
+
+  r.write (");\n\n"); /* Close the function call */
+}
+
+}
+
 /* The make_debug_string specialization for <void *>, rendering it as
      (TARGET_TYPE)HEX
    e.g.
@@ -5740,17 +5898,24 @@ static const char * const binary_op_strings[] = {
   "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
   ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+  "", /* GCC_JIT_BINARY_OP_COMPLEX - dummy not used */
 };
 
 recording::string *
 recording::binary_op::make_debug_string ()
 {
   enum precedence prec = get_precedence ();
-  return string::from_printf (m_ctxt,
-			      "%s %s %s",
-			      m_a->get_debug_string_parens (prec),
-			      binary_op_strings[m_op],
-			      m_b->get_debug_string_parens (prec));
+  if (m_op == GCC_JIT_BINARY_OP_COMPLEX)
+    return string::from_printf (m_ctxt,
+				"(%s + %s * _Imaginary_I)",
+				m_a->get_debug_string_parens (prec),
+				m_b->get_debug_string_parens (prec));
+  else
+    return string::from_printf (m_ctxt,
+				"%s %s %s",
+				m_a->get_debug_string_parens (prec),
+				binary_op_strings[m_op],
+				m_b->get_debug_string_parens (prec));
 }
 
 const char * const binary_op_reproducer_strings[] = {
@@ -5765,7 +5930,8 @@ const char * const binary_op_reproducer_strings[] = {
   "GCC_JIT_BINARY_OP_LOGICAL_AND",
   "GCC_JIT_BINARY_OP_LOGICAL_OR",
   "GCC_JIT_BINARY_OP_LSHIFT",
-  "GCC_JIT_BINARY_OP_RSHIFT"
+  "GCC_JIT_BINARY_OP_RSHIFT",
+  "GCC_JIT_BINARY_OP_COMPLEX",
 };
 
 /* Implementation of recording::memento::write_reproducer for binary ops.  */
@@ -5806,6 +5972,7 @@ static const enum precedence binary_op_precedence[] = {
   PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */
+  PRECEDENCE_CAST, /* GCC_JIT_BINARY_OP_COMPLEX */
 };
 } /* namespace recording */
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 4a8082991fb..a2d1329a07c 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -30,6 +30,16 @@ namespace gcc {
 
 namespace jit {
 
+template<typename HOST_TYPE>
+struct host_pair
+{
+  host_pair (HOST_TYPE a, HOST_TYPE b) :
+    m_a (a), m_b (b) {}
+  HOST_TYPE m_a;
+  HOST_TYPE m_b;
+};
+
+
 extern const char * const unary_op_reproducer_strings[];
 extern const char * const binary_op_reproducer_strings[];
 
@@ -165,6 +175,12 @@ public:
   new_rvalue_from_const (type *type,
 			 HOST_TYPE value);
 
+  template <typename HOST_TYPE>
+  rvalue *
+  new_rvalue_from_const (type *type,
+			 HOST_TYPE value_a,
+			 HOST_TYPE value_b);
+
   rvalue *
   new_string_literal (const char *value);
 
@@ -567,6 +583,7 @@ public:
   virtual bool is_int () const = 0;
   virtual bool is_float () const = 0;
   virtual bool is_bool () const = 0;
+  virtual bool is_complex () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_volatile () { return NULL; }
   virtual type *is_restrict () { return NULL; }
@@ -578,6 +595,9 @@ public:
   virtual vector_type *is_vector () { return NULL; }
   virtual bool has_known_size () const { return true; }
   virtual bool is_signed () const = 0;
+  /* Used to pair complex float types with real float type
+     of the same "base type". */
+  virtual int float_size_qual () const { return 0; }
 
   bool is_numeric () const
   {
@@ -640,11 +660,31 @@ public:
   bool is_int () const final override;
   bool is_float () const final override;
   bool is_bool () const final override;
+  bool is_complex () const final override;
   type *is_pointer () final override { return dereference (); }
   type *is_array () final override { return NULL; }
   bool is_void () const final override { return m_kind == GCC_JIT_TYPE_VOID; }
   bool is_signed () const final override;
 
+  int float_size_qual () const final override
+  {
+    switch (m_kind)
+      {
+      default:
+	return 0;
+      case GCC_JIT_TYPE_FLOAT:
+      case GCC_JIT_TYPE_COMPLEX_FLOAT:
+	return 1;
+      case GCC_JIT_TYPE_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+	return 2;
+      case GCC_JIT_TYPE_LONG_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+	return 3;
+      }
+  }
+
+
 public:
   void replay_into (replayer *r) final override;
 
@@ -675,6 +715,7 @@ public:
   bool is_int () const final override { return false; }
   bool is_float () const final override { return false; }
   bool is_bool () const final override { return false; }
+  bool is_complex () const final override { return false; }
   type *is_pointer () final override { return m_other_type; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
@@ -708,6 +749,7 @@ public:
   type *is_array () final override { return m_other_type->is_array (); }
   struct_ *is_struct () final override { return m_other_type->is_struct (); }
   bool is_signed () const final override { return m_other_type->is_signed (); }
+  bool is_complex () const final override { return m_other_type->is_complex (); }
 
 protected:
   type *m_other_type;
@@ -873,6 +915,8 @@ class array_type : public type
   bool is_bool () const final override { return false; }
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return m_element_type; }
+  bool is_complex () const final override { return false; }
+
   int num_elements () { return m_num_elements; }
   bool is_signed () const final override { return false; }
 
@@ -909,6 +953,7 @@ public:
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
+  bool is_complex () const final override { return false; }
 
   void replay_into (replayer *) final override;
 
@@ -1023,6 +1068,7 @@ public:
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
+  bool is_complex () const final override  { return false; }
 
   bool has_known_size () const final override { return m_fields != NULL; }
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index f9a0017cae5..b965d99d3f8 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -128,6 +128,7 @@ namespace gccjit
 
     void set_bool_allow_unreachable_blocks (int bool_value);
     void set_bool_use_external_driver (int bool_value);
+    void set_bool_enable_complex_types (int bool_value);
 
     void add_command_line_option (const char *optname);
     void add_driver_option (const char *optname);
@@ -191,6 +192,12 @@ namespace gccjit
     rvalue one (type numeric_type) const;
     rvalue new_rvalue (type numeric_type,
 		       double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       long double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       double real, double imag) const;
+    rvalue new_rvalue (type numeric_type,
+		       long double real, long double imag) const;
     rvalue new_rvalue (type pointer_type,
 		       void *value) const;
     rvalue new_rvalue (const std::string &value) const;
@@ -748,6 +755,13 @@ context::set_bool_use_external_driver (int bool_value)
 						bool_value);
 }
 
+inline void
+context::set_bool_enable_complex_types (int bool_value)
+{
+  gcc_jit_context_set_bool_enable_complex_types (m_inner_ctxt,
+						 bool_value);
+}
+
 inline void
 context::add_command_line_option (const char *optname)
 {
@@ -966,6 +980,28 @@ context::new_rvalue (type numeric_type,
 					    value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     long double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_long_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     double real, double imag) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_complex_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      real, imag));
+}
+
 inline rvalue
 context::new_rvalue (type pointer_type,
 		     void *value) const
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 0451b4df7f9..79a213624da 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -470,6 +470,14 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt,
      && type < NUM_GCC_JIT_TYPES),
     ctxt, NULL,
     "unrecognized value for enum gcc_jit_types: %i", type);
+  if (type >= GCC_JIT_TYPE_COMPLEX_FLOAT
+      && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE)
+    RETURN_NULL_IF_FAIL (
+      ctxt->get_inner_bool_option(
+	gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES),
+      ctxt, NULL,
+      "complex types are only available after enabling them with"
+      " gcc_jit_context_set_bool_enable_complex_types()");
 
   return (gcc_jit_type *)ctxt->get_type (type);
 }
@@ -2027,6 +2035,28 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 	  ->new_rvalue_from_const <double> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						double real,
+						double imag)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    numeric_type->is_float (),
+    ctxt, NULL,
+    "not a floating point type (type: %s)",
+    numeric_type->get_debug_string ());
+
+  return ((gcc_jit_rvalue *)ctxt
+	  ->new_rvalue_from_const <gcc::jit::host_pair<double>> (
+	      numeric_type, gcc::jit::host_pair<double> (real, imag)));
+}
+
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -2122,6 +2152,14 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
     result_type->get_debug_string ());
   RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
 
+  if (rvalue->get_type ()->is_complex ())
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      op == GCC_JIT_UNARY_OP_MINUS,
+      ctxt, loc,
+      "only unary minus defined for complex types: %s (type: %s)",
+      rvalue->get_debug_string (),
+      rvalue->get_type ()->get_debug_string ());
+
   return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
 }
 
@@ -2133,7 +2171,7 @@ static bool
 valid_binary_op_p (enum gcc_jit_binary_op op)
 {
   return (op >= GCC_JIT_BINARY_OP_PLUS
-	  && op <= GCC_JIT_BINARY_OP_RSHIFT);
+	  && op <= GCC_JIT_BINARY_OP_COMPLEX);
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -2178,6 +2216,43 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
     a->get_debug_string (), b->get_debug_string (),
     result_type->get_debug_string ());
 
+  if (op == GCC_JIT_BINARY_OP_COMPLEX)
+    {
+      RETURN_NULL_IF_FAIL (
+	ctxt->get_inner_bool_option (gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES),
+	ctxt, NULL,
+	"the complex operator is only available after enabling it with"
+	" gcc_jit_context_set_bool_enable_complex_types()");
+      RETURN_NULL_IF_FAIL (
+	result_type->is_complex (),
+	ctxt, loc,
+       "return type is not complex");
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!a->get_type ()->is_complex () &&
+	a->get_type ()->is_float (),
+	ctxt, loc,
+	"first operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	a->get_debug_string (),
+	a->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!b->get_type ()->is_complex () &&
+	b->get_type ()->is_float (),
+	ctxt, loc,
+	"2nd operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	b->get_debug_string (),
+	b->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	a->get_type ()-> float_size_qual () ==
+	result_type->float_size_qual (),
+	ctxt, loc,
+	"size qualifiers of complex operand's not the same as the result:"
+	" operands: %s, result:  %s",
+	a->get_type ()->get_debug_string (),
+	result_type->get_debug_string ());
+    }
+
   return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
 }
 
@@ -2214,6 +2289,14 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
     b->get_debug_string (),
     b->get_type ()->get_debug_string ());
 
+  if (a->get_type ()->is_complex())
+    RETURN_NULL_IF_FAIL_PRINTF1 (
+      (op == GCC_JIT_COMPARISON_EQ
+       || op == GCC_JIT_COMPARISON_NE),
+      ctxt, loc,
+      "invalid enum gcc_jit_comparison for complex operands: %i",
+      op);
+
   return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
 }
 
@@ -3554,6 +3637,17 @@ gcc_jit_context_set_bool_print_errors_to_stderr (gcc_jit_context *ctxt,
     enabled);
 }
 
+void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  ctxt->set_inner_bool_option (
+    gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
+    bool_value);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 749f6c24177..6ca3cd90b57 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -22,6 +22,21 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <stdio.h>
 
+#ifdef __GNUC__
+
+/* Include entrypoints with long long parameter types. */
+#  define LIBGCCJIT_INCLUDE_LONGLONGS
+
+#else
+
+#  if __STDC_VERSION__ >= 199901L
+#    define LIBGCCJIT_INCLUDE_LONGLONGS
+#  elif __cplusplus >= 201103L
+#    define LIBGCCJIT_INCLUDE_LONGLONGS
+#  endif
+
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -1083,6 +1098,18 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					gcc_jit_type *numeric_type,
 					double value);
 
+/* Complex floating-point constants.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX */
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						double real,
+						double imag);
+
 /* Pointers.  */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
@@ -1194,7 +1221,26 @@ enum gcc_jit_binary_op
   /* Right shift; analogous to:
        (EXPR_A) >> (EXPR_B)
      in C.  */
-  GCC_JIT_BINARY_OP_RSHIFT
+  GCC_JIT_BINARY_OP_RSHIFT,
+
+  /* Create a complex floating point value from
+     two real floating point values. The operands
+     and the result need to have the same size
+     qualifier.
+
+     Analogous to:
+       CMPLX (real,imag)
+     in C.
+
+     The first operand is the real part, the other
+     the imaginary. Negative zeroes are preserved
+     and Inf:s do not lead to NaNs.
+
+     This operator  was added in LIBGCCJIT_ABI_26;
+     you can test for its presence using
+       #ifdef LIBGCCJIT_HAVE_COMPLEX
+  */
+  GCC_JIT_BINARY_OP_COMPLEX
 };
 
 extern gcc_jit_rvalue *
@@ -1740,6 +1786,19 @@ gcc_jit_timer_print (gcc_jit_timer *timer,
 		     FILE *f_out);
 
 
+#define LIBGCCJIT_HAVE_COMPLEX
+
+/* Enables complex type support in libgccjit.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX
+*/
+
+extern void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value);
+
 #define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
 
 /* Mark/clear a call as needing tail-call optimization.
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 8b90a0e2ff3..efa80d9cf2f 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -276,3 +276,9 @@ LIBGCCJIT_ABI_25 {
   global:
     gcc_jit_type_get_restrict;
 } LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+  global:
+    gcc_jit_context_new_rvalue_from_complex_double;
+    gcc_jit_context_set_bool_enable_complex_types;
+} LIBGCCJIT_ABI_25;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index e762563f9bd..b8693bd5b9c 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -112,6 +112,36 @@
 #undef create_code
 #undef verify_code
 
+/* test-complex-builtins.c */
+#define create_code create_code_complex_builtins
+#define verify_code verify_code_complex_builtins
+#include "test-complex-builtins.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-literals.c */
+#define create_code create_code_complex_literals
+#define verify_code verify_code_complex_literals
+#include "test-complex-literals.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-misc.c */
+#define create_code create_code_complex_misc
+#define verify_code verify_code_complex_misc
+#include "test-complex-misc.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-operators.c */
+#define create_code create_code_complex_operators
+#define verify_code verify_code_complex_operators
+#include "test-complex-operators.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-types.c: Quite long, don't include here */
+
 /* test-compound-assignment.c */
 #define create_code create_code_compound_assignment
 #define verify_code verify_code_compound_assignment
diff --git a/gcc/testsuite/jit.dg/test-complex-builtins.c b/gcc/testsuite/jit.dg/test-complex-builtins.c
new file mode 100644
index 00000000000..1e7dedfd4c5
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-builtins.c
@@ -0,0 +1,213 @@
+/*
+  This test just checks that the builtins cimag, creal and
+  conj are usable.
+
+  Also, they should be inlined, which can be checked by
+  disassembling the object file manually.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+static void
+make_code_unop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type_return,
+		 int type_arg,
+		 gcc_jit_function *fn)
+{
+  gcc_jit_block *block;
+
+  gcc_jit_type *tr = gcc_jit_context_get_type (ctxt, type_return);
+  gcc_jit_type *ta = gcc_jit_context_get_type (ctxt, type_arg);
+
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, ta, "f1");
+
+  gcc_jit_param *params[] = {param1};
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 1, params, 0);
+
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1)
+  };
+
+  /* return fn(f1); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, fn,
+     1,
+     args);
+
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+static void
+make_code_binop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 gcc_jit_function *builtin)
+{
+  gcc_jit_block *block;
+
+  gcc_jit_type *t1 = gcc_jit_context_get_type (ctxt, type1);
+  gcc_jit_type *t2 = gcc_jit_context_get_type (ctxt, type2);
+
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, t1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, t2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    t1, fn_name, 2, params, 0);
+
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 1));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1),
+    gcc_jit_lvalue_as_rvalue (f2)
+  };
+
+  /* return builtin(f1,f2); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, builtin,
+     2,
+     args);
+
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_function *fn_cpow = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cpow");
+
+  make_code_binop_builtins (ctxt, "cpow_builtin",
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   fn_cpow);
+
+  gcc_jit_function *fn_conj = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_conj");
+
+  /* In a good world conj should be inlined */
+  make_code_unop_builtins (ctxt, "conj_inlined",
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_conj);
+
+  gcc_jit_function *fn_creal = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creal");
+  gcc_jit_function *fn_crealf = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_crealf");
+  gcc_jit_function *fn_creall = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creall");
+  gcc_jit_function *fn_cimag = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cimag");
+
+  /* These should be inlined too */
+  make_code_unop_builtins (ctxt, "creal_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_creal);
+  make_code_unop_builtins (ctxt, "cimag_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_cimag);
+
+  make_code_unop_builtins (ctxt, "crealf_inlined",
+		  GCC_JIT_TYPE_FLOAT,
+		  GCC_JIT_TYPE_COMPLEX_FLOAT,
+		  fn_crealf);
+  make_code_unop_builtins (ctxt, "creall_inlined",
+		  GCC_JIT_TYPE_LONG_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		  fn_creall);
+
+  /* Use to inspect code manually and assure conj, creal, cimag
+     are inlined. At the time of writing they are on my x64 machine */
+  #if 0
+  gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+				   "test-complex-builtins.o");
+  #endif
+}
+
+typedef _Complex double (*cd_cdcd)(_Complex double, _Complex double);
+typedef _Complex double (*cd_cd)(_Complex double);
+typedef double (*d_cd)(_Complex double);
+typedef float (*f_cf)(_Complex float);
+typedef long double (*ld_cld)(_Complex long double);
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test binary builtins */
+    {
+       cd_cdcd fn =
+	gcc_jit_result_get_code (result, "cpow_builtin");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (2, 2), 4.);
+       _Complex double ans = fn (-1., 0.5);
+       _Complex double key = __builtin_cpow (-1., 0.5);
+
+       CHECK_DOUBLE_VALUE (creal (ans), creal (key));
+       CHECK_DOUBLE_VALUE (cimag (ans), cimag (key));
+    }
+  }
+  {/* Test unary builtins */
+    { /* conj */
+      cd_cd fn = gcc_jit_result_get_code (result, "conj_inlined");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE( fn (1. - 1.j), 1. + 1.j);
+    }
+    { /* creal */
+      d_cd fn = gcc_jit_result_get_code (result, "creal_inlined");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1. - 1.j), 1.);
+    }
+    { /* cimag */
+      d_cd fn = gcc_jit_result_get_code (result, "cimag_inlined");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1. - 1.j), -1.);
+    }
+    { /* crealf */
+      f_cf fn = gcc_jit_result_get_code (result, "crealf_inlined");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f - 1.fj), 1.f);
+    }
+    { /* creall */
+      ld_cld fn = gcc_jit_result_get_code (result, "creall_inlined");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.L - 1.Lj), 1.L);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-literals.c b/gcc/testsuite/jit.dg/test-complex-literals.c
new file mode 100644
index 00000000000..47a0621703c
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-literals.c
@@ -0,0 +1,146 @@
+/*
+  Test the new 'gcc_jit_context_new_rvalue_from_complex_double()'
+  aswell as test that the old '_from_int ... _from_double"
+  can produce complex values.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code (gcc_jit_context *ctxt,
+	   const char *fn_name,
+	   int type,
+	   double real, double imag,
+	   int lit_type)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  if (lit_type == 'c')
+    r1 = gcc_jit_context_new_rvalue_from_complex_double (ctxt, tt,
+							 real, imag);
+  else if (lit_type == 'd')
+    r1 = gcc_jit_context_new_rvalue_from_double (ctxt, tt, real);
+  else if (lit_type == 'l')
+    r1 = gcc_jit_context_new_rvalue_from_long (ctxt, tt, real);
+  else if (lit_type == 'i')
+    r1 = gcc_jit_context_new_rvalue_from_int (ctxt, tt, real);
+
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue (f1));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code (ctxt, "complex_float_clit_1c1_2c2j",
+	     GCC_JIT_TYPE_COMPLEX_FLOAT,
+	     1.1, 2.2, 'c');
+  make_code (ctxt, "complex_double_clit_1c1_2c2j",
+	     GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	     1.1, 2.2, 'c');
+  make_code (ctxt, "complex_long_double_clit_1c1_2c2j",
+	     GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	     1.1, 2.2, 'c');
+  make_code (ctxt, "float_clit_1c1",
+	     GCC_JIT_TYPE_FLOAT,
+	     1.1, 2.2, 'c');
+  make_code (ctxt, "double_clit_1c1",
+	     GCC_JIT_TYPE_DOUBLE,
+	     1.1, 2.2, 'c');
+  make_code (ctxt, "long_double_clit_1c1",
+	     GCC_JIT_TYPE_LONG_DOUBLE,
+	     1.1, 2.2, 'c');
+
+  /* Make complex from "from_double", "from_long","from_int" */
+  make_code (ctxt, "complex_float_dlit_1c1",
+	     GCC_JIT_TYPE_COMPLEX_FLOAT,
+	     1.1, 0, 'd');
+  make_code (ctxt, "complex_double_dlit_1c1",
+	     GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	     1.1, 0, 'd');
+  make_code (ctxt, "complex_long_double_dlit_1c1",
+	     GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	     1.1, 0, 'd');
+  make_code (ctxt, "complex_double_llit_2",
+	     GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	     2, 0, 'l');
+  make_code (ctxt, "complex_double_ilit_3",
+	     GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	     3, 0, 'i');
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test literals */
+    {
+      _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_clit_1c1_2c2j");
+
+      CHECK_VALUE(f (), 1.1f + 2.2fj);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_clit_1c1_2c2j");
+      CHECK_VALUE(f (), 1.1 + 2.2j);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_clit_1c1_2c2j");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (),1.1 + 2.2j);
+    }
+    {
+      float (*f)() = gcc_jit_result_get_code (result, "float_clit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      double (*f)() = gcc_jit_result_get_code (result, "double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      long double (*f)() = gcc_jit_result_get_code (result, "long_double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_dlit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_dlit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_dlit_1c1");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_llit_2");
+      CHECK_VALUE(f (), 2);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_ilit_3");
+      CHECK_VALUE(f (), 3);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-misc.c b/gcc/testsuite/jit.dg/test-complex-misc.c
new file mode 100644
index 00000000000..748ecb01031
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-misc.c
@@ -0,0 +1,241 @@
+/*
+  This test checks wether complex types work with structs, unions
+  and pointers.
+
+  Aswell as const and volatile, but only in the sense that having
+  those qualifiers doesn't crash gcc.
+
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_type *type_int =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *type_cd =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  gcc_jit_type *type_float =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+  gcc_jit_lvalue *cd_gbl = gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    type_cd,
+    "a_complex_global_double_2");
+
+  /* These globals are not used for anything */
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_volatile (type_cd),
+    "a_volatile_complex_double");
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_const (type_cd),
+    "a_const_complex_double");
+
+  gcc_jit_type *arr_type =
+    gcc_jit_context_new_array_type (ctxt,
+      0, type_cd, 10);
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    arr_type,
+    "a_const_complex_double_array");
+
+  /* Verify that folding a global init works. */
+  { /* _Complex double foo = (1. + 5.i) * ((_Complex double)3.f + (3. + 2.i)) */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      type_cd,
+      "another_complex_double_global");
+    gcc_jit_rvalue *rval_0 = gcc_jit_context_new_rvalue_from_double (
+      ctxt, type_float, 3);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_complex_double (
+      ctxt, type_cd, 3, 2);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_complex_double (
+      ctxt, type_cd, 1, 5);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      type_cd,
+      gcc_jit_context_new_cast (ctxt, 0,
+				rval_0,
+				type_cd),
+      rval_1);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      type_cd,
+      rval_plus,
+      rval_2);
+
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_mul);
+  }
+
+  {/* Make a function returning union with 3.14 + 1516.j in it */
+    gcc_jit_field *cd_field =
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field =
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi =
+      gcc_jit_context_new_union_type (ctxt,
+				      0,
+				      "cdi",
+				      2,
+				      fields);
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi, "a_uniony_fn_returning_union", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi, "union_local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field
+      (local, 0, cd_field);
+    gcc_jit_block_add_assignment
+      (block, 0, lv_field,
+       gcc_jit_context_new_rvalue_from_complex_double (
+         ctxt, type_cd, 3.14, 1592.));
+
+    /* Note: Writes to global here */
+    gcc_jit_block_add_assignment (
+      block, 0, cd_gbl,
+      gcc_jit_context_new_rvalue_from_complex_double (
+	ctxt, type_cd, 6535, 9.));
+
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function returning a complexy struct */
+    gcc_jit_field *cd_field =
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field =
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi_struct =
+      gcc_jit_struct_as_type(
+	gcc_jit_context_new_struct_type (ctxt,
+					0,
+					"cdi_struct",
+					2,
+					fields));
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi_struct, "a_structy_fn_returning_struct", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi_struct, "local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field (
+      local, 0, cd_field);
+    gcc_jit_block_add_assignment (
+       block, 0, lv_field,
+       /* Note: Reads from global here */
+       gcc_jit_lvalue_as_rvalue(cd_gbl));
+
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function taking a pointer to a complex double,
+      add 1+1.j to it, and return the pointer */
+      gcc_jit_type *type_return =
+	gcc_jit_type_get_pointer (type_cd);
+
+      gcc_jit_param *param = gcc_jit_context_new_param (
+	ctxt, 0, gcc_jit_type_get_pointer (type_cd), "pcd");
+
+      gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+	GCC_JIT_FUNCTION_EXPORTED,
+	type_return,
+	"a_pointy_fn_returning_points", 1, &param, 0);
+      gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+      gcc_jit_rvalue *param_rv = gcc_jit_param_as_rvalue (
+	gcc_jit_function_get_param (foo, 0));
+
+      gcc_jit_rvalue *rval = gcc_jit_context_new_binary_op (
+	ctxt, 0, GCC_JIT_BINARY_OP_PLUS, type_cd,
+	gcc_jit_context_new_rvalue_from_complex_double (
+	  ctxt, type_cd, 1, 1),
+	  gcc_jit_lvalue_as_rvalue (
+	    gcc_jit_rvalue_dereference (
+	      param_rv, 0)));
+      gcc_jit_block_add_assignment (block, 0,
+	gcc_jit_rvalue_dereference (
+	  param_rv, 0),
+	rval);
+
+      gcc_jit_block_end_with_return (
+	block, 0, param_rv);
+  }
+}
+
+typedef union {
+  _Complex double cd;
+  int i;
+} complex_test_union;
+
+typedef struct {
+  _Complex double cd;
+  int i;
+} complex_test_struct;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    complex_test_union (*fn)() = gcc_jit_result_get_code (result, "a_uniony_fn_returning_union");
+    CHECK_NON_NULL (fn);
+
+    complex_test_union u = fn();
+    CHECK_VALUE (u.cd, 3.14 + 1592.j);
+  }
+  {
+    complex_test_struct (*fn)() = gcc_jit_result_get_code (result, "a_structy_fn_returning_struct");
+    CHECK_NON_NULL (fn);
+
+    complex_test_struct s = fn();
+    CHECK_VALUE (s.cd, 6535 + 9.j);
+  }
+  {
+    _Complex double *
+    (*fn)(_Complex double *) = gcc_jit_result_get_code (result, "a_pointy_fn_returning_points");
+    CHECK_NON_NULL (fn);
+
+    _Complex double s = 2. + 3.i;
+    _Complex double *p = fn(&s);
+    CHECK_VALUE (p, &s);
+    CHECK_VALUE (s, 3. + 4.i);
+  }
+  {
+    _Complex double* cd = gcc_jit_result_get_code (
+      result, "another_complex_double_global");
+    CHECK_VALUE (*cd, (1. + 5.i) * (3.f + (3. + 2.i)));
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-operators.c b/gcc/testsuite/jit.dg/test-complex-operators.c
new file mode 100644
index 00000000000..eda745f5e60
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-operators.c
@@ -0,0 +1,353 @@
+/*
+  Test ==, !=, the create-complex-from-reals-operator,
+  unary minus and *-/+
+ */
+
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code_compop (gcc_jit_context *ctxt,
+		  const char *fn_name,
+		  int type,
+		  enum gcc_jit_comparison op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, tt, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, tt, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    bool_type, fn_name, 2, params, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 1));
+
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rcompop = gcc_jit_context_new_comparison
+    (ctxt, 0, op,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+
+  gcc_jit_block_end_with_return (block, 0, rcompop);
+}
+
+static void
+make_code_binop (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 int return_type,
+		 enum gcc_jit_binary_op op)
+{
+  gcc_jit_type *tt1 = gcc_jit_context_get_type(ctxt, type1);
+  gcc_jit_type *tt2 = gcc_jit_context_get_type(ctxt, type2);
+  gcc_jit_type *tr = gcc_jit_context_get_type(ctxt, return_type);
+
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param(ctxt, 0, tt2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 2, params, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 1));
+
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_binary_op
+    (ctxt, 0, op, tr,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+static void
+make_code_unop (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int type1,
+	    enum gcc_jit_unary_op op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type(ctxt, type1);
+
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt, "f1");
+
+  gcc_jit_param *params[] = {param1};
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, params, 0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+
+  /* return op f1; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_unary_op
+    (ctxt, 0, op, tt,
+     gcc_jit_lvalue_as_rvalue (f1));
+
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code_binop (ctxt, "plus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_PLUS);
+  make_code_binop (ctxt, "minus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MINUS);
+  make_code_binop (ctxt, "div_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_DIVIDE);
+  make_code_binop (ctxt, "mul_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MULT);
+
+  make_code_binop (ctxt, "cmplx_float_float",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_binop (ctxt, "should_not_work",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+#endif
+
+  make_code_binop (ctxt, "cmplx_double_double",
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  make_code_binop (ctxt, "cmplx_long_double_long_double",
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  make_code_unop (ctxt, "minus_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_UNARY_OP_MINUS);
+
+  make_code_compop (ctxt, "equal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_compop (ctxt, "qweasdzxc",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_GE);
+#endif
+
+}
+
+typedef _Complex float (*cf_cfcf)(_Complex float, _Complex float);
+typedef _Complex float (*cf_cf)(_Complex float);
+typedef _Bool (*b_cfcf)(_Complex float, _Complex float);
+typedef _Bool (*b_cdcd)(_Complex double, _Complex double);
+typedef _Bool (*b_cldcld)(_Complex long double, _Complex long double);
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  (void) ctxt;
+  CHECK_NON_NULL (result);
+
+  {/* Test binary operators */
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "plus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) + (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) - (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "div_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)/(3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "mul_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)*(3.f + 4.fj));
+    }
+    {
+      _Complex float (*fn)(float, float) =
+	gcc_jit_result_get_code (result, "cmplx_float_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1, 2), 1.f + 2.fi);
+      /* Note that the real answer is 0 not nan as it would have been by
+	 multiplying INF * 1.fi */
+      CHECK_VALUE (fn (0, INFINITY), CMPLXF (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXF (0, -INFINITY));
+
+      CHECK_VALUE (crealf (fn (0, NAN)), crealf (CMPLXF (0, NAN)));
+      CHECK (isnanf (cimagf (fn (0, NAN))));
+
+      /* -0 need be preserved */
+      _Complex float f = fn (0, -0.);
+      CHECK (signbit ( cimagf (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.));
+    }
+    {
+      _Complex double (*fn)(double, double) =
+	gcc_jit_result_get_code (result, "cmplx_double_double");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1, 2), 1. + 2.i);
+      CHECK_VALUE (fn (0, INFINITY), CMPLX (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLX (0, -INFINITY));
+
+      CHECK_VALUE (creal (fn (0, NAN)), creal (CMPLX (0, NAN)));
+      CHECK (isnan (cimag (fn (0, NAN))));
+
+      _Complex double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.));
+    }
+    {
+      _Complex long double (*fn)(long double, long double) =
+	gcc_jit_result_get_code (result, "cmplx_long_double_long_double");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1, 2), 1.L + 2.Li);
+      CHECK_VALUE (fn (0, INFINITY), CMPLXL (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXL (0, -INFINITY));
+
+      CHECK_VALUE (creall (fn (0, NAN)), creall (CMPLXL (0, NAN)));
+      CHECK (isnanl (cimagl (fn (0, NAN))));
+
+      _Complex long double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXL (0, -0.));
+    }
+  }
+
+  {/* Test unary ops */
+    {
+       cf_cf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float");
+      CHECK_NON_NULL (fn);
+
+      CHECK_VALUE (fn (1.f + 2.fj), -(1.f + 2.fj));
+    }
+  }
+  {/* Test comp ops */
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "equal_complex_float");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 1);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 0);
+    }
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "nequal_complex_float");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 0);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 1);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "equal_complex_double");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "nequal_complex_double");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "equal_complex_long_double");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "nequal_complex_long_double");
+       CHECK_NON_NULL (fn);
+
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-types.c b/gcc/testsuite/jit.dg/test-complex-types.c
new file mode 100644
index 00000000000..6271d2ac236
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-types.c
@@ -0,0 +1,677 @@
+/*
+  Test cast from all complex types to all primitive types
+  except bool and amongst the complex types them self.
+
+  Also test some cast from non-complex to complex.
+
+  Also call a mathlib complex function and create a
+  complex global.
+ */
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+/*
+  Make code 1: (check that function calls works)
+   complex float csqrtf(complex float f);
+
+   complex float complex_float_foo(complex float f)
+   {
+     return csqrtf( f * (complex float)2.);
+   }
+
+  Make code 2: (check casts)
+   int float complex_float_to_int (complex float f)
+   {
+     return f;
+   }
+
+  with different types and function names.
+ */
+
+
+static void
+make_code1(gcc_jit_context* ctxt,
+	   const char *fn_name,
+	   const char *sqrt_fn,
+	   int type)
+{
+  gcc_jit_rvalue *rval1, *rval2;
+  gcc_jit_block *block;
+
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *func = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_IMPORTED,
+    ct, sqrt_fn, 1, &param, 0);
+
+  param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    ct, fn_name, 1, &param, 0);
+
+  block = gcc_jit_function_new_block (foo, "start");
+
+  rval1 = gcc_jit_context_new_binary_op (ctxt, 0, GCC_JIT_BINARY_OP_MULT, ct,
+    gcc_jit_param_as_rvalue (
+      gcc_jit_function_get_param (foo, 0)),
+    gcc_jit_context_new_rvalue_from_double (ctxt, ct, 2.));
+
+  rval2 = gcc_jit_context_new_call (ctxt, 0, func, 1, &rval1);
+
+  gcc_jit_block_end_with_return (block, 0, rval2);
+}
+
+static void
+make_code2 (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int complex_type,
+	    int target_type)
+{
+  gcc_jit_block *block;
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, target_type);
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, complex_type);
+
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, &param, 0);
+
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_block_end_with_return (block, 0,
+    gcc_jit_context_new_cast (ctxt, 0,
+      gcc_jit_param_as_rvalue (
+	gcc_jit_function_get_param (foo, 0)), tt));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE),
+    "a_complex_global_double");
+
+  make_code1 (ctxt, "complex_float_foo", "csqrtf", GCC_JIT_TYPE_COMPLEX_FLOAT);
+  make_code1 (ctxt, "complex_double_foo", "csqrt", GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  make_code1 (ctxt, "complex_long_double_foo", "csqrtl", GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
+
+#define MAKE_CODE_2(name ,complex_type, target_type)\
+  make_code2 (ctxt, #name, GCC_JIT_TYPE_ ## complex_type, GCC_JIT_TYPE_ ## target_type);
+
+#define MAKE_CODE_2_OUTER(name, type)\
+  MAKE_CODE_2(name ## _to_char, type, CHAR)\
+  MAKE_CODE_2(name ## _to_long_double, type, LONG_DOUBLE)\
+  MAKE_CODE_2(name ## _to_double, type, DOUBLE)\
+  MAKE_CODE_2(name ## _to_float, type, FLOAT)\
+  MAKE_CODE_2(name ## _to_signed_char, type, SIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_short, type, SHORT)\
+  MAKE_CODE_2(name ## _to_int, type, INT)\
+  MAKE_CODE_2(name ## _to_long, type, LONG)\
+  MAKE_CODE_2(name ## _to_long_long, type, LONG_LONG)\
+  MAKE_CODE_2(name ## _to_u_char, type, UNSIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_u_short, type, UNSIGNED_SHORT)\
+  MAKE_CODE_2(name ## _to_u_int, type, UNSIGNED_INT)\
+  MAKE_CODE_2(name ## _to_u_long, type, UNSIGNED_LONG)\
+  MAKE_CODE_2(name ## _to_u_long_long, type, UNSIGNED_LONG_LONG)\
+  MAKE_CODE_2(name ## _to_complex_float, type, COMPLEX_FLOAT)\
+  MAKE_CODE_2(name ## _to_complex_double, type, COMPLEX_DOUBLE)\
+  MAKE_CODE_2(name ## _to_complex_long_double, type, COMPLEX_LONG_DOUBLE)
+
+  /* Test all these casts */
+  MAKE_CODE_2_OUTER (complex_float, COMPLEX_FLOAT)
+  MAKE_CODE_2_OUTER (complex_double, COMPLEX_DOUBLE)
+  MAKE_CODE_2_OUTER (complex_long_double, COMPLEX_LONG_DOUBLE)
+
+  /* Test some of these casts */
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(float, FLOAT)
+  MAKE_CODE_2_OUTER(int, INT)
+
+  /* Writing the reproducer takes annoyingly long time with all these
+     functions bellow, so #if them out. */
+#if 0
+  MAKE_CODE_2_OUTER(long_double,LONG_DOUBLE)
+  MAKE_CODE_2_OUTER(double, DOUBLE)
+  MAKE_CODE_2_OUTER(long_long, LONG_LONG)
+  MAKE_CODE_2_OUTER(long, LONG)
+  MAKE_CODE_2_OUTER(short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(signed_char, SIGNED_CHAR)
+  MAKE_CODE_2_OUTER(unsigned_long_long, UNSIGNED_LONG_LONG)
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(unsigned_int, UNSIGNED_INT)
+  MAKE_CODE_2_OUTER(unsigned_short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(unsigned_char, UNSIGNED_CHAR)
+
+  MAKE_CODE_2_OUTER(char, CHAR)
+  /* Note: No bool */
+#endif
+
+#undef MAKE_CODE_2
+#undef MAKE_CODE_2_OUTER
+}
+
+typedef complex long double (*ld_foop)();
+typedef complex double (*d_foop)();
+typedef complex float (*f_foop)();
+
+#define FOO_to_BAR(foo, foo_txt) \
+typedef long long (* foo_txt ## _to_ll)(_Complex foo);\
+typedef long (* foo_txt ## _to_l)(_Complex foo);\
+typedef int (* foo_txt ## _to_i)(_Complex foo);\
+typedef short (* foo_txt ## _to_h)(_Complex foo);\
+typedef signed char (* foo_txt ## _to_sc)(_Complex foo);\
+typedef char (* foo_txt ## _to_c)(_Complex foo);\
+typedef unsigned long long (* foo_txt ## _to_ull)(_Complex foo);\
+typedef unsigned long (* foo_txt ## _to_ul)(_Complex foo);\
+typedef unsigned int (* foo_txt ## _to_ui)(_Complex foo);\
+typedef unsigned short (* foo_txt ## _to_uh)(_Complex foo);\
+typedef unsigned char (* foo_txt ## _to_uc)(_Complex foo);\
+typedef double (* foo_txt ## _to_d)(_Complex foo);\
+typedef float (* foo_txt ## _to_f)(_Complex foo);\
+typedef long double (* foo_txt ## _to_ld)(_Complex foo);\
+typedef _Complex double (* foo_txt ## _to_cd)(_Complex foo);\
+typedef _Complex float (* foo_txt ## _to_cf)(_Complex foo);\
+typedef _Complex long double (* foo_txt ## _to_cld)(_Complex foo);\
+typedef _Bool (* foo_txt ## _to_b)(_Complex foo);
+
+FOO_to_BAR (float, cf)
+FOO_to_BAR (double, cd)
+FOO_to_BAR (long double, cld)
+
+#undef FOO_to_BAR
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+   {/* Just check that we can get the global. */
+     _Complex double *d = gcc_jit_result_get_global (result, "a_complex_global_double");
+     CHECK_NON_NULL (d);
+   }
+  }
+  {/* Check the square rooty thing. */
+   {
+     d_foop d_foop = gcc_jit_result_get_code (result, "complex_double_foo");
+     CHECK_NON_NULL (d_foop);
+
+     complex double q = 2. + 2.i;
+     complex double ref = csqrt (q * 2.);
+     complex double ans = d_foop (q);
+     CHECK (cabs (ref - ans) < 0.0001);
+   }
+   {
+     f_foop f_foop = gcc_jit_result_get_code (result, "complex_float_foo");
+     CHECK_NON_NULL (f_foop);
+
+     complex float q = 2.f + 2.fi;
+     complex float ref = csqrtf (q * 2.f);
+     complex float ans = f_foop (q);
+     CHECK (cabs (ref - ans) < 0.0001);
+   }
+   {
+     ld_foop ld_foop = gcc_jit_result_get_code (result, "complex_long_double_foo");
+     CHECK_NON_NULL (ld_foop);
+
+     complex long double q = 2.L + 2.Li;
+     complex long double ref = csqrtl (q * 2.L);
+     complex long double ans = ld_foop (q);
+     CHECK (cabs (ref - ans) < 0.0001);
+   }
+  }
+  /* With the power of M-w C-y */
+
+  {/* Cast hither and thither */
+   {
+     cf_to_ld fn = gcc_jit_result_get_code (result, "complex_float_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_d fn = gcc_jit_result_get_code (result, "complex_float_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_f fn = gcc_jit_result_get_code (result, "complex_float_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1.1f);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0.f);
+   }
+   {
+     cf_to_ll fn = gcc_jit_result_get_code (result, "complex_float_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_l fn = gcc_jit_result_get_code (result, "complex_float_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_i fn = gcc_jit_result_get_code (result, "complex_float_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_h fn = gcc_jit_result_get_code (result, "complex_float_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_sc fn = gcc_jit_result_get_code (result, "complex_float_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_c fn = gcc_jit_result_get_code (result, "complex_float_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ull fn = gcc_jit_result_get_code (result, "complex_float_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ul fn = gcc_jit_result_get_code (result, "complex_float_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ui fn = gcc_jit_result_get_code (result, "complex_float_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uh fn = gcc_jit_result_get_code (result, "complex_float_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uc fn = gcc_jit_result_get_code (result, "complex_float_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+  }
+
+  {/* complex double to ... */
+   {
+     cd_to_ld fn = gcc_jit_result_get_code (result, "complex_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.);
+   }
+   {
+     cd_to_d fn = gcc_jit_result_get_code (result, "complex_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_f fn = gcc_jit_result_get_code (result, "complex_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_ll fn = gcc_jit_result_get_code (result, "complex_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_l fn = gcc_jit_result_get_code (result, "complex_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_i fn = gcc_jit_result_get_code (result, "complex_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_h fn = gcc_jit_result_get_code (result, "complex_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_sc fn = gcc_jit_result_get_code (result, "complex_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_c fn = gcc_jit_result_get_code (result, "complex_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ull fn = gcc_jit_result_get_code (result, "complex_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ul fn = gcc_jit_result_get_code (result, "complex_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ui fn = gcc_jit_result_get_code (result, "complex_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uh fn = gcc_jit_result_get_code (result, "complex_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uc fn = gcc_jit_result_get_code (result, "complex_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  {/* complex long double to ... */
+   {
+     cld_to_ld fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_d fn = gcc_jit_result_get_code (result, "complex_long_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_f fn = gcc_jit_result_get_code (result, "complex_long_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_ll fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_l fn = gcc_jit_result_get_code (result, "complex_long_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_i fn = gcc_jit_result_get_code (result, "complex_long_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_h fn = gcc_jit_result_get_code (result, "complex_long_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_sc fn = gcc_jit_result_get_code (result, "complex_long_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_c fn = gcc_jit_result_get_code (result, "complex_long_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ull fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ul fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ui fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uh fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uc fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  { /* Try casting complex types to complex types */
+   {
+     cld_to_cld fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L + 2.2Li);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L + 0.0Li);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0L + 2.2Li);
+   }
+   {
+     cld_to_cd fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0 + 2.2i);
+   }
+   {
+     cld_to_cf fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0f + 2.2fi);
+   }
+   {
+     cd_to_cld fn = gcc_jit_result_get_code (result, "complex_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cd fn = gcc_jit_result_get_code (result, "complex_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cf fn = gcc_jit_result_get_code (result, "complex_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cld fn = gcc_jit_result_get_code (result, "complex_float_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cd fn = gcc_jit_result_get_code (result, "complex_float_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cf fn = gcc_jit_result_get_code (result, "complex_float_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+  }
+
+  {/* Test some of the non-complex to non-complex/complex casts  */
+    {
+      _Complex float(*fn)(float) = gcc_jit_result_get_code (result, "float_to_complex_float");
+      CHECK_VALUE ( fn(3.f), 3.f);
+    }
+    {
+      _Complex float(*fn)(int) = gcc_jit_result_get_code (result, "int_to_complex_float");
+      CHECK_VALUE ( fn(-3), -3.f);
+    }
+    {
+      _Complex double(*fn)(unsigned long) = gcc_jit_result_get_code (result, "unsigned_long_to_complex_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      double(*fn)(int) = gcc_jit_result_get_code (result, "int_to_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      int(*fn)(float) = gcc_jit_result_get_code (result, "float_to_int");
+      CHECK_VALUE ( fn(3.), 3);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-error-complex-noenable.c b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
new file mode 100644
index 00000000000..0a7ba131f28
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
@@ -0,0 +1,31 @@
+/*
+  Test that we can't get a complex type without enabling them first
+  with
+    gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+*/
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt,
+					       GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  CHECK_VALUE (tt, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Verify that the diagnostic led to the context failing... */
+  CHECK_VALUE (result, NULL);
+
+  /* ...and that the message was captured by the API.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_get_type: complex types are only "
+		      "available after enabling them with "
+		      "gcc_jit_context_set_bool_enable_complex_types()");
+}
-- 
2.42.0


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

* Re: [PATCH 1/2] jit: Complex types and loong constants
  2023-11-20 22:10 ` [PATCH 1/2] " Petter Tomner
@ 2023-11-21 14:43   ` David Malcolm
  2023-11-26 23:15     ` Petter Tomner
  0 siblings, 1 reply; 6+ messages in thread
From: David Malcolm @ 2023-11-21 14:43 UTC (permalink / raw)
  To: Petter Tomner, jit

On Mon, 2023-11-20 at 23:10 +0100, Petter Tomner wrote:
> This patch fixes support for complex types.
> 
> It adds the entrypoints:
> gcc_jit_context_new_rvalue_from_complex_double
> gcc_jit_context_set_bool_enable_complex_types
> 
> Aswell as the binary operator GCC_JIT_BINARY_OP_COMPLEX, to make
> complex numbers from two real number rvalues.
> 
> Note that the complex types already are in the type enum, so I
> thought the
> cleanest solution is to enable them, rather than to have a
> "get_complex_type"
> function.
> 
> When I wrote the patch originally, the complex enums were not usable
> due to a
> range check, but I think they accidentally were included when int8_t
> etc were added.
> However, casts to complex types segfaults currently and some other
> issues, so I would say
> an explicit enable is the least confusing, since the enums have been
> there since the get go.
> 
> See attachement.

> Subject: [PATCH 1/2] Complex
> 
> Fix support for complex types

Thanks for the patch.

> 
> The patch adds support of complex floating point types to libgccjit.
> A new binary operator 'COMPLEX' is added to create complex values
> from real values. Aswell as a function to create a complex double
> literal.

The patch adds usage of "_Complex" to libgccjit.h.  According to
https://en.cppreference.com/w/c/language/arithmetic_types#Complex_floating_types
this is a C99 feature.

I think libgccjit.h is currently only requiring C89 (but I'm not sure),
so this declaration probably needs some kind of "C99 or later"
preprocessor guard.

Also, this needs to be includeable from C++; I'm not sure what the
precise requirements there are.

> 
> To notify users if a binary linking to libgccjit depends on complex
> types, complex type support most be enabled with a new option function
> since they allready are in the types enum.

I like this approach, but I see that the patch only uses it to guard
gcc_jit_context_get_type.

It seems to me that it should guard every entrypoint that uses an enum
that's expanded by the API, so presumably it should also guard
gcc_jit_context_new_binary_op with op == GCC_JIT_BINARY_OP_COMPLEX. 
Although you'd need a complex type from gcc_jit_context_get_type to get
the result, it's probably easier for the user to understand if we
document and validate the gcc_jit_context_new_binary_op with op ==
GCC_JIT_BINARY_OP_COMPLEX explicitly.

I looked through the rest of the patch and it seems OK, though I'm
nervous about all the tests that are comparing floating point values
for equality; do we always get the precise expected value, on every
target?  Floating point equality comparisons tend to be a nightmare in
unit tests.

Thanks again for the patch
Dave


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

* [PATCH 1/2] jit: Complex types and loong constants
  2023-11-20 22:02 [PATCH 0/2] " Petter Tomner
@ 2023-11-20 22:10 ` Petter Tomner
  2023-11-21 14:43   ` David Malcolm
  0 siblings, 1 reply; 6+ messages in thread
From: Petter Tomner @ 2023-11-20 22:10 UTC (permalink / raw)
  To: jit


[-- Attachment #1.1: Type: text/plain, Size: 804 bytes --]

This patch fixes support for complex types.

It adds the entrypoints:
gcc_jit_context_new_rvalue_from_complex_double
gcc_jit_context_set_bool_enable_complex_types

Aswell as the binary operator GCC_JIT_BINARY_OP_COMPLEX, to make
complex numbers from two real number rvalues.

Note that the complex types already are in the type enum, so I thought the
cleanest solution is to enable them, rather than to have a "get_complex_type"
function.

When I wrote the patch originally, the complex enums were not usable due to a
range check, but I think they accidentally were included when int8_t etc were added.
However, casts to complex types segfaults currently and some other issues, so I would say
an explicit enable is the least confusing, since the enums have been there since the get go.

See attachement.

[-- Attachment #2: 0001-Complex.patch --]
[-- Type: text/x-patch, Size: 91750 bytes --]

From 286241c0dc9c8ad1235fdf156174182582d2ef38 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@bahnhof.se>
Date: Fri, 15 Oct 2021 20:16:54 +0200
Subject: [PATCH 1/2] Complex

Fix support for complex types

The patch adds support of complex floating point types to libgccjit.
A new binary operator 'COMPLEX' is added to create complex values
from real values. Aswell as a function to create a complex double
literal.

To notify users if a binary linking to libgccjit depends on complex
types, complex type support most be enabled with a new option function
since they allready are in the types enum.

Signed-off-by:
2021-10-21  Petter Tomner  <tomner@bahnhof.se>

gcc/jit/
	* jit-common.h : (INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES): New
	* jit-playback.c : Create imaginary literals, conversions
	  (complex_real_to_real) : New
	  (new_rvalue_from_const<...>) : Also build complex constants
	  (new_rvalue_from_const <_Complex double>) : New
	  (new_binary_op) : Add COMPLEX operator
	  (build_cast) : Casts to complex
	  (memento_of_new_rvalue_from_const <_Complex double>) : New
	  (binary_op::make_debug_string) : Handle complex operator
	* jit-recording.c : Reproducer, debug strings, forwarding
	* jit-recording.h :
	  (float_size_qual) : Poll size qualifier of float types
	  (is_complex) : Poll if type is complex
	* libgccjit++.h : New entrypoints, see below
	* libgccjit.c : Implementation of new entry points, see .h
	  (gcc_jit_context_get_type) : Extend range check, validation
	  (valid_binary_op_p) : Extend range check
	  (gcc_jit_context_new_binary_op) : Validation
	  (gcc_jit_context_new_unary_op) : Validation
	  (gcc_jit_context_new_comparison) : Validation
	* libgccjit.h :
	  (gcc_jit_context_new_rvalue_from_complex_double) : New
	  (GCC_JIT_BINARY_OP_COMPLEX) : New
	  (LIBGCCJIT_HAVE_COMPLEX) : New
	  (gcc_jit_context_set_bool_enable_complex_types) : New
	* libgccjit.map : Added new entrypoints
	  (LIBGCCJIT_ABI_26) : New

gcc/testsuite/
	* jit.dg/test-complex-builtins.c : New
	* jit.dg/test-complex-literals.c : New
	* jit.dg/test-complex-misc.c : New
	* jit.dg/test-complex-operators.c : New
	* jit.dg/test-complex-types.c : New
	* jit.dg/test-error-complex-noenable.c : New

gcc/jit/docs/topics/
	* compatibility.rst : Update docs
	* contexts.rst
	* expressions.rst
	* types.rst
---
 gcc/jit/docs/topics/compatibility.rst         |  16 +
 gcc/jit/docs/topics/contexts.rst              |  21 +-
 gcc/jit/docs/topics/expressions.rst           | 124 ++--
 gcc/jit/docs/topics/types.rst                 |  12 +-
 gcc/jit/jit-common.h                          |   2 +-
 gcc/jit/jit-playback.cc                       | 165 ++++-
 gcc/jit/jit-recording.cc                      | 124 +++-
 gcc/jit/jit-recording.h                       |  30 +
 gcc/jit/libgccjit++.h                         |  21 +
 gcc/jit/libgccjit.cc                          |  89 ++-
 gcc/jit/libgccjit.h                           |  44 +-
 gcc/jit/libgccjit.map                         |   6 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |  30 +
 gcc/testsuite/jit.dg/test-complex-builtins.c  | 217 ++++++
 gcc/testsuite/jit.dg/test-complex-literals.c  | 145 ++++
 gcc/testsuite/jit.dg/test-complex-misc.c      | 204 ++++++
 gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++
 gcc/testsuite/jit.dg/test-complex-types.c     | 677 ++++++++++++++++++
 .../jit.dg/test-error-complex-noenable.c      |  31 +
 19 files changed, 2246 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-complex-builtins.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-literals.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-misc.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-operators.c
 create mode 100644 gcc/testsuite/jit.dg/test-complex-types.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-complex-noenable.c

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index ebede440ee4..6922a2f67e9 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -378,3 +378,19 @@ alignment of a variable:
 --------------------
 ``LIBGCCJIT_ABI_25`` covers the addition of
 :func:`gcc_jit_type_get_restrict`
+
+.. _LIBGCCJIT_ABI_26:
+
+``LIBGCCJIT_ABI_26``
+--------------------
+``LIBGCCJIT_ABI_26`` covers the addition of support for complex types,
+literals for complex types as well as the
+complex binary operator.
+
+Note that :c:macro:`GCC_JIT_TYPE_COMPLEX_FLOAT` etc. existed in earlier
+ABI:s, but were not functional.
+
+  *  :func:`gcc_jit_context_new_rvalue_from_complex_double`
+  *  :func:`gcc_jit_context_set_bool_enable_complex_types`
+  *  :c:macro:`GCC_JIT_BINARY_OP_COMPLEX`
+
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index b22eb2aa983..2561b2bafa7 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -502,7 +502,26 @@ Boolean options
 
    .. code-block:: c
 
-      #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_print_errors_to_stderr
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_print_errors_to_stderr
+
+.. function:: void\
+              gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,\
+                                                             int bool_value);
+
+   This option can enable complex type support in libgccjit. By default,
+   no complex types can be used.
+
+   If you use complex types, it is recommended to use builtin functions
+   `creal`, `cimag` and `conj` etc. with the correct type suffix, since
+   those are inlined into the code, rather then imported functions from
+   the math lib which are not. See :ref:`gcc_jit_context_get_builtin_function`.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
 
 Integer options
 ***************
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 42cfee36302..2af19dcbe28 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -98,6 +98,22 @@ Simple expressions
    Given a numeric type (integer or floating point), build an rvalue for
    the given constant :expr:`double` value.
 
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \
+                                                              gcc_jit_type *numeric_type, \
+                                                              _Complex double value)
+
+   Given a floating point type, build an rvalue for
+   the given constant :expr:`_Complex double`. When the result type is
+   non-complex, the imaginary part is discarded.
+
+   This function was added in :ref:`LIBGCCJIT_ABI_26`;
+   you can test for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
                                                    gcc_jit_type *pointer_type, \
@@ -313,20 +329,14 @@ Unary Operations
 
 The available unary operations are:
 
-.. list-table::
-   :header-rows: 1
-
-   * - Unary Operation
-     - C equivalent
-
-   * - :c:macro:`GCC_JIT_UNARY_OP_MINUS`
-     - `-(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`
-     - `~(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`
-     - `!(EXPR)`
-   * - :c:macro:`GCC_JIT_UNARY_OP_ABS`
-     - `abs (EXPR)`
+==========================================  ============  ======================
+Unary Operation                             C equivalent  Supported types
+==========================================  ============  ======================
+:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`     integer, real, complex
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`     integer
+:c:macro:`GCC_JIT_UNARY_OP_ABS`             `abs (EXPR)`  integer, real
+==========================================  ============  ======================
 
 .. c:macro:: GCC_JIT_UNARY_OP_MINUS
 
@@ -386,36 +396,23 @@ Binary Operations
 
 The available binary operations are:
 
-.. list-table::
-   :header-rows: 1
-
-   * - Binary Operation
-     - C equivalent
-
-   * - :c:macro:`GCC_JIT_BINARY_OP_PLUS`
-     - `x + y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MINUS`
-     - `x - y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MULT`
-     - `x * y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_DIVIDE`
-     - `x / y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_MODULO`
-     - `x % y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`
-     - `x & y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`
-     - `x ^ y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`
-     - `x | y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`
-     - `x && y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`
-     - `x || y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_LSHIFT`
-     - `x << y`
-   * - :c:macro:`GCC_JIT_BINARY_OP_RSHIFT`
-     - `x >> y`
+========================================  =============== =======================
+Binary Operation                          C equivalent    Supported operand types
+========================================  =============== =======================
+:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`         integer, real, complex
+:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`         integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`        integer
+:c:macro:`GCC_JIT_BINARY_OP_COMPLEX`      `CMPLX (r, i)`  real
+========================================  =============== =======================
 
 .. c:macro:: GCC_JIT_BINARY_OP_PLUS
 
@@ -543,6 +540,31 @@ The available binary operations are:
 
    in C.
 
+.. c:macro:: GCC_JIT_BINARY_OP_COMPLEX
+
+   Create a complex floating point value from
+   two real floating point values with the same
+   size qualifier as the complex result type.
+   I.e two floats for a _Complex float, etc.
+
+   Analogous to:
+
+   .. code-block:: c
+     CMPLX (real,imag)
+
+   in C.
+
+   The first operand is the real part, the other
+   the imaginary. Negative zeroes are preserved
+   and Inf:s do not lead to NaNs.
+
+   This operator  was added in LIBGCCJIT_ABI_26;
+   you can test for its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_COMPLEX
+
 Comparisons
 ***********
 
@@ -575,6 +597,9 @@ Comparisons
    * - :c:macro:`GCC_JIT_COMPARISON_GE`
      - `x >= y`
 
+
+Note: Only `==` and `!=` are defined for complex types.
+
 Function calls
 **************
 .. function:: gcc_jit_rvalue *\
@@ -676,10 +701,17 @@ Type-coercion
 
    Currently only a limited set of conversions are possible:
 
-     * int <-> float
-     * int <-> bool
+     * integer <-> integer
+     * floating point <-> floating point
+     * integer <-> floating point
+     * integer <-> bool
      * P*  <-> Q*, for pointer types P and Q
 
+   Note: "floating point" includes complex types.
+
+   When a complex type is converted to a non-complex type, the
+   imaginary part is discarded.
+
 .. function:: gcc_jit_rvalue *\
               gcc_jit_context_new_bitcast (gcc_jit_context *ctxt,\
                                            gcc_jit_location *loc,\
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index d8c1d15d69d..45816403eb1 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -124,11 +124,17 @@ Standard types
      * - :c:data:`GCC_JIT_TYPE_FILE_PTR`
        - C type: ``(FILE *)``
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT`
-       - C99's ``_Complex float``
+       - C99's ``_Complex float``, ABI 26
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE`
-       - C99's ``_Complex double``
+       - C99's ``_Complex double``, ABI 26
      * - :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE`
-       - C99's ``_Complex long double``
+       - C99's ``_Complex long double``, ABI 26
+
+   The complex types are available from :ref:`LIBGCCJIT_ABI_26` after
+   setting :ref:`gcc_jit_context_set_bool_enable_complex_types`.
+
+   You can test for complex types support with the define
+   `#ifdef LIBGCCJIT_HAVE_COMPLEX`.
 
 .. function:: gcc_jit_type *\
               gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 80c1618da96..af085b2671b 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -199,7 +199,7 @@ enum inner_bool_option
   INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS,
   INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER,
   INNER_BOOL_OPTION_PRINT_ERRORS_TO_STDERR,
-
+  INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
   NUM_INNER_BOOL_OPTIONS
 };
 
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 18cc4da25b8..49ea10fd1cb 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc.h"
 #include "diagnostic.h"
 #include "stmt.h"
+#include "complex.h"
 
 #include "jit-playback.h"
 #include "jit-result.h"
@@ -77,6 +78,8 @@ convert (tree dst_type, tree expr)
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
       return fold (convert_to_integer (dst_type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (dst_type, expr));
 
     default:
       gcc_assert (gcc::jit::active_playback_ctxt);
@@ -873,6 +876,24 @@ new_global_initialized (location *loc,
 namespace playback
 {
 
+/* Return the corrensponding not complex float type of a
+   float type. I.e. complex float -> float */
+static tree
+complex_real_to_real (tree complex_type)
+{
+  if (TYPE_CANONICAL (complex_type) ==
+      TYPE_CANONICAL (complex_float_type_node))
+    return float_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_double_type_node))
+    return double_type_node;
+  else if (TYPE_CANONICAL (complex_type) ==
+	   TYPE_CANONICAL (complex_long_double_type_node))
+    return long_double_type_node;
+  else
+    gcc_unreachable();
+}
+
 /* Specialization of making an rvalue from a const, for host <int>.  */
 
 template <>
@@ -888,6 +909,25 @@ new_rvalue_from_const <int> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -912,6 +952,25 @@ new_rvalue_from_const <long> (type *type,
       tree inner = build_int_cst (inner_type, value);
       return new rvalue (this, inner);
     }
+  else if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+      REAL_VALUE_TYPE real_value;
+      REAL_VALUE_TYPE imag_value;
+
+      real_type = complex_real_to_real (inner_type);
+
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      real_from_integer (&imag_value, VOIDmode, 0, SIGNED);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
   else
     {
       REAL_VALUE_TYPE real_value;
@@ -937,19 +996,104 @@ new_rvalue_from_const <double> (type *type,
      real.cc:real_from_target appears to require the representation to be
      split into 32-bit values, and then sent as an pair of host long
      ints.  */
+
+  union
+  {
+    double as_double;
+    uint32_t as_uint32s[2];
+  } u_real, u_imag;
+
+  u_real.as_double = value;
+  long int as_long_ints[2];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
   REAL_VALUE_TYPE real_value;
+  real_from_target (&real_value, as_long_ints, DFmode);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int zero_as_long_ints[2];
+      u_imag.as_double = 0.;
+      zero_as_long_ints[0] = u_imag.as_uint32s[0];
+      zero_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, zero_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
+/* Specialization of making an rvalue from a const,
+   for host <double _Complex>. */
+
+template <>
+rvalue *
+context::
+new_rvalue_from_const <_Complex double> (type *type,
+					 _Complex double  value)
+{
+  tree inner_type = type->as_tree ();
+
   union
   {
     double as_double;
     uint32_t as_uint32s[2];
-  } u;
-  u.as_double = value;
+  } u_real, u_imag;
+
+  u_real.as_double = creal(value);
   long int as_long_ints[2];
-  as_long_ints[0] = u.as_uint32s[0];
-  as_long_ints[1] = u.as_uint32s[1];
+  as_long_ints[0] = u_real.as_uint32s[0];
+  as_long_ints[1] = u_real.as_uint32s[1];
+
+  REAL_VALUE_TYPE real_value;
   real_from_target (&real_value, as_long_ints, DFmode);
-  tree inner = build_real (inner_type, real_value);
-  return new rvalue (this, inner);
+
+  if (COMPLEX_FLOAT_TYPE_P (inner_type))
+    {
+      tree tree_real;
+      tree tree_imag;
+      tree real_type;
+
+      REAL_VALUE_TYPE imag_value;
+
+      long int value_as_long_ints[2];
+      u_imag.as_double = cimag(value);
+      value_as_long_ints[0] = u_imag.as_uint32s[0];
+      value_as_long_ints[1] = u_imag.as_uint32s[1];
+
+      real_from_target (&imag_value, value_as_long_ints, DFmode);
+
+      real_type = complex_real_to_real (inner_type);
+
+      tree_real = build_real (real_type, real_value);
+      tree_imag = build_real (real_type, imag_value);
+
+      tree inner = build_complex (inner_type, tree_real, tree_imag);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
 }
 
 /* Specialization of making an rvalue from a const, for host <void *>.  */
@@ -1190,6 +1334,11 @@ new_binary_op (location *loc,
     case GCC_JIT_BINARY_OP_RSHIFT:
       inner_op = RSHIFT_EXPR;
       break;
+
+    /* Create complex value from two real values */
+    case GCC_JIT_BINARY_OP_COMPLEX:
+      inner_op = COMPLEX_EXPR;
+      break;
     }
 
   tree inner_expr = build2 (inner_op,
@@ -1400,6 +1549,10 @@ playback::context::build_cast (playback::location *loc,
 		      build_int_cst (TREE_TYPE (t_expr), 0));
       goto maybe_fold;
 
+    case COMPLEX_TYPE:
+      t_ret = convert_to_complex (t_dst_type, t_expr);
+      goto maybe_fold;
+
     case REAL_TYPE:
       t_ret = convert_to_real (t_dst_type, t_expr);
       goto maybe_fold;
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 9b5b8005ebe..ed788502c15 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "pretty-print.h"
 #include "toplev.h"
 
+#include <complex.h>
 
 #include "jit-builtins.h"
 #include "jit-recording.h"
@@ -1712,6 +1713,7 @@ static const char * const
   "gcc_jit_context_set_bool_allow_unreachable_blocks",
   "gcc_jit_context_set_bool_use_external_driver",
   "gcc_jit_context_set_bool_print_errors_to_stderr",
+  "gcc_jit_context_set_bool_enable_complex_types"
 };
 
 /* Write the current value of all options to the log file (if any).  */
@@ -2645,6 +2647,59 @@ recording::memento_of_get_type::is_float () const
     }
 }
 
+/* Implementation of pure virtual hook recording::type::is_complex for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_complex () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return true;
+    }
+}
+
 /* Implementation of pure virtual hook recording::type::is_bool for
    recording::memento_of_get_type.  */
 
@@ -5071,6 +5126,7 @@ recording::global::write_reproducer (reproducer &r)
 template class recording::memento_of_new_rvalue_from_const <int>;
 template class recording::memento_of_new_rvalue_from_const <long>;
 template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <_Complex double>;
 template class recording::memento_of_new_rvalue_from_const <void *>;
 
 /* Implementation of the pure virtual hook recording::memento::replay_into
@@ -5248,6 +5304,53 @@ recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproduc
     m_value);
 }
 
+/* The make_debug_string specialization for <double complex>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(complex float)(42.0+42.0j)".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <_Complex double>::make_debug_string ()
+{
+  double real = creal(m_value);
+  double imag = cimag(m_value);
+  return string::from_printf (m_ctxt,
+			      "(%s)(%g%+gj)",
+			      m_type->get_debug_string (),
+			      real, imag);
+}
+
+/* The get_wide_int specialization for <double complex>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <_Complex double>::
+get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* The write_reproducer specialization for <double>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <_Complex double>::
+write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  double real = creal(m_value);
+  double imag = cimag(m_value);
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n"
+    "                                            %s, /* gcc_jit_type *numeric_type */\n"
+    "                                            %f+%fj); /* double value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    real, imag);
+}
+
 /* The make_debug_string specialization for <void *>, rendering it as
      (TARGET_TYPE)HEX
    e.g.
@@ -5740,17 +5843,24 @@ static const char * const binary_op_strings[] = {
   "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
   ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+  "", /* GCC_JIT_BINARY_OP_COMPLEX - dummy not used */
 };
 
 recording::string *
 recording::binary_op::make_debug_string ()
 {
   enum precedence prec = get_precedence ();
-  return string::from_printf (m_ctxt,
-			      "%s %s %s",
-			      m_a->get_debug_string_parens (prec),
-			      binary_op_strings[m_op],
-			      m_b->get_debug_string_parens (prec));
+  if (m_op == GCC_JIT_BINARY_OP_COMPLEX)
+    return string::from_printf (m_ctxt,
+				"(%s + %s * _Imaginary_I)",
+				m_a->get_debug_string_parens (prec),
+				m_b->get_debug_string_parens (prec));
+  else
+    return string::from_printf (m_ctxt,
+				"%s %s %s",
+				m_a->get_debug_string_parens (prec),
+				binary_op_strings[m_op],
+				m_b->get_debug_string_parens (prec));
 }
 
 const char * const binary_op_reproducer_strings[] = {
@@ -5765,7 +5875,8 @@ const char * const binary_op_reproducer_strings[] = {
   "GCC_JIT_BINARY_OP_LOGICAL_AND",
   "GCC_JIT_BINARY_OP_LOGICAL_OR",
   "GCC_JIT_BINARY_OP_LSHIFT",
-  "GCC_JIT_BINARY_OP_RSHIFT"
+  "GCC_JIT_BINARY_OP_RSHIFT",
+  "GCC_JIT_BINARY_OP_COMPLEX",
 };
 
 /* Implementation of recording::memento::write_reproducer for binary ops.  */
@@ -5806,6 +5917,7 @@ static const enum precedence binary_op_precedence[] = {
   PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */
   PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */
+  PRECEDENCE_CAST, /* GCC_JIT_BINARY_OP_COMPLEX */
 };
 } /* namespace recording */
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 4a8082991fb..1e9990440ae 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -567,6 +567,7 @@ public:
   virtual bool is_int () const = 0;
   virtual bool is_float () const = 0;
   virtual bool is_bool () const = 0;
+  virtual bool is_complex () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_volatile () { return NULL; }
   virtual type *is_restrict () { return NULL; }
@@ -578,6 +579,9 @@ public:
   virtual vector_type *is_vector () { return NULL; }
   virtual bool has_known_size () const { return true; }
   virtual bool is_signed () const = 0;
+  /* Used to pair complex float types with real float type
+     of the same "base type". */
+  virtual int float_size_qual () const { return 0; }
 
   bool is_numeric () const
   {
@@ -640,11 +644,31 @@ public:
   bool is_int () const final override;
   bool is_float () const final override;
   bool is_bool () const final override;
+  bool is_complex () const final override;
   type *is_pointer () final override { return dereference (); }
   type *is_array () final override { return NULL; }
   bool is_void () const final override { return m_kind == GCC_JIT_TYPE_VOID; }
   bool is_signed () const final override;
 
+  int float_size_qual () const final override
+  {
+    switch (m_kind)
+      {
+      default:
+	return 0;
+      case GCC_JIT_TYPE_FLOAT:
+      case GCC_JIT_TYPE_COMPLEX_FLOAT:
+	return 1;
+      case GCC_JIT_TYPE_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+	return 2;
+      case GCC_JIT_TYPE_LONG_DOUBLE:
+      case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+	return 3;
+      }
+  }
+
+
 public:
   void replay_into (replayer *r) final override;
 
@@ -675,6 +699,7 @@ public:
   bool is_int () const final override { return false; }
   bool is_float () const final override { return false; }
   bool is_bool () const final override { return false; }
+  bool is_complex () const final override { return false; }
   type *is_pointer () final override { return m_other_type; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
@@ -708,6 +733,7 @@ public:
   type *is_array () final override { return m_other_type->is_array (); }
   struct_ *is_struct () final override { return m_other_type->is_struct (); }
   bool is_signed () const final override { return m_other_type->is_signed (); }
+  bool is_complex () const final override { return m_other_type->is_complex (); }
 
 protected:
   type *m_other_type;
@@ -873,6 +899,8 @@ class array_type : public type
   bool is_bool () const final override { return false; }
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return m_element_type; }
+  bool is_complex () const final override { return false; }
+
   int num_elements () { return m_num_elements; }
   bool is_signed () const final override { return false; }
 
@@ -909,6 +937,7 @@ public:
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
+  bool is_complex () const final override { return false; }
 
   void replay_into (replayer *) final override;
 
@@ -1023,6 +1052,7 @@ public:
   type *is_pointer () final override { return NULL; }
   type *is_array () final override { return NULL; }
   bool is_signed () const final override { return false; }
+  bool is_complex () const final override  { return false; }
 
   bool has_known_size () const final override { return m_fields != NULL; }
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index f9a0017cae5..f95b9ad67d7 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -128,6 +128,7 @@ namespace gccjit
 
     void set_bool_allow_unreachable_blocks (int bool_value);
     void set_bool_use_external_driver (int bool_value);
+    void set_bool_enable_complex_types (int bool_value);
 
     void add_command_line_option (const char *optname);
     void add_driver_option (const char *optname);
@@ -191,6 +192,8 @@ namespace gccjit
     rvalue one (type numeric_type) const;
     rvalue new_rvalue (type numeric_type,
 		       double value) const;
+    rvalue new_rvalue (type numeric_type,
+		       _Complex double value) const;
     rvalue new_rvalue (type pointer_type,
 		       void *value) const;
     rvalue new_rvalue (const std::string &value) const;
@@ -748,6 +751,13 @@ context::set_bool_use_external_driver (int bool_value)
 						bool_value);
 }
 
+inline void
+context::set_bool_enable_complex_types (int bool_value)
+{
+  gcc_jit_context_set_bool_enable_complex_types (m_inner_ctxt,
+						 bool_value);
+}
+
 inline void
 context::add_command_line_option (const char *optname)
 {
@@ -966,6 +976,17 @@ context::new_rvalue (type numeric_type,
 					    value));
 }
 
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     _Complex double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_complex_double (
+      m_inner_ctxt,
+      numeric_type.get_inner_type (),
+      value));
+}
+
 inline rvalue
 context::new_rvalue (type pointer_type,
 		     void *value) const
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 0451b4df7f9..2c605d0ddf0 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -470,6 +470,14 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt,
      && type < NUM_GCC_JIT_TYPES),
     ctxt, NULL,
     "unrecognized value for enum gcc_jit_types: %i", type);
+  if (type >= GCC_JIT_TYPE_COMPLEX_FLOAT
+      && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE)
+    RETURN_NULL_IF_FAIL (
+      ctxt->get_inner_bool_option(
+	gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES),
+      ctxt, NULL,
+      "complex types are only available after enabling them with"
+      " gcc_jit_context_set_bool_enable_complex_types()");
 
   return (gcc_jit_type *)ctxt->get_type (type);
 }
@@ -2027,6 +2035,26 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 	  ->new_rvalue_from_const <double> (numeric_type, value));
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						double _Complex value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    numeric_type->is_float (),
+    ctxt, NULL,
+    "not a floating point type (type: %s)",
+    numeric_type->get_debug_string ());
+
+  return ((gcc_jit_rvalue *)ctxt
+	   ->new_rvalue_from_const <double _Complex> (numeric_type, value));
+}
+
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -2122,6 +2150,14 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
     result_type->get_debug_string ());
   RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
 
+  if (rvalue->get_type ()->is_complex ())
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      op == GCC_JIT_UNARY_OP_MINUS,
+      ctxt, loc,
+      "only unary minus defined for complex types: %s (type: %s)",
+      rvalue->get_debug_string (),
+      rvalue->get_type ()->get_debug_string ());
+
   return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
 }
 
@@ -2133,7 +2169,7 @@ static bool
 valid_binary_op_p (enum gcc_jit_binary_op op)
 {
   return (op >= GCC_JIT_BINARY_OP_PLUS
-	  && op <= GCC_JIT_BINARY_OP_RSHIFT);
+	  && op <= GCC_JIT_BINARY_OP_COMPLEX);
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -2178,6 +2214,38 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
     a->get_debug_string (), b->get_debug_string (),
     result_type->get_debug_string ());
 
+  if (op == GCC_JIT_BINARY_OP_COMPLEX)
+    {
+      RETURN_NULL_IF_FAIL (
+	result_type->is_complex (),
+	ctxt, loc,
+       "return type is not complex");
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!a->get_type ()->is_complex () &&
+	a->get_type ()->is_float (),
+	ctxt, loc,
+	"first operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	a->get_debug_string (),
+	a->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	!b->get_type ()->is_complex () &&
+	b->get_type ()->is_float (),
+	ctxt, loc,
+	"2nd operand of %s is not real: %s (type: %s)",
+	gcc::jit::binary_op_reproducer_strings[op],
+	b->get_debug_string (),
+	b->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	a->get_type ()-> float_size_qual () ==
+	result_type->float_size_qual (),
+	ctxt, loc,
+	"size qualifiers of complex operand's not the same as the result:"
+	" operands: %s, result:  %s",
+	a->get_type ()->get_debug_string (),
+	result_type->get_debug_string ());
+    }
+
   return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
 }
 
@@ -2214,6 +2282,14 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
     b->get_debug_string (),
     b->get_type ()->get_debug_string ());
 
+  if (a->get_type ()->is_complex())
+    RETURN_NULL_IF_FAIL_PRINTF1 (
+      (op == GCC_JIT_COMPARISON_EQ
+       || op == GCC_JIT_COMPARISON_NE),
+      ctxt, loc,
+      "invalid enum gcc_jit_comparison for complex operands: %i",
+      op);
+
   return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
 }
 
@@ -3554,6 +3630,17 @@ gcc_jit_context_set_bool_print_errors_to_stderr (gcc_jit_context *ctxt,
     enabled);
 }
 
+void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  ctxt->set_inner_bool_option (
+    gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES,
+    bool_value);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 749f6c24177..cdaec450981 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1083,6 +1083,16 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					gcc_jit_type *numeric_type,
 					double value);
 
+/* Complex floating-point constants.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt,
+						gcc_jit_type *numeric_type,
+						_Complex double value);
+
 /* Pointers.  */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
@@ -1194,7 +1204,26 @@ enum gcc_jit_binary_op
   /* Right shift; analogous to:
        (EXPR_A) >> (EXPR_B)
      in C.  */
-  GCC_JIT_BINARY_OP_RSHIFT
+  GCC_JIT_BINARY_OP_RSHIFT,
+
+  /* Create a complex floating point value from
+     two real floating point values. The operands
+     and the result need to have the same size
+     qualifier.
+
+     Analogous to:
+       CMPLX (real,imag)
+     in C.
+
+     The first operand is the real part, the other
+     the imaginary. Negative zeroes are preserved
+     and Inf:s do not lead to NaNs.
+
+     This operator  was added in LIBGCCJIT_ABI_26;
+     you can test for its presence using
+       #ifdef LIBGCCJIT_HAVE_COMPLEX
+  */
+  GCC_JIT_BINARY_OP_COMPLEX
 };
 
 extern gcc_jit_rvalue *
@@ -1740,6 +1769,19 @@ gcc_jit_timer_print (gcc_jit_timer *timer,
 		     FILE *f_out);
 
 
+#define LIBGCCJIT_HAVE_COMPLEX
+
+/* Enables complex type support in libgccjit.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_COMPLEX
+*/
+
+extern void
+gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,
+					       int bool_value);
+
 #define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
 
 /* Mark/clear a call as needing tail-call optimization.
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 8b90a0e2ff3..efa80d9cf2f 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -276,3 +276,9 @@ LIBGCCJIT_ABI_25 {
   global:
     gcc_jit_type_get_restrict;
 } LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+  global:
+    gcc_jit_context_new_rvalue_from_complex_double;
+    gcc_jit_context_set_bool_enable_complex_types;
+} LIBGCCJIT_ABI_25;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index e762563f9bd..b8693bd5b9c 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -112,6 +112,36 @@
 #undef create_code
 #undef verify_code
 
+/* test-complex-builtins.c */
+#define create_code create_code_complex_builtins
+#define verify_code verify_code_complex_builtins
+#include "test-complex-builtins.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-literals.c */
+#define create_code create_code_complex_literals
+#define verify_code verify_code_complex_literals
+#include "test-complex-literals.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-misc.c */
+#define create_code create_code_complex_misc
+#define verify_code verify_code_complex_misc
+#include "test-complex-misc.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-operators.c */
+#define create_code create_code_complex_operators
+#define verify_code verify_code_complex_operators
+#include "test-complex-operators.c"
+#undef create_code
+#undef verify_code
+
+/* test-complex-types.c: Quite long, don't include here */
+
 /* test-compound-assignment.c */
 #define create_code create_code_compound_assignment
 #define verify_code verify_code_compound_assignment
diff --git a/gcc/testsuite/jit.dg/test-complex-builtins.c b/gcc/testsuite/jit.dg/test-complex-builtins.c
new file mode 100644
index 00000000000..fce2c9b2d09
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-builtins.c
@@ -0,0 +1,217 @@
+/*
+  This test just checks that the builtins cimag, creal and
+  conj are usable.
+
+  Also, they should be inlined, which can be checked by
+  disassembling the object file manually.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+static void
+make_code_unop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type_return,
+		 int type_arg,
+		 gcc_jit_function *fn)
+{ 
+  gcc_jit_block *block;
+
+  gcc_jit_type *tr = gcc_jit_context_get_type (ctxt, type_return);
+  gcc_jit_type *ta = gcc_jit_context_get_type (ctxt, type_arg);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, ta, "f1");
+
+  gcc_jit_param *params[] = {param1};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 1, params, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1)
+  };
+  
+  /* return fn(f1); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, fn,
+     1,
+     args);
+  
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+static void
+make_code_binop_builtins (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 gcc_jit_function *builtin)
+{
+  gcc_jit_block *block;
+  
+  gcc_jit_type *t1 = gcc_jit_context_get_type (ctxt, type1);
+  gcc_jit_type *t2 = gcc_jit_context_get_type (ctxt, type2);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, t1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, t2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    t1, fn_name, 2, params, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param(foo, 1));
+
+  gcc_jit_rvalue *args[] = {
+    gcc_jit_lvalue_as_rvalue (f1),
+    gcc_jit_lvalue_as_rvalue (f2)
+  };
+  
+  /* return builtin(f1,f2); */
+  gcc_jit_rvalue *r = gcc_jit_context_new_call
+    (ctxt, 0, builtin,
+     2,
+     args);
+  
+  gcc_jit_block_end_with_return (block, 0, r);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+  
+  gcc_jit_function *fn_cpow = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cpow");
+
+  make_code_binop_builtins (ctxt, "cpow_builtin",
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   fn_cpow);
+
+  gcc_jit_function *fn_conj = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_conj");
+  
+  /* In a good world conj should be inlined */
+  make_code_unop_builtins (ctxt, "conj_inlined",
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_conj);
+
+  gcc_jit_function *fn_creal = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creal");
+  gcc_jit_function *fn_crealf = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_crealf");
+  gcc_jit_function *fn_creall = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_creall");
+  gcc_jit_function *fn_cimag = gcc_jit_context_get_builtin_function
+    (ctxt, "__builtin_cimag");
+
+  /* These should be inlined too */
+  make_code_unop_builtins (ctxt, "creal_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_creal);
+  make_code_unop_builtins (ctxt, "cimag_inlined",
+		  GCC_JIT_TYPE_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		  fn_cimag);
+
+  make_code_unop_builtins (ctxt, "crealf_inlined",
+		  GCC_JIT_TYPE_FLOAT,
+		  GCC_JIT_TYPE_COMPLEX_FLOAT,
+		  fn_crealf);
+  make_code_unop_builtins (ctxt, "creall_inlined",
+		  GCC_JIT_TYPE_LONG_DOUBLE,
+		  GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		  fn_creall);
+  
+  /* Use to inspect code manually and assure conj, creal, cimag
+     are inlined. At the time of writing they are on my x64 machine */
+  #if 0
+  gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+				   "test-complex-builtins.o");
+  #endif
+}
+
+typedef _Complex double (*cd_cdcd)(_Complex double, _Complex double);
+typedef _Complex double (*cd_cd)(_Complex double);
+typedef double (*d_cd)(_Complex double);
+typedef float (*f_cf)(_Complex float);
+typedef long double (*ld_cld)(_Complex long double);
+
+/* We need this to fool GCC into not precomputing the built-in ...
+   precomputing seems like a feuture libgccjit misses. */
+volatile _Complex double half = 0.5;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test binary builtins */
+    {
+       cd_cdcd fn =
+	gcc_jit_result_get_code (result, "cpow_builtin");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (2, 2), 4.);
+       _Complex double ans = fn (-1., 0.5);
+       _Complex double key = __builtin_cpow (-1., half);
+
+       /* This test fails if libgccjit can precompute builtins */
+       CHECK_VALUE (ans, key); /* Almost 1.j */
+    }
+  }
+  {/* Test unary builtins */
+    { /* conj */
+      cd_cd fn = gcc_jit_result_get_code (result, "conj_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE( fn (1. - 1.j), 1. + 1.j);
+    }
+    { /* creal */
+      d_cd fn = gcc_jit_result_get_code (result, "creal_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1. - 1.j), 1.);
+    }
+    { /* cimag */
+      d_cd fn = gcc_jit_result_get_code (result, "cimag_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1. - 1.j), -1.);
+    }
+    { /* crealf */
+      f_cf fn = gcc_jit_result_get_code (result, "crealf_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f - 1.fj), 1.f);
+    }
+    { /* creall */
+      ld_cld fn = gcc_jit_result_get_code (result, "creall_inlined");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.L - 1.Lj), 1.L);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-literals.c b/gcc/testsuite/jit.dg/test-complex-literals.c
new file mode 100644
index 00000000000..4bf5d96ac06
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-literals.c
@@ -0,0 +1,145 @@
+/*
+  Test the new 'gcc_jit_context_new_rvalue_from_complex_double()'
+  aswell as test that the old '_from_int ... _from_double"
+  can produce complex values.
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code (gcc_jit_context *ctxt,
+	   const char *fn_name,
+	   int type,
+	   _Complex double local_val,
+	   int lit_type)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 0, 0, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  /* local_type f1 = local_val; */
+  gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1");
+
+  gcc_jit_rvalue *r1;
+
+  if (lit_type == 'c')
+    r1 = gcc_jit_context_new_rvalue_from_complex_double (ctxt, tt, local_val);
+  else if (lit_type == 'd')
+    r1 = gcc_jit_context_new_rvalue_from_double (ctxt, tt, creal(local_val));
+  else if (lit_type == 'l')
+    r1 = gcc_jit_context_new_rvalue_from_long (ctxt, tt, creal(local_val));
+  else if (lit_type == 'i')
+    r1 = gcc_jit_context_new_rvalue_from_int (ctxt, tt, creal(local_val));
+    
+  gcc_jit_block_add_assignment (block, 0, f1, r1);
+  
+  gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code (ctxt, "complex_float_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_FLOAT,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "complex_double_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "complex_long_double_clit_1c1_2c2j",
+	       GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "float_clit_1c1",
+	       GCC_JIT_TYPE_FLOAT,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "double_clit_1c1",
+	       GCC_JIT_TYPE_DOUBLE,
+	       1.1 + 2.2j, 'c');
+  make_code (ctxt, "long_double_clit_1c1",
+	       GCC_JIT_TYPE_LONG_DOUBLE,
+	       1.1 + 2.2j, 'c');
+
+  /* Make complex from "from_double", "from_long","from_int" */
+  make_code (ctxt, "complex_float_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_FLOAT,
+	       1.1, 'd');
+  make_code (ctxt, "complex_double_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       1.1, 'd');
+  make_code (ctxt, "complex_long_double_dlit_1c1",
+	       GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+	       1.1, 'd');
+  make_code (ctxt, "complex_double_llit_2",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       2, 'l');
+  make_code (ctxt, "complex_double_ilit_3",
+	       GCC_JIT_TYPE_COMPLEX_DOUBLE,
+	       3, 'i');
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {/* Test literals */
+    {
+      _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_clit_1c1_2c2j");
+
+      CHECK_VALUE(f (), 1.1f + 2.2fj);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_clit_1c1_2c2j");
+      CHECK_VALUE(f (), 1.1 + 2.2j);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_clit_1c1_2c2j");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (),1.1 + 2.2j);
+    }
+    {
+      float (*f)() = gcc_jit_result_get_code (result, "float_clit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      double (*f)() = gcc_jit_result_get_code (result, "double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      long double (*f)() = gcc_jit_result_get_code (result, "long_double_clit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_dlit_1c1");
+      CHECK_VALUE(f (), 1.1f);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_dlit_1c1");
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_dlit_1c1");
+      /* Note: The literal in the function is complex double */
+      CHECK_VALUE(f (), 1.1);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_llit_2");
+      CHECK_VALUE(f (), 2);
+    }
+    {
+      _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_ilit_3");
+      CHECK_VALUE(f (), 3);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-misc.c b/gcc/testsuite/jit.dg/test-complex-misc.c
new file mode 100644
index 00000000000..fe0cdade927
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-misc.c
@@ -0,0 +1,204 @@
+/*
+  This test checks wether complex types work with structs, unions
+  and pointers.
+
+  Aswell as const and volatile, but only in the sense that having
+  those qualifiers doesn't crash gcc.
+
+*/
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_type *type_int =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *type_cd =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE);
+
+  gcc_jit_lvalue *cd_gbl = gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    type_cd,
+    "a_complex_global_double_2");
+
+  /* These globals are not used for anything */
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_volatile (type_cd),
+    "a_volatile_complex_double");
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_const (type_cd),
+    "a_const_complex_double");
+
+  gcc_jit_type *arr_type =
+    gcc_jit_context_new_array_type (ctxt,
+      0, type_cd, 10);
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    arr_type,
+    "a_const_complex_double_array");  
+
+  {/* Make a function returning union with 3.14 + 1516.j in it */
+    gcc_jit_field *cd_field = 
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field = 
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi =
+      gcc_jit_context_new_union_type (ctxt,
+				      0,
+				      "cdi",
+				      2,
+				      fields);
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi, "a_uniony_fn_returning_union", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi, "union_local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field
+      (local, 0, cd_field);
+    gcc_jit_block_add_assignment
+      (block, 0, lv_field,
+       gcc_jit_context_new_rvalue_from_complex_double (
+         ctxt, type_cd, 3.14 + 1592.j));
+
+    /* Note: Writes to global here */
+    gcc_jit_block_add_assignment (
+      block, 0, cd_gbl,
+      gcc_jit_context_new_rvalue_from_complex_double (
+         ctxt, type_cd, 6535 + 9.j));
+    
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function returning a complexy struct */
+    gcc_jit_field *cd_field = 
+      gcc_jit_context_new_field (ctxt,
+				 0,
+			         type_cd,
+			         "cd");
+    gcc_jit_field *i_field = 
+      gcc_jit_context_new_field (ctxt,
+			         0,
+			         type_int,
+			         "i");
+    gcc_jit_field *fields[] = {cd_field, i_field};
+    gcc_jit_type *cdi_struct =
+      gcc_jit_struct_as_type(
+	gcc_jit_context_new_struct_type (ctxt,
+					0,
+					"cdi_struct",
+					2,
+					fields));
+
+    gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+      GCC_JIT_FUNCTION_EXPORTED,
+      cdi_struct, "a_structy_fn_returning_struct", 0, 0, 0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (foo, 0, cdi_struct, "local");
+    gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field (
+      local, 0, cd_field);
+    gcc_jit_block_add_assignment (
+       block, 0, lv_field,
+       /* Note: Reads from global here */
+       gcc_jit_lvalue_as_rvalue(cd_gbl));
+    
+    gcc_jit_block_end_with_return (
+      block, 0, gcc_jit_lvalue_as_rvalue (local));
+  }
+  {/* Make a function taking a pointer to a complex double,
+      add 1+1.j to it, and return the pointer */
+      gcc_jit_type *type_return =
+	gcc_jit_type_get_pointer (type_cd);
+      
+      gcc_jit_param *param = gcc_jit_context_new_param (
+	ctxt, 0, gcc_jit_type_get_pointer (type_cd), "pcd");
+      
+      gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+	GCC_JIT_FUNCTION_EXPORTED,
+	type_return,
+	"a_pointy_fn_returning_points", 1, &param, 0);
+      gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+      
+      gcc_jit_rvalue *param_rv = gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0));
+
+      gcc_jit_rvalue *rval = gcc_jit_context_new_binary_op (
+	ctxt, 0, GCC_JIT_BINARY_OP_PLUS, type_cd,
+	gcc_jit_context_new_rvalue_from_complex_double (
+	  ctxt, type_cd, 1 + 1.j),
+	gcc_jit_lvalue_as_rvalue (
+	  gcc_jit_rvalue_dereference (
+	    param_rv, 0)));
+      gcc_jit_block_add_assignment (block, 0,
+        gcc_jit_rvalue_dereference (
+	    param_rv, 0),
+	rval);
+
+      gcc_jit_block_end_with_return (
+	block, 0, param_rv);
+  }
+}
+
+typedef union {
+  _Complex double cd;
+  int i;
+} complex_test_union;
+
+typedef struct {
+  _Complex double cd;
+  int i;
+} complex_test_struct;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    complex_test_union (*fn)() = gcc_jit_result_get_code (result, "a_uniony_fn_returning_union");
+    CHECK_NON_NULL (fn);
+
+    complex_test_union u = fn();
+    CHECK_VALUE (u.cd, 3.14 + 1592.j);
+  }
+  {
+    complex_test_struct (*fn)() = gcc_jit_result_get_code (result, "a_structy_fn_returning_struct");
+    CHECK_NON_NULL (fn);
+
+    complex_test_struct s = fn();
+    CHECK_VALUE (s.cd, 6535 + 9.j);
+  }
+  {
+    _Complex double *
+    (*fn)(_Complex double *) = gcc_jit_result_get_code (result, "a_pointy_fn_returning_points");
+    CHECK_NON_NULL (fn);
+
+    _Complex double s = 2. + 3.i;
+    _Complex double *p = fn(&s);
+    CHECK_VALUE (p, &s);
+    CHECK_VALUE (s, 3. + 4.i);
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-operators.c b/gcc/testsuite/jit.dg/test-complex-operators.c
new file mode 100644
index 00000000000..091b56fb4d2
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-operators.c
@@ -0,0 +1,353 @@
+/*
+  Test ==, !=, the create-complex-from-reals-operator,
+  unary minus and *-/+
+ */
+
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+static void
+make_code_compop (gcc_jit_context *ctxt,
+		  const char *fn_name,
+		  int type,
+		  enum gcc_jit_comparison op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, tt, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, tt, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    bool_type, fn_name, 2, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue (
+    gcc_jit_function_get_param (foo, 1));
+ 
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rcompop = gcc_jit_context_new_comparison
+    (ctxt, 0, op,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+  
+  gcc_jit_block_end_with_return (block, 0, rcompop);
+}
+
+static void
+make_code_binop (gcc_jit_context *ctxt,
+		 const char *fn_name,
+		 int type1,
+		 int type2,
+		 int return_type,
+		 enum gcc_jit_binary_op op)
+{
+  gcc_jit_type *tt1 = gcc_jit_context_get_type(ctxt, type1);
+  gcc_jit_type *tt2 = gcc_jit_context_get_type(ctxt, type2);
+  gcc_jit_type *tr = gcc_jit_context_get_type(ctxt, return_type);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt1, "f1");
+  gcc_jit_param *param2 = gcc_jit_context_new_param(ctxt, 0, tt2, "f2");
+
+  gcc_jit_param *params[] = {param1, param2};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tr, fn_name, 2, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+  gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 1));
+ 
+  /* return f1 op f2; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_binary_op
+    (ctxt, 0, op, tr,
+     gcc_jit_lvalue_as_rvalue (f1),
+     gcc_jit_lvalue_as_rvalue (f2));
+  
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+static void
+make_code_unop (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int type1,
+	    enum gcc_jit_unary_op op)
+{
+  gcc_jit_type *tt = gcc_jit_context_get_type(ctxt, type1);
+  
+  gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt, "f1");
+
+  gcc_jit_param *params[] = {param1};
+  
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, params, 0);
+  
+  gcc_jit_block *block = gcc_jit_function_new_block(foo, "start");
+
+  gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue(
+    gcc_jit_function_get_param(foo, 0));
+ 
+  /* return op f1; */
+  gcc_jit_rvalue *rbinop = gcc_jit_context_new_unary_op
+    (ctxt, 0, op, tt,
+     gcc_jit_lvalue_as_rvalue (f1));
+  
+  gcc_jit_block_end_with_return (block, 0, rbinop);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  make_code_binop (ctxt, "plus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_PLUS);
+  make_code_binop (ctxt, "minus_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MINUS);
+  make_code_binop (ctxt, "div_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_DIVIDE);
+  make_code_binop (ctxt, "mul_complex_float_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_MULT);
+
+  make_code_binop (ctxt, "cmplx_float_float",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_binop (ctxt, "should_not_work",
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_FLOAT,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+#endif
+
+  make_code_binop (ctxt, "cmplx_double_double",
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+
+  make_code_binop (ctxt, "cmplx_long_double_long_double",
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_LONG_DOUBLE,
+		   GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		   GCC_JIT_BINARY_OP_COMPLEX);
+  
+  make_code_unop (ctxt, "minus_complex_float",
+		   GCC_JIT_TYPE_COMPLEX_FLOAT,
+		   GCC_JIT_UNARY_OP_MINUS);
+
+  make_code_compop (ctxt, "equal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_float",
+		    GCC_JIT_TYPE_COMPLEX_FLOAT,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_double",
+		    GCC_JIT_TYPE_COMPLEX_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+  make_code_compop (ctxt, "equal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_EQ);
+  make_code_compop (ctxt, "nequal_complex_long_double",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_NE);
+
+  /* Unundef to test different error msgs */
+#if 0
+  make_code_compop (ctxt, "qweasdzxc",
+		    GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
+		    GCC_JIT_COMPARISON_GE);
+#endif
+
+}
+
+typedef _Complex float (*cf_cfcf)(_Complex float, _Complex float);
+typedef _Complex float (*cf_cf)(_Complex float);
+typedef _Bool (*b_cfcf)(_Complex float, _Complex float);
+typedef _Bool (*b_cdcd)(_Complex double, _Complex double);
+typedef _Bool (*b_cldcld)(_Complex long double, _Complex long double);
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  (void) ctxt;
+  CHECK_NON_NULL (result);
+
+  {/* Test binary operators */
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "plus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) + (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) - (3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "div_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)/(3.f + 4.fj));
+    }
+    {
+      cf_cfcf fn =
+	gcc_jit_result_get_code (result, "mul_complex_float_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)*(3.f + 4.fj));
+    }
+    {
+      _Complex float (*fn)(float, float) =
+	gcc_jit_result_get_code (result, "cmplx_float_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1.f + 2.fi);
+      /* Note that the real answer is 0 not nan as it would have been by
+	 multiplying INF * 1.fi */
+      CHECK_VALUE (fn (0, INFINITY), CMPLXF (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXF (0, -INFINITY));
+
+      CHECK_VALUE (crealf (fn (0, NAN)), crealf (CMPLXF (0, NAN)));
+      CHECK (isnanf (cimagf (fn (0, NAN))));
+      
+      /* -0 need be preserved */
+      _Complex float f = fn (0, -0.);
+      CHECK (signbit ( cimagf (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.)); 
+    }
+    {
+      _Complex double (*fn)(double, double) =
+        gcc_jit_result_get_code (result, "cmplx_double_double");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1. + 2.i);
+      CHECK_VALUE (fn (0, INFINITY), CMPLX (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLX (0, -INFINITY));
+      
+      CHECK_VALUE (creal (fn (0, NAN)), creal (CMPLX (0, NAN)));
+      CHECK (isnan (cimag (fn (0, NAN))));      
+      
+      _Complex double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXF (0, -0.)); 
+    }
+    {
+      _Complex long double (*fn)(long double, long double) =
+	gcc_jit_result_get_code (result, "cmplx_long_double_long_double");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1, 2), 1.L + 2.Li);
+      CHECK_VALUE (fn (0, INFINITY), CMPLXL (0, INFINITY));
+      CHECK_VALUE (fn (0, -INFINITY), CMPLXL (0, -INFINITY));
+
+      CHECK_VALUE (creall (fn (0, NAN)), creall (CMPLXL (0, NAN)));
+      CHECK (isnanl (cimagl (fn (0, NAN))));      
+
+      _Complex long double f = fn (0, -0.);
+      CHECK (signbit (cimag (f)) != 0);
+      CHECK_VALUE (f, CMPLXL (0, -0.)); 
+    }
+  }
+
+  {/* Test unary ops */
+    {
+       cf_cf fn =
+	gcc_jit_result_get_code (result, "minus_complex_float");
+      CHECK_NON_NULL (fn);
+      
+      CHECK_VALUE (fn (1.f + 2.fj), -(1.f + 2.fj));
+    }
+  }
+  {/* Test comp ops */
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "equal_complex_float");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 1);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 0);
+    }
+    {
+       b_cfcf fn =
+	gcc_jit_result_get_code (result, "nequal_complex_float");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 0);
+       CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 1);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "equal_complex_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cdcd fn =
+	gcc_jit_result_get_code (result, "nequal_complex_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "equal_complex_long_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0);
+    }
+    {
+       b_cldcld fn =
+	gcc_jit_result_get_code (result, "nequal_complex_long_double");
+       CHECK_NON_NULL (fn);
+       
+       CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0);
+       CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1);
+    }
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-complex-types.c b/gcc/testsuite/jit.dg/test-complex-types.c
new file mode 100644
index 00000000000..c555133367b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-complex-types.c
@@ -0,0 +1,677 @@
+/*
+  Test cast from all complex types to all primitive types
+  except bool and amongst the complex types them self.
+
+  Also test some cast from non-complex to complex.
+
+  Also call a mathlib complex function and create a
+  complex global.
+ */
+
+#include <math.h>
+#include <complex.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+/*
+  Make code 1: (check that function calls works)
+   complex float csqrtf(complex float f);
+
+   complex float complex_float_foo(complex float f)
+   {
+     return csqrtf( f * (complex float)2.);
+   }
+
+  Make code 2: (check casts)
+   int float complex_float_to_int (complex float f)
+   {
+     return f;
+   }
+   
+  with different types and function names.
+ */
+
+
+static void
+make_code1(gcc_jit_context* ctxt,
+	   const char *fn_name,
+	   const char *sqrt_fn,
+	   int type)
+{
+  gcc_jit_rvalue *rval1, *rval2;
+  gcc_jit_block *block;
+
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, type);
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *func = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_IMPORTED,
+    ct, sqrt_fn, 1, &param, 0);
+
+  param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    ct, fn_name, 1, &param, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+  
+  rval1 = gcc_jit_context_new_binary_op (ctxt, 0, GCC_JIT_BINARY_OP_MULT, ct,
+    gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0)),
+    gcc_jit_context_new_rvalue_from_double (ctxt, ct, 2.));
+  
+  rval2 = gcc_jit_context_new_call (ctxt, 0, func, 1, &rval1);
+  
+  gcc_jit_block_end_with_return (block, 0, rval2);
+}
+
+static void
+make_code2 (gcc_jit_context *ctxt,
+	    const char *fn_name,
+	    int complex_type,
+	    int target_type)
+{
+  gcc_jit_block *block;
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, target_type);
+  gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, complex_type);
+  
+  gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f");
+
+  gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0,
+    GCC_JIT_FUNCTION_EXPORTED,
+    tt, fn_name, 1, &param, 0);
+  
+  block = gcc_jit_function_new_block (foo, "start");
+
+  gcc_jit_block_end_with_return (block, 0,
+    gcc_jit_context_new_cast (ctxt, 0,
+      gcc_jit_param_as_rvalue (
+        gcc_jit_function_get_param (foo, 0)), tt));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+
+  gcc_jit_context_new_global (
+    ctxt, 0, GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE),
+    "a_complex_global_double");
+  
+  make_code1 (ctxt, "complex_float_foo", "csqrtf", GCC_JIT_TYPE_COMPLEX_FLOAT);
+  make_code1 (ctxt, "complex_double_foo", "csqrt", GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  make_code1 (ctxt, "complex_long_double_foo", "csqrtl", GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
+
+#define MAKE_CODE_2(name ,complex_type, target_type)\
+  make_code2 (ctxt, #name, GCC_JIT_TYPE_ ## complex_type, GCC_JIT_TYPE_ ## target_type);
+
+#define MAKE_CODE_2_OUTER(name, type)\
+  MAKE_CODE_2(name ## _to_char, type, CHAR)\
+  MAKE_CODE_2(name ## _to_long_double, type, LONG_DOUBLE)\
+  MAKE_CODE_2(name ## _to_double, type, DOUBLE)\
+  MAKE_CODE_2(name ## _to_float, type, FLOAT)\
+  MAKE_CODE_2(name ## _to_signed_char, type, SIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_short, type, SHORT)\
+  MAKE_CODE_2(name ## _to_int, type, INT)\
+  MAKE_CODE_2(name ## _to_long, type, LONG)\
+  MAKE_CODE_2(name ## _to_long_long, type, LONG_LONG)\
+  MAKE_CODE_2(name ## _to_u_char, type, UNSIGNED_CHAR)\
+  MAKE_CODE_2(name ## _to_u_short, type, UNSIGNED_SHORT)\
+  MAKE_CODE_2(name ## _to_u_int, type, UNSIGNED_INT)\
+  MAKE_CODE_2(name ## _to_u_long, type, UNSIGNED_LONG)\
+  MAKE_CODE_2(name ## _to_u_long_long, type, UNSIGNED_LONG_LONG)\
+  MAKE_CODE_2(name ## _to_complex_float, type, COMPLEX_FLOAT)\
+  MAKE_CODE_2(name ## _to_complex_double, type, COMPLEX_DOUBLE)\
+  MAKE_CODE_2(name ## _to_complex_long_double, type, COMPLEX_LONG_DOUBLE)
+
+  /* Test all these casts */
+  MAKE_CODE_2_OUTER (complex_float, COMPLEX_FLOAT)
+  MAKE_CODE_2_OUTER (complex_double, COMPLEX_DOUBLE)
+  MAKE_CODE_2_OUTER (complex_long_double, COMPLEX_LONG_DOUBLE)    
+
+  /* Test some of these casts */
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(float, FLOAT)
+  MAKE_CODE_2_OUTER(int, INT)
+
+  /* Writing the reproducer takes annoyingly long time with all these
+     functions bellow, so #if them out. */
+#if 0
+  MAKE_CODE_2_OUTER(long_double,LONG_DOUBLE)
+  MAKE_CODE_2_OUTER(double, DOUBLE)
+  MAKE_CODE_2_OUTER(long_long, LONG_LONG)
+  MAKE_CODE_2_OUTER(long, LONG)
+  MAKE_CODE_2_OUTER(short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(signed_char, SIGNED_CHAR)
+  MAKE_CODE_2_OUTER(unsigned_long_long, UNSIGNED_LONG_LONG)
+  MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG)
+  MAKE_CODE_2_OUTER(unsigned_int, UNSIGNED_INT)
+  MAKE_CODE_2_OUTER(unsigned_short, UNSIGNED_SHORT)
+  MAKE_CODE_2_OUTER(unsigned_char, UNSIGNED_CHAR)
+
+  MAKE_CODE_2_OUTER(char, CHAR)
+  /* Note: No bool */
+#endif
+    
+#undef MAKE_CODE_2
+#undef MAKE_CODE_2_OUTER
+}
+
+typedef complex long double (*ld_foop)();
+typedef complex double (*d_foop)();
+typedef complex float (*f_foop)();
+
+#define FOO_to_BAR(foo, foo_txt) \
+typedef long long (* foo_txt ## _to_ll)(_Complex foo);\
+typedef long (* foo_txt ## _to_l)(_Complex foo);\
+typedef int (* foo_txt ## _to_i)(_Complex foo);\
+typedef short (* foo_txt ## _to_h)(_Complex foo);\
+typedef signed char (* foo_txt ## _to_sc)(_Complex foo);\
+typedef char (* foo_txt ## _to_c)(_Complex foo);\
+typedef unsigned long long (* foo_txt ## _to_ull)(_Complex foo);\
+typedef unsigned long (* foo_txt ## _to_ul)(_Complex foo);\
+typedef unsigned int (* foo_txt ## _to_ui)(_Complex foo);\
+typedef unsigned short (* foo_txt ## _to_uh)(_Complex foo);\
+typedef unsigned char (* foo_txt ## _to_uc)(_Complex foo);\
+typedef double (* foo_txt ## _to_d)(_Complex foo);\
+typedef float (* foo_txt ## _to_f)(_Complex foo);\
+typedef long double (* foo_txt ## _to_ld)(_Complex foo);\
+typedef _Complex double (* foo_txt ## _to_cd)(_Complex foo);\
+typedef _Complex float (* foo_txt ## _to_cf)(_Complex foo);\
+typedef _Complex long double (* foo_txt ## _to_cld)(_Complex foo);\
+typedef _Bool (* foo_txt ## _to_b)(_Complex foo);
+ 
+FOO_to_BAR (float, cf)
+FOO_to_BAR (double, cd)
+FOO_to_BAR (long double, cld)
+     
+#undef FOO_to_BAR
+  
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+   {/* Just check that we can get the global. */
+     _Complex double *d = gcc_jit_result_get_global (result, "a_complex_global_double");
+     CHECK_NON_NULL (d);
+   }
+  }
+  {/* Check the square rooty thing. */
+   { 
+     d_foop d_foop = gcc_jit_result_get_code (result, "complex_double_foo");
+     CHECK_NON_NULL (d_foop);
+
+     complex double q = 2. + 2.i;
+     complex double ref = csqrt (q * 2.);
+     complex double ans = d_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+   {
+     f_foop f_foop = gcc_jit_result_get_code (result, "complex_float_foo");
+     CHECK_NON_NULL (f_foop);
+
+     complex float q = 2.f + 2.fi;
+     complex float ref = csqrtf (q * 2.f);
+     complex float ans = f_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+   {
+     ld_foop ld_foop = gcc_jit_result_get_code (result, "complex_long_double_foo");
+     CHECK_NON_NULL (ld_foop);
+
+     complex long double q = 2.L + 2.Li;
+     complex long double ref = csqrtl (q * 2.L);
+     complex long double ans = ld_foop (q);
+     CHECK_VALUE (ref, ans);
+   }
+  }
+  /* With the power of M-w C-y */
+
+  {/* Cast hither and thither */
+   {
+     cf_to_ld fn = gcc_jit_result_get_code (result, "complex_float_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_d fn = gcc_jit_result_get_code (result, "complex_float_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cf_to_f fn = gcc_jit_result_get_code (result, "complex_float_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1.1f);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0.f);
+   }
+   {
+     cf_to_ll fn = gcc_jit_result_get_code (result, "complex_float_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_l fn = gcc_jit_result_get_code (result, "complex_float_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_i fn = gcc_jit_result_get_code (result, "complex_float_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_h fn = gcc_jit_result_get_code (result, "complex_float_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_sc fn = gcc_jit_result_get_code (result, "complex_float_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_c fn = gcc_jit_result_get_code (result, "complex_float_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ull fn = gcc_jit_result_get_code (result, "complex_float_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ul fn = gcc_jit_result_get_code (result, "complex_float_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_ui fn = gcc_jit_result_get_code (result, "complex_float_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uh fn = gcc_jit_result_get_code (result, "complex_float_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+   {
+     cf_to_uc fn = gcc_jit_result_get_code (result, "complex_float_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1);
+     CHECK_VALUE (fn (1.1f + 0.fi), 1);
+     CHECK_VALUE (fn (0.f + 2.2fi), 0);
+   }
+  }
+  
+  {/* complex double to ... */
+   {
+     cd_to_ld fn = gcc_jit_result_get_code (result, "complex_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.);
+   }
+   {
+     cd_to_d fn = gcc_jit_result_get_code (result, "complex_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_f fn = gcc_jit_result_get_code (result, "complex_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f);
+     CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f);
+     CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f);
+   }
+   {
+     cd_to_ll fn = gcc_jit_result_get_code (result, "complex_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_l fn = gcc_jit_result_get_code (result, "complex_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_i fn = gcc_jit_result_get_code (result, "complex_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_h fn = gcc_jit_result_get_code (result, "complex_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_sc fn = gcc_jit_result_get_code (result, "complex_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_c fn = gcc_jit_result_get_code (result, "complex_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ull fn = gcc_jit_result_get_code (result, "complex_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ul fn = gcc_jit_result_get_code (result, "complex_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_ui fn = gcc_jit_result_get_code (result, "complex_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uh fn = gcc_jit_result_get_code (result, "complex_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cd_to_uc fn = gcc_jit_result_get_code (result, "complex_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  {/* complex long double to ... */
+   {
+     cld_to_ld fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_d fn = gcc_jit_result_get_code (result, "complex_long_double_to_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }
+   {
+     cld_to_f fn = gcc_jit_result_get_code (result, "complex_long_double_to_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.);
+   }    
+   {
+     cld_to_ll fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_l fn = gcc_jit_result_get_code (result, "complex_long_double_to_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_i fn = gcc_jit_result_get_code (result, "complex_long_double_to_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_h fn = gcc_jit_result_get_code (result, "complex_long_double_to_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_sc fn = gcc_jit_result_get_code (result, "complex_long_double_to_signed_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_c fn = gcc_jit_result_get_code (result, "complex_long_double_to_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ull fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ul fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_ui fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_int");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uh fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_short");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+   {
+     cld_to_uc fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_char");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0);
+   }
+  }
+
+  { /* Try casting complex types to complex types */
+   {
+     cld_to_cld fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L + 2.2Li);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L + 0.0Li);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0L + 2.2Li);
+   }
+   {
+     cld_to_cd fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0 + 2.2i);
+   }
+   {
+     cld_to_cf fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0L + 2.2Li), 0.0f + 2.2fi);
+   }
+   {
+     cd_to_cld fn = gcc_jit_result_get_code (result, "complex_double_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cd fn = gcc_jit_result_get_code (result, "complex_double_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i);
+   }
+   {
+     cd_to_cf fn = gcc_jit_result_get_code (result, "complex_double_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cld fn = gcc_jit_result_get_code (result, "complex_float_to_complex_long_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cd fn = gcc_jit_result_get_code (result, "complex_float_to_complex_double");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+   {
+     cf_to_cf fn = gcc_jit_result_get_code (result, "complex_float_to_complex_float");
+     CHECK_NON_NULL (fn);
+
+     CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi);
+     CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi);
+     CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi);
+   }
+  }
+
+  {/* Test some of the non-complex to non-complex/complex casts  */
+    {
+      _Complex float(*fn)(float) = gcc_jit_result_get_code (result, "float_to_complex_float");
+      CHECK_VALUE ( fn(3.f), 3.f);
+    }
+    {
+      _Complex float(*fn)(int) = gcc_jit_result_get_code (result, "int_to_complex_float");
+      CHECK_VALUE ( fn(-3), -3.f);
+    }
+    {
+      _Complex double(*fn)(unsigned long) = gcc_jit_result_get_code (result, "unsigned_long_to_complex_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      double(*fn)(int) = gcc_jit_result_get_code (result, "int_to_double");
+      CHECK_VALUE ( fn(3), 3.f);
+    }
+    {
+      int(*fn)(float) = gcc_jit_result_get_code (result, "float_to_int");
+      CHECK_VALUE ( fn(3.), 3);
+    }
+  } 
+}
diff --git a/gcc/testsuite/jit.dg/test-error-complex-noenable.c b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
new file mode 100644
index 00000000000..0a7ba131f28
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-complex-noenable.c
@@ -0,0 +1,31 @@
+/*
+  Test that we can't get a complex type without enabling them first
+  with
+    gcc_jit_context_set_bool_enable_complex_types (ctxt, 1);
+*/
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+
+  gcc_jit_type *tt = gcc_jit_context_get_type (ctxt,
+					       GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  CHECK_VALUE (tt, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Verify that the diagnostic led to the context failing... */
+  CHECK_VALUE (result, NULL);
+
+  /* ...and that the message was captured by the API.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_get_type: complex types are only "
+		      "available after enabling them with "
+		      "gcc_jit_context_set_bool_enable_complex_types()");
+}
-- 
2.42.0


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

end of thread, other threads:[~2023-11-26 23:15 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-21 13:02 [PATCH 0/2] jit: Complex types and loong constants Petter Tomner
2021-10-21 13:07 ` [PATCH 1/2] " Petter Tomner
2021-10-21 13:13 ` [PATCH 2/2] " Petter Tomner
2023-11-20 22:02 [PATCH 0/2] " Petter Tomner
2023-11-20 22:10 ` [PATCH 1/2] " Petter Tomner
2023-11-21 14:43   ` David Malcolm
2023-11-26 23:15     ` Petter Tomner

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