public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] jit: Add support for global rvalue initialization and ctors
@ 2021-11-29 20:03 Petter Tomner
  2021-11-30 17:09 ` SV: " Petter Tomner
  2021-12-10 18:49 ` Marc Nieper-Wißkirchen
  0 siblings, 2 replies; 7+ messages in thread
From: Petter Tomner @ 2021-11-29 20:03 UTC (permalink / raw)
  To: gcc-patches, jit

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

Hi!

I have wrapped up the patch than adds support for initialization of global variables 
with rvalues aswell as rvalue constructors for structs, arrays and unions.

New entrypoints are:

gcc_jit_global_set_initializer_rvalue

Which sets the initial value of a global to a rvalue.

And:

gcc_jit_context_new_array_constructor
gcc_jit_context_new_struct_constructor
gcc_jit_context_new_union_constructor

Those three makes a constructor with a rvalue that e.g. can be assigned to a local or returned
from a function, or most importantly used to set the initial value of global variables 
with gcc_jit_global_set_initializer_rvalue.

If no fields are specified for a struct or union to the constructors, definition order is assumed.

There can be gaps in the fields specified to the struct constructor, but they need to be in order.

For pointer arithmetic to work with setting DECL_INITIAL, alot of folding is added.

make check-jit runs fine on gnu-linux-x64 Debian.

Regards,

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-suport-for-global-rvalue-initialization-and-cons.patch --]
[-- Type: text/x-patch; name="0001-Add-suport-for-global-rvalue-initialization-and-cons.patch", Size: 151745 bytes --]

From 377a4f7c074b6fcea83d1c7a97f94245c39948a0 Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Mon, 29 Nov 2021 20:27:28 +0100
Subject: [PATCH] Add suport for global rvalue initialization and constructors

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.

Signed-off-by:
2021-11-29	Petter Tomner	<tomner@kth.se>

gcc/jit/
	* jit-playback.c : Folding and setting intitial
	(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 :
	(global_set_init_rvalue) : New
	(new_ctor) : New
	* jit-recording.c : New classes
	* jit-recording.h :
	(new_global_init_rvalue) : New
	(new_ctor) : New
	(ctor) : New, inherits rvalue
	(global_init_rvalue) : New, inherits memento
	(type::is_union) : New
	* libgccjit++.h : New entrypoints, see C-header
	* libgccjit.c : See .h
	* libgccjit.h : New entrypoints
	(gcc_jit_context_new_array_constructor) : New
	(gcc_jit_context_new_struct_constructor) : New
	(gcc_jit_context_new_union_constructor) : New
	(gcc_jit_global_set_initializer_rvalue) : New
	(LIBGCCJIT_HAVE_CTORS) : New feuture macro
	* libgccjit.map : New entrypoints added to ABI 16

gcc/testsuite/
	* jit.dg/all-non-failing-tests.h: Added two tests
	* jit.dg/test-error-ctor-array-wrong-type.c: New
	* jit.dg/test-error-ctor-struct-too-big.c: New
	* jit.dg/test-error-ctor-struct-wrong-field-name.c: New
	* jit.dg/test-error-ctor-struct-wrong-type.c: New
	* jit.db/test-error-ctor-struct-wrong-type2.c
	* jit.dg/test-error-ctor-union-wrong-field-name.c: New
	* jit.dg/test-error-global-allready-init.c: New
	* jit.dg/test-error-global-common-section.c: New
	* jit.dg/test-error-global-init-too-small-array.c: New
	* jit.dg/test-error-global-lvalue-init.c: New
	* jit.dg/test-error-global-nonconst-init.c: New
	* jit.dg/test-global-init-rvalue.c: New
	* jit.dg/test-local-init-rvalue.c: New

gcc/jit/docs/topics/
	* expressions.rst : Updated docs
---
 gcc/jit/docs/topics/expressions.rst           |  172 ++
 gcc/jit/jit-common.h                          |    9 +
 gcc/jit/jit-playback.c                        |  267 ++-
 gcc/jit/jit-playback.h                        |   20 +-
 gcc/jit/jit-recording.c                       |  469 ++++-
 gcc/jit/jit-recording.h                       |   94 +
 gcc/jit/libgccjit++.h                         |   90 +
 gcc/jit/libgccjit.c                           |  391 ++++-
 gcc/jit/libgccjit.h                           |  150 ++
 gcc/jit/libgccjit.map                         |    5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |   14 +
 .../jit.dg/test-error-ctor-array-wrong-type.c |   54 +
 .../jit.dg/test-error-ctor-struct-too-big.c   |   86 +
 .../test-error-ctor-struct-wrong-field-name.c |   85 +
 .../test-error-ctor-struct-wrong-type.c       |   78 +
 .../test-error-ctor-struct-wrong-type2.c      |   77 +
 .../test-error-ctor-union-wrong-field-name.c  |   76 +
 .../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  |   65 +
 .../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          | 1526 +++++++++++++++++
 gcc/testsuite/jit.dg/test-local-init-rvalue.c |  614 +++++++
 24 files changed, 4550 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-array-wrong-type.c
 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-struct-wrong-type2.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 396259ef07e..ee40e92bbf9 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -126,6 +126,146 @@ Simple expressions
    underlying string, so it is valid to pass in a pointer to an on-stack
    buffer.
 
+Constructor expressions
+***********************
+
+   The following functions make constructors for array, struct and union
+   types.
+
+   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, but its address
+   can't be taken.
+
+   Note that arrays in libgccjit does not collapse to pointers like in
+   C. I.e. if an array constructor is used as e.g. a return value, the whole
+   array would be returned by value - array constructors can be assigned to
+   array variables.
+
+   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.
+
+   These entrypoints were added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presense using:
+
+   .. code-block:: c
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,\
+						     gcc_jit_location *loc,\
+						     gcc_jit_type *type,\
+						     size_t arr_length,\
+						     gcc_jit_rvalue **values)
+
+   Create a constructor for an array as a rvalue.
+
+   Returns NULL on error.
+
+   ``type`` specifies what the constructor will build and has to be
+   an array.
+
+   ``arr_length`` specifies the number of elements in ``values`` and
+   it can't have more elements than the array type.
+
+   Each value in ``values`` sets the corresponding value in the array.
+   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 type's element type.
+
+   If ``arr_length`` is 0, the ``values`` parameter will be
+   ignored and zero initialization will be used.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presense using:
+
+   .. code-block:: c
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,\
+						      gcc_jit_location *loc,\
+						      gcc_jit_type *type,\
+						      size_t arr_length,\
+						      gcc_jit_field **fields,\
+						      gcc_jit_rvalue **value)
+
+
+   Create a constructor for an 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 and has to be
+   a struct.
+
+   ``arr_length`` specifies the number of elements in ``values``.
+
+   ``fields`` need to have the same length as ``values``, or be NULL.
+
+   If ``fields`` is null, the values are applied in definition order.
+
+   Otherwise, each field in ``fields`` specifies which field in the struct to
+   set to the corresponding value in ``values``. ``fields`` and ``values``
+   are paired by index.
+
+   The fields in ``fields`` have to be in definition order, but there
+   can be gaps. Any field in the struct that is not specified in
+   ``fields`` will be zeroed.
+
+   The fields in ``fields`` need to be the same objects that were used
+   to create the struct.
+
+   Each value has to have have the same unqualified type as the field
+   it is applied to.
+
+   A NULL value element  in ``values`` is a shorthand for zero initialization
+   of the corresponding field.
+
+   If ``arr_length`` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presense using:
+
+   .. code-block:: c
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,\
+						     gcc_jit_location *loc,\
+						     gcc_jit_type *type,\
+						     gcc_jit_field *field,\
+						     gcc_jit_rvalue *value)
+
+   Create a constructor for an union as a rvalue.
+
+   Returns NULL on error.
+
+   ``type`` specifies what the constructor will build and has to be
+   an union.
+
+   ``field`` specifies which field to set. If it is NULL, the first
+   field in the union will be set.``field`` need to be the same object
+   that were used to create the union.
+
+   ``value`` specifies what value to set the corresponding field to.
+   If ``value`` is NULL, zero initialization will be used.
+
+   Each value has to have have the same unqualified type as the field
+   it is applied to.
+
+   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
 ******************
 
