public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC] Setting data segment and loong constants - WIP
@ 2021-10-06  8:23 Petter Tomner
  2021-10-06  8:40 ` Basile Starynkevitch
  2021-10-21 13:27 ` SV: " Petter Tomner
  0 siblings, 2 replies; 3+ messages in thread
From: Petter Tomner @ 2021-10-06  8:23 UTC (permalink / raw)
  To: jit

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

Hi,

I have two patches I am working with and I wanted to share the concept
if anyone has feedback. Both are dependent on my patch pending review
on complex types:
https://gcc.gnu.org/pipermail/jit/2021q3/001365.html

So essentially it is one patch with:

gcc_jit_context_new_rvalue_from_long_long (...)
gcc_jit_context_new_rvalue_from_long_double (...)
gcc_jit_context_new_rvalue_from_complex_long_double (...)

Those do what it seems. long_long is for making 64bit constants on
32bit machines without silly workarounds. 


And one patch adding support for setting initial values of global
variables:

gcc_jit_lvalue *
gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
                                 gcc_jit_rvalue *init_value);

gcc_jit_rvalue *
gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
                                 gcc_jit_location *loc,
                                 gcc_jit_type *type,
                                 int arr_length,
                                 gcc_jit_field **fields,
                                 gcc_jit_rvalue **values);


gcc_jit_global_set_initializer_rvalue() assigns the rvalue to
DECL_INITIAL (global).

There is another patch in the mailing list for this
(https://gcc.gnu.org/pipermail/jit/2021q2/001308.html)
but it has problems with that the rvalue need to be created before
the global, for replay order. Also it has no constructor support.

gcc_jit_context_new_constructor() is needed for setting init values
of global array, struct or union variables. But it could also be used for 
locals, in theory. Each field in fields is set to its corresponding rvalue 
in values, by index. They do not need to be in the same order as in a 
struct definition. Unspecified fields are set to 0.

Any thoughts?

I attached a WIP patch mess if someone wants a looksie. Needs more work
on error handling and array and union ctor functionality.

Regards,

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

From bec2b4d30e689e0135b1d71513317a042ab8b770 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Wed, 15 Sep 2021 13:19:48 +0200
Subject: [PATCH 1/3] complex

---
 gcc/jit/docs/topics/contexts.rst              |  20 +
 gcc/jit/docs/topics/expressions.rst           |  89 ++-
 gcc/jit/docs/topics/types.rst                 |  12 +-
 gcc/jit/jit-common.h                          |   1 +
 gcc/jit/jit-playback.c                        | 165 ++++-
 gcc/jit/jit-recording.c                       | 116 ++-
 gcc/jit/jit-recording.h                       |  28 +
 gcc/jit/libgccjit++.h                         |  23 +-
 gcc/jit/libgccjit.c                           |  97 ++-
 gcc/jit/libgccjit.h                           |  45 +-
 gcc/jit/libgccjit.map                         |   6 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |  30 +
 gcc/testsuite/jit.dg/test-complex-builtins.c  | 217 ++++++
 gcc/testsuite/jit.dg/test-complex-literals.c  | 145 ++++
 gcc/testsuite/jit.dg/test-complex-misc.c      | 206 ++++++
 gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++
 gcc/testsuite/jit.dg/test-complex-types.c     | 677 ++++++++++++++++++
 17 files changed, 2188 insertions(+), 42 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

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

From c67c027ce553291594133ab7e9e70b5960570bac Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Thu, 16 Sep 2021 09:04:07 +0200
Subject: [PATCH 2/3] WIP

---
 gcc/jit/docs/topics/expressions.rst          |  45 +-
 gcc/jit/jit-playback.c                       | 145 +++++-
 gcc/jit/jit-recording.c                      | 468 +++++++++++++++++--
 gcc/jit/libgccjit.c                          |  46 ++
 gcc/jit/libgccjit.h                          |  39 +-
 gcc/jit/libgccjit.map                        |   3 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h |   7 +
 gcc/testsuite/jit.dg/test-long-literals.c    | 283 +++++++++++
 8 files changed, 996 insertions(+), 40 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-long-literals.c

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

From b152e32a0f3f45699a95c552562a15d693cc8e1b Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Mon, 20 Sep 2021 17:47:26 +0200
Subject: [PATCH 3/3] global init

---
 gcc/jit/jit-playback.c                        |  95 ++-
 gcc/jit/jit-playback.h                        |  11 +
 gcc/jit/jit-recording.c                       | 198 +++++++
 gcc/jit/jit-recording.h                       |  86 ++-
 gcc/jit/libgccjit.c                           |  32 +
 gcc/jit/libgccjit.h                           |  12 +
 gcc/jit/libgccjit.map                         |   4 +-
 .../jit.dg/test-global-init-rvalue.c          | 554 ++++++++++++++++++
 8 files changed, 982 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-global-init-rvalue.c

diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index f62cfc5c804..dd9a7f117cd 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -605,6 +605,71 @@ new_global (location *loc,
   return global_finalize_lvalue (inner);
 }
 
+void
+playback::context::
+global_set_init_rvalue (lvalue* global,
+			rvalue* init)
+{
+  tree inner = global->as_tree ();
+  /* We need to fold all expressions as much as possible. The code
+     for a DECL_INITIAL only handles some operations ...
+     etc addition, minus, 'address of'. See output_addressed_constants()
+     in varasm.c  */
+  
+  tree folded = fold(init->as_tree ());
+  DECL_INITIAL (inner) = folded;
+  gcc_assert (TREE_CONSTANT (DECL_INITIAL (inner)));
+}
+
+playback::rvalue *
+playback::context::
+new_ctor (location *loc,
+	  type *type,
+	  const auto_vec<field*> *fields,
+	  const auto_vec<rvalue*> *rvalues)
+{
+  tree type_tree = type->as_tree ();
+  /* Handle empty ctors first. I.e. set everything to "0" */
+  if (fields->length () == 0)
+    return new rvalue (this, build_constructor (type_tree, NULL));
+
+  int n = fields->length ();
+  
+  /* The vec for the constructor node */
+  vec<constructor_elt, va_gc> *v = NULL;
+  vec_alloc(v, n);
+
+  int i = 0;
+  tree field = TYPE_FIELDS (type_tree);
+
+  /* Iterate over the fields, building initializations.  */
+  for (; field && i < n; field = DECL_CHAIN (field), i++)
+    {
+      /*
+      tree td = DECL_NAME(field);
+      const char* field_name = IDENTIFIER_POINTER (td);
+      */
+      
+      /* If the value is NULL, it means we should zero the field */
+      if ((*rvalues)[i])
+	CONSTRUCTOR_APPEND_ELT(v, field, (*rvalues)[i]->as_tree ());
+      else
+	{
+	  tree zero_cst = build_zero_cst (TREE_TYPE (field));
+	  CONSTRUCTOR_APPEND_ELT(v, field, zero_cst);
+	}
+    }
+
+  /* Any fields remaining are set to 0 */
+  for (; field; field = DECL_CHAIN (field))
+    {
+      tree zero_cst = build_zero_cst (TREE_TYPE (field));
+      CONSTRUCTOR_APPEND_ELT(v, field, zero_cst);
+    }
+  
+  return new rvalue(this, build_constructor (type_tree, v));
+}
+
 /* Fill 'constructor_elements' with the memory content of
    'initializer'.  Each element of the initializer is of the size of
    type T.  In use by new_global_initialized.*/
@@ -1109,7 +1174,8 @@ as_truth_value (tree expr, location *loc)
   if (loc)
     set_tree_location (typed_zero, loc);
 
-  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  expr = fold_build2_loc (UNKNOWN_LOCATION,
+    NE_EXPR, integer_type_node, expr, typed_zero);
   if (loc)
     set_tree_location (expr, loc);
 
@@ -1176,6 +1242,10 @@ new_unary_op (location *loc,
   inner_result = build1 (inner_op,
 			 result_type->as_tree (),
 			 node);
+
+  /* Try to fold */			    
+  inner_result = fold (inner_result);
+  
   if (loc)
     set_tree_location (inner_result, loc);
 
@@ -1275,6 +1345,10 @@ new_binary_op (location *loc,
 			    result_type->as_tree (),
 			    node_a,
 			    node_b);
+
+  /* Try to fold the expression */
+  inner_expr = fold (inner_expr);
+  
   if (loc)
     set_tree_location (inner_expr, loc);
 
@@ -1326,6 +1400,10 @@ new_comparison (location *loc,
 			    boolean_type_node,
 			    a->as_tree (),
 			    b->as_tree ());
+
+  /* Try to fold */			    
+  inner_expr = fold (inner_expr);
+			    
   if (loc)
     set_tree_location (inner_expr, loc);
   return new rvalue (this, inner_expr);
@@ -1515,6 +1593,7 @@ new_array_access (location *loc,
     {
       tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
 			      NULL_TREE, NULL_TREE);
+      t_result = fold (t_result);
       if (loc)
 	set_tree_location (t_result, loc);
       return new lvalue (this, t_result);
@@ -1524,12 +1603,14 @@ new_array_access (location *loc,
       /* Convert index to an offset in bytes.  */
       tree t_sizeof = size_in_bytes (t_type_star_ptr);
       t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
-      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
-
+      tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
+        MULT_EXPR, sizetype, t_index, t_sizeof);
+      
       /* Locate (ptr + offset).  */
-      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+      tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
+        POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
 
-      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
       if (loc)
 	{
 	  set_tree_location (t_sizeof, loc);
@@ -1577,7 +1658,7 @@ new_dereference (tree ptr,
   gcc_assert (ptr);
 
   tree type = TREE_TYPE (TREE_TYPE(ptr));
-  tree datum = build1 (INDIRECT_REF, type, ptr);
+  tree datum = fold_build1 (INDIRECT_REF, type, ptr);
   if (loc)
     set_tree_location (datum, loc);
   return datum;
@@ -1731,7 +1812,7 @@ get_address (location *loc)
   tree t_lvalue = as_tree ();
   tree t_thistype = TREE_TYPE (t_lvalue);
   tree t_ptrtype = build_pointer_type (t_thistype);
-  tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+  tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
   if (loc)
     get_context ()->set_tree_location (ptr, loc);
   if (mark_addressable (loc))
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index f670c9e81df..0d062761a06 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -120,6 +120,17 @@ public:
                           const void *initializer,
                           const char *name);
 
+  rvalue *
+  new_ctor (location *log,
+	    type *type,
+	    const auto_vec<field*> *fields,
+	    const auto_vec<rvalue*> *rvalues);
+	    
+
+  void
+  global_set_init_rvalue (lvalue* global,
+			  rvalue* init);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 9d07062131e..071dd302af9 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1064,6 +1064,15 @@ recording::context::new_global (recording::location *loc,
   return result;
 }
 
+void
+recording::context::new_global_init_rvalue (lvalue *global,
+					    rvalue *init)
+{
+  recording::global_init_rvalue *obj =
+    new recording::global_init_rvalue (this, global, init);
+  record (obj);
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1096,12 +1105,26 @@ recording::context::new_rvalue_from_vector (location *loc,
   return result;
 }
 
+recording::rvalue *
+recording::context::new_ctor (recording::location *loc,
+			      recording::type *type,
+			      int size,
+			      recording::field **fields,
+			      recording::rvalue **rvalues)
+{
+  recording::rvalue *result =
+    new ctor (this, loc, type, size, fields, rvalues);
+  record (result);
+  return result;
+}
+
 /* Create a recording::unary_op instance and add it to this context's
    list of mementos.
 
    Implements the post-error-checking part of
    gcc_jit_context_new_unary_op.  */
 
+
 recording::rvalue *
 recording::context::new_unary_op (recording::location *loc,
 				  enum gcc_jit_unary_op op,
@@ -5583,6 +5606,150 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
 	   elements_id);
 }
 
+void
+recording::ctor::visit_children (rvalue_visitor *v)
+{
+  for (unsigned int i = 0; i < m_values.length (); i++)
+    v->visit (m_values[i]);
+}
+
+recording::string *
+recording::ctor::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "ctor");
+}
+
+void
+recording::ctor::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s;\n", id);
+  r.write ("  {\n"); /* Open scope for locals */
+
+  /* Write the array of values */
+  r.write ("    gcc_jit_rvalue *values[] = {\n");
+  for (unsigned int i = 0; i < m_values.length (); i++)
+    r.write ("      %s,\n", r.get_identifier (m_values[i]));
+  r.write ("      };\n");
+  /* Write the array of fields */
+  r.write ("    gcc_jit_field *fields[] = {\n");
+  for (unsigned int i = 0; i < m_fields.length (); i++)
+    r.write ("      %s,\n", r.get_identifier (m_fields[i]));
+  r.write ("      };\n");
+  
+  r.write (
+"    %s =\n"
+"      gcc_jit_context_new_constructor (%s,\n"
+"                                       %s, /* gcc_jit_location *loc */\n"
+"                                       %s, /* gcc_jit_type *type */\n"
+"                                       %i, /* int arr_length */\n"
+"                                       fields,\n"
+"                                       values);\n",
+	     id,
+	     r.get_identifier (get_context ()),
+	     r.get_identifier (m_loc),
+	     r.get_identifier_as_type (get_type ()),
+	     m_fields.length ());
+  
+  r.write ("  }\n"); /* Close scope for locals */
+}
+
+void
+recording::ctor::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_values;
+  auto_vec<playback::field *> playback_fields;
+
+  int n = m_values.length();
+  playback_values.reserve (n, false);
+  playback_fields.reserve (n, false);
+
+  /* Check if we need to sort the fields */
+  int is_sorted = 1;
+
+  type *type = get_type ();
+  compound_type *ct = static_cast<compound_type *>(type);
+  
+  fields *fields = ct->get_fields ();
+  int n_fields = fields->length ();
+  
+  for (int i = 0; i < n && i < n_fields; i++)
+    {
+      field *field_struct = fields->get_field (i);
+      field *field_ctor = m_fields[i];
+
+      /* Do the fields have the same type and the same name? */
+      if (
+	    (field_struct->get_type ()->
+	       accepts_writes_from (field_ctor->get_type()))
+	    &&
+	    (0 == strcmp (field_struct->get_name ()->c_str (),
+			    field_ctor->get_name ()->c_str ()))
+	 )
+	;
+      else
+	{
+	  is_sorted = 0;
+	  break;
+	}
+    }
+
+  if (is_sorted)
+    {
+      for (int i = 0; i < n; i++)
+	playback_values.quick_push (m_values[i]->playback_rvalue ());
+      for (int i = 0; i < n; i++)
+	playback_fields.quick_push (m_fields[i]->playback_field ());
+    }
+  else
+    {
+      int n_hits = 0;
+      for (int i = 0; i < n_fields; i++)
+	{
+	  field *field_struct = fields->get_field (i);
+
+	  int found = 0;
+	  for (int j = 0; j < n; j++)
+	    {
+	      field *field_ctor = m_fields[j];
+
+	      if (
+		   (field_struct->get_type ()->
+		       accepts_writes_from (field_ctor->get_type()))
+		    &&
+		   (0 == strcmp (field_struct->get_name ()->c_str (),
+				 field_ctor->get_name ()->c_str ()))
+		 )
+	        {
+		  playback_values.safe_push (m_values[j]->playback_rvalue ());
+		  playback_fields.safe_push (m_fields[j]->playback_field ());
+		  found = 1;
+		  n_hits++;
+		  break;
+		}
+	    }
+	  /* Push null value if not found, to zero the field. */
+	  if (!found)
+	    {
+	      playback_values.safe_push (NULL);
+	      playback_fields.safe_push (field_struct->playback_field ());
+	    }
+	}
+      /* Verify that we found all the fields specified. */
+      if (n_hits != n)
+	{
+	  /* TODO: Move to new_ctor and raise error. */
+	}
+      
+    }
+  
+  set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				 get_type ()->playback_type (),
+				 &playback_fields,
+				 &playback_values));
+}
+
 /* The implementation of class gcc::jit::recording::unary_op.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -7556,6 +7723,37 @@ recording::top_level_asm::write_reproducer (reproducer &r)
 	   m_asm_stmts->get_debug_string ());
 }
 
+void
+recording::global_init_rvalue::replay_into (replayer *r)
+{
+  r->global_set_init_rvalue (m_global->playback_lvalue(),
+			     m_init->playback_rvalue());
+}
+
+void
+recording::global_init_rvalue::write_reproducer (reproducer &r)
+{
+  r.write (
+    "  gcc_jit_global_set_initializer_rvalue (%s, /* lvalue *global */\n"
+    "                                         %s);/* rvalue *init */\n",
+    r.get_identifier (m_global),
+    r.get_identifier (m_init));
+}
+
+void
+recording::global_init_rvalue::write_to_dump (dump &d)
+{
+  d.write ("%s;\n", get_debug_string ());
+}
+
+recording::string *
+recording::global_init_rvalue::make_debug_string ()
+{
+    return string::from_printf(m_ctxt, "%s = {%s}",
+      m_global->get_debug_string (),
+      m_init->get_debug_string ());
+}
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index d5e0c359a48..e711dce25c8 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -42,7 +42,7 @@ class reproducer;
  **********************************************************************/
 
 namespace recording {
-
+  
 playback::location *
 playback_location (replayer *r, location *loc);
 
@@ -149,6 +149,17 @@ public:
 	      type *type,
 	      const char *name);
 
