public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
From: Petter Tomner <tomner@bahnhof.se>
To: jit@gcc.gnu.org
Subject: [PATCH 1/2] jit: Complex types and loong constants
Date: Mon, 20 Nov 2023 23:10:29 +0100	[thread overview]
Message-ID: <3c502ba4-ffc1-4faf-8e3f-f7b7367a50e5@bahnhof.se> (raw)
In-Reply-To: <697d6d25-c8fb-452b-8997-7ea28b6eb659@bahnhof.se>


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


  reply	other threads:[~2023-11-20 22:10 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-20 22:02 [PATCH 0/2] " Petter Tomner
2023-11-20 22:10 ` Petter Tomner [this message]
2023-11-21 14:43   ` [PATCH 1/2] " David Malcolm
2023-11-26 23:15     ` Petter Tomner
2023-11-20 22:15 ` [PATCH 2/2] " Petter Tomner
2023-11-21 15:56   ` David Malcolm
2023-11-26 23:15     ` Petter Tomner
2023-12-11 23:35       ` Petter Tomner
  -- strict thread matches above, loose matches on Subject: below --
2021-10-21 13:02 [PATCH 0/2] " Petter Tomner
2021-10-21 13:07 ` [PATCH 1/2] " Petter Tomner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3c502ba4-ffc1-4faf-8e3f-f7b7367a50e5@bahnhof.se \
    --to=tomner@bahnhof.se \
    --cc=jit@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).