@@ -603,6 +743,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 f88e6755b00..2e723c38d78 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -202,6 +202,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 b412eae6aa8..ef59fa942d7 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -97,6 +97,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.  */
 
@@ -537,15 +574,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:
@@ -564,6 +614,9 @@ global_new_decl (location *loc,
       break;
     }
 
+  if (TYPE_READONLY (type_tree))
+    TREE_READONLY (inner) = 1;
+
   if (loc)
     set_tree_location (inner, loc);
 
@@ -588,13 +641,165 @@ 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);
+
+  /* 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;
+    }
+
+  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;
+    }
+
+  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++)
+	{
+	  rvalue *rv = (*rvalues)[i];
+	  /* null rvalues indicate that the element should be zeroed.  */
+	  if (rv)
+	    CONSTRUCTOR_APPEND_ELT (v,
+				    build_int_cst (size_type_node, i),
+				    rv->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);
+
+  /* Iterate over the fields, building initializations.  */
+  for (int i = 0;i < n; i++)
+    {
+      tree field = (*fields)[i]->as_tree ();
+      rvalue *rv = (*rvalues)[i];
+      /* If the value is NULL, it means we should zero the field.  */
+      if (rv)
+	CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ());
+      else
+	{
+	  tree zero_cst = build_zero_cst (TREE_TYPE (field));
+	  CONSTRUCTOR_APPEND_ELT (v, field, zero_cst);
+	}
+    }
+
+  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.*/
@@ -628,9 +833,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;
 
@@ -830,7 +1036,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);
 
@@ -866,6 +1073,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)
@@ -897,6 +1106,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);
 
@@ -921,7 +1134,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)
     {
@@ -991,6 +1207,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);
 
@@ -1038,10 +1258,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);
@@ -1141,6 +1370,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);
@@ -1219,7 +1450,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);
 
@@ -1227,6 +1461,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);
@@ -1236,12 +1471,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);
@@ -1289,7 +1526,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;
@@ -1443,7 +1680,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..0db9b6fb53b 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);
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 117ff70114c..869603440b7 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1062,6 +1062,18 @@ 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);
+
+  global *gbl = (global *) variable;
+  gbl->set_rvalue_init (init); /* Needed by the global for write dump.  */
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1094,6 +1106,72 @@ recording::context::new_rvalue_from_vector (location *loc,
   return result;
 }
 