+  rvalue *
+  new_ctor (location *loc,
+	    type *type,
+	    int size,
+	    field **fields,
+	    rvalue **values);
+
+  void
+  new_global_init_rvalue (lvalue *global,
+			  rvalue *init);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
@@ -873,6 +884,7 @@ public:
   {}
 
   type * get_type () const { return m_type; }
+  string * get_name () const { return m_name; }
 
   compound_type * get_container () const { return m_container; }
   void set_container (compound_type *c) { m_container = c; }
@@ -1397,7 +1409,14 @@ public:
 
   void replay_into (replayer *) FINAL OVERRIDE;
 
-  void visit_children (rvalue_visitor *) FINAL OVERRIDE {}
+  void visit_children (rvalue_visitor *v) FINAL OVERRIDE
+  {
+    if (m_init_rvalue)
+      {
+	v->visit (m_init_rvalue);
+	//m_init_rvalue->visit_children (v);
+      }
+  }
 
   void write_to_dump (dump &d) FINAL OVERRIDE;
 
@@ -1414,6 +1433,12 @@ public:
     m_initializer_num_bytes = num_bytes;
   }
 
+  void
+  set_initializer_rvalue (rvalue *rv)
+  {
+    m_init_rvalue = rv;
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1423,6 +1448,7 @@ private:
   {
     return PRECEDENCE_PRIMARY;
   }
+  rvalue *m_init_rvalue = 0;
 
 private:
   enum gcc_jit_global_kind m_kind;
@@ -1512,6 +1538,44 @@ private:
   auto_vec<rvalue *> m_elements;
 };
 
+class ctor : public rvalue
+{
+public:
+  ctor (context *ctxt,
+	location *loc,
+	type *type,
+	int size,
+	field **fields,
+	rvalue **values)
+  : rvalue (ctxt, loc, type)
+  {
+    m_fields.reserve (size, false);
+    m_values.reserve (size, false);
+    
+    for (int i = 0; i < size; i++)
+      {
+	m_fields.quick_push (fields[i]);
+	m_values.quick_push (values[i]);
+      }
+  }
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_PRIMARY;
+  }
+
+private:
+  auto_vec<field *> m_fields;
+  auto_vec<rvalue *> m_values;
+};
+
 class unary_op : public rvalue
 {
 public:
@@ -2355,6 +2419,24 @@ private:
   string *m_asm_stmts;
 };
 
+class global_init_rvalue : public memento
+{
+public:
+  global_init_rvalue (context *ctxt, lvalue *global, rvalue *init) :
+    memento(ctxt), m_global (global), m_init (init) {};
+
+  void write_to_dump (dump &d) FINAL OVERRIDE;
+
+private:
+  void replay_into (replayer *r) FINAL OVERRIDE;
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+  lvalue *m_global;
+  rvalue *m_init;
+};
+
 } // namespace gcc::jit::recording
 
 /* Create a recording::memento_of_new_rvalue_from_const instance and add
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 9b4e847c499..fd19c61bd3e 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -1130,6 +1130,38 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
   return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name);
 }
 
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values)
+{
+  int a = 3;
+  return (gcc_jit_rvalue *)ctxt->new_ctor (
+    loc,
+    type,
+    arr_length,
+    (gcc::jit::recording::field **)fields,
+    (gcc::jit::recording::rvalue **)values);
+}
+
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_value)
+{
+  RETURN_NULL_IF_FAIL( global, NULL, NULL,"NULL global");
+  RETURN_NULL_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL,
+			       "lvalue \"%s\" not a global",
+			       global->get_debug_string ());
+
+  global->get_context ()->new_global_init_rvalue (global, init_value);
+  
+  return global;
+}
+
 /* 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 49e359f420c..be1d9096c4e 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -795,6 +795,18 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
 			    gcc_jit_type *type,
 			    const char *name);
 
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values);
+	    
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_value);
+			    
 #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
 /* Set an initial value for a global, which must be an array of
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 4022dbb6fbc..c5a1afdeacf 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 {
 
 LIBGCCJIT_ABI_16 {
   global:
+    gcc_jit_context_new_constructor;
     gcc_jit_context_new_rvalue_from_complex_double;
     gcc_jit_context_new_rvalue_from_complex_long_double;
-    gcc_jit_context_set_bool_enable_complex_types;
     gcc_jit_context_new_rvalue_from_long_double;
     gcc_jit_context_new_rvalue_from_long_long;
+    gcc_jit_context_set_bool_enable_complex_types;
+    gcc_jit_global_set_initializer_rvalue;
 } LIBGCCJIT_ABI_15;
\ No newline at end of file
diff --git a/gcc/testsuite/jit.dg/test-global-init-rvalue.c b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
new file mode 100644
index 00000000000..efd77ed2753
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
@@ -0,0 +1,554 @@
+
+
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_BOOL);
+
+  /* Make a struct: struct fi { float f; int i;} */
+  gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 float_type,
+						 "f");
+  gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "i");
+  gcc_jit_field *fields[] = {f1, f2};
+
+  gcc_jit_type *struct_fi_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "fi",
+				       2,
+				       fields));
+
+  /* Make a struct:
+
+     strict bar {
+       int ii;
+       struct fi fi;
+       float ff;
+     }
+  */
+  f1 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  float_type,
+				  "ff");
+  f2 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  int_type,
+				  "ii");
+  gcc_jit_field *fi = gcc_jit_context_new_field (ctxt,
+						 0,
+						 struct_fi_type,
+						 "fi");
+  gcc_jit_field *fields2[] = {f1, fi, f2};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields2));
+
+  /* Make globals initialized with ctors */
+  
+  { /* struct bar bar = {.ii = 4, .ff = 1, .fi = {.i = 3, .f = 2}};
+       I.e. nested struct and nested ctors in "wrong" order.
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_1");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");   
+    
+    gcc_jit_rvalue *vals[] = { ival, fval};
+    gcc_jit_field *fields[] = {fi_i, fi_f};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+
+    gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						       0,
+						       struct_fi_type,
+						       "fi");
+    gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt,
+						       0,
+						       float_type,
+						       "ff");
+    gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt,
+						       0,
+						       int_type,
+						       "ii");
+    
+    gcc_jit_rvalue *vals2[] = {ival, fval, ctor};
+    gcc_jit_field *fields2[] = {bar_ii, bar_ff, bar_fi};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       fields2,
+       vals2);
+    
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+{ /* struct bar bar = {1, {2, 3}, 4};
+       I.e. nested struct and nested ctors in "right" order.
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_2");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");   
+    
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+
+    gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						       0,
+						       struct_fi_type,
+						       "fi");
+    gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt,
+						       0,
+						       float_type,
+						       "ff");
+    gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt,
+						       0,
+						       int_type,
+						       "ii");
+    
+    gcc_jit_rvalue *vals2[] = {fval, ctor, ival};
+    gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       fields2,
+       vals2);
+    
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+  { /* struct fi foo = {2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_1");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {f1, f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i = 3, .f = 2};
+
+       I.e. "wrong" order of fields.  */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_2");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { ival, fval};
+    gcc_jit_field *fields[] = {f2, f1};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {2 * 2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_3");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *fval2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      float_type,
+      fval,
+      fval2);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { rval_mul, ival};
+    gcc_jit_field *fields[] = {f1, f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  } 
+  { /* int foo = 3; */
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3); 
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int1_3"); 
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* Try the above, but with opposite order of global and literal calls */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int2_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* int foo = 3 * (3 + 3) */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int3_18");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      rval_plus,
+      rval3_2);
+    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_mul);
+  }
+  { /* int foo = 3; int *pfoo = &foo; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int4_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint5");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (foo, 0));
+  }
+  { /* int foo = 3; int *pfoo = &foo + 1; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int6_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint7");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (
+	gcc_jit_context_new_array_access(
+	  ctxt,
+	  0,
+	  gcc_jit_lvalue_get_address(foo, 0),
+	  gcc_jit_context_one(ctxt, int_type)),
+	0));
+  }
+  {
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double1_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval);
+  }
+  { /* double foo = 3 * 3 + 3 */
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double2_12");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      double_type,
+      rval,
+      rval);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      double_type,
+      rval_mul,
+      rval);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval_plus);
+  }
+  { /* bool foo = 3 + 3 <= 6; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      bool_type,
+      "global_bool1_1");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 6);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt,
+      0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_le = gcc_jit_context_new_comparison (ctxt,
+      0,
+      GCC_JIT_COMPARISON_LE,
+      rval_plus,
+      rval6);
+    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_le);
+  }
+}
+
+struct fi {
+  float f;
+  int i;
+};
+
+struct bar {
+  float ff;
+  struct fi fi;
+  int ii;
+};
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_1");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_2");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_3");
+
+    CHECK_VALUE (fi->f, 2 * 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct bar *bar = gcc_jit_result_get_global (result, "global_struct_bar_1");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->ii, 4);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+
+    bar = gcc_jit_result_get_global (result, "global_struct_bar_2");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->ii, 4);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int2_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int3_18");
+
+    CHECK_VALUE (*foo, 18);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int4_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint5");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo, *pfoo);
+    CHECK_VALUE (**pfoo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int6_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint7");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo + 1, *pfoo);
+    CHECK_VALUE (*(*pfoo - 1), 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double2_12");
+
+    CHECK_VALUE (*foo, 12);
+  }
+  {
+    _Bool *foo = gcc_jit_result_get_global (result, "global_bool1_1");
+
+    CHECK_VALUE (*foo, 1);
+  }
+}
-- 
2.30.2


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

* Re: [RFC] Setting data segment and loong constants - WIP
  2021-10-06  8:23 [RFC] Setting data segment and loong constants - WIP Petter Tomner
@ 2021-10-06  8:40 ` Basile Starynkevitch
  2021-10-21 13:27 ` SV: " Petter Tomner
  1 sibling, 0 replies; 3+ messages in thread
From: Basile Starynkevitch @ 2021-10-06  8:40 UTC (permalink / raw)
  To: Petter Tomner; +Cc: jit


On 10/6/21 10:23 AM, Petter Tomner via Jit wrote:
> Hi,
>
> I have two patches I am working with and I wanted to share the concept
> if anyone has feedback. Both are dependent on my patch pending review
> on complex types:
> https://gcc.gnu.org/pipermail/jit/2021q3/001365.html
>
> So essentially it is one patch with:
>
> gcc_jit_context_new_rvalue_from_long_long (...)
> gcc_jit_context_new_rvalue_from_long_double (...)
> gcc_jit_context_new_rvalue_from_complex_long_double (...)
>
> Those do what it seems. long_long is for making 64bit constants on
> 32bit machines without silly workarounds.
>
>
> And one patch adding support for setting initial values of global
> variables:
>
> gcc_jit_lvalue *
> gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
>                                   gcc_jit_rvalue *init_value);
>
> gcc_jit_rvalue *
> gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
>                                   gcc_jit_location *loc,
>                                   gcc_jit_type *type,
>                                   int arr_length,
>                                   gcc_jit_field **fields,
>                                   gcc_jit_rvalue **values);


I hope this patch would be approved.

(and we are considering perhaps using libgccjit in theRefPerSys project, 
see http://refpersys.org/ for details)

Thanks

-- 
Basile Starynkevitch                  <basile@starynkevitch.net>
(only mine opinions / les opinions sont miennes uniquement)
92340 Bourg-la-Reine, France
web page: starynkevitch.net/Basile/


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

* SV: [RFC] Setting data segment and loong constants - WIP
  2021-10-06  8:23 [RFC] Setting data segment and loong constants - WIP Petter Tomner
  2021-10-06  8:40 ` Basile Starynkevitch
@ 2021-10-21 13:27 ` Petter Tomner
  1 sibling, 0 replies; 3+ messages in thread
From: Petter Tomner @ 2021-10-21 13:27 UTC (permalink / raw)
  To: jit

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

I think I more or less got a working patch for constructors and global rvalue init.

The remaining concern is that type matching on the other entry points
only remove one qualifier (not recursive), and does not match on eg. 
"pointer to const x" made from different function calls. Which makes cast 
pretty much mandatory for any nested type.

I made a "strip all and compare types" for the new entrypoints, but I wonder if that
just makes it more confusing for the user?

I attached a WIP patch.

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

From b69a55876a44187ffabec6ee37509f76e4a74a97 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Fri, 15 Oct 2021 20:17:40 +0200
Subject: [PATCH 3/3] ctor

Add suport for global rvalue initialization and ctors

This patch adds support for initialization of global variables
with rvalues and creating constructors for array, struct and
union types which can be used as rvalues.

gcc/jit/
	* jit-playback.c :
	(global_new_decl) : Handle const global generation
	(new_global) : New flag
	(global_set_init_rvalue) : New
	(new_ctor) : New
	(new_global_initialized) : Flag
	(as_truth_value) : Fold
	(new_unary_op) : Fold
	(new_binary_op) : Fold
	(new_comparison) : Fold
	(new_array_access) : Fold
	(new_dereference) : Fold
	(get_address) : Fold
	* jit-playback.h :
	(rvalue::as_tree) : Fold to DECL_INITIAL for const VAR_DECL
	* jit-recording.c : See .h
	* jit-recording.h :
	(new_global_init_rvalue) : New
	(new_ctor) : New
	(ctor) : New, inherits rvalue
	(global_init_rvalue) : New, inherits memento
	(type::is_struct) : New
	(type::is_union) : New
	(field::get_name) : New
	* libgccjit++.h : New entrypoints
	* libgccjit.c : See .h
	* libgccjit.h :
	(gcc_jit_context_new_constructor) : New
	(gcc_jit_global_set_initializer_rvalue) : New
	(LIBGCCJIT_HAVE_CTORS) : New
	* libgccjit.map : New entrypoints added to ABI 16

gcc/testsuite/
	* jit.dg/test-error-global-init-too-small-array.c : All new
	* jit.dg/test-error-global-lvalue-init.c
	* jit.dg/test-error-global-nonconst-init.c
	* jit.dg/test-global-init-rvalue.c
	* jit.dg/test-local-init-rvalue.c

gcc/jit/docs/topics/
	* expressions.rst : Updated docs
---
 gcc/jit/docs/topics/expressions.rst           |   89 ++
 gcc/jit/jit-common.h                          |    9 +
 gcc/jit/jit-playback.c                        |  280 +++-
 gcc/jit/jit-playback.h                        |   25 +-
 gcc/jit/jit-recording.c                       |  436 +++++-
 gcc/jit/jit-recording.h                       |   92 ++
 gcc/jit/libgccjit++.h                         |   44 +
 gcc/jit/libgccjit.c                           |  229 ++-
 gcc/jit/libgccjit.h                           |   77 +
 gcc/jit/libgccjit.map                         |    4 +-
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |   14 +
 .../jit.dg/test-error-ctor-struct-too-big.c   |   86 +
 .../test-error-ctor-struct-wrong-field-name.c |   81 +
 .../test-error-ctor-struct-wrong-type.c       |   85 +
 .../test-error-ctor-union-wrong-field-name.c  |   80 +
 .../jit.dg/test-error-global-allready-init.c  |   46 +
 .../jit.dg/test-error-global-common-section.c |   54 +
 .../test-error-global-init-too-small-array.c  |   64 +
 .../jit.dg/test-error-global-lvalue-init.c    |   60 +
 .../jit.dg/test-error-global-nonconst-init.c  |   80 +
 .../jit.dg/test-global-init-rvalue.c          | 1394 +++++++++++++++++
 gcc/testsuite/jit.dg/test-local-init-rvalue.c |  576 +++++++
 22 files changed, 3880 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-allready-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-common-section.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-global-init-rvalue.c
 create mode 100644 gcc/testsuite/jit.dg/test-local-init-rvalue.c

diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 30a3b9780f9..3a1738e4628 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -176,6 +176,63 @@ Simple expressions
    underlying string, so it is valid to pass in a pointer to an on-stack
    buffer.
 
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_context_new_constructor (gcc_jit_context *ctxt,\
+                                               gcc_jit_location *loc,\
+				               gcc_jit_type *type,\
+				               size_t arr_length,\
+				               gcc_jit_field **fields,\
+				               gcc_jit_rvalue **values)
+
+   Create a constructor for an array, union or struct as a rvalue.
+
+   Returns NULL on error. The two parameter arrays are copied and
+   do not have to outlive the context.
+
+   ``type`` specifies what the constructor will build.
+
+   For a struct or union ``type``, each field in ``fields`` specifies
+   which field in the struct or union type to set to the corresponding
+   value in ``values``. ``fields`` and ``values`` are paired by index
+   and the pair need to have the same unqualified type.
+
+   For an array ``type``, the ``fields`` parameter is ignored.
+   
+   ``arr_length`` specifies the number of elements in ``values``.
+   For struct and unions, ``fields`` need to have the same length as
+   ``values``.
+
+   For unions, ``arr_length`` need to be 1.
+
+   For non-unions, if ``arr_length`` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+ 
+   For an array ``type``, if the array type itself has more elements than
+   ``values``, the left-over elements will be zeroed. Each value in
+   ``values`` need to be the same unqualified type as the array elements.
+
+   For a struct ``type``, the fields in ``fields`` do not have to be in
+   definition order, but being in order avoids a sort operation. Any
+   field in the struct that is not specified in ``fields`` will be zeroed.
+      
+   A NULL value in ``values`` is a shorthand for zero initialization
+   of the corresponding field or array element. 
+
+   The constructor rvalue can be used for assignment to locals.
+   It can be used to initialize global variables with
+   :func:`gcc_jit_global_set_initializer_rvalue`. It can also be used as a
+   temporary value for function calls and return values.
+
+   The constructor can contain nested constructors. Note that a string
+   literal rvalue can't be used to construct a char array. It need one
+   rvalue for each char.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presense using:
+
+   .. code-block:: c
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
 Vector expressions
 ******************
 
@@ -681,6 +738,38 @@ Global variables
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
+.. function:: gcc_jit_lvalue *\
+	      gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+	                                             gcc_jit_rvalue *init_value)
+
+   Set the initial value of a global with an rvalue.
+
+   The rvalue need to be a constant expression, i.e. no function calls.
+
+   The global can't have the ``kind`` :ref:`GCC_JIT_GLOBAL_IMPORTED`.
+   
+   As a non-comprehensive example it is OK to do the equivalent of:
+
+   .. code-block:: c
+
+       int foo = 3 * 2; /* rvalue from gcc_jit_context_new_binary_op */
+       int arr[] = {1,2,3,4}; /* rvalue from gcc_jit_context_new_constructor */
+       int *bar = &arr[2] + 1; /* rvalue from nested "get address" of "array access" */
+       const int baz = 3; /* rvalue from gcc_jit_context_rvalue_from_int */
+       int boz = baz; /* rvalue from gcc_jit_lvalue_as_rvalue */
+
+   Use together with :ref:`gcc_jit_context_new_constructor` to
+   initialize structs, unions and arrays.
+
+   On success, returns the ``global`` parameter unchanged. Otherwise, ``NULL``.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presence using:
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_CTORS
+
 Working with pointers, structs and unions
 -----------------------------------------
 
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index bc0453fba05..7c937478793 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -203,6 +203,15 @@ enum inner_bool_option
   NUM_INNER_BOOL_OPTIONS
 };
 
