public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
From: Petter Tomner <tomner@bahnhof.se>
To: David Malcolm <dmalcolm@redhat.com>, jit@gcc.gnu.org
Subject: Re: [PATCH 1/2] jit: Complex types and loong constants
Date: Mon, 27 Nov 2023 00:15:28 +0100	[thread overview]
Message-ID: <51b4053d-bcd3-425b-9e54-f9fc5dcaac72@bahnhof.se> (raw)
In-Reply-To: <4f908fb2947d419a0260bd17107a353f4f0ab057.camel@redhat.com>

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

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

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

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

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

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

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

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

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

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

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

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

E.g.:

#include <stdio.h>

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

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

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

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

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

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

JIT: Fix support for complex types

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

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

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

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

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

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

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


  reply	other threads:[~2023-11-26 23:15 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 ` [PATCH 1/2] " Petter Tomner
2023-11-21 14:43   ` David Malcolm
2023-11-26 23:15     ` Petter Tomner [this message]
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=51b4053d-bcd3-425b-9e54-f9fc5dcaac72@bahnhof.se \
    --to=tomner@bahnhof.se \
    --cc=dmalcolm@redhat.com \
    --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).