+recording::rvalue *
+recording::context::new_ctor (recording::location *loc,
+			      recording::type *type,
+			      int arr_length,
+			      field **fields,
+			      rvalue **values)
+{
+  recording::ctor *result = new ctor (this, loc, type);
+
+  /* Short cut for zero init.  */
+  if (!arr_length)
+    {
+      record (result);
+      return result;
+    }
+
+  bool is_struct_or_union = type->is_struct () || type->is_union ();
+
+  /* We need to copy fields and values into result's auto_vec:s.
+     Both for structs and unions and only values for arrays.  */
+  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 (is_struct_or_union && fields)
+    {
+      /* ctor values are paired with user specified fields.  */
+
+      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[i]);
+	}
+    }
+  else if (is_struct_or_union && !fields)
+    {
+      /* ctor values are in definition order one by one,
+	 so take the fields from the type object.  */
+
+      result->m_values.reserve (arr_length, false);
+      result->m_fields.reserve (arr_length, false);
+
+      compound_type *ct = reinterpret_cast<compound_type *>(type);
+      recording::fields *fields = ct->get_fields ();
+
+      /* The entry point checks that arr_length is not greater than
+	 the amount of fields in 'fields'.  */
+      for (int i = 0; i < arr_length; i++)
+	{
+	  result->m_values.quick_push (values[i]);
+	  result->m_fields.quick_push (fields->get_field (i));
+	}
+    }
+  else
+    gcc_unreachable ();
+
+  record (result);
+  return result;
+}
+
 /* Create a recording::unary_op instance and add it to this context's
    list of mementos.
 
@@ -4556,11 +4634,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
@@ -4609,21 +4689,30 @@ recording::global::write_to_dump (dump &d)
 	   m_type->get_debug_string (),
 	   get_debug_string ());
 
-  if (!m_initializer)
+  if (!m_initializer && !m_rvalue_init)
     {
       d.write (";\n");
-      return;
     }
-
-  d.write ("=\n  { ");
-  const unsigned char *p = (const unsigned char *)m_initializer;
-  for (size_t i = 0; i < m_initializer_num_bytes; i++)
+  else if (m_initializer)
     {
-      d.write ("0x%x, ", p[i]);
-      if (i && !(i % 64))
-	d.write ("\n    ");
+      d.write ("=\n  { ");
+      const unsigned char *p = (const unsigned char *)m_initializer;
+      for (size_t i = 0; i < m_initializer_num_bytes; i++)
+	{
+	  d.write ("0x%x, ", p[i]);
+	  if (i && !(i % 64))
+	    d.write ("\n    ");
+	}
+      d.write ("};\n");
     }
-  d.write ("};\n");
+  else if (m_rvalue_init)
+    {
+      d.write (" = ");
+      d.write (m_rvalue_init->get_debug_string ());
+      d.write (";\n");
+    }
+
+  return;
 }
 
 /* A table of enum gcc_jit_global_kind values expressed in string
@@ -5070,6 +5159,201 @@ 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 ()
+{
+  //Make a compound literal-ish
+  pretty_printer pp;
+
+  pp_string (&pp, "(");
+  pp_string (&pp, m_type->get_debug_string ());
+  pp_string (&pp, ") {");
+
+  int field_n = m_fields.length ();
+  int values_n = m_values.length ();
+
+  if (!field_n && !values_n)
+    ;
+  else if (!field_n && values_n)
+    {
+      for (int i = 0; i < values_n; i++)
+	{
+	  if (m_values[i])
+	    pp_string (&pp, m_values[i]->get_debug_string ());
+	  else
+	    pp_string (&pp, "0");
+	  if (i + 1 != values_n)
+	    pp_string (&pp, ", ");
+	}
+    }
+  else if (field_n && values_n)
+    {
+      for (int i = 0; i < values_n; i++)
+	{
+	  pp_string (&pp, ".");
+	  pp_string (&pp, m_fields[i]->get_debug_string ());
+	  pp_string (&pp, "=");
+	  if (m_values[i])
+	    pp_string (&pp, m_values[i]->get_debug_string ());
+	  else
+	    pp_string (&pp, "0");
+	  if (i + 1 != values_n)
+	    pp_string (&pp, ", ");
+	}
+    }
+  /* m_fields are never populated with m_values empty.  */
+
+  pp_string (&pp, "}");
+
+  return new_string (pp_formatted_text (&pp));
+}
+
+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.  */
+
+  if (type->is_union ())
+    {
+      if (m_values.length () == 0)
+	r.write ("    gcc_jit_rvalue *value = NULL;\n");
+      else
+	r.write ("    gcc_jit_rvalue *value = %s;\n",
+		 r.get_identifier (m_values[0]));
+
+      if (m_fields.length () == 0)
+	r.write ("    gcc_jit_field *field = NULL;\n");
+      else
+	r.write ("    gcc_jit_field *field = %s;\n",
+		 r.get_identifier (m_fields[0]));
+    }
+  else
+    {
+      /* Write the array of values.  */
+      if (m_values.length () == 0)
+	r.write ("    gcc_jit_rvalue **values = NULL;\n");
+      else
+	{
+	  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 (m_fields.length () == 0)
+	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");
+	}
+    }
+  if (type->is_array ())
+    r.write (
+"    %s =\n"
+"      gcc_jit_context_new_array_constructor (%s,\n"
+"                                             %s, /* gcc_jit_location *loc */\n"
+"                                             %s, /* gcc_jit_type *type */\n"
+"                                             %i, /* int arr_length */\n"
+"                                             values);\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (get_type ()),
+	   m_values.length ());
+  else if (type->is_struct ())
+    r.write (
+"    %s =\n"
+"      gcc_jit_context_new_struct_constructor (%s,\n"
+"                                              %s, /* 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 ());
+  else if (type->is_union ())
+    r.write (
+"    %s =\n"
+"      gcc_jit_context_new_union_constructor (%s,\n"
+"                                             %s, /* loc */\n"
+"                                             %s, /* gcc_jit_type *type */\n"
+"                                             field,\n"
+"                                             value);\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (get_type ()));
+  else
+    gcc_unreachable ();
+
+  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;
+    }
+  /* ... else handle unions and 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
@@ -7034,6 +7318,167 @@ 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 ());
+}
+
+enum strip_flags {
+  STRIP_FLAG_NONE,
+  STRIP_FLAG_ARR,
+  STRIP_FLAG_VEC
+};
+
+/* Strips type down to array, vector or base type (whichever comes first)
+
+   Also saves 'ptr_depth' and sets 'flags' for array or vector types.  */
+static
+recording::type *
+strip_and_count (recording::type *type_to_strip,
+		 int &ptr_depth,
+		 strip_flags &flags)
+{
+  recording::type *t = type_to_strip;
+
+  while (true)
+    {
+      if (!t)
+	gcc_unreachable (); /* Should only happen on corrupt input.  */
+
+      recording::type *pointed_to_type = t->is_pointer ();
+      if (pointed_to_type != NULL)
+	{
+	  ptr_depth++;
+	  t = pointed_to_type;
+	  continue;
+	}
+
+      recording::type *array_el = t->is_array ();
+      if (array_el != NULL)
+	{
+	  flags = STRIP_FLAG_ARR;
+	  break;
+	}
+
+      recording::type *vec = t->dyn_cast_vector_type ();
+      if (vec != NULL)
+	{
+	  flags = STRIP_FLAG_VEC;
+	  break;
+	}
+
+      /* unqualified () returns 'this' on base types.  */
+      recording::type *next = t->unqualified ();
+      if (next == t)
+	{
+	  break;
+	}
+      t = next;
+    }
+
+  return t;
+}
+
+/* Strip qualifiers and count pointer depth, returning true
+   if the types' base type and pointer depth are
+   the same, otherwise false.
+
+   For array and vector types the number of element also
+   has to match.
+
+   Do not call this directly.  Call 'types_kinda_same'.  */
+bool
+types_kinda_same_internal (recording::type *a, recording::type *b)
+{
+  int ptr_depth_a = 0;
+  int ptr_depth_b = 0;
+  recording::type *base_a;
+  recording::type *base_b;
+
+  strip_flags flags_a = STRIP_FLAG_NONE;
+  strip_flags flags_b = STRIP_FLAG_NONE;
+
+  base_a = strip_and_count (a, ptr_depth_a, flags_a);
+  base_b = strip_and_count (b, ptr_depth_b, flags_b);
+
+  if (ptr_depth_a != ptr_depth_b)
+    return false;
+
+  if (base_a == base_b)
+    return true;
+
+  if (flags_a != flags_b)
+    return false;
+
+  /* If the "base type" is an array or vector we might need to
+     check deeper.  */
+  if (flags_a == STRIP_FLAG_ARR)
+    {
+      recording::array_type *arr_a =
+	static_cast<recording::array_type*> (base_a);
+      recording::array_type *arr_b =
+	static_cast<recording::array_type*> (base_b);
+
+      if (arr_a->num_elements () != arr_b->num_elements ())
+	return false;
+
+      /* is_array returns element type.  */
+      recording::type *el_a = arr_a->is_array ();
+      recording::type *el_b = arr_b->is_array ();
+
+      if (el_a == el_b)
+	return true;
+
+      return types_kinda_same_internal (el_a, el_b);
+    }
+  if (flags_a == STRIP_FLAG_VEC)
+    {
+      recording::vector_type *arr_a =
+	static_cast<recording::vector_type*> (base_a);
+      recording::vector_type *arr_b =
+	static_cast<recording::vector_type*> (base_b);
+
+      if (arr_a->get_num_units () != arr_b->get_num_units ())
+	return false;
+
+      recording::type *el_a = arr_a->get_element_type ();
+      recording::type *el_b = arr_b->get_element_type ();
+
+      if (el_a == el_b)
+	return true;
+
+      return types_kinda_same_internal (el_a, el_b);
+    }
+
+  return false;
+}
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 4a994fe7094..f2f1e3461b1 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,7 @@ public:
   virtual type *is_pointer () = 0;
   virtual type *is_array () = 0;
   virtual struct_ *is_struct () { return NULL; }
+  virtual bool is_union () const { return false; }
   virtual bool is_void () const { return false; }
   virtual vector_type *is_vector () { return NULL; }
   virtual bool has_known_size () const { return true; }
@@ -996,6 +1008,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;
@@ -1393,6 +1407,23 @@ 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;
+  }
+
+  void set_rvalue_init (rvalue *val) { m_rvalue_init = val; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1405,8 +1436,10 @@ private:
 
 private:
   enum gcc_jit_global_kind m_kind;
+  enum global_var_flags flags = GLOBAL_VAR_FLAGS_NONE;
   string *m_name;
   void *m_initializer;
+  rvalue *m_rvalue_init = nullptr; /* Only needed for write_dump.  */
   size_t m_initializer_num_bytes;
 };
 