+/* Flags for global variables class. For when the playback of the
+   global need to know what will happen to it later. */
+enum global_var_flags
+{
+  GLOBAL_VAR_FLAGS_NONE = 0,
+  GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT = 1,
+  GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT = 2,
+};
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 1f4dc31a1c1..914afd6bd9f 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -107,6 +107,43 @@ namespace jit {
  Playback.
  **********************************************************************/
 
+/* Fold a readonly non-volatile variable with an initial constant value,
+   to that value.
+
+   Otherwise return the argument unchanged.
+
+   This fold is needed for setting a variable's DECL_INITIAL to the value
+   of a const variable. The c-frontend does this in its own special
+   fold(), so we lift this part out and do it explicitly where there is a
+   potential for variables to be used as rvalues. */
+static tree
+fold_const_var (tree node)
+{
+  /* See c_fully_fold_internal in c-fold.c and decl_constant_value_1
+     in c-typeck.c */
+  if (VAR_P (node)
+      && TREE_READONLY (node)
+      && !TREE_THIS_VOLATILE (node)
+      && DECL_INITIAL (node) != NULL_TREE
+      /* "This is invalid if initial value is not constant.
+	  If it has either a function call, a memory reference,
+	  or a variable, then re-evaluating it could give different
+	  results." */
+      && TREE_CONSTANT (DECL_INITIAL (node)))
+    {
+      tree ret = DECL_INITIAL (node);
+      /* "Avoid unwanted tree sharing between the initializer and current
+	  function's body where the tree can be modified e.g. by the
+	  gimplifier."  */
+      if (TREE_STATIC (node))
+	ret = unshare_expr (ret);
+
+      return ret;
+    }
+
+  return node;
+}
+
 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
    The TREE_TYPE is not initialized.  */
 
@@ -547,15 +584,28 @@ playback::context::
 global_new_decl (location *loc,
 		 enum gcc_jit_global_kind kind,
 		 type *type,
-		 const char *name)
+		 const char *name,
+		 enum global_var_flags flags)
 {
   gcc_assert (type);
   gcc_assert (name);
+
+  tree type_tree = type->as_tree ();
+
   tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
 			   get_identifier (name),
-			   type->as_tree ());
+			   type_tree);
+
   TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
-  DECL_COMMON (inner) = 1;
+
+
+  int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
+			      GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
+
+  /* A VAR_DECL with DECL_INITIAL will not end up in .common section */
+  if (!will_be_init)
+    DECL_COMMON (inner) = 1;
+
   switch (kind)
     {
     default:
@@ -574,6 +624,9 @@ global_new_decl (location *loc,
       break;
     }
 
+  if (TYPE_READONLY (type_tree))
+    TREE_READONLY(inner) = 1;
+
   if (loc)
     set_tree_location (inner, loc);
 
@@ -598,13 +651,178 @@ playback::context::
 new_global (location *loc,
 	    enum gcc_jit_global_kind kind,
 	    type *type,
-	    const char *name)
+	    const char *name,
+	    enum global_var_flags flags)
 {
-  tree inner = global_new_decl (loc, kind, type, name);
+  tree inner =
+    global_new_decl (loc, kind, type, name, flags);
 
   return global_finalize_lvalue (inner);
 }
 
+/* Helper function for usage with walk_tree in global_set_init_rvalue.
+   If the tree contains a DECL_VAR without DECL_INITIAL set, it will be
+   returned.
+
+   Otherwise, returns NULL_TREE. */
+static tree
+validate_var_has_init (tree *tp, int *walk_subtree, void *data)
+{
+  (void) data;
+  (void) walk_subtree;
+
+  if (VAR_P (*tp) && DECL_INITIAL (*tp) == NULL_TREE)
+    return *tp;
+  return NULL_TREE;
+}
+
+void
+playback::context::
+global_set_init_rvalue (lvalue* variable,
+			rvalue* init)
+{
+  tree inner = variable->as_tree ();
+
+  /* We need to fold all expressions as much as possible. The code
+     for a DECL_INITIAL only handles some operations,
+     etc addition, minus, 'address of'. See output_addressed_constants()
+     in varasm.c  */
+  tree init_tree = init->as_tree ();
+  tree folded = fold_const_var (init_tree);
+
+  if (!TREE_CONSTANT (folded))
+    {
+      tree name = DECL_NAME (inner);
+
+      add_error (NULL,
+		 "init rvalue for the global variable %s does not seem"
+		 " to be constant",
+		 name != NULL_TREE ? IDENTIFIER_POINTER (name) : NULL);
+      return;
+    }
+
+  /* Find any VAR_DECL without DECL_INITIAL set.
+     Assume that any ..._CST is OK to save some CPU.
+     Handle CONSTRUCTORs explicitly to avoid tree walks
+     on array inits consisting of only ..._CSTs. */
+  tree sinner = NULL_TREE;
+  
+  if (TREE_CODE (folded) == CONSTRUCTOR)
+    {
+      unsigned HOST_WIDE_INT idx;
+      tree elt;
+      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (folded), idx, elt)
+	{
+	  if (!CONSTANT_CLASS_P (elt))
+	    sinner = walk_tree (&elt, validate_var_has_init, NULL, NULL);
+	  if (sinner != NULL_TREE)
+	    break;
+	}
+    }
+  else if (!CONSTANT_CLASS_P (folded))
+    sinner = walk_tree (&folded, validate_var_has_init, NULL, NULL);
+
+  if (sinner != NULL_TREE)
+    {
+      tree name = DECL_NAME (inner);
+      tree rvname = DECL_NAME (sinner);
+      add_error (NULL,
+		 "can't initialize %s with %s since it has no "
+		 "initial value set",
+		 name != NULL_TREE ? IDENTIFIER_POINTER (name) : NULL,
+		 rvname != NULL_TREE ? IDENTIFIER_POINTER (rvname) : NULL);
+      return;
+    }
+
+  DECL_INITIAL (inner) = folded;
+}
+
+playback::rvalue *
+playback::context::
+new_ctor (location *loc,
+	  type *type,
+	  const auto_vec<field*> *fields,
+	  const auto_vec<rvalue*> *rvalues)
+{
+  tree type_tree = type->as_tree ();
+
+  /* Handle empty ctors first. I.e. set everything to 0 */
+  if (rvalues->length () == 0)
+    return new rvalue (this, build_constructor (type_tree, NULL));
+
+  /* Handle arrays (and return) */
+  if (TREE_CODE (type_tree) == ARRAY_TYPE)
+    {
+      int n = rvalues->length ();
+      /* The vec for the constructor node */
+      vec<constructor_elt, va_gc> *v = NULL;
+      vec_alloc(v, n);
+
+      for (int i = 0; i < n; i++)
+	{
+	  /* null rvalues indicate that the element should be zeroed */
+	  if ((*rvalues)[i])
+	    CONSTRUCTOR_APPEND_ELT(v,
+				   build_int_cst (size_type_node, i),
+				   (*rvalues)[i]->as_tree ());
+	  else
+	    CONSTRUCTOR_APPEND_ELT(v,
+				   build_int_cst (size_type_node, i),
+				   build_zero_cst (TREE_TYPE (type_tree)));
+	}
+
+      tree ctor = build_constructor (type_tree, v);
+
+      if (loc)
+	set_tree_location (ctor, loc);
+
+      return new rvalue(this, ctor);
+    }
+
+  /* Handle structs and unions */
+  int n = fields->length ();
+
+  /* The vec for the constructor node */
+  vec<constructor_elt, va_gc> *v = NULL;
+  vec_alloc(v, n);
+
+  int i = 0;
+  tree field = TYPE_FIELDS (type_tree);
+
+  /* Iterate over the fields, building initializations. */
+  for (; field && i < n; field = DECL_CHAIN (field), i++)
+    {
+      /* If the value is NULL, it means we should zero the field */
+      if ((*rvalues)[i])
+	CONSTRUCTOR_APPEND_ELT(v, field, (*rvalues)[i]->as_tree ());
+      else
+	{
+	  tree zero_cst = build_zero_cst (TREE_TYPE (field));
+	  CONSTRUCTOR_APPEND_ELT(v, field, zero_cst);
+	}
+    }
+
+  /* Any fields remaining are set to 0, for structs (not unions) */
+  if (TREE_CODE (type_tree) == RECORD_TYPE)
+    {
+      for (; field && i < n; field = DECL_CHAIN (field), i++)
+	{
+	  tree zero_cst = build_zero_cst (TREE_TYPE (field));
+	  CONSTRUCTOR_APPEND_ELT(v, field, zero_cst);
+	}
+      /* Assert that we got as many fields as we think we got */
+      gcc_assert (field == NULL_TREE);
+      gcc_assert (n == i);
+    }
+
+  tree ctor = build_constructor (type_tree, v);
+
+  if (loc)
+    set_tree_location (ctor, loc);
+
+  return new rvalue(this, build_constructor (type_tree, v));
+}
+
 /* Fill 'constructor_elements' with the memory content of
    'initializer'.  Each element of the initializer is of the size of
    type T.  In use by new_global_initialized.*/
@@ -638,9 +856,10 @@ new_global_initialized (location *loc,
                         size_t element_size,
 			size_t initializer_num_elem,
 			const void *initializer,
-			const char *name)
+			const char *name,
+			enum global_var_flags flags)
 {
-  tree inner = global_new_decl (loc, kind, type, name);
+  tree inner = global_new_decl (loc, kind, type, name, flags);
 
   vec<constructor_elt, va_gc> *constructor_elements = NULL;
 
@@ -1109,7 +1328,8 @@ as_truth_value (tree expr, location *loc)
   if (loc)
     set_tree_location (typed_zero, loc);
 
-  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  expr = fold_build2_loc (UNKNOWN_LOCATION,
+    NE_EXPR, integer_type_node, expr, typed_zero);
   if (loc)
     set_tree_location (expr, loc);
 
@@ -1145,6 +1365,8 @@ new_unary_op (location *loc,
   gcc_assert (a);
 
   tree node = a->as_tree ();
+  node = fold_const_var (node);
+
   tree inner_result = NULL;
 
   switch (op)
@@ -1176,6 +1398,10 @@ new_unary_op (location *loc,
   inner_result = build1 (inner_op,
 			 result_type->as_tree (),
 			 node);
+
+  /* Try to fold */
+  inner_result = fold (inner_result);
+
   if (loc)
     set_tree_location (inner_result, loc);
 
@@ -1200,7 +1426,10 @@ new_binary_op (location *loc,
   gcc_assert (b);
 
   tree node_a = a->as_tree ();
+  node_a = fold_const_var (node_a);
+
   tree node_b = b->as_tree ();
+  node_b = fold_const_var (node_b);
 
   switch (op)
     {
@@ -1275,6 +1504,10 @@ new_binary_op (location *loc,
 			    result_type->as_tree (),
 			    node_a,
 			    node_b);
+
+  /* Try to fold the expression */
+  inner_expr = fold (inner_expr);
+
   if (loc)
     set_tree_location (inner_expr, loc);
 
@@ -1322,10 +1555,19 @@ new_comparison (location *loc,
       break;
     }
 
+  tree node_a = a->as_tree ();
+  node_a = fold_const_var (node_a);
+  tree node_b = b->as_tree ();
+  node_b = fold_const_var (node_b);
+
   tree inner_expr = build2 (inner_op,
 			    boolean_type_node,
-			    a->as_tree (),
-			    b->as_tree ());
+			    node_a,
+			    node_b);
+
+  /* Try to fold */
+  inner_expr = fold (inner_expr);
+
   if (loc)
     set_tree_location (inner_expr, loc);
   return new rvalue (this, inner_expr);
@@ -1425,6 +1667,8 @@ playback::context::build_cast (playback::location *loc,
 
      Only some kinds of cast are currently supported here.  */
   tree t_expr = expr->as_tree ();
+  t_expr = fold_const_var (t_expr);
+
   tree t_dst_type = type_->as_tree ();
   tree t_ret = NULL;
   t_ret = targetm.convert_to_type (t_dst_type, t_expr);
@@ -1507,7 +1751,10 @@ new_array_access (location *loc,
        c-family/c-common.c: pointer_int_sum
   */
   tree t_ptr = ptr->as_tree ();
+  t_ptr = fold_const_var (t_ptr);
   tree t_index = index->as_tree ();
+  t_index = fold_const_var (t_index);
+
   tree t_type_ptr = TREE_TYPE (t_ptr);
   tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
 
@@ -1515,6 +1762,7 @@ new_array_access (location *loc,
     {
       tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
 			      NULL_TREE, NULL_TREE);
+      t_result = fold (t_result);
       if (loc)
 	set_tree_location (t_result, loc);
       return new lvalue (this, t_result);
@@ -1524,12 +1772,14 @@ new_array_access (location *loc,
       /* Convert index to an offset in bytes.  */
       tree t_sizeof = size_in_bytes (t_type_star_ptr);
       t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
-      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+      tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
+	MULT_EXPR, sizetype, t_index, t_sizeof);
 
       /* Locate (ptr + offset).  */
-      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+      tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
+	POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
 
-      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
       if (loc)
 	{
 	  set_tree_location (t_sizeof, loc);
@@ -1577,7 +1827,7 @@ new_dereference (tree ptr,
   gcc_assert (ptr);
 
   tree type = TREE_TYPE (TREE_TYPE(ptr));
-  tree datum = build1 (INDIRECT_REF, type, ptr);
+  tree datum = fold_build1 (INDIRECT_REF, type, ptr);
   if (loc)
     set_tree_location (datum, loc);
   return datum;
@@ -1731,7 +1981,7 @@ get_address (location *loc)
   tree t_lvalue = as_tree ();
   tree t_thistype = TREE_TYPE (t_lvalue);
   tree t_ptrtype = build_pointer_type (t_thistype);
-  tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+  tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
   if (loc)
     get_context ()->set_tree_location (ptr, loc);
   if (mark_addressable (loc))
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index f670c9e81df..d445d7ccb95 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -109,7 +109,8 @@ public:
   new_global (location *loc,
 	      enum gcc_jit_global_kind kind,
 	      type *type,
-	      const char *name);
+	      const char *name,
+	      enum global_var_flags flags);
 
   lvalue *
   new_global_initialized (location *loc,
@@ -118,7 +119,19 @@ public:
                           size_t element_size,
                           size_t initializer_num_elem,
                           const void *initializer,
-                          const char *name);
+                          const char *name,
+			  enum global_var_flags flags);
+
+  rvalue *
+  new_ctor (location *log,
+	    type *type,
+	    const auto_vec<field*> *fields,
+	    const auto_vec<rvalue*> *rvalues);
+
+
+  void
+  global_set_init_rvalue (lvalue* variable,
+			  rvalue* init);
 
   template <typename HOST_TYPE>
   rvalue *
@@ -286,7 +299,8 @@ private:
   global_new_decl (location *loc,
                    enum gcc_jit_global_kind kind,
                    type *type,
-                   const char *name);
+		   const char *name,
+		   enum global_var_flags flags);
   lvalue *
   global_finalize_lvalue (tree inner);
 
@@ -635,7 +649,10 @@ public:
   rvalue *
   as_rvalue () { return this; }
 
-  tree as_tree () const { return m_inner; }
+  tree as_tree () const
+  {
+    return m_inner;
+  }
 
   context *get_context () const { return m_ctxt; }
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 8d34956fc67..2e266c95bef 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1064,6 +1064,15 @@ recording::context::new_global (recording::location *loc,
   return result;
 }
 
+void
+recording::context::new_global_init_rvalue (lvalue *variable,
+					    rvalue *init)
+{
+  recording::global_init_rvalue *obj =
+    new recording::global_init_rvalue (this, variable, init);
+  record (obj);
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1096,6 +1105,233 @@ recording::context::new_rvalue_from_vector (location *loc,
   return result;
 }
 
+
+/* For sorting */
+struct fieldval_pair {
+  gcc::jit::recording::field *field;
+  gcc::jit::recording::rvalue *value;
+};
+
+static int cmp_fieldvalue (const void *l, const void *r)
+{
+  const fieldval_pair *p_l = (const fieldval_pair*)l;
+  const fieldval_pair *p_r = (const fieldval_pair*)r;
+  
+  return strcmp (p_l->field->get_name ()->c_str (),
+		 p_r->field->get_name ()->c_str ());
+}
+
+recording::rvalue *
+recording::context::new_ctor (recording::location *loc,
+			      recording::type *type,
+			      int arr_length,
+			      field **fields_arr,
+			      rvalue **values)
+{
+  recording::ctor *result = new ctor (this, loc, type);
+
+  /* We need to copy fields and values into result's auto_vec:s.
+
+     We also do some validation and return NULL on error, deleting
+     result. */
+
+  if (type->is_array () != NULL)
+    {
+      result->m_values.reserve (arr_length, false);
+
+      for (int i = 0; i < arr_length; i++)
+	result->m_values.quick_push (values[i]);
+    }
+  else if (type->is_union ())
+    {
+      /* Check that the field actually exists in the union, then copy */
+      
+      field *field_ctor = fields_arr[0];
+      
+      compound_type *ct = reinterpret_cast<compound_type *>(type);
+
+      fields *fields_union = ct->get_fields ();
+      int n_fields = fields_union->length ();
+
+      recording::type *field_ctor_type = field_ctor->get_type ()->unqualified ();
+      
+      const char *field_ctor_name = field_ctor->get_name ()->c_str ();
+
+      int hit = 0;
+      for (int i = 0; i < n_fields; i++)
+	{
+	  field *field_union = fields_union->get_field (i);
+
+	  /* Do the fields have the same unqualified type and the same name? */
+	  if (
+		types_kinda_same (field_union->get_type (),
+				  field_ctor_type)
+		&&
+		(0 == strcmp (field_union->get_name ()->c_str (),
+			      field_ctor_name))
+	     )
+	    {
+	      hit = 1;
+	      break;
+	    }
+	}
+
+      if (!hit)
+	{
+	  add_error(
+	    loc,
+	    "gcc_jit_context_new_constructor: constructor field does not exist "
+	    "in the union type (field: %s %s)(type: %s)",
+	    field_ctor->get_type ()->get_debug_string (),
+	    field_ctor->get_name ()->c_str (),
+	    type->get_debug_string ());
+	  goto err;
+	}
+   
+      result->m_values.safe_push (values[0]);
+      result->m_fields.safe_push (fields_arr[0]);
+    }
+  else if (type->is_struct ())
+    {
+      /* If the type is a struct, we might need to sort the fields and add
+	 intermittent fields with null values to zero them later.
+
+	 We also want any error here at the call site not at replay time. */
+
+      compound_type *ct = reinterpret_cast<compound_type *>(type);
+
+      fields *fields_struct = ct->get_fields ();
+      int n_fields = fields_struct->length ();
+
+      if (n_fields < arr_length)
+	{
+	  add_error(
+	    loc,
+	    "gcc_jit_context_new_constructor: more fields in constructor than "
+	    "in the target struct");
+	  goto err;
+	}
+
+      /* Sorted fields should be the normal case so we check if the fields
+	 are sorted before sorting them to save some CPU time */
+      int is_sorted = 1;
+
+      for (int i = 0; i < arr_length; i++)
+	{
+	  field *field_struct = fields_struct->get_field (i);
+
+	  field *field_ctor = fields_arr[i];
+
+	  /* Do the fields have the same unqualified type and the same name? */
+	  if (
+		types_kinda_same (field_struct->get_type (),
+				  field_ctor->get_type ())
+		&&
+		(0 == strcmp (field_struct->get_name ()->c_str (),
+			      field_ctor->get_name ()->c_str ()))
+	     )
+	    ;
+	  else
+	    {
+	      is_sorted = 0;
+	      break;
+	    }
+	}
+
+      if (is_sorted)
+	{
+	  result->m_values.reserve (arr_length, false);
+	  result->m_fields.reserve (arr_length, false);
+
+	  for (int i = 0; i < arr_length; i++)
+	    {
+	      result->m_values.quick_push (values[i]);
+	      result->m_fields.quick_push (fields_arr[i]);
+	    }
+	}
+      else
+	{
+	  int n_hits = 0;
+	  /* For all fields in the struct type, find the corrensponding
+	     field in the ctor and push it to the vectors. If a field is
+	     missing in the ctor, push a null value to indicate that it
+	     needs zeroing.
+
+	     The c-front end sorts the struct fields when they are more
+	     than 15, see c-decl.c : finish_struct(), to do fancy searches
+	     for big structs and fast linear for small, but we do binary
+	     always to save some code complexity. */
+	  auto_vec<fieldval_pair> v_fieldvals;
+	  v_fieldvals.reserve (arr_length, false);
+
+	  for (int i = 0; i < arr_length; i++)
+	    v_fieldvals.quick_push (
+	      {reinterpret_cast<field *>(fields_arr[i]),
+	       reinterpret_cast<rvalue *>(values[i])});
+
+	  v_fieldvals.qsort (cmp_fieldvalue);
+	  
+	  for (int i = 0; i < n_fields; i++)
+	    {
+	      field *field_struct = fields_struct->get_field (i);
+
+	      fieldval_pair key = {field_struct, NULL};
+
+	      fieldval_pair *ans = v_fieldvals.bsearch (&key, cmp_fieldvalue);
+
+	      if (ans)
+		{
+		  n_hits++;
+
+		  if (!types_kinda_same (field_struct->get_type (),
+					 ans->field->get_type ()))
+		    {
+		      add_error(
+			loc,
+			"gcc_jit_context_new_constructor:"
+			"type of struct field differs from type of construct field"
+			" (struct: %s %s)(ctor: %s %s)",
+			field_struct->get_type ()->get_debug_string (),
+			field_struct->get_name ()->c_str (),
+			ans->field->get_type ()->get_debug_string (),
+			ans->field->get_name ()->c_str ());
+		      goto err;
+		    }
+
+		  result->m_values.safe_push (ans->value);
+		  result->m_fields.safe_push (ans->field);
+		}
+	      else
+		{
+		  /* Push null value if not found, to zero the field. */
+		  result->m_values.safe_push (NULL);
+		  result->m_fields.safe_push (field_struct);
+		}
+	    }
+
+	  /* Verify that we found all the fields specified. */
+	  if (n_hits != arr_length)
+	    {
+	      add_error(
+		loc,
+		"gcc_jit_context_new_constructor:"
+		"could not find matching field in struct for"
+		" all fields in constructor");
+	      goto err;	    
+	    }
+	}
+    }
+  else
+    gcc_unreachable();
+
+  record (result);
+  return result;
+
+ err:
+  delete result;
+  return NULL;
+}
+
 /* Create a recording::unary_op instance and add it to this context's
    list of mementos.
 
@@ -4652,11 +4888,13 @@ recording::global::replay_into (replayer *r)
 				 m_initializer_num_bytes
 				 / m_type->dereference ()->get_size (),
 				 m_initializer,
-				 playback_string (m_name))
+				 playback_string (m_name),
+				 flags)
     : r->new_global (playback_location (r, m_loc),
 		     m_kind,
 		     m_type->playback_type (),
-		     playback_string (m_name)));
+		     playback_string (m_name),
+		     flags));
 }
 
 /* Override the default implementation of
@@ -5583,6 +5821,125 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
 	   elements_id);
 }
 
+void
+recording::ctor::visit_children (rvalue_visitor *v)
+{
+  for (unsigned int i = 0; i < m_values.length (); i++)
+    v->visit (m_values[i]);
+}
+
+recording::string *
+recording::ctor::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "ctor");
+}
+
+void
+recording::ctor::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  type *type = get_type();
+
+  r.write ("  gcc_jit_rvalue *%s;\n", id);
+  r.write ("  {\n"); /* Open scope for locals */
+
+  /* Write the array of values */
+  r.write ("    gcc_jit_rvalue *values[] = {\n");
+  for (unsigned i = 0; i < m_values.length (); i++)
+    r.write ("        %s,\n", r.get_identifier (m_values[i]));
+  r.write ("      };\n");
+
+  /* Write the array of fields */
+  if (type->is_array ())
+    r.write ("    gcc_jit_field **fields = NULL;\n");
+  else
+    {
+      r.write ("    gcc_jit_field *fields[] = {\n");
+      for (unsigned i = 0; i < m_fields.length (); i++)
+	r.write ("        %s,\n", r.get_identifier (m_fields[i]));
+      r.write ("      };\n");
+    }
+  r.write (
+"    %s =\n"
+"      gcc_jit_context_new_constructor (%s,\n"
+"                                       %s, /* gcc_jit_location *loc */\n"
+"                                       %s, /* gcc_jit_type *type */\n"
+"                                       %i, /* int arr_length */\n"
+"                                       fields,\n"
+"                                       values);\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (get_type ()),
+	   m_values.length ());
+
+  r.write ("  }\n"); /* Close scope for locals */
+}
+
+void
+recording::ctor::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_values;
+  auto_vec<playback::field *> playback_fields;
+
+  int n = m_values.length();
+
+  type *type = get_type ();
+
+  /* Handle arrays, and return */
+  if (type->is_array ())
+    {
+      playback_values.reserve (n, false);
+
+      for (int i = 0; i < n; i++)
+	{
+	  /* null m_values element indicates zero ctor */
+	  playback_values.quick_push (m_values[i] ?
+				      m_values[i]->playback_rvalue () :
+				      NULL);
+	}
+      set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				     get_type ()->playback_type (),
+				     NULL,
+				     &playback_values));
+      return;
+    }
+  /* Handle unions, and return */
+  else if (type->is_union ())
+    {
+      playback_values.safe_push (m_values[0] ?
+				   m_values[0]->playback_rvalue () :
+				   NULL);
+      playback_fields.safe_push (m_fields[0]->playback_field ());
+
+      set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				     get_type ()->playback_type (),
+				     &playback_fields,
+				     &playback_values));
+
+      return;
+    }
+  /* ... else, handle structs */
+
+  playback_values.reserve (n, false);
+  playback_fields.reserve (n, false);
+
+  for (int i = 0; i < n; i++)
+    {
+      /* null m_values element indicates zero ctor */
+      playback_values.quick_push (m_values[i] ?
+				    m_values[i]->playback_rvalue () :
+				    NULL);
+      playback_fields.quick_push (m_fields[i]->playback_field ());
+    }
+
+  set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				 get_type ()->playback_type (),
+				 &playback_fields,
+				 &playback_values));
+}
+
 /* The implementation of class gcc::jit::recording::unary_op.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -7556,6 +7913,81 @@ recording::top_level_asm::write_reproducer (reproducer &r)
 	   m_asm_stmts->get_debug_string ());
 }
 
+void
+recording::global_init_rvalue::replay_into (replayer *r)
+{
+  r->global_set_init_rvalue (m_variable->playback_lvalue(),
+			       m_init->playback_rvalue());
+}
+
+void
+recording::global_init_rvalue::write_reproducer (reproducer &r)
+{
+  r.write (
+    "  gcc_jit_global_set_initializer_rvalue (%s, /* lvalue *global */\n"
+    "                                         %s);/* rvalue *init */\n",
+    r.get_identifier (m_variable),
+    r.get_identifier_as_rvalue (m_init));
+}
+
+void
+recording::global_init_rvalue::write_to_dump (dump &d)
+{
+  d.write ("%s;\n", get_debug_string ());
+}
+
+recording::string *
+recording::global_init_rvalue::make_debug_string ()
+{
+    return string::from_printf(m_ctxt, "%s = %s",
+      m_variable->get_debug_string (),
+      m_init->get_debug_string ());
+}
+
+/* Strip qualifiers and count pointer depth, returning true
+   if the types' base type and pointer depth are
+   the same, otherwise false.
+
+   Do not call this directly. Call 'types_kinda_same' */
+bool
+types_kinda_same_internal (recording::type *a, recording::type *b)
+{
+  int ptr_depth[2] = {};
+  recording::type *base_types[2];
+  recording::type *types[2] = {a, b};
+
+  /* Strip qualifiers and count pointerness */
+  for (int i = 0; i < 2; i++)
+    {
+      recording::type *t = types[i];
+      while (true)
+	{
+	  if (!t)
+	    return false; /* Should only happen on bad input */
+
+	  recording::type *pointed_to_type = t->is_pointer();
+	  if (pointed_to_type != NULL)
+	    {
+	      ptr_depth[i]++;
+	      t = pointed_to_type;
+	      continue;
+	    }
+
+	  /* unqualified() returns 'this' on base types */
+	  recording::type *next = t->unqualified ();
+	  if (next == t)
+	    {
+	      base_types[i] = t;
+	      break;
+	    }
+	  t = next;
+	}
+    }
+
+  return base_types[0] == base_types[1] &&
+    (ptr_depth[0] == ptr_depth[1]);
+}
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index d5e0c359a48..afd61132e69 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -149,6 +149,17 @@ public:
 	      type *type,
 	      const char *name);
 