@@ -1491,6 +1524,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:
@@ -2334,6 +2393,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
@@ -2353,6 +2430,23 @@ recording::context::new_rvalue_from_const (recording::type *type,
   return result;
 }
 
+/* Don't call this directly.  Call types_kinda_same.  */
+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.
+
+   For array and vector types the number of element also
+   has to match, aswell as the element types themself.  */
+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 82831ff5da0..25414620afb 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -197,6 +197,20 @@ namespace gccjit
     rvalue new_rvalue (type vector_type,
 		       std::vector<rvalue> elements) const;
 
+    rvalue new_struct_ctor (type type_,
+			    std::vector<field> &fields,
+			    std::vector<rvalue> &values,
+			    location loc = location ());
+
+    rvalue new_array_ctor (type type_,
+			   std::vector<rvalue> &values,
+			   location loc = location ());
+
+    rvalue new_union_ctor (type type_,
+			   field field,
+			   rvalue value,
+			   location loc = location ());
+
     /* Generic unary operations...  */
     rvalue new_unary_op (enum gcc_jit_unary_op op,
 			 type result_type,
@@ -500,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
@@ -1831,6 +1846,81 @@ 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_struct_ctor (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_struct_constructor (
+	     m_inner_ctxt,
+	     loc.get_inner_location (),
+	     type_.get_inner_type (),
+	     (int)values.size (),
+	     fields_arr,
+	     values_arr));
+}
+
+inline rvalue
+context::new_array_ctor (type type_,
+			 std::vector<rvalue> &values,
+			 location loc)
+{
+  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_array_constructor (
+	     m_inner_ctxt,
+	     loc.get_inner_location (),
+	     type_.get_inner_type (),
+	     (int)values.size (),
+	     values_arr));
+}
+
+inline rvalue
+context::new_union_ctor (type type_,
+			 field field,
+			 rvalue value,
+			 location loc)
+{
+  return rvalue (
+	   gcc_jit_context_new_union_constructor (
+	     m_inner_ctxt,
+	     loc.get_inner_location (),
+	     type_.get_inner_type (),
+	     field.get_inner_field (),
+	     value.get_inner_rvalue ()));
+}
+
+
 // 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 5d051e43e1e..eeb0befbec3 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -1386,6 +1386,379 @@ 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_struct_constructor (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_type *type,