+  rvalue *
+  new_ctor (location *loc,
+	    type *type,
+	    int arr_length,
+	    field **fields,
+	    rvalue **values);
+
+  void
+  new_global_init_rvalue (lvalue *variable,
+			  rvalue *init);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
@@ -547,6 +558,8 @@ public:
   virtual bool is_complex () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_array () = 0;
+  virtual bool is_struct () const { return false; }
+  virtual bool is_union () const { return false; }
   virtual bool is_void () const { return false; }
   virtual bool has_known_size () const { return true; }
   /* Used to pair complex float types with real float type
@@ -873,6 +886,7 @@ public:
   {}
 
   type * get_type () const { return m_type; }
+  string * get_name () const { return m_name; }
 
   compound_type * get_container () const { return m_container; }
   void set_container (compound_type *c) { m_container = c; }
@@ -979,6 +993,8 @@ public:
 
   const char *access_as_type (reproducer &r) FINAL OVERRIDE;
 
+  virtual bool is_struct () const FINAL OVERRIDE { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1017,6 +1033,8 @@ public:
 
   void replay_into (replayer *r) FINAL OVERRIDE;
 
+  virtual bool is_union () const FINAL OVERRIDE { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1414,6 +1432,21 @@ public:
     m_initializer_num_bytes = num_bytes;
   }
 
+  void set_flags (int flag_fields)
+  {
+    flags = (enum global_var_flags)(flags | flag_fields);
+  }
+  /* Returns true if any of the flags in the argument is set */
+  bool test_flags_anyof (int flag_fields) const
+  {
+    return flags & flag_fields;
+  }
+
+  enum gcc_jit_global_kind get_kind() const
+  {
+    return m_kind;
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1426,9 +1459,11 @@ private:
 
 private:
   enum gcc_jit_global_kind m_kind;
+  enum global_var_flags flags = GLOBAL_VAR_FLAGS_NONE;
   string *m_name;
   void *m_initializer;
   size_t m_initializer_num_bytes;
+  
 };
 
 template <typename HOST_TYPE>
@@ -1512,6 +1547,32 @@ private:
   auto_vec<rvalue *> m_elements;
 };
 
+class ctor : public rvalue
+{
+public:
+  ctor (context *ctxt,
+	location *loc,
+	type *type)
+  : rvalue (ctxt, loc, type)
+  { }
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_PRIMARY;
+  }
+
+public:
+  auto_vec<field *> m_fields;
+  auto_vec<rvalue *> m_values;
+};
+
 class unary_op : public rvalue
 {
 public:
@@ -2355,6 +2416,24 @@ private:
   string *m_asm_stmts;
 };
 
+class global_init_rvalue : public memento
+{
+public:
+  global_init_rvalue (context *ctxt, lvalue *variable, rvalue *init) :
+    memento(ctxt), m_variable (variable), m_init (init) {};
+
+  void write_to_dump (dump &d) FINAL OVERRIDE;
+
+private:
+  void replay_into (replayer *r) FINAL OVERRIDE;
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+  lvalue *m_variable;
+  rvalue *m_init;
+};
+
 } // namespace gcc::jit::recording
 
 /* Create a recording::memento_of_new_rvalue_from_const instance and add
@@ -2374,6 +2453,19 @@ recording::context::new_rvalue_from_const (recording::type *type,
   return result;
 }
 
+bool
+types_kinda_same_internal (recording::type *a,
+			   recording::type *b);
+
+/* Strip *all* qualifiers and count pointer depth, returning true
+   if the types and pointer depth are the same, otherwise false. */
+static inline bool
+types_kinda_same (recording::type *a, recording::type *b)
+{
+  /* Handle trivial case here, to allow for inlining. */
+  return a == b || types_kinda_same_internal (a, b);
+}
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index b94cdc85c8e..019172854a7 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -206,6 +206,11 @@ namespace gccjit
     rvalue new_rvalue (type vector_type,
 		       std::vector<rvalue> elements) const;
 
+    rvalue new_constructor (type type_,
+			    std::vector<field> &fields,
+			    std::vector<rvalue> &values,
+			    location loc = location ());
+
     /* Generic unary operations...  */
     rvalue new_unary_op (enum gcc_jit_unary_op op,
 			 type result_type,
@@ -509,6 +514,7 @@ namespace gccjit
 
     rvalue get_address (location loc = location ());
     lvalue set_initializer (const void *blob, size_t num_bytes);
+    lvalue set_initializer_rvalue (rvalue init_value);
   };
 
   class param : public lvalue
@@ -1891,6 +1897,44 @@ lvalue::set_initializer (const void *blob, size_t num_bytes)
   return *this;
 }
 
+inline lvalue
+lvalue::set_initializer_rvalue (rvalue init_value)
+{
+  return lvalue (gcc_jit_global_set_initializer_rvalue (
+		   get_inner_lvalue (),
+		   init_value.get_inner_rvalue()));
+}
+
+inline rvalue
+context::new_constructor (type type_,
+			  std::vector<field> &fields,
+			  std::vector<rvalue> &values,
+			  location loc)
+{
+  field *pfields = nullptr;
+  if (fields.size())
+    pfields = &fields[0];
+
+  gcc_jit_field **fields_arr =
+    reinterpret_cast<gcc_jit_field **> (pfields);
+
+  rvalue *pvalues = nullptr;
+  if (values.size())
+    pvalues = &values[0];
+
+  gcc_jit_rvalue **values_arr =
+    reinterpret_cast<gcc_jit_rvalue **> (pvalues);
+
+  return rvalue (
+	   gcc_jit_context_new_constructor (m_inner_ctxt,
+					    loc.get_inner_location (),
+					    type_.get_inner_type(),
+					    (int)values.size(),
+					    fields_arr,
+					    values_arr));
+}
+
+
 // class param : public lvalue
 inline param::param () : lvalue () {}
 inline param::param (gcc_jit_param *inner)
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 97c5aba643e..56f310f398f 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -335,7 +335,7 @@ jit_error (gcc::jit::recording::context *ctxt,
 
    This is implemented by calling the
    gcc::jit::recording::type::accepts_writes_from virtual function on
-   LTYPE.  */
+   LTYPE. For const types accepts_writes_from always returns false. */
 
 static bool
 compatible_types (gcc::jit::recording::type *ltype,
@@ -1130,6 +1130,215 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
   return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   Builds a ctor for arrays, unions and structs.
+
+   The way many entrypoints compare types for sameness is abit
+   broken, since they only strip one qualifier, making eg.
+   'const volatile int' and 'volatile const int' incompatible,
+   or 'const volatile int' and 'int' incompatible. Or
+   'const volatile int' incompatible with it self if the types
+   were built from two different function calls.
+
+   However, for the constructor we need to strip everything. */
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+
+  bool is_union = type->is_union ();
+  bool is_struct = type->is_struct ();
+  bool is_array = type->is_array () != NULL; /* is_array() returns ptr */
+
+  RETURN_NULL_IF_FAIL (is_union || is_struct || is_array,
+		       ctxt, loc,
+		       "constructor type not an union, array or struct");
+
+  if (is_array)
+    fields = NULL; /* fields are ignored for array constructors */
+  if (!arr_length)
+    {
+      /* Ignore fields and values if arr_length is zero */
+      fields = NULL;
+      values = NULL;
+    }
+
+  if (is_union)
+    RETURN_NULL_IF_FAIL (arr_length == 1, ctxt, loc,
+			 "union constructor 'arr_length' not 1");
+
+  if (arr_length)
+    {
+      if (is_struct || is_union)
+	RETURN_NULL_IF_FAIL (
+	  fields && values,
+	  ctxt, loc,
+	  "'fields' and/or 'values' NULL with non-zero 'arr_length'");
+      else if (is_array)
+	{
+	  RETURN_NULL_IF_FAIL (
+	    values,
+	    ctxt, loc,
+	    "'values' NULL with non-zero 'arr_length'");
+
+	  gcc::jit::recording::array_type *arr_type =
+	    reinterpret_cast<gcc::jit::recording::array_type*>(type);
+	  int n_el = arr_type->num_elements ();
+
+	  RETURN_NULL_IF_FAIL (
+	    n_el >= arr_length,
+	    ctxt, loc,
+	    "array constructor has more values than the array type's length");
+	}
+    }
+
+  if (fields && values) /* Union or struct */
+    {
+      for (int i = 0; i < arr_length; i++)
+	{
+	  RETURN_NULL_IF_FAIL_PRINTF1 (
+	    fields[i],
+	    ctxt, loc,
+	    "NULL field in 'fields', at index %d", i);
+
+	  if (values[i])
+	    {
+	      RETURN_NULL_IF_FAIL_PRINTF1 (
+		!values[i]->get_type ()->is_void (),
+		ctxt, loc,
+		"can't construct the void type, at index %d", i);
+	      RETURN_NULL_IF_FAIL_PRINTF3 (
+		gcc::jit::types_kinda_same (values[i]->get_type (),
+					    fields[i]->get_type ()),
+		ctxt, loc,
+		"value and field not the same unqualified type, at index %d"
+		" (field type: %s)(value type: %s)",
+		i,
+		fields[i]->get_type ()->get_debug_string (),
+		values[i]->get_type ()->get_debug_string ());
+	    }
+	}
+    }
+  else if (values) /* Array */
+    {
+      /* For arrays, all values need to be the same type */
+      gcc::jit::recording::type *type0 = NULL;
+      int i = 0;
+      /* Find first non-null value */
+      for (;i < arr_length; i++)
+	{
+	  if (values[i])
+	    break;
+	}
+
+      if (i < arr_length) /* All values might be null */
+       type0 = values[i]->get_type ();
+
+      /* If we got a type0, check that all other values have
+	 the same type */
+      for (; i < arr_length; i++)
+	{
+	  if (values[i])
+	    RETURN_NULL_IF_FAIL_PRINTF3 (
+	      gcc::jit::types_kinda_same (type0,
+					  values[i]->get_type ()),
+	      ctxt, loc,
+	      "value type at index %d differ from first value type"
+	      " (first type: %s)(different type: %s)",
+	      i,
+	      type0->get_debug_string (),
+	      values[i]->get_type ()->get_debug_string ());
+	}
+
+      /* Compare type0 with the element type specified in the
+	 type of the array. */
+      if (type0)
+	{
+	  gcc::jit::recording::type *el_type =
+	    type->is_array ();
+
+	  RETURN_NULL_IF_FAIL_PRINTF2 (
+	    gcc::jit::types_kinda_same (type0, el_type),
+	    ctxt, loc,
+	    "array element value types differ from types in 'values'"
+	    " (element type: %s)('values' type: %s)",
+	    el_type->get_debug_string (),
+	    type0->get_debug_string ());
+	}
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_ctor (
+    loc,
+    type,
+    arr_length,
+    reinterpret_cast<gcc::jit::recording::field**>(fields),
+    reinterpret_cast<gcc::jit::recording::rvalue**>(values));
+}
+
+/* Public entrypoint.  See description in libgccjit.h. */
+
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_rvalue)
+{
+  RETURN_NULL_IF_FAIL (global, NULL, NULL,"NULL global");
+  
+  gcc::jit::recording::context *ctxt = global->get_context ();
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL,"NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (init_rvalue, ctxt, NULL,"NULL init_rvalue");
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (global->is_global (),
+			       ctxt, NULL,
+			       "lvalue \"%s\" not a global",
+			       global->get_debug_string ());
+
+  gcc::jit::recording::global *gbl =
+    reinterpret_cast<gcc::jit::recording::global *> (global);
+  
+  RETURN_NULL_IF_FAIL_PRINTF1 (gbl->get_kind () !=
+			       GCC_JIT_GLOBAL_IMPORTED,
+			       ctxt, NULL,
+			       "can't initialize \"%s\", it is imported",
+			       global->get_debug_string ());
+
+  RETURN_NULL_IF_FAIL_PRINTF4 (gcc::jit::types_kinda_same (
+				 global->get_type (),
+				 init_rvalue->get_type()),
+			       ctxt, NULL,
+			       "mismatching types:"
+			       " initializing %s (type: %s) with %s (type: %s)",
+			       global->get_debug_string (),
+			       global->get_type ()->get_debug_string (),
+			       init_rvalue->get_debug_string (),
+			       init_rvalue->get_type ()->get_debug_string ());
+
+  /* Check that there are no initializers set for the global yet */
+  RETURN_NULL_IF_FAIL_PRINTF1 (!gbl->test_flags_anyof (
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT),
+			       ctxt, NULL,
+			       "global variable allready initialized: %s",
+			       global->get_debug_string ());
+
+  /* The global need to know during playback that it will be
+     initialized. */
+  gbl->set_flags (gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT);
+
+  ctxt->new_global_init_rvalue (global, init_rvalue);
+
+  return global;
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -1163,8 +1372,22 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
     " global \"%s\" has size %zu whereas initializer has size %zu",
     global->get_debug_string (), lvalue_size, num_bytes);
 
-  reinterpret_cast <gcc::jit::recording::global *> (global)
-    ->set_initializer (blob, num_bytes);
+  /* Check that the rvalue initializer is not set for this global.
+     Note that we do not check if this blob type initializer is
+     allready set, since that check was not present when the entrypoint
+     was initially written. */
+  gcc::jit::recording::global *gbl =
+    reinterpret_cast<gcc::jit::recording::global *> (global);
+  RETURN_NULL_IF_FAIL_PRINTF1 (!gbl->test_flags_anyof (
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT),
+			       NULL, NULL,
+			       "global variable allready initialized: %s",
+			       global->get_debug_string ());
+
+  gbl->set_initializer (blob, num_bytes);
+  /* The global need to know during playback that it will be
+     initialized. */  
+  gbl->set_flags (gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
 
   return global;
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index c510c5cc902..2fce399d6ff 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -795,6 +795,83 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
 			    gcc_jit_type *type,
 			    const char *name);
 
+#define LIBGCCJIT_HAVE_CTORS
+
+/* Create a constructor for an array, union or struct as a rvalue.
+
+   Returns NULL on error. The two parameter arrays are copied and
+   do not have to outlive the context.
+
+   'type' specifies what the constructor will build.
+
+   For a struct or union 'type', each field in 'fields' specifies
+   which field in the struct or union type to set to the corresponding
+   value in 'values'. 'fields' and 'values' are paired by index
+   and the pair need to have the same unqualified type.
+
+   For an array 'type', the 'fields' parameter is ignored.
+   
+   'arr_length' specifies the number of elements in 'values'.
+   For struct and unions, 'fields' need to have the same length as
+   'values'.
+
+   For unions, 'arr_length' need to be 1.
+
+   For non-unions, if 'arr_length' is 0, the array parameters will be
+   ignored and zero initialization will be used.
+ 
+   For an array 'type', if the array type itself has more elements than
+   'values', the left-over elements will be zeroed. Each value in
+   'values' need to be the same unqualified type as the array elements.
+
+   For a struct 'type', the fields in 'fields' do not have to be in
+   definition order, but being in order avoids a sort operation. Any
+   field in the struct that is not specified in 'fields' will be zeroed.
+      
+   A NULL value in 'values' is a shorthand for zero initialization
+   of the corresponding field or array element. 
+
+   The constructor rvalue can be used for assignment to locals.
+   It can be used to initialize global variables with
+   'gcc_jit_global_set_initializer_rvalue'. It can also be used as a
+   temporary value for function calls and return values.
+
+   The constructor can contain nested constructors. Note that a string
+   literal rvalue can't be used to construct a char array. It need one
+   rvalue for each char.
+
+   This entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presense using:
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
+*/
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values);
+
+/* Set the initial value of a global with an rvalue.
+
+   The rvalue need to be a constant expression, i.e. no function calls.
+
+   The global can't have the 'kind' GCC_JIT_GLOBAL_IMPORTED.
+   
+   Use together with gcc_jit_context_new_constructor() to
+   initialize structs, unions and arrays.
+
+   On success, returns the 'global' parameter. Otherwise, NULL.
+
+   This entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presence using:
+     #ifdef LIBGCCJIT_HAVE_CTORS
+*/
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_value);
+
 #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
 /* Set an initial value for a global, which must be an array of
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 4022dbb6fbc..c5a1afdeacf 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 {
 
 LIBGCCJIT_ABI_16 {
   global:
+    gcc_jit_context_new_constructor;
     gcc_jit_context_new_rvalue_from_complex_double;
     gcc_jit_context_new_rvalue_from_complex_long_double;
-    gcc_jit_context_set_bool_enable_complex_types;
     gcc_jit_context_new_rvalue_from_long_double;
     gcc_jit_context_new_rvalue_from_long_long;
+    gcc_jit_context_set_bool_enable_complex_types;
+    gcc_jit_global_set_initializer_rvalue;
 } LIBGCCJIT_ABI_15;
\ No newline at end of file
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 8416b312bad..26f45fe0811 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -211,6 +211,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-global-init-rvalue.c */
+#define create_code create_code_global_init_rvalue
+#define verify_code verify_code_global_init_rvalue
+#include "test-global-init-rvalue.c"
+#undef create_code
+#undef verify_code
+
 /* test-global-set-initializer.c */
 #define create_code create_code_global_set_initializer
 #define verify_code verify_code_global_set_initializer