+					int arr_length,
+					gcc_jit_field **fields,
+					gcc_jit_rvalue **values)
+{
+  using namespace gcc::jit::recording;
+
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (type->is_struct (),
+			       ctxt, loc,
+			       "constructor type is not a struct: %s",
+			       type->get_debug_string ());
+
+  compound_type *ct = reinterpret_cast<compound_type *>(type);
+  gcc::jit::recording::fields *fields_struct = ct->get_fields ();
+  int n_fields = fields_struct->length ();
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (ct->has_known_size (),
+			       ctxt, loc,
+			       "struct can't be opaque: %s",
+			       type->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF1 (n_fields,
+			       ctxt, loc,
+			       "no fields in struct: %s",
+			       type->get_debug_string ());
+
+  /* If there is no array input we just short circuit to zero the struct.  */
+  if (!arr_length)
+    return (gcc_jit_rvalue *)ctxt->new_ctor (loc, type, 0, NULL, NULL);
+
+  RETURN_NULL_IF_FAIL (n_fields >= arr_length,
+		       ctxt, loc,
+		       "more values in constructor than fields in "
+		       "target struct");
+
+  /* It is OK if fields are null here, indicating definiton order,
+     but there has to be a values array.  */
+  RETURN_NULL_IF_FAIL (values,
+		       ctxt, loc,
+		       "'values' NULL with non-zero 'arr_length'");
+
+  int idx = 0; /* Runner index for fields in the type object.  */
+
+  for (int i = 0; i < arr_length; i++)
+    {
+      gcc::jit::recording::rvalue *rv = values[i];
+
+      /* rv kan be NULL, which would indicate zero init for the field.  */
+      gcc::jit::recording::type *rv_type = rv ? rv->get_type () : nullptr;
+
+      /* If fields are specified we need to check that they are in
+	 definition order.  */
+      if (fields)
+	{
+	  gcc::jit::recording::field *f = fields[i];
+
+	  RETURN_NULL_IF_FAIL_PRINTF1 (
+	    f,
+	    ctxt, loc,
+	    "NULL field in 'fields', at index %d", i);
+
+	  RETURN_NULL_IF_FAIL_PRINTF2 (
+	    f->get_container () ==
+	    static_cast<gcc::jit::recording::type*>(type),
+	    ctxt, loc,
+	    "field at index %d, was not used when creating "
+	    "the struct (%s)",
+	    i,
+	    f->get_debug_string ());
+
+	  /* Fields in the constructor need to be in struct definition
+	     order, but there can be gaps.  */
+	  int j;
+	  for (j = idx; j < n_fields; j++)
+	    {
+	      field *fs = fields_struct->get_field (j);
+	      if (fs == f)
+		{
+		  idx = j; /* Advance runner index for next iteration.  */
+		  break;
+		}
+	    }
+
+	  RETURN_NULL_IF_FAIL_PRINTF3 (
+	    j != n_fields,
+	    ctxt, loc,
+	    "field at index %d in 'fields' is not in definition order "
+	    "(struct: %s) (ctor field: %s)",
+	    i,
+	    type->get_debug_string (),
+	    f->get_debug_string ());
+
+	  /* Check that the specified field has the same type as the
+	     value, unless the value is null (a zero value init).  */
+	  RETURN_NULL_IF_FAIL_PRINTF3 (
+	    !rv || gcc::jit::types_kinda_same (rv_type,
+					       f->get_type ()),
+	    ctxt, loc,
+	    "value and field not the same unqualified type, at index %d"
+	    " (field type: %s)(value type: %s)",
+	    i,
+	    f->get_type ()->get_debug_string (),
+	    rv_type->get_debug_string ());
+	}
+
+      /* If no fields are specified, check that the value has the same type
+	 as the field in the definition of the struct.  */
+      if (rv && !fields)
+	{
+	  RETURN_NULL_IF_FAIL_PRINTF3 (
+	    gcc::jit::types_kinda_same (rv_type,
+					fields_struct->
+					  get_field (i)->get_type ()),
+	    ctxt, loc,
+	    "value and field not the same unqualified type, at index %d"
+	    " (field type: %s)(value type: %s)",
+	    i,
+	    fields_struct->get_field (i)->get_type ()->get_debug_string (),
+	    rv_type->get_debug_string ());
+	}
+
+      if (rv)
+	{
+	  RETURN_NULL_IF_FAIL_PRINTF1 (
+	    !rv_type->is_void (),
+	    ctxt, loc,
+	    "can't construct the void type, at index %d", i);
+	}
+    }
+
+  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));
+}
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *type,
+				       gcc_jit_field *field,
+				       gcc_jit_rvalue *value)
+{
+  using namespace gcc::jit::recording;
+
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (type->is_union (),
+			       ctxt, loc,
+			       "constructor type is not an union: %s",
+			       type->get_debug_string ());
+
+  compound_type *ct = reinterpret_cast<compound_type *>(type);
+  gcc::jit::recording::fields *fields_union = ct->get_fields ();
+  int n_fields = fields_union->length ();
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (ct->has_known_size (),
+			       ctxt, loc,
+			       "union can't be opaque: %s",
+			       type->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF1 (n_fields,
+			       ctxt, loc,
+			       "no fields in union: %s",
+			       type->get_debug_string ());
+
+  /* If value is NULL we are just supposed to zero the whole union.  */
+  if (!value)
+    return (gcc_jit_rvalue *)ctxt->new_ctor (loc, type, 0, NULL, NULL);
+
+  gcc::jit::recording::type *rv_type = value->get_type ();
+
+  RETURN_NULL_IF_FAIL (
+    !rv_type->is_void (),
+    ctxt, loc,
+    "can't construct the void type");
+
+  if (field)
+    {
+      RETURN_NULL_IF_FAIL_PRINTF1 (
+	field->get_container () ==
+	static_cast<gcc::jit::recording::type*>(type),
+	ctxt, loc,
+	"field was not used when creating "
+	"the union (%s)",
+	field->get_debug_string ());
+
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	gcc::jit::types_kinda_same (rv_type,
+				    field->get_type ()),
+	ctxt, loc,
+	"value and field are not the same unqualified type"
+	" (field type: %s)(value type: %s)",
+	field->get_type ()->get_debug_string (),
+	rv_type->get_debug_string ());
+    }
+  /* If no field is specified, check that the value has the same type
+     as the first field in the definition of the union.  */
+  if (!field)
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      gcc::jit::types_kinda_same (rv_type,
+				  fields_union->
+				    get_field (0)->get_type ()),
+      ctxt, loc,
+      "value and first union field not the same unqualified type"
+      " (field type: %s)(value type: %s)",
+      fields_union->get_field (0)->get_type ()->get_debug_string (),
+      rv_type->get_debug_string ());
+
+
+  return (gcc_jit_rvalue *)ctxt->new_ctor (
+    loc,
+    type,
+    1,
+    /* A NULL fields array tells new_ctor to take fields from the type obj.  */
+    reinterpret_cast<gcc::jit::recording::field**>(field ? &field : NULL),
+    reinterpret_cast<gcc::jit::recording::rvalue**>(&value));
+}
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *type,
+				       int arr_length,
+				       gcc_jit_rvalue **values)
+{
+  using namespace gcc::jit::recording;
+
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+
+  RETURN_NULL_IF_FAIL (type->is_array () != NULL,
+		       ctxt, loc,
+		       "constructor type not an array");
+
+  if (!arr_length)
+    values = NULL;
+
+  if (arr_length)
+    {
+      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");
+
+      /* For arrays, all values need to be the same base 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 and i == arr_length.  */
+	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,
+    NULL,
+    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
@@ -1419,8 +1792,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 a1c9436c545..6ab652a5b5c 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -812,6 +812,156 @@ 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 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 and has to be
+   a struct.
+
+   `arr_length` specifies the number of elements in `values`.
+
+   `fields` need to have the same length as `values`, or be NULL.
+
+   If `fields` is null, the values are applied in definition order.
+
+   Otherwise, each field in `fields` specifies which field in the struct to
+   set to the corresponding value in `values`.  `fields` and `values`
+   are paired by index.
+
+   Each value has to have have the same unqualified type as the field
+   it is applied to.
+
+   A NULL value element  in `values` is a shorthand for zero initialization
+   of the corresponding field.
+
+   The fields in `fields` have to be in definition order, but there
+   can be gaps.  Any field in the struct that is not specified in
+   `fields` will be zeroed.
+
+   The fields in `fields` need to be the same objects that were used
+   to create the struct.
+
+   If `arr_length` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+
+   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.
+
+   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_struct_constructor (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_type *type,
+					int arr_length,
+					gcc_jit_field **fields,
+					gcc_jit_rvalue **values);
+
+/* Create a constructor for an union as a rvalue.
+
+   Returns NULL on error.
+
+   `type` specifies what the constructor will build and has to be
+   an union.
+
+   `field` specifies which field to set.  If it is NULL, the first
+   field in the union will be set.  `field` need to be the same
+   object that were used to create the union.
+
+   `value` specifies what value to set the corresponding field to.
+   If `value` is NULL, zero initialization will be used.
+
+   Each value has to have have the same unqualified type as the field
+   it is applied to.
+
+   `field` need to be the same objects that were used
+   to create the union.
+
+   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.
+
+   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_union_constructor (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *type,
+				       gcc_jit_field *field,
+				       gcc_jit_rvalue *value);
+
+/* Create a constructor for an array as a rvalue.
+
+   Returns NULL on error.
+
+   `type` specifies what the constructor will build and has to be
+   an array.
+
+   `arr_length` specifies the number of elements in `values` and
+   it can't have more elements than the array type.
+
+   Each value in `values` sets the corresponding value in the array.
+   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 type's element type.
+
+   If `arr_length` is 0, the `values` parameter will be
+   ignored and zero initialization will be used.
+
+   Note that a string literal rvalue can't be used to construct a char
+   array.  It needs 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_array_constructor (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *type,
+				       int arr_length,
+				       gcc_jit_rvalue **values);
+
+/* Set the initial value of a global of any type with an rvalue.
+
+   The rvalue need to be a constant expression, e.g. 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 unchanged.  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 64e790949e8..c8abd8908a2 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -208,11 +208,15 @@ LIBGCCJIT_ABI_15 {
 
 LIBGCCJIT_ABI_16 {
   global:
+    gcc_jit_context_new_array_constructor;
+    gcc_jit_context_new_struct_constructor;
+    gcc_jit_context_new_union_constructor;
     gcc_jit_function_get_return_type;
     gcc_jit_function_get_param_count;
     gcc_jit_function_type_get_return_type;
     gcc_jit_function_type_get_param_count;
     gcc_jit_function_type_get_param_type;
+    gcc_jit_global_set_initializer_rvalue;
     gcc_jit_type_unqualified;
     gcc_jit_type_dyncast_array;
     gcc_jit_type_is_bool;
@@ -226,3 +230,4 @@ LIBGCCJIT_ABI_16 {
     gcc_jit_type_is_struct;
     gcc_jit_struct_get_field_count;
 } LIBGCCJIT_ABI_15;
+
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index a7fddf96db8..56a3eb3cd8e 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -181,6 +181,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
@@ -202,6 +209,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-array-wrong-type.c b/gcc/testsuite/jit.dg/test-error-ctor-array-wrong-type.c
new file mode 100644
index 00000000000..1ce83b2ed6c
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-array-wrong-type.c
@@ -0,0 +1,54 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an array type, but has the type wrong on an element.
+
+*/
+
+#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 *arr_type =
+    gcc_jit_context_new_array_type (ctxt, 0, int_type, 10);
+
+  gcc_jit_rvalue *frv = gcc_jit_context_new_rvalue_from_double (ctxt,
+								float_type,
+								12);
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_array_constructor
+    (ctxt, 0,
+     arr_type,
+     1,
+     &frv);
+
+  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_array_constructor: array element "
+		      "value types differ from types in 'values' (element "
+		      "type: int)('values' type: float)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_array_constructor: array element "
+		      "value types differ from types in 'values' (element "
+		      "type: int)('values' type: float)");
+}
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..cba349065ab
--- /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_struct_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_struct_constructor: more values in "
+		      "constructor than fields in target struct");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_struct_constructor: more values in "
+		      "constructor than fields in 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..3466bcdfcea
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
@@ -0,0 +1,85 @@
+/*
+
+  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 *b4 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "d");
+  gcc_jit_field *b5 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "d");
+  gcc_jit_field *fields_b[] = {b1, b2, b3, b4, b5};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       5,
+				       fields_b));
+
+
+  gcc_jit_field *b44 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "d");
+
+  gcc_jit_field *fields_ctor[] = {b1, b2, b44, b5};
+  gcc_jit_rvalue *values[] = {0,0,0,0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_struct_constructor: field at index "
+		      "2, was "
+		      "not used when creating the struct (d)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_struct_constructor: field at index "
+		      "2, was "
+		      "not used when creating the struct (d)");
+}
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..ce1476e4014
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
@@ -0,0 +1,78 @@
+/*
+
+  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_rvalue *frv = gcc_jit_context_new_rvalue_from_double (ctxt,
+								float_type,
+								12);
+
+  gcc_jit_field *fields_ctor[] = {b2};
+  gcc_jit_rvalue *values[] = {frv};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+    (ctxt, 0,
+     struct_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_struct_constructor: value and "
+		      "field not "
+		      "the same unqualified type, "
+		      "at index 0 (field type: int)(value type: float)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_struct_constructor: value and "
+		      "field not "
+		      "the same unqualified type, "
+		      "at index 0 (field type: int)(value type: float)");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type2.c b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type2.c
new file mode 100644
index 00000000000..e1f155b42af
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type2.c
@@ -0,0 +1,77 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an struct type, but has the type wrong on a field.
+
+  Like test-error-ctor-struct-wrong-type.c, but with implicit 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_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_rvalue *frv = gcc_jit_context_new_rvalue_from_double (ctxt,
+								float_type,
+								12);
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     1,
+     0,
+     &frv);
+
+  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_struct_constructor: value and "
+		      "field not "
+		      "the same unqualified type, "
+		      "at index 0 (field type: int)(value type: float)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_struct_constructor: value and "
+		      "field not "
+		      "the same unqualified type, "
+		      "at index 0 (field type: int)(value type: float)");
+}
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..35023599482
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
@@ -0,0 +1,76 @@
+/*
+
+  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,
+						  "c");
+
+  gcc_jit_rvalue *val =
+    gcc_jit_context_new_rvalue_from_double (ctxt, double_type, 1);
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_union_constructor
+    (ctxt, 0,
+     union_bar_type,
+     b33,
+     val);
+
+  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_union_constructor: field "
+		      "was not used when creating the union (c)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_union_constructor: field "
+		      "was not used when creating the union (c)");
+}
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..02d9b21ff8b
--- /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..24ca136f554
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
@@ -0,0 +1,65 @@
+/*
+
+  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_array_constructor (ctxt,
+								0,
+								arr_type,
+								2,
+								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_array_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_array_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..d93b807e8d0
--- /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..a3ba4b59456
--- /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..6e194ea32e7
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
@@ -0,0 +1,1526 @@
+/* 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. */
+
+#include <stdio.h>
+#include <string.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 *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 *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_field *fields[] = {fi_f, fi_i};
+
+  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;
+     }
+  */
+  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_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						     0,
+						     struct_fi_type,
+						     "fi");
+  gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii};
+
+  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;
+     };
+  */
+  gcc_jit_field *ubar_ff = gcc_jit_context_new_field (ctxt,
+						      0,
+						      float_type,
+						      "ff");
+  gcc_jit_field *ubar_ii = gcc_jit_context_new_field (ctxt,
+						      0,
+						      int_type,
+						      "ii");
+  gcc_jit_field *fields3[] = {ubar_ff, ubar_ii};
+
+  gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt,
+						       0,
+						       "ubar",
+						       2,
+						       fields3);
+
+  { /* struct bar bar = {.ff=1, .fi={.f=2, .i=3}, .ii=4};
+       I.e. nested ctors and with fields specified
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_1234_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_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *vals2[] = {fval, ctor, ival};
+    gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_struct_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 ctors and fields implicit in definition order (fields=NULL)
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_1234_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_rvalue *vals[] = { fval, ival};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       0,
+       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_rvalue *vals2[] = {fval, ctor, ival};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       0,
+       vals2);
+
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+  { /* struct fi foo = {.f=2, .i=3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_23_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_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* 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_23_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_rvalue *vals[] = { fval, ival};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       0,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i=0, .f=0}; (null init) */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_00_1");
+
+    gcc_jit_rvalue *vals[] = { 0, 0};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {0, 0}; (null fields, null elements in values) */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_00_2");
+
+    gcc_jit_rvalue *vals[] = { 0, 0};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       0,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i = 0} (null init);
+
+       Null init values. */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_0_1");
+
+    gcc_jit_rvalue *vals[] = {0};
+    gcc_jit_field *fields[] = {fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       1,
+       fields,
+       vals);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {0};
+
+       Null init values. */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_0_2");
+
+    gcc_jit_rvalue *vals[] = {0};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       1,
+       0,
+       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_struct_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_rvalue *vals[] = { rval_mul, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+       ctxt, float_type, 3);
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_union_constructor (
+       ctxt,
+       0,
+       ubar,
+       ubar_ff,
+       fval);
+
+     gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* union ubar foo = {.ii = 2}; */
+     gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      ubar,
+      "global_union_ufoo_ii2");
+
+     gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+       ctxt, int_type, 2);
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_union_constructor (
+       ctxt,
+       0,
+       ubar,
+       ubar_ii,
+       ival);
+
+     gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* union ubar foo = {1.1f}; should init first field  */
+     gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      ubar,
+      "global_union_ufoo_ff1c1");
+
+     gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_double (
+       ctxt, float_type, 1.1);
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_union_constructor (
+       ctxt,
+       0,
+       ubar,
+       0,
+       fval);
+
+     gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* union ubar foo = (union ubar){}; */
+     gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      ubar,
+      "global_union_ufoo_0");
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_union_constructor (
+       ctxt,
+       0,
+       ubar,
+       0,
+       0);
+
+     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);
+  }
+  { /* const volatile 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,
+      gcc_jit_type_get_const (gcc_jit_type_get_volatile (int_type)),
+      "global_cvint1_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 = ~(-(((((2 | 8) & 15) ^ 0) << 3 >> 2 - 1) / 2)); */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int_alotofoperators");
+    gcc_jit_rvalue *rval_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 8);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 15);
+    gcc_jit_rvalue *rval_3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 0);
+    gcc_jit_rvalue *rval_4 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_5 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_7 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+
+    gcc_jit_rvalue *rval_or = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_BITWISE_OR,
+      int_type,
+      rval_0,
+      rval_1);
+    gcc_jit_rvalue *rval_and = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_BITWISE_AND,
+      int_type,
+      rval_or,
+      rval_2);
+    gcc_jit_rvalue *rval_xor = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_BITWISE_XOR,
+      int_type,
+      rval_and,
+      rval_3);
+    gcc_jit_rvalue *rval_lsh = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_LSHIFT,
+      int_type,
+      rval_xor,
+      rval_4);
+    gcc_jit_rvalue *rval_rsh = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_RSHIFT,
+      int_type,
+      rval_lsh,
+      rval_5);
+    gcc_jit_rvalue *rval_min = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MINUS,
+      int_type,
+      rval_rsh,
+      rval_6);
+    gcc_jit_rvalue *rval_div = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      int_type,
+      rval_min,
+      rval_7);
+    gcc_jit_rvalue *rval_umin =  gcc_jit_context_new_unary_op (ctxt, 0,
+      GCC_JIT_UNARY_OP_MINUS,
+      int_type,
+      rval_div);
+    gcc_jit_rvalue *rval_neg =  gcc_jit_context_new_unary_op (ctxt, 0,
+      GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+      int_type,
+      rval_umin);
+
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_neg);
+  }
+  { /* 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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  4,
+								  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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  2,
+								  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};
+       With different array objects of same size and type. */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    gcc_jit_type *arr_type1 = 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_array_constructor (ctxt,
+								  0,
+								  arr_type1,
+								  2,
+								  values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_12_2");
+    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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  2,
+								  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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  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, 5, 6}; (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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  7,
+								  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], 0}; */
+
+    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 *rval_3 = gcc_jit_context_null (ctxt, pint_type);
+
+    gcc_jit_rvalue *values[] = {0, rval_2, rval_3};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  2,
+								  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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  4,
+								  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_array_constructor (ctxt,
+					     0,
+					     row_type,
+					     2,
+					     rvals_row0);
+    gcc_jit_rvalue *ctor_row1 =
+      gcc_jit_context_new_array_constructor (ctxt,
+					     0,
+					     row_type,
+					     2,
+					     rvals_row1);
+    gcc_jit_rvalue *ctors_row[] = {ctor_row0, ctor_row1};
+
+    gcc_jit_rvalue *ctor_arr =
+      gcc_jit_context_new_array_constructor (ctxt,
+					     0,
+					     arr_type,
+					     2,
+					     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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  2,
+								  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_array_constructor (ctxt,
+								  0,
+								  arr_type,
+								  4,
+								  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_INTERNAL,
+      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_INTERNAL,
+      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_INTERNAL,
+      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 = 0xEEEFBEEF}; */
+    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_rvalue *val = gcc_jit_context_new_rvalue_from_long (
+      ctxt, size_type, 0xEEEFBEEF);
+
+    gcc_jit_rvalue *ctor =
+      gcc_jit_context_new_union_constructor (ctxt,
+					     0,
+					     ubar,
+					     f1,
+					     val);
+
+    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_dump_to_file(ctxt, "./dump.c", 1);
+
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_23_1");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_23_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_00_1");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_00_2");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_0_1");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_0_2");
+
+    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_1234_1");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+    CHECK_VALUE (bar->ii, 4);
+  }
+  {
+    struct bar1 *bar =
+      gcc_jit_result_get_global (result, "global_struct_bar_1234_2");
+
+    CHECK_VALUE (bar->ff, 1);
+    CHECK_VALUE (bar->fi.f, 2);
+    CHECK_VALUE (bar->fi.i, 3);
+    CHECK_VALUE (bar->ii, 4);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						  "global_union_ufoo_ff3");
+    CHECK_VALUE (foo->ff, 3);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						  "global_union_ufoo_ii2");
+    CHECK_VALUE (foo->ii, 2);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						  "global_union_ufoo_0");
+    CHECK_VALUE (foo->ii, 0);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						  "global_union_ufoo_ff1c1");
+    CHECK_VALUE (foo->ff, 1.1f);
+  }
+
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_cvint1_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_int_alotofoperators");
+
+    CHECK_VALUE (*foo, ~(-((((((2 | 8) & 15) ^ 0) << 3 >> 2) - 1) / 2)));
+  }
+  {
+    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_12_2");
+
+    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*)0xEEEFBEEF);
+  }
+}
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..0dcc771379b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-local-init-rvalue.c
@@ -0,0 +1,614 @@
+#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 *char_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_CHAR);
+  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);
+  gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_VOID);
+
+  /* Make a struct: struct fi { float f; int i;} */
+  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_field *fields[] = {fi_f, fi_i};
+
+  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;
+       char cc;
+     }
+  */
+  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_field *bar_cc = gcc_jit_context_new_field (ctxt,
+				  0,
+				  char_type,
+				  "cc");
+  gcc_jit_type *int50arr_type =
+    gcc_jit_context_new_array_type (ctxt,
+				    0,
+				    int_type,
+				    50);
+  gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int50arr_type,
+						 "arr");
+  gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii, bar_cc};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       4,
+				       fields2));
+
+  /* Make an union:
+
+     union ubar {
+       float ff;
+       int ii;
+     };
+  */
+  gcc_jit_field *ubar_ff = gcc_jit_context_new_field (ctxt,
+						      0,
+						      float_type,
+						      "ff");
+  gcc_jit_field *ubar_ii = gcc_jit_context_new_field (ctxt,
+						      0,
+						      int_type,
+						      "ii");
+  gcc_jit_field *fields3[] = {ubar_ff, ubar_ii};
+  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_rvalue *vals[] = { rval_f1, rval_i2};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {fi_f, fi_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {fi_f, fi_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *vals[] = { rval_f1, rval_i2};
+      gcc_jit_field *fields[] = {fi_f, fi_i};
+
+      gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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_rvalue *vals[] = { rval_f1, rval_i2};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_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);
+  }
+  { /*
+       void foo(struct bar *b) { *b = (struct bar) {.arr = {1,2}; }
+     */
+
+    gcc_jit_param *param =
+      gcc_jit_context_new_param (ctxt, 0,
+				 gcc_jit_type_get_pointer (struct_bar_type),
+				 "b");
+
+
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    void_type,
+				    "fn_pbar_12",
+				    1,
+				    &param,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *rval_i1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+
+    gcc_jit_rvalue *arr_vals[] = { rval_i1, rval_i2};
+
+    gcc_jit_rvalue *arr_ctor = gcc_jit_context_new_array_constructor
+      (ctxt, 0,
+       int50arr_type,
+       2,
+       arr_vals);
+
+    gcc_jit_rvalue *str_ctor = gcc_jit_context_new_struct_constructor
+      (ctxt,
+       0,
+       struct_bar_type,
+       1,
+       &bar_fi,
+       &arr_ctor);
+
+    gcc_jit_param *p0 = gcc_jit_function_get_param (fn, 0);
+    gcc_jit_lvalue *lv0 =  gcc_jit_param_as_lvalue (p0);
+    gcc_jit_lvalue *deref =
+      gcc_jit_rvalue_dereference (gcc_jit_lvalue_as_rvalue (lv0), 0);
+
+    gcc_jit_block_add_assignment (block, 0,
+				  deref,
+				  str_ctor);
+
+    gcc_jit_block_end_with_void_return (block, 0);
+  }
+  { /* 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_struct_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_array_constructor
+	(ctxt, 0,
+	 int50arr_type,
+	 6,
+	 values);
+
+    gcc_jit_lvalue *arr_lv = gcc_jit_lvalue_access_field (local,
+							  0,
+							  bar_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_array_constructor (
+	 ctxt,
+	 0,
+	 int50arr_type,
+	 6,
+	 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;
+  char c;
+};
+
+union ubar2 {
+  float ff;
+  int ii;
+};
+
+struct int50arr {
+  int arr[50];
+};
+
+void __attribute__((optimize(0)))
+scramble_stack(void)
+  {
+    char *p = alloca(100);
+    for (int i = 0; i < 100; i++)
+      *p++ = 0xF0;
+    asm(""); /* Mark for side-effect */
+  }
+
+void __attribute__((optimize(0)))
+scramble_arr (char *arr, int len)
+{
+  for (int i = 0; i < len; i++)
+    *arr++ = i;
+  asm(""); /* Mark for side-effect */
+}
+
+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);
+  }
+  {
+
+    void (*fn) (struct bar2 *) = gcc_jit_result_get_code (result, "fn_pbar_12");
+
+    struct bar2 bar = (struct bar2) {};
+
+    scramble_arr ((char*)&bar, sizeof bar);
+    scramble_stack();
+
+    fn (&bar);
+
+    struct bar2 key = {.arr = {1,2}};
+    __builtin_clear_padding (&key);
+
+    CHECK_VALUE (memcmp (&bar, &key, sizeof (key)), 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] 7+ messages in thread

end of thread, other threads:[~2022-01-27 20:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-29 20:03 [PATCH] jit: Add support for global rvalue initialization and ctors Petter Tomner
2021-11-30 17:09 ` SV: " Petter Tomner
2021-12-10 18:49 ` Marc Nieper-Wißkirchen
2021-12-11 15:51   ` SV: " Petter Tomner
2021-12-15 14:13     ` Petter Tomner
2022-01-24 13:43       ` Marc Nieper-Wißkirchen
2022-01-27 20:01         ` 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).