@@ -232,6 +239,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-local-init-rvalue.c */
+#define create_code create_code_local_init_rvalue
+#define verify_code verify_code_local_init_rvalue
+#include "test-local-init-rvalue.c"
+#undef create_code
+#undef verify_code
+
 /* test-long-names.c */
 #define create_code create_code_long_names
 #define verify_code verify_code_long_names
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c b/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
new file mode 100644
index 00000000000..6f0b9806285
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
@@ -0,0 +1,86 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an struct type, but have too many fields.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields_b));
+  
+  gcc_jit_field *b11 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "a");
+  gcc_jit_field *b22 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "b");
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+  gcc_jit_field *b44 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+
+  gcc_jit_field *fields_ctor[] = {b11, b22, b33, b44};
+  gcc_jit_rvalue *values[] = {0,0,0,0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     4,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: more fields in "
+		      "constructor than in the target struct");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: more fields in "
+		      "constructor than in the target struct");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
new file mode 100644
index 00000000000..f269ccad488
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
@@ -0,0 +1,81 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an struct type, but has the name wrong on a field.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields_b));
+  
+  gcc_jit_field *b11 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "a");
+  gcc_jit_field *b22 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "bb"); /* wrong */
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+  gcc_jit_field *fields_ctor[] = {b11, b22, b33};
+  gcc_jit_rvalue *values[] = {0,0,0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     3,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: could not find "
+		      "matching field in struct for all fields in constructor");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: could not find "
+		      "matching field in struct for all fields in constructor");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
new file mode 100644
index 00000000000..3effa0bfd8b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
@@ -0,0 +1,85 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an struct type, but has the type wrong on a field.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields_b));
+  
+  gcc_jit_field *b11 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "a");
+  gcc_jit_field *b22 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  float_type, /* wrong */
+						  "b");
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+  gcc_jit_field *fields_ctor[] = {b11, b22, b33};
+  gcc_jit_rvalue *values[] = {0,0,0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     3,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: type of struct "
+		      "field differs from type of construct field "
+		      "(struct: int b)(ctor: float b)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: type of struct "
+		      "field differs from type of construct field "
+		      "(struct: int b)(ctor: float b)");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c b/gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
new file mode 100644
index 00000000000..f5b76095f69
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
@@ -0,0 +1,80 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an union type, but don't provide a correct field.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 float_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 double_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *union_bar_type =
+      gcc_jit_context_new_union_type (ctxt,
+				      0,
+				      "bar",
+				      3,
+				      fields_b);
+  
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  double_type,
+						  "cc"); /* wrong */
+
+
+  gcc_jit_field *fields_ctor[] = {b33};
+  gcc_jit_rvalue *values[] = {0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     union_bar_type,
+     1,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: constructor field "
+		      "does not exist in the union type (field: double cc)"
+		      "(type: union bar)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: constructor field "
+		      "does not exist in the union type (field: double cc)"
+		      "(type: union bar)");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-allready-init.c b/gcc/testsuite/jit.dg/test-error-global-allready-init.c
new file mode 100644
index 00000000000..7eaf182029d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-allready-init.c
@@ -0,0 +1,46 @@
+/*
+
+  Test that we can't set the initializer on a global twice.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+    ctxt, NULL,
+    GCC_JIT_GLOBAL_EXPORTED,
+    int_type,
+    "global_lvalueinit_int_0");
+
+  gcc_jit_global_set_initializer_rvalue (
+    bar,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1));
+  gcc_jit_global_set_initializer_rvalue (
+    bar,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_global_set_initializer_rvalue: global variable "
+		      "allready initialized: global_lvalueinit_int_0");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_global_set_initializer_rvalue: global variable "
+		      "allready initialized: global_lvalueinit_int_0");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-common-section.c b/gcc/testsuite/jit.dg/test-error-global-common-section.c
new file mode 100644
index 00000000000..000f59489a2
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-common-section.c
@@ -0,0 +1,54 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with a global that has no DECL_INITIAL (and is marked
+  DECL_COMMON(NODE) = 1).
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+
+  /* const int foo;
+     int bar = foo;
+   */
+  gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+    ctxt, NULL,
+    GCC_JIT_GLOBAL_EXPORTED,
+    gcc_jit_type_get_const (int_type),
+    "global_const_int_0");
+  gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+    ctxt, NULL,
+    GCC_JIT_GLOBAL_EXPORTED,
+    int_type,
+    "global_lvalueinit_int_0"); 
+  gcc_jit_global_set_initializer_rvalue (bar,
+					 gcc_jit_lvalue_as_rvalue (foo));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "can't initialize global_lvalueinit_int_0 "
+		      "with global_const_int_0 since it has no "
+		      "initial value set");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "can't initialize global_lvalueinit_int_0 "
+		      "with global_const_int_0 since it has no "
+		      "initial value set");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
new file mode 100644
index 00000000000..137bae6c6b5
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
@@ -0,0 +1,64 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with another non-const global's rvalue.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{ /* float foo[1] = {1,2}; */
+
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							   0,
+							   float_type,
+							   1);
+  gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+    ctxt, float_type, 1);
+  gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+    ctxt, float_type, 2);
+
+  gcc_jit_rvalue *values[] = {rval_1, rval_2};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							  0,
+							  arr_type,
+							  2,
+							  0,
+							  values);
+  if (!ctor)
+    return;
+  
+  gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+    ctxt, NULL,
+    GCC_JIT_GLOBAL_EXPORTED,
+    arr_type,
+    "global_floatarr_12");
+  gcc_jit_global_set_initializer_rvalue (foo, ctor);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: array constructor has"
+		      " more values than the array type's length");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: array constructor has"
+		      " more values than the array type's length");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c b/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
new file mode 100644
index 00000000000..c6e1f0ea4fe
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
@@ -0,0 +1,60 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with another non-const global's rvalue.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+
+  gcc_jit_lvalue *foo;
+  { /* int bar; */
+    foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int1");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* int foo = bar; */
+	     
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int2"); 
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_lvalueinit_int2 does not seem to be constant");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_lvalueinit_int2 does not seem to be constant");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c b/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
new file mode 100644
index 00000000000..d04db8ba8ab
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
@@ -0,0 +1,80 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with a function call.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  
+  gcc_jit_function *fn_int_3; 
+  { /* int foo () { int local = 3; return local;} */
+    fn_int_3 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_int_3",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn_int_3, "start");
+    gcc_jit_lvalue *local = gcc_jit_function_new_local (fn_int_3,
+							0,
+							int_type,
+							"local");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+
+    gcc_jit_block_add_assignment (block, 0, local, rval);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+							  
+  }
+
+  { /* int bar = foo(); */
+    gcc_jit_rvalue *rval =
+      gcc_jit_context_new_call (ctxt,
+			        0,
+				fn_int_3,
+				0,0);
+						     
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_nonconst_int"); 
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_nonconst_int does not seem to be constant");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_nonconst_int does not seem to be constant");
+}
diff --git a/gcc/testsuite/jit.dg/test-global-init-rvalue.c b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
new file mode 100644
index 00000000000..dd7c4277c68
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
@@ -0,0 +1,1394 @@
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+/* This testcase checks that gcc_jit_global_set_initializer_rvalue() works
+   with rvalues, especially with gcc_jit_context_new_constructor() for
+   struct, unions and arrays. */
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *short_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SHORT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_BOOL);
+  gcc_jit_type *char_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *cpchar_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *size_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SIZE_T);
+
+  /* Make a struct: struct fi { float f; int i;} */
+  gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 float_type,
+						 "f");
+  gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "i");
+  gcc_jit_field *fields[] = {f1, f2};
+
+  gcc_jit_type *struct_fi_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "fi",
+				       2,
+				       fields));
+
+  /* Make a struct:
+
+     struct bar {
+       int ii;
+       struct fi fi;
+       float ff;
+     }
+  */
+  f1 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  float_type,
+				  "ff");
+  f2 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  int_type,
+				  "ii");
+  gcc_jit_field *fi = gcc_jit_context_new_field (ctxt,
+						 0,
+						 struct_fi_type,
+						 "fi");
+  gcc_jit_field *fields2[] = {f1, fi, f2};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields2));
+
+  /* Make an union:
+
+     union ubar {
+       float ff;
+       int ii;
+     };
+  */
+  f1 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  float_type,
+				  "ff");
+  f2 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  int_type,
+				  "ii");
+  gcc_jit_field *fields3[] = {f1, f2};
+  
+  gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt,
+						       0,
+						       "ubar",
+						       2,
+						       fields3);
+  
+  { /* struct bar bar = {.ii = 4, .ff = 1, .fi = {.i = 3, .f = 2}};
+       I.e. nested struct and nested ctors in "wrong" order.
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_1");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");   
+    
+    gcc_jit_rvalue *vals[] = { ival, fval};
+    gcc_jit_field *fields[] = {fi_i, fi_f};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+
+    gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						       0,
+						       struct_fi_type,
+						       "fi");
+    gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt,
+						       0,
+						       float_type,
+						       "ff");
+    gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt,
+						       0,
+						       int_type,
+						       "ii");
+    
+    gcc_jit_rvalue *vals2[] = {ival, fval, ctor};
+    gcc_jit_field *fields2[] = {bar_ii, bar_ff, bar_fi};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       fields2,
+       vals2);
+    
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+  { /* struct bar bar = {1, {2, 3}, 4};
+       I.e. nested struct and nested ctors in "right" order.
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_2");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");   
+    
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+
+    gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						       0,
+						       struct_fi_type,
+						       "fi");
+    gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt,
+						       0,
+						       float_type,
+						       "ff");
+    gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt,
+						       0,
+						       int_type,
+						       "ii");
+    
+    gcc_jit_rvalue *vals2[] = {fval, ctor, ival};
+    gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       fields2,
+       vals2);
+    
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+  { /* struct fi foo = {2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_1");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {f1, f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i = 3, .f = 2};
+
+       I.e. "wrong" order of fields.  */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_2");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { ival, fval};
+    gcc_jit_field *fields[] = {f2, f1};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {0, 0}; (null init) */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_4");
+
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { 0, 0};
+    gcc_jit_field *fields[] = {f1, f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i = 0};
+
+       I.e. "wrong" order of fields.
+       Null init values. */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_5");
+
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = {0};
+    gcc_jit_field *fields[] = {f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       1,
+       fields,
+       vals);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {}; (null init)
+
+       Null fields and values. */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_6");
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       0,
+       0,
+       0);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {2 * 2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_3");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *fval2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      float_type,
+      fval,
+      fval2);
+    
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");    
+    
+    gcc_jit_rvalue *vals[] = { rval_mul, ival};
+    gcc_jit_field *fields[] = {f1, f2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* union ubar foo = {.ff = 3}; */
+     gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      ubar,
+      "global_union_ufoo_ff3");
+     
+     gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						    0,
+						    float_type,
+						    "ff");
+     gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+       ctxt, float_type, 3);
+     
+     gcc_jit_rvalue *vals[] = {fval};
+     gcc_jit_field *fields[] = {f1};
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (
+       ctxt,
+       0,
+       ubar,
+       1,
+       fields,
+       vals);
+     
+     gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int foo = 3; */
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3); 
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int1_3"); 
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* Try the above, but with opposite order of global and literal calls */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int2_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* int foo = 3 * (3 + 3) */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int3_18");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      rval_plus,
+      rval3_2);
+    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_mul);
+  }
+  { /* int foo = 3; int *pfoo = &foo; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int4_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint5");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (foo, 0));
+  }
+  { /* int foo = 3; int *pfoo = &foo + 1; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int6_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint7");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (
+	gcc_jit_context_new_array_access(
+	  ctxt,
+	  0,
+	  gcc_jit_lvalue_get_address(foo, 0),
+	  gcc_jit_context_one(ctxt, int_type)),
+	0));
+  }
+  { /* double foo = 3; */
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double1_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval);
+  }
+  { /* double foo = 3 * 3 + 3 */
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double2_12");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      double_type,
+      rval,
+      rval);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      double_type,
+      rval_mul,
+      rval);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval_plus);
+  }
+  { /* bool foo = 3 + 3 <= 6; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      bool_type,
+      "global_bool1_1");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 6);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt,
+      0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_le = gcc_jit_context_new_comparison (ctxt,
+      0,
+      GCC_JIT_COMPARISON_LE,
+      rval_plus,
+      rval6);
+    
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_le);
+  }
+  gcc_jit_lvalue *global_intarr_1234;
+  { /* int foo[] = {1,2,3,4}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_4 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, rval_3, rval_4};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    values);
+    global_intarr_1234 = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_intarr_1234");
+    gcc_jit_global_set_initializer_rvalue (global_intarr_1234, ctor);
+  }
+  { /* float foo[4] = {1,2}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_12");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {1,2,0}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, 0};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_120");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    0,
+							    0,
+							    0);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_0000");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {NULL , NULL, 3, NULL}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     8);
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 3);
+    gcc_jit_rvalue *rval5 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 5);
+    gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 6);
+
+    gcc_jit_rvalue *values[] = {0, 0, rval3, 0, rval5, rval6, 0 };
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    7,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_00305600");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int *foo[4] = {0, &global_intarr_1234[1]}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     pint_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_lvalue *arr_access = gcc_jit_context_new_array_access (
+      ctxt,
+      0,
+      gcc_jit_lvalue_as_rvalue (global_intarr_1234),
+      rval_1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_lvalue_get_address (arr_access, 0);
+
+    gcc_jit_rvalue *values[] = {0, rval_2};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_pintarr_x2xx");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* char foo[4] = {'q','w','e',0}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     char_type,
+							     4);
+
+
+    gcc_jit_rvalue *rvals[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'q'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'w'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'e'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 0)     
+    };
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    rvals);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_chararr_qwe");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int foo[2][2] = {{1,2},{3,4}}; */
+
+    gcc_jit_type *row_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     2);
+    
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     row_type,
+							     2);
+    gcc_jit_rvalue *rvals_row0[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 1),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 2)
+    };
+    gcc_jit_rvalue *rvals_row1[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 3),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 4)
+    };
+
+    gcc_jit_rvalue *ctor_row0 =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       row_type,
+				       2,
+				       0,
+				       rvals_row0);
+    gcc_jit_rvalue *ctor_row1 =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       row_type,
+				       2,
+				       0,
+				       rvals_row1);
+    gcc_jit_rvalue *ctors_row[] = {ctor_row0, ctor_row1};
+    
+    gcc_jit_rvalue *ctor_arr =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       arr_type,
+				       2,
+				       0,
+				       ctors_row);
+    
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_int2x2matrix_1234");
+    
+    gcc_jit_global_set_initializer_rvalue (foo, ctor_arr);
+  }  
+  { /* const char *foo[4] = {"qwe", "asd"}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     cpchar_type,
+							     4);
+
+
+    gcc_jit_rvalue *rvals[] = {
+      gcc_jit_context_new_string_literal (ctxt, "qwe"),
+      gcc_jit_context_new_string_literal (ctxt, "asd")
+    };
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    rvals);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_cpchararr_qwe_asd");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* const int foo = 3;
+       int bar = foo;
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_3");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int_3"); 
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+  { /* int foo = 3 * 2;
+       int arr[] = {1,2,3,4};
+       int *bar = &arr[2] + 1
+
+       Example in the docs.
+     */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_4 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, rval_3, rval_4};
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    values);
+    gcc_jit_lvalue *global_intarr_1234 =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  arr_type,
+				  "global_intarr_1234_2");
+    
+    gcc_jit_global_set_initializer_rvalue (global_intarr_1234, ctor);
+
+    gcc_jit_lvalue *bar =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  int_type,
+				  "global_int_6");
+    gcc_jit_global_set_initializer_rvalue
+      (bar,
+       gcc_jit_context_new_binary_op
+	 (ctxt, 0, GCC_JIT_BINARY_OP_MULT,
+	  int_type,
+	  gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 3),
+	  gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2)));
+    
+    gcc_jit_lvalue *pfoo =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  gcc_jit_type_get_pointer (int_type),
+				  "global_pint_4");
+    /* int *bar = &arr[2] + 1;
+
+       In practice we could just do &foo[3]
+       but just prove folding this works. */
+    gcc_jit_global_set_initializer_rvalue (
+       pfoo,
+       gcc_jit_lvalue_get_address (
+         gcc_jit_context_new_array_access (
+           ctxt, 0, 
+           gcc_jit_lvalue_get_address (
+	     gcc_jit_context_new_array_access (
+	       ctxt, 0,
+	       gcc_jit_lvalue_as_rvalue (global_intarr_1234),
+	       gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2)),
+	       0),
+	   gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)),
+	   0));
+  }
+  { /*  static int bar = 11;
+        int foo () { return bar; } */
+    
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_static_int_11");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 11);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_int_11",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(bar));
+							  
+  }
+  { /* static const int cbar = 11;
+       int cfoo () { return cbar; } */
+
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_static_cint_11");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 11);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_cint_11",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(bar));
+  }
+  { /* static const int cbar = 12;
+       const int* cfoo () { return &cbar; } */
+
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_static_cint_12");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 12);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    gcc_jit_type_get_pointer(int_type),
+				    "fn_cint_12",
+				    0,
+				    0,
+				    0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_get_address (bar, 0));
+  }
+  { /* const int foo = 3;
+       short bar = (short)foo;
+
+       Assure casts fold
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_4");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      short_type,
+      "global_lvalueinit_short_3"); 
+    gcc_jit_global_set_initializer_rvalue (
+      bar,
+      gcc_jit_context_new_cast( ctxt, 0,
+				gcc_jit_lvalue_as_rvalue (foo),
+				short_type));
+  }
+  { /* const int foo = 3;
+       const int const *bar = &foo; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_6");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (
+        gcc_jit_type_get_pointer (
+          gcc_jit_type_get_const (
+	    int_type))),
+      "global_lvalueinit_cpcint_3"); 
+    gcc_jit_global_set_initializer_rvalue (
+      bar,
+      gcc_jit_lvalue_get_address (foo, 0));
+  }
+  { /* const int __attribute__ ((aligned (64))) foo = 3;
+       int bar = foo;
+
+       Assure alignement does not make the constant "miss"
+       or something strange.
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (gcc_jit_type_get_aligned (int_type, 64)),
+      "global_const_int_7");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int_4"); 
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+  {
+    /* union upintsize { size_t s; int *p } u = {.s = 0x0EEFBEEF}; */
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   size_type,
+						   "s");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   pint_type,
+						   "p");
+    gcc_jit_field *fields1[] = {f1, f2};
+  
+    gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt,
+							 0,
+							 "upintsize",
+							 2,
+							 fields1);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (ubar),
+      "global_const_upintsize_1");
+
+    
+    gcc_jit_field *ff = gcc_jit_context_new_field (ctxt,
+						   0,
+						   size_type,
+						   "s");
+    gcc_jit_rvalue *val = gcc_jit_context_new_rvalue_from_long_long (
+      ctxt, size_type, 0xBAAAABBEEEEFBEEF);
+     
+    gcc_jit_rvalue *vals[] = {val};
+    gcc_jit_field *fields2[] = {ff};
+
+    gcc_jit_rvalue *ctor =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       ubar,
+				       1,
+				       fields2,
+				       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+}
+
+struct fi {
+  float f;
+  int i;
+};
+
+struct bar1 {
+  float ff;
+  struct fi fi;
+  int ii;
+};
+
+union ubar1 {
+  float ff;
+  int ii;
+};
+
+union upintsize {
+  size_t s;
+  int *p;
+};
+
+int test_aligned64_works_in_linker_1 __attribute__ ((aligned (64))) = 0;
+int test_aligned64_works_in_linker_2 __attribute__ ((aligned (64))) = 0;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+  gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, "a.out");
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_1");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_2");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_3");
+
+    CHECK_VALUE (fi->f, 2 * 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_4");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_5");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_6");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }  
+  {
+    struct bar1 *bar = gcc_jit_result_get_global (result, "global_struct_bar_1");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->ii, 4);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+
+    bar = gcc_jit_result_get_global (result, "global_struct_bar_2");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->ii, 4);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						 "global_union_ufoo_ff3");
+    CHECK_VALUE (foo->ff, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int2_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int3_18");
+
+    CHECK_VALUE (*foo, 18);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int4_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint5");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo, *pfoo);
+    CHECK_VALUE (**pfoo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int6_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint7");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo + 1, *pfoo);
+    CHECK_VALUE (*(*pfoo - 1), 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_lvalueinit_int_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double2_12");
+
+    CHECK_VALUE (*foo, 12);
+  }
+  {
+    _Bool *foo = gcc_jit_result_get_global (result, "global_bool1_1");
+
+    CHECK_VALUE (*foo, 1);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_intarr_1234");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 3);
+    CHECK_VALUE (foo[3], 4);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_12");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_120");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_0000");
+
+    CHECK_VALUE (foo[0], 0);
+    CHECK_VALUE (foo[1], 0);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_00305600");
+
+    float key[] = {0,0,3,0,5,6,0,0};
+
+    CHECK_VALUE (memcmp (foo, key, sizeof key), 0);
+  }    
+  {
+    int **foo = gcc_jit_result_get_global (result, "global_pintarr_x2xx");
+
+    CHECK_VALUE (foo[0], 0);
+    CHECK_VALUE (*foo[1], 2);
+  }
+  {
+    char *foo = gcc_jit_result_get_global (result, "global_chararr_qwe");
+    const char *key = "qwe";
+    CHECK_VALUE (strcmp (foo, key), 0);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int2x2matrix_1234");
+
+    for (int i = 0; i < 4; i++)
+      CHECK_VALUE (foo[i], i + 1);
+  }
+  {
+    const char **foo =
+      gcc_jit_result_get_global (result, "global_cpchararr_qwe_asd");
+
+    CHECK_VALUE (strcmp (foo[0], "qwe"), 0);
+    CHECK_VALUE (strcmp (foo[1], "asd"), 0);    
+  }
+  {
+    int **pint =
+      gcc_jit_result_get_global (result, "global_pint_4");
+    int *foo =
+      gcc_jit_result_get_global (result, "global_int_6");    
+    CHECK_VALUE (**pint, 4);
+    CHECK_VALUE (*foo, 6);    
+  }
+  {
+    int (*fn)(void) = gcc_jit_result_get_code (result, "fn_int_11");
+    CHECK_VALUE (fn (), 11);
+  }
+  {
+    int (*fn)(void) = gcc_jit_result_get_code (result, "fn_cint_11");
+    CHECK_VALUE (fn (), 11);
+  }
+  {
+    short *foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_short_3");
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int **foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_cpcint_3");
+    CHECK_VALUE (**foo, 3);
+  }
+  {
+    int *foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_int_4");
+    CHECK_VALUE (*foo, 4);
+
+    int *bar =
+      gcc_jit_result_get_code (result, "global_const_int_7");
+    CHECK_VALUE (*bar, 4);
+    /* The linker does not have to support up to 64 alignment, so test that
+       it does before testing that it works in libgccjit. */
+    if ((size_t) &test_aligned64_works_in_linker_1 % 64 == 0 &&
+	(size_t) &test_aligned64_works_in_linker_2 % 64 == 0)
+      CHECK_VALUE ((size_t) bar % 64, 0); /* __attribute__ ((aligned (64))) */
+  }
+  {
+    union upintsize *foo =
+      gcc_jit_result_get_code (result, "global_const_upintsize_1");
+    CHECK_VALUE (foo->p, (void*)0xBAAAABBEEEEFBEEF);
+  }  
+}
diff --git a/gcc/testsuite/jit.dg/test-local-init-rvalue.c b/gcc/testsuite/jit.dg/test-local-init-rvalue.c
new file mode 100644
index 00000000000..7ca26e9034f
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-local-init-rvalue.c
@@ -0,0 +1,576 @@
+
+
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* This testcase checks that gcc_jit_context_new_constructor() works
+   with locals. Tests that constructors can be used as return
+   values or function call values. Test that constructors can have side
+   effects and be assigned to locals.
+ */
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_BOOL);
+  gcc_jit_type *size_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *voidptr_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_VOID_PTR);  
+
+  /* Make a struct: struct fi { float f; int i;} */
+  gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 float_type,
+						 "f");
+  gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "i");
+  gcc_jit_field *fields[] = {f1, f2};
+
+  gcc_jit_type *struct_fi_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "fi",
+				       2,
+				       fields));
+
+  /* Make a struct:
+
+     struct bar {
+       int ii;
+       int arr[50];
+       float ff;
+     }
+  */
+  f1 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  float_type,
+				  "ff");
+  f2 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  int_type,
+				  "ii");
+  gcc_jit_type *int50arr_type =
+    gcc_jit_context_new_array_type (ctxt,
+				    0,
+				    int_type,
+				    50);
+  gcc_jit_field *fi = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int50arr_type,
+						 "arr");
+  gcc_jit_field *fields2[] = {f1, fi, f2};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields2));
+
+  /* Make an union:
+
+     union ubar {
+       float ff;
+       int ii;
+     };
+  */
+  f1 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  float_type,
+				  "ff");
+  f2 = gcc_jit_context_new_field (ctxt,
+				  0,
+				  int_type,
+				  "ii");
+  gcc_jit_field *fields3[] = {f1, f2};
+  
+  gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt,
+						       0,
+						       "ubar",
+						       2,
+						       fields3);
+  
+  (void) ubar;
+  (void) struct_bar_type;
+  (void) struct_fi_type;
+  (void) bool_type;
+  (void) double_type;
+  (void) pint_type;
+  (void) voidptr_type;
+  (void) size_type;
+
+  gcc_jit_function *fn_int_3; 
+  { /* int foo () { int local = 3; return local;} */
+    fn_int_3 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_int_3",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn_int_3, "start");
+    gcc_jit_lvalue *local = gcc_jit_function_new_local (fn_int_3,
+							0,
+							int_type,
+							"local");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+
+    gcc_jit_block_add_assignment (block, 0, local, rval);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+							  
+  }
+  { /* struct fi foo() { return (struct fi){1,2};} */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_fi_type,
+				    "fn_fi_1_2",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+    gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+
+    gcc_jit_field *f_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");
+
+    gcc_jit_rvalue *vals[] = { rval_f1, rval_i2};
+    gcc_jit_field *fields[] = {f_f, f_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   ctor);
+  }
+  { /* struct fi foo() { struct fi local = {1,2};
+                         local = (struct fi){5,6};
+                         return local;} */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_fi_type,
+				    "fn_fi_5_6",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local = gcc_jit_function_new_local (fn,
+							0,
+							struct_fi_type,
+							"local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    {
+      gcc_jit_rvalue *rval_f1 =
+	gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 1);
+      gcc_jit_rvalue *rval_i2 =
+	gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2);
+
+      gcc_jit_field *f_f = gcc_jit_context_new_field (ctxt,
+						      0,
+						      float_type,
+						      "f");
+      gcc_jit_field *f_i = gcc_jit_context_new_field (ctxt,
+						      0,
+						      int_type,
+						      "i");
+
+      gcc_jit_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {f_f, f_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 struct_fi_type,
+	 2,
+	 fields,
+	 vals);
+      gcc_jit_block_add_assignment (block, 0, local, ctor);
+    }
+    {
+      gcc_jit_rvalue *rval_f1 =
+	gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 5);
+      gcc_jit_rvalue *rval_i2 =
+	gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 6);
+
+      gcc_jit_field *f_f = gcc_jit_context_new_field (ctxt,
+						      0,
+						      float_type,
+						      "f");
+      gcc_jit_field *f_i = gcc_jit_context_new_field (ctxt,
+						      0,
+						      int_type,
+						      "i");
+
+      gcc_jit_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {f_f, f_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 struct_fi_type,
+	 2,
+	 fields,
+	 vals);
+      gcc_jit_block_add_assignment (block, 0, local, ctor);
+    }
+    
+    
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+  { /* struct fi foo() { struct fi local = {1, fn_int_3()};
+                         return local;}
+
+       The ctor has a side effect (funccall) */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_fi_type,
+				    "fn_fi_1_3",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local = gcc_jit_function_new_local (fn,
+							0,
+							struct_fi_type,
+							"local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    {
+      gcc_jit_rvalue *rval_f1 =
+	gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 1);
+      gcc_jit_rvalue *rval_i2 =
+	gcc_jit_context_new_call (ctxt, 0, fn_int_3, 0, 0);
+
+      gcc_jit_field *f_f = gcc_jit_context_new_field (ctxt,
+						      0,
+						      float_type,
+						      "f");
+      gcc_jit_field *f_i = gcc_jit_context_new_field (ctxt,
+						      0,
+						      int_type,
+						      "i");
+
+      gcc_jit_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {f_f, f_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 struct_fi_type,
+	 2,
+	 fields,
+	 vals);
+      gcc_jit_block_add_assignment (block, 0, local, ctor);
+    }
+    
+    
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }   
+  { /* struct fi foo(fi) { return fi;}
+       struct fi bar() { return foo((struct fi){3, 4}); } 
+     */
+
+    gcc_jit_param *fi_param =
+      gcc_jit_context_new_param (ctxt, 0, struct_fi_type, "fi");
+    
+    gcc_jit_function *fn0 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_fi_type,
+				    "fn_fi_x_x",
+				    1,
+				    &fi_param,
+				    0);
+    gcc_jit_block *block0 = gcc_jit_function_new_block (fn0, "start");
+    gcc_jit_block_end_with_return (block0,
+				   0,
+				   gcc_jit_param_as_rvalue (
+	                             gcc_jit_function_get_param (fn0, 0)));
+
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_fi_type,
+				    "fn_fi_3_4",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 3);
+    gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+
+    gcc_jit_field *f_f = gcc_jit_context_new_field (ctxt,
+						   0,
+						   float_type,
+						   "f");
+    gcc_jit_field *f_i = gcc_jit_context_new_field (ctxt,
+						   0,
+						   int_type,
+						   "i");
+
+    gcc_jit_rvalue *vals[] = { rval_f1, rval_i2};
+    gcc_jit_field *fields[] = {f_f, f_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_rvalue *call = gcc_jit_context_new_call (ctxt, 0, fn0, 1, &ctor);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   call);
+  }
+  { /* struct bar foo() { struct bar local = {};
+                          return local;}
+     */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_bar_type,
+				    "fn_bar_0s",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (fn,
+				  0,
+				  struct_bar_type,
+				  "local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 struct_bar_type,
+	 0,
+	 0,
+	 0);
+    gcc_jit_block_add_assignment (block, 0, local, ctor);
+   
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+  { /* struct bar foo() { struct bar local;
+                          local.arr = (int [50]){1,2,3,4,5,6};
+                          return local;}
+     */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_bar_type,
+				    "fn_bar_123s",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (fn,
+				  0,
+				  struct_bar_type,
+				  "local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *values[6];
+
+    for (int i = 0; i < 6; i++)
+      values[i] = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, i + 1);
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 int50arr_type,
+	 6,
+	 0,
+	 values);
+
+    gcc_jit_lvalue *arr_lv = gcc_jit_lvalue_access_field (local,
+							  0,
+							  fi);
+    gcc_jit_block_add_assignment (block, 0, arr_lv, ctor);
+							  
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+  { /* int[50] foo() { int arr[50];
+                       arr = (int [50]){1,2,3,4,5,6};
+                       return arr;}
+
+       N.B: Not a typo, returning an array. 
+     */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int50arr_type,
+				    "fn_int50arr_123s",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (fn,
+				  0,
+				  int50arr_type,
+				  "local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *values[6];
+
+    for (int i = 0; i < 6; i++)
+      values[i] = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, i + 1);
+    
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 int50arr_type,
+	 6,
+	 0,
+	 values);
+
+    gcc_jit_block_add_assignment (block, 0, local, ctor);
+							  
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+}
+
+struct fi2 {
+  float f;
+  int i;
+};
+
+struct bar2 {
+  float ff;
+  int arr[50];
+  int ii;
+};
+
+union ubar2 {
+  float ff;
+  int ii;
+};
+
+struct int50arr {
+  int arr[50];
+};
+
+void
+scramble_stack(void)
+  {
+    char *p = alloca(100);
+    for (int i = 0; i < 100; i++)
+      *p++ = 0xF0;
+    asm(""); /* Don't touch my code, optimizers. */
+  }
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_2");
+    scramble_stack();
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 1);
+    CHECK_VALUE (fi.i, 2);
+  }
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_5_6");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 5);
+    CHECK_VALUE (fi.i, 6);
+  }
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_3");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 1);
+    CHECK_VALUE (fi.i, 3);
+  }  
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_3_4");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 3);
+    CHECK_VALUE (fi.i, 4);
+  }
+  {
+    scramble_stack();
+    struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_0s");
+    struct bar2 bar = fn();
+    struct bar2 key = {};
+
+    CHECK_VALUE (bar.ff, 0);
+    CHECK_VALUE (bar.ii, 0);
+    CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0);
+  }
+  {
+    scramble_stack();
+    struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_123s");
+    struct bar2 bar = fn();
+    struct bar2 key = {.arr = {1,2,3,4,5,6} };
+
+    CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0);
+  }
+  {
+    scramble_stack();
+    /* This is abit shady. Lets just pretend that array returns à la Fortran
+       is the same thing as returning a struct with an array in it in C. */
+    struct int50arr (*fn) (void) =
+      gcc_jit_result_get_code (result, "fn_int50arr_123s");
+    struct int50arr ans = fn();
+    int key[50] = {1,2,3,4,5,6};
+
+    CHECK_VALUE (memcmp (ans.arr, key, sizeof (key)), 0);
+  }
+}
-- 
2.30.2


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

end of thread, other threads:[~2021-10-21 13:27 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-06  8:23 [RFC] Setting data segment and loong constants - WIP Petter Tomner
2021-10-06  8:40 ` Basile Starynkevitch
2021-10-21 13:27 ` SV: " Petter Tomner

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