public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
@ 2021-05-21  1:27 Antoni Boucher
  2021-06-11 20:44 ` Antoni Boucher
  0 siblings, 1 reply; 12+ messages in thread
From: Antoni Boucher @ 2021-05-21  1:27 UTC (permalink / raw)
  To: jit, gcc-patches

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

Hi.

I made this patch to set an arbitrary value to a global variable.

This patch suffers from the same issue as inline assembly
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
segfaults if the `rvalue` is created after the global variable.
It seems to be a design issue so I'm not sure what would be the fix for
it and having it fixed would allow me to test this new function much
more and see if things are missing (i.e. it might require a way to
create a constant struct).
See the link above for an explanation of this issue.

Thanks for the review.

[-- Attachment #2: 0001-Add-function-to-set-the-initial-value-of-a-global-va.patch --]
[-- Type: text/x-patch, Size: 12334 bytes --]

From 0a5fd7f759e1bd7becc993f01bdcf84ff8fc5fd5 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Sat, 15 May 2021 10:54:36 -0400
Subject: [PATCH] Add function to set the initial value of a global variable
 [PR96089]

2021-05-20  Antoni Boucher  <bouanto@zoho.com>

    gcc/jit/
            PR target/96089
            * docs/topics/compatibility.rst (LIBGCCJIT_ABI_19): New ABI
            tag.
            * docs/topics/expressions.rst: Add documentation for the
            function gcc_jit_global_set_initializer_value.
            * jit-playback.c: New function (new_global_with_value).
            * jit-playback.h: New function (new_global_with_value).
            * jit-recording.c: Add support for setting a value to a
            global variable.
            * jit-recording.h: New function (set_initializer_value) and
            new field m_initializer_value.
            * libgccjit.c: New macro RETURN_IF_FAIL_PRINTF5 and new
            function (gcc_jit_global_set_initializer_value).
            * libgccjit.h: New function (gcc_jit_global_set_initializer_value).
            * libgccjit.map (LIBGCCJIT_ABI_19): New ABI tag.

    gcc/testsuite/
            PR target/96089
            * jit.dg/test-global-set-initializer.c: Add test for the new
            function (gcc_jit_global_set_initializer_value).
---
 gcc/jit/docs/topics/compatibility.rst         |  9 ++++
 gcc/jit/docs/topics/expressions.rst           | 14 ++++++
 gcc/jit/jit-playback.c                        | 18 ++++++++
 gcc/jit/jit-playback.h                        |  7 +++
 gcc/jit/jit-recording.c                       | 34 ++++++++++++---
 gcc/jit/jit-recording.h                       |  8 ++++
 gcc/jit/libgccjit.c                           | 43 +++++++++++++++++++
 gcc/jit/libgccjit.h                           | 13 ++++++
 gcc/jit/libgccjit.map                         | 14 ++++++
 .../jit.dg/test-global-set-initializer.c      | 15 +++++++
 10 files changed, 169 insertions(+), 6 deletions(-)

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 239b6aa1a92..666eb3a1c51 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -243,3 +243,12 @@ embedding assembler instructions:
   * :func:`gcc_jit_extended_asm_add_input_operand`
   * :func:`gcc_jit_extended_asm_add_clobber`
   * :func:`gcc_jit_context_add_top_level_asm`
+
+.. _LIBGCCJIT_ABI_19:
+
+``LIBGCCJIT_ABI_19``
+-----------------------
+``LIBGCCJIT_ABI_19`` covers the addition of an API entrypoint to set the value
+of a global variable:
+
+  * :func:`gcc_jit_global_set_initializer_value`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 396259ef07e..f638cb68fdd 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -603,6 +603,20 @@ Global variables
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
+.. function:: void
+              gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,\
+                                                    gcc_jit_rvalue *value)
+
+   Set an initializer for ``global`` using the specified value.
+   ``global`` must be the same type as ``value``.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_19`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer_value
+
 Working with pointers, structs and unions
 -----------------------------------------
 
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index c6136301243..d86701a8ae6 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -664,6 +664,24 @@ new_global_initialized (location *loc,
   return global_finalize_lvalue (inner);
 }
 
+playback::lvalue *
+playback::context::
+new_global_with_value (location *loc,
+		       enum gcc_jit_global_kind kind,
+		       type *type,
+		       playback::rvalue *value,
+		       const char *name)
+{
+  tree inner = global_new_decl (loc, kind, type, name);
+
+  tree inner_type = type->as_tree ();
+  tree initial = value->as_tree ();
+  gcc_assert (TREE_CONSTANT (initial));
+  DECL_INITIAL (inner) = initial;
+
+  return global_finalize_lvalue (inner);
+}
+
 /* Implementation of the various
       gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
    methods.
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 825a3e172e9..958284df539 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -120,6 +120,13 @@ public:
                           const void *initializer,
                           const char *name);
 
+  lvalue*
+  new_global_with_value (location *loc,
+			 enum gcc_jit_global_kind kind,
+			 type *type,
+			 rvalue *value,
+			 const char *name);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 117ff70114c..a26e4928084 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -4547,20 +4547,34 @@ recording::block::dump_edges_to_dot (pretty_printer *pp)
 void
 recording::global::replay_into (replayer *r)
 {
-  set_playback_obj (
-    m_initializer
-    ? r->new_global_initialized (playback_location (r, m_loc),
+  playback::lvalue * obj;
+  if (m_initializer)
+  {
+      obj = r->new_global_initialized (playback_location (r, m_loc),
 				 m_kind,
 				 m_type->playback_type (),
 				 m_type->dereference ()->get_size (),
 				 m_initializer_num_bytes
 				 / m_type->dereference ()->get_size (),
 				 m_initializer,
-				 playback_string (m_name))
-    : r->new_global (playback_location (r, m_loc),
+				 playback_string (m_name));
+  }
+  else if (m_initializer_value)
+  {
+      obj = r->new_global_with_value (playback_location (r, m_loc),
+				 m_kind,
+				 m_type->playback_type (),
+				 m_initializer_value->playback_rvalue (),
+				 playback_string (m_name));
+  }
+  else
+  {
+      obj = r->new_global (playback_location (r, m_loc),
 		     m_kind,
 		     m_type->playback_type (),
-		     playback_string (m_name)));
+		     playback_string (m_name));
+  }
+  set_playback_obj (obj);
 }
 
 /* Override the default implementation of
@@ -4675,6 +4689,14 @@ recording::global::write_reproducer (reproducer &r)
     r.get_identifier_as_type (get_type ()),
     m_name->get_debug_string ());
 
+  if (m_initializer_value)
+  {
+    r.write ("  gcc_jit_global_set_initializer_value (%s, /* gcc_jit_lvalue *global */\n"
+      "    %s/* gcc_jit_rvalue *value */);\n",
+    id,
+    r.get_identifier_as_rvalue (m_initializer_value));
+  }
+
   if (m_initializer)
     switch (m_type->dereference ()->get_size ())
       {
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 03fa1160cf0..61de2e1dcd4 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1360,6 +1360,7 @@ public:
     m_name (name)
   {
     m_initializer = NULL;
+    m_initializer_value = NULL;
     m_initializer_num_bytes = 0;
   }
   ~global ()
@@ -1386,6 +1387,12 @@ public:
     m_initializer_num_bytes = num_bytes;
   }
 
+  void
+  set_initializer_value (rvalue* value)
+  {
+    m_initializer_value = value;
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1400,6 +1407,7 @@ private:
   enum gcc_jit_global_kind m_kind;
   string *m_name;
   void *m_initializer;
+  rvalue *m_initializer_value;
   size_t m_initializer_num_bytes;
 };
 
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 7fa948007ad..b7fd4d9bebb 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -269,6 +269,17 @@ struct gcc_jit_extended_asm : public gcc::jit::recording::extended_asm
       }								\
   JIT_END_STMT
 
+#define RETURN_IF_FAIL_PRINTF5(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, \
+			       A4) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,			\
+		   __func__, (A0), (A1), (A2), (A3), (A4));		\
+	return;							\
+      }								\
+  JIT_END_STMT
+
 /* Check that BLOCK is non-NULL, and that it's OK to add statements to
    it.  This will fail if BLOCK has already been terminated by some
    kind of jump or a return.  */
@@ -1161,6 +1172,38 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
   return global;
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::global::set_initializer_value method, in
+   jit-recording.c.  */
+
+void
+gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,
+				gcc_jit_rvalue *value)
+{
+  RETURN_IF_FAIL (global, NULL, NULL, "NULL global");
+  RETURN_IF_FAIL (value, NULL, NULL, "NULL value");
+  RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL,
+			       "lvalue \"%s\" not a global",
+			       global->get_debug_string ());
+
+      RETURN_IF_FAIL_PRINTF5 (
+	compatible_types (global->get_type (),
+			  value->get_type ()),
+	NULL, NULL,
+	"mismatching types for global \"%s\":"
+	" assignment to global %s (type: %s) from %s (type: %s)",
+	global->get_debug_string (),
+	global->get_debug_string (),
+	global->get_type ()->get_debug_string (),
+	value->get_debug_string (),
+	value->get_type ()->get_debug_string ());
+
+  reinterpret_cast <gcc::jit::recording::global *> (global)
+    ->set_initializer_value (value);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, this calls the trivial
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 5c722c2c57f..98762d05271 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -810,6 +810,19 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
 				const void *blob,
 				size_t num_bytes);
 
+#define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer_value
+
+/* Set an initial value for a global, which must be a constant.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_19; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer_value
+*/
+
+extern void
+gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,
+				gcc_jit_rvalue *value);
+
 /* Upcasting.  */
 extern gcc_jit_object *
 gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 337ea6c7fe4..a0e72c925d0 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -205,3 +205,17 @@ LIBGCCJIT_ABI_15 {
     gcc_jit_extended_asm_add_clobber;
     gcc_jit_context_add_top_level_asm;
 } LIBGCCJIT_ABI_14;
+
+LIBGCCJIT_ABI_16 {
+} LIBGCCJIT_ABI_15;
+
+LIBGCCJIT_ABI_17 {
+} LIBGCCJIT_ABI_16;
+
+LIBGCCJIT_ABI_18 {
+} LIBGCCJIT_ABI_17;
+
+LIBGCCJIT_ABI_19 {
+  global:
+    gcc_jit_global_set_initializer_value;
+} LIBGCCJIT_ABI_18;
diff --git a/gcc/testsuite/jit.dg/test-global-set-initializer.c b/gcc/testsuite/jit.dg/test-global-set-initializer.c
index d38aba7d73f..418ed7dcf3f 100644
--- a/gcc/testsuite/jit.dg/test-global-set-initializer.c
+++ b/gcc/testsuite/jit.dg/test-global-set-initializer.c
@@ -21,6 +21,7 @@ create_code (gcc_jit_context *ctxt, void *user_data)
      signed char bin_blob1[] = { 0xc, 0xa, 0xf, 0xf, 0xe };
      unsigned bin_blob2[] = { 0x3, 0x2, 0x1, 0x0, 0x1, 0x2, 0x3 };
      unsigned char bin_blob3[4096]...
+     unsigned int integer = 42;
   */
   gcc_jit_type *unsigned_char_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
@@ -56,6 +57,16 @@ create_code (gcc_jit_context *ctxt, void *user_data)
 				      sizeof (test_blob3)),
       "bin_blob3");
   gcc_jit_global_set_initializer (glob, test_blob3, sizeof (test_blob3));
+
+  gcc_jit_rvalue *forty_two = gcc_jit_context_new_rvalue_from_int (
+      ctxt, unsigned_type, 42);
+
+  glob =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED,
+      unsigned_type,
+      "integer");
+  gcc_jit_global_set_initializer_value (glob, forty_two);
 }
 
 void
@@ -75,4 +86,8 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
   CHECK_NON_NULL (glob);
   CHECK_VALUE (memcmp (test_blob3, glob, sizeof (test_blob3)), 0);
 
+  glob = gcc_jit_result_get_global (result, "integer");
+  CHECK_NON_NULL (glob);
+  int *value = glob;
+  CHECK_VALUE (*value, 42);
 }
-- 
2.31.1


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

* Re: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-05-21  1:27 [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089] Antoni Boucher
@ 2021-06-11 20:44 ` Antoni Boucher
  2021-11-23  2:01   ` Antoni Boucher
  0 siblings, 1 reply; 12+ messages in thread
From: Antoni Boucher @ 2021-06-11 20:44 UTC (permalink / raw)
  To: David Malcolm; +Cc: jit, gcc-patches

David: this one wasn't reviewed yet by you, so you can review it.

Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> Hi.
> 
> I made this patch to set an arbitrary value to a global variable.
> 
> This patch suffers from the same issue as inline assembly
> (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> segfaults if the `rvalue` is created after the global variable.
> It seems to be a design issue so I'm not sure what would be the fix
> for
> it and having it fixed would allow me to test this new function much
> more and see if things are missing (i.e. it might require a way to
> create a constant struct).
> See the link above for an explanation of this issue.
> 
> Thanks for the review.



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

* Re: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-06-11 20:44 ` Antoni Boucher
@ 2021-11-23  2:01   ` Antoni Boucher
  2021-11-23 10:51     ` SV: " Petter Tomner
  0 siblings, 1 reply; 12+ messages in thread
From: Antoni Boucher @ 2021-11-23  2:01 UTC (permalink / raw)
  To: David Malcolm; +Cc: jit, gcc-patches

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

Hi David!

I updated the patch to allow initializing global variables with values
of type array or struct.

I also fixed the bug I was talking in my previous message by using the
following workaround: I create a new memento for the action of setting
the global variable initial value and as such, both the global variable
and the initial value are bound to exist when setting the global
variable initializer.
Is that workaround good enough?
(I guess that workaround could be used to fix the same issue that we
have for inline assembly.)

Thanks for the review!

Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> David: this one wasn't reviewed yet by you, so you can review it.
> 
> Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > Hi.
> > 
> > I made this patch to set an arbitrary value to a global variable.
> > 
> > This patch suffers from the same issue as inline assembly
> > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > segfaults if the `rvalue` is created after the global variable.
> > It seems to be a design issue so I'm not sure what would be the fix
> > for
> > it and having it fixed would allow me to test this new function
> > much
> > more and see if things are missing (i.e. it might require a way to
> > create a constant struct).
> > See the link above for an explanation of this issue.
> > 
> > Thanks for the review.
> 


[-- Attachment #2: 0001-libgccjit-Add-function-to-set-the-initial-value-of-a.patch --]
[-- Type: text/x-patch, Size: 42876 bytes --]

From a095291f43ca8348b6c84f94a598895969d94d1b Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Sat, 25 Sep 2021 16:37:47 -0400
Subject: [PATCH] libgccjit: Add function to set the initial value of a global
 variable [PR96089]

2021-11-22  Antoni Boucher  <bouanto@zoho.com>

    gcc/jit/
            PR target/96089
            * docs/topics/compatibility.rst (LIBGCCJIT_ABI_21): New ABI
            tag.
            * docs/topics/expressions.rst: Add documentation for the
            function gcc_jit_global_set_initializer_value,
            gcc_jit_context_new_rvalue_from_array,
            and gcc_jit_context_new_rvalue_from_struct.
            * jit-common.h: Add missing reference to array_type in class
            hierarchy.
            * jit-playback.c: New functions (new_global_with_value,
            set_global_initial_value, new_rvalue_from_struct, new_rvalue_from_array).
            * jit-playback.h: New functions (new_global_with_value,
            set_global_initial_value, new_rvalue_from_struct, new_rvalue_from_array).
            * jit-recording.c: Add support for setting a value to a
            global variable and new methods
            (global_initializer::write_reproducer,
            global_initializer::make_debug_string,
            global_initializer::write_to_dump,
            global_initializer::replay_into,
            context::new_global_value_initializer,
            memento_of_new_rvalue_from_struct::write_reproducer,
            memento_of_new_rvalue_from_struct::make_debug_string,
            memento_of_new_rvalue_from_struct::visit_children,
            memento_of_new_rvalue_from_struct::replay_into,
            memento_of_new_rvalue_from_struct::
              memento_of_new_rvalue_from_struct,
            context::new_rvalue_from_struct,
            memento_of_new_rvalue_from_array::write_reproducer,
            memento_of_new_rvalue_from_array::make_debug_string,
            memento_of_new_rvalue_from_array::visit_children,
            memento_of_new_rvalue_from_array::replay_into,
            memento_of_new_rvalue_from_array::
              memento_of_new_rvalue_from_array,
            new_rvalue_from_array).
            * jit-recording.h: New functions (set_initializer_value,
            new_global_value_initializer, new_rvalue_from_struct, new_rvalue_from_array,
            get_kind),
            new field m_initializer_value and new classes (global_initializer,
            memento_of_new_rvalue_from_struct, memento_of_new_rvalue_from_array).
            * libgccjit.c: New macro RETURN_IF_FAIL_PRINTF5 and new
            functions (gcc_jit_global_set_initializer_value,
            gcc_jit_context_new_rvalue_from_struct,
            gcc_jit_context_new_rvalue_from_array).
            * libgccjit.h: New functions (gcc_jit_global_set_initializer_value,
            gcc_jit_context_new_rvalue_from_struct,
            gcc_jit_context_new_rvalue_from_array).
            * libgccjit.map (LIBGCCJIT_ABI_21): New ABI tag.

    gcc/testsuite/
            PR target/96089
            * jit.dg/test-global-set-initializer.c: Add test for the new
            function (gcc_jit_global_set_initializer_value).
            * jit.dg/test-error-imported-global-initializer.c: Add test
            for error checking in setting a value to a global variable.
---
 gcc/jit/docs/topics/compatibility.rst         |  13 +
 gcc/jit/docs/topics/expressions.rst           |  62 ++++
 gcc/jit/jit-common.h                          |   1 +
 gcc/jit/jit-playback.c                        |  72 +++++
 gcc/jit/jit-playback.h                        |  21 ++
 gcc/jit/jit-recording.c                       | 305 +++++++++++++++++-
 gcc/jit/jit-recording.h                       | 140 ++++++++
 gcc/jit/libgccjit.c                           | 161 +++++++++
 gcc/jit/libgccjit.h                           |  27 ++
 gcc/jit/libgccjit.map                         |  19 ++
 .../test-error-imported-global-initializer.c  |  40 +++
 .../jit.dg/test-global-set-initializer.c      |  81 +++++
 12 files changed, 936 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-imported-global-initializer.c

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 52ee3f860a7..f6dc0e43cad 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -284,3 +284,16 @@ entrypoints:
   * :func:`gcc_jit_struct_get_field`
 
   * :func:`gcc_jit_struct_get_field_count`
+
+.. _LIBGCCJIT_ABI_21:
+
+``LIBGCCJIT_ABI_21``
+-----------------------
+``LIBGCCJIT_ABI_21`` covers the addition of an API entrypoint to set the value
+of a global variable:
+
+  * :func:`gcc_jit_global_set_initializer_value`
+
+  * :func:`gcc_jit_context_new_rvalue_from_struct`
+
+  * :func:`gcc_jit_context_new_rvalue_from_array`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 396259ef07e..a59309f172f 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -150,6 +150,54 @@ Vector expressions
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
 
+Array expressions
+******************
+
+.. function:: gcc_jit_rvalue * \
+              gcc_jit_context_new_rvalue_from_array (gcc_jit_context *ctxt, \
+                                                     gcc_jit_location *loc, \
+                                                     gcc_jit_type *array_type, \
+                                                     size_t num_elements, \
+                                                     gcc_jit_rvalue **elements)
+
+   Build an array rvalue from an array of elements.
+
+   "type" should be an array type, created using
+   :func:`gcc_jit_context_new_array_type`.
+
+   "num_elements" should match that of the array type.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_21`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_GLOBAL_INITIALIZER_VALUE
+
+Struct expressions
+******************
+
+.. function:: gcc_jit_rvalue * \
+              gcc_jit_context_new_rvalue_from_struct (gcc_jit_context *ctxt, \
+                                                      gcc_jit_location *loc, \
+                                                      gcc_jit_struct *struct_type, \
+                                                      size_t num_fields, \
+                                                      gcc_jit_rvalue **fields)
+
+   Build a struct rvalue from an array of fields.
+
+   "struct_type" should be a struct type, created using
+   :func:`gcc_jit_context_new_struct_type`.
+
+   "num_fields" should match that the number of fields in the struct type.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_21`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_GLOBAL_INITIALIZER_VALUE
+
 Unary Operations
 ****************
 
@@ -603,6 +651,20 @@ Global variables
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
+.. function:: void
+              gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,\
+                                                    gcc_jit_rvalue *value)
+
+   Set an initializer for ``global`` using the specified constant value.
+   ``global`` must be the same type as ``value``.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_21`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_GLOBAL_INITIALIZER_VALUE
+
 Working with pointers, structs and unions
 -----------------------------------------
 
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index f88e6755b00..2898db7dd75 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -117,6 +117,7 @@ namespace recording {
       class compound_type;
         class struct_;
 	class union_;
+      class array_type;
       class vector_type;
     class field;
       class bitfield;
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 59399dee251..3e046cba62c 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -667,6 +667,38 @@ new_global_initialized (location *loc,
   return global_finalize_lvalue (inner);
 }
 
+playback::lvalue *
+playback::context::
+new_global_with_value (location *loc,
+		       enum gcc_jit_global_kind kind,
+		       type *type,
+		       playback::rvalue *value,
+		       const char *name)
+{
+  tree inner = global_new_decl (loc, kind, type, name);
+
+  tree initial = value->as_tree ();
+  gcc_assert (TREE_CONSTANT (initial));
+  DECL_INITIAL (inner) = initial;
+
+  return global_finalize_lvalue (inner);
+}
+
+void
+playback::context::
+set_global_initial_value (playback::lvalue *global,
+			  playback::rvalue *value)
+{
+  tree initial = value->as_tree ();
+  if (!TREE_CONSTANT (initial))
+  {
+    add_error (NULL, "initial value for global is not a constant");
+    debug_tree (initial);
+    gcc_assert (TREE_CONSTANT (initial));
+  }
+  DECL_INITIAL (global->as_tree ()) = initial;
+}
+
 /* Implementation of the various
       gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
    methods.
@@ -817,6 +849,46 @@ playback::context::new_rvalue_from_vector (location *,
   return new rvalue (this, t_ctor);
 }
 
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   struct.  */
+
+playback::rvalue *
+playback::context::new_rvalue_from_struct (location *,
+					   type *type,
+					   const auto_vec<rvalue *> &fields)
+{
+  vec<constructor_elt, va_gc> *v;
+  vec_alloc (v, fields.length ());
+  tree field_decl = TYPE_FIELDS (type->as_tree ());
+  for (unsigned i = 0; i < fields.length (); ++i)
+  {
+    CONSTRUCTOR_APPEND_ELT (v, field_decl, fields[i]->as_tree ());
+    field_decl = TREE_CHAIN (field_decl);
+  }
+
+  tree t_ctor = build_constructor (type->as_tree (), v);
+  return new rvalue (this, t_ctor);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   array.  */
+
+playback::rvalue *
+playback::context::new_rvalue_from_array (location *,
+					  type *type,
+					  const auto_vec<rvalue *> &elements)
+{
+  vec<constructor_elt, va_gc> *v;
+  vec_alloc (v, elements.length ());
+  for (unsigned i = 0; i < elements.length (); ++i)
+  {
+    tree index = build_int_cst (long_unsigned_type_node, i);
+    CONSTRUCTOR_APPEND_ELT (v, index, elements[i]->as_tree ());
+  }
+  tree t_ctor = build_constructor (type->as_tree (), v);
+  return new rvalue (this, t_ctor);
+}
+
 /* Coerce a tree expression into a boolean tree expression.  */
 
 tree
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index f670c9e81df..e4c1816dbaf 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -120,6 +120,17 @@ public:
                           const void *initializer,
                           const char *name);
 
+  lvalue*
+  new_global_with_value (location *loc,
+			 enum gcc_jit_global_kind kind,
+			 type *type,
+			 rvalue *value,
+			 const char *name);
+
+  void
+  set_global_initial_value (playback::lvalue *global,
+			    playback::rvalue *value);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
@@ -133,6 +144,16 @@ public:
 			  type *type,
 			  const auto_vec<rvalue *> &elements);
 
+  rvalue *
+  new_rvalue_from_struct (location *loc,
+			  type *type,
+			  const auto_vec<rvalue *> &fields);
+
+  rvalue *
+  new_rvalue_from_array (location *loc,
+			 type *type,
+			 const auto_vec<rvalue *> &elements);
+
   rvalue *
   new_unary_op (location *loc,
 		enum gcc_jit_unary_op op,
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 117ff70114c..21813f497cb 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1062,6 +1062,21 @@ recording::context::new_global (recording::location *loc,
   return result;
 }
 
+/* Create a memento instance to initialize a global variable and add it to this
+ * context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_global_set_initializer_value.  */
+
+void
+recording::context::new_global_value_initializer (recording::lvalue *global,
+				recording::rvalue *value)
+{
+  recording::global_initializer *result =
+    new recording::global_initializer (global, value);
+  record (result);
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1077,6 +1092,40 @@ recording::context::new_string_literal (const char *value)
   return result;
 }
 
+/* Create a recording::memento_of_new_rvalue_from_struct instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_struct.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_struct (location *loc,
+					    struct_ *type,
+					    rvalue **fields)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_struct (this, loc, type, fields);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_array instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_array.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_array (location *loc,
+					   array_type *type,
+					   rvalue **elements)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_array (this, loc, type, elements);
+  record (result);
+  return result;
+}
+
 /* Create a recording::memento_of_new_rvalue_from_vector instance and add it
    to this context's list of mementos.
 
@@ -4547,20 +4596,34 @@ recording::block::dump_edges_to_dot (pretty_printer *pp)
 void
 recording::global::replay_into (replayer *r)
 {
-  set_playback_obj (
-    m_initializer
-    ? r->new_global_initialized (playback_location (r, m_loc),
+  playback::lvalue *global;
+  if (m_initializer)
+  {
+    global = r->new_global_initialized (playback_location (r, m_loc),
 				 m_kind,
 				 m_type->playback_type (),
 				 m_type->dereference ()->get_size (),
 				 m_initializer_num_bytes
 				 / m_type->dereference ()->get_size (),
 				 m_initializer,
-				 playback_string (m_name))
-    : r->new_global (playback_location (r, m_loc),
+				 playback_string (m_name));
+  }
+  else if (m_initializer_value)
+  {
+    global = r->new_global_with_value (playback_location (r, m_loc),
+				 m_kind,
+				 m_type->playback_type (),
+				 m_initializer_value->playback_rvalue (),
+				 playback_string (m_name));
+  }
+  else
+  {
+    global = r->new_global (playback_location (r, m_loc),
 		     m_kind,
 		     m_type->playback_type (),
-		     playback_string (m_name)));
+		     playback_string (m_name));
+  }
+  set_playback_obj (global);
 }
 
 /* Override the default implementation of
@@ -4697,6 +4760,56 @@ recording::global::write_reproducer (reproducer &r)
       }
 }
 
+/* The implementation of class gcc::jit::recording::global_initializer.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::global_initializer.  */
+
+void
+recording::global_initializer::replay_into (replayer *r)
+{
+  r->set_global_initial_value (m_global->playback_lvalue (),
+    m_value->playback_rvalue ());
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for globals.
+   This will be of the form:
+
+        GLOBAL = INITIALIZER;
+
+   These are written to the top of the dump by
+   recording::context::dump_to_file.  */
+
+void
+recording::global_initializer::write_to_dump (dump &d)
+{
+  d.write ("  %s = %s;\n",
+	  m_global->get_debug_string (),
+	  m_value->get_debug_string ());
+}
+
+recording::string *
+recording::global_initializer::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+				"%s = %s",
+				m_global->get_debug_string (),
+				m_value->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for global
+   initializers.  */
+
+void
+recording::global_initializer::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_global_set_initializer_value (%s, /* gcc_jit_lvalue *global */\n"
+    "                                         %s); /* gcc_jit_rvalue *value */\n",
+    r.get_identifier_as_lvalue (m_global),
+    r.get_identifier_as_rvalue (m_value));
+}
+
 /* The implementation of the various const-handling classes:
    gcc::jit::recording::memento_of_new_rvalue_from_const <HOST_TYPE>.  */
 
@@ -5070,6 +5183,186 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
 	   elements_id);
 }
 
+/* The implementation of class
+   gcc::jit::recording::memento_of_new_rvalue_from_struct.  */
+
+/* The constructor for
+   gcc::jit::recording::memento_of_new_rvalue_from_struct.  */
+
+recording::memento_of_new_rvalue_from_struct::
+memento_of_new_rvalue_from_struct (context *ctxt,
+				   location *loc,
+				   struct_ *type,
+				   rvalue **fields)
+: rvalue (ctxt, loc, type),
+  m_struct_type (type),
+  m_fields ()
+{
+  for (int i = 0; i < type->get_fields ()->length (); i++)
+    m_fields.safe_push (fields[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_struct.  */
+
+void
+recording::memento_of_new_rvalue_from_struct::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_fields;
+  playback_fields.create (m_fields.length ());
+  for (unsigned i = 0; i< m_fields.length (); i++)
+    playback_fields.safe_push (m_fields[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_rvalue_from_struct (playback_location (r, m_loc),
+					       m_type->playback_type (),
+					       playback_fields));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::memento_of_new_rvalue_from_struct.  */
+
+void
+recording::memento_of_new_rvalue_from_struct::visit_children (rvalue_visitor *v)
+{
+  for (unsigned i = 0; i< m_fields.length (); i++)
+    v->visit (m_fields[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   vectors.  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_struct::make_debug_string ()
+{
+  comma_separated_string fields (m_fields, get_precedence ());
+
+  /* Now build a string.  */
+  string *result = string::from_printf (m_ctxt,
+					"{%s}",
+					fields.as_char_ptr ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   vectors.  */
+
+void
+recording::memento_of_new_rvalue_from_struct::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "struct");
+  const char *fields_id = r.make_tmp_identifier ("fields_for_", this);
+  r.write ("  gcc_jit_rvalue *%s[%i] = {\n",
+	   fields_id,
+	   m_fields.length ());
+  for (unsigned i = 0; i< m_fields.length (); i++)
+    r.write ("    %s,\n", r.get_identifier_as_rvalue (m_fields[i]));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_rvalue_from_struct (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                            %s, /* gcc_jit_location *loc */\n"
+	   "                                            %s, /* gcc_jit_struct *struct_type */\n"
+	   "                                            %i, /* size_t num_fields  */ \n"
+	   "                                            %s); /* gcc_jit_rvalue **fields*/\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_struct_type),
+	   m_fields.length (),
+	   fields_id);
+}
+
+/* The implementation of class
+   gcc::jit::recording::memento_of_new_rvalue_from_array.  */
+
+/* The constructor for
+   gcc::jit::recording::memento_of_new_rvalue_from_array.  */
+
+recording::memento_of_new_rvalue_from_array::
+memento_of_new_rvalue_from_array (context *ctxt,
+				  location *loc,
+				  array_type *type,
+				  rvalue **elements)
+: rvalue (ctxt, loc, type),
+  m_array_type (type),
+  m_elements ()
+{
+  for (int i = 0; i < type->num_elements (); i++)
+    m_elements.safe_push (elements[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_array.  */
+
+void
+recording::memento_of_new_rvalue_from_array::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_elements;
+  playback_elements.create (m_elements.length ());
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    playback_elements.safe_push (m_elements[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_rvalue_from_array (playback_location (r, m_loc),
+					      m_type->playback_type (),
+					      playback_elements));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::memento_of_new_rvalue_from_array.  */
+
+void
+recording::memento_of_new_rvalue_from_array::visit_children (rvalue_visitor *v)
+{
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    v->visit (m_elements[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   vectors.  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_array::make_debug_string ()
+{
+  comma_separated_string elements (m_elements, get_precedence ());
+
+  /* Now build a string.  */
+  string *result = string::from_printf (m_ctxt,
+					"{%s}",
+					elements.as_char_ptr ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   vectors.  */
+
+void
+recording::memento_of_new_rvalue_from_array::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "array");
+  const char *elements_id = r.make_tmp_identifier ("elements_for_", this);
+  r.write ("  gcc_jit_rvalue *%s[%i] = {\n",
+	   elements_id,
+	   m_elements.length ());
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    r.write ("    %s,\n", r.get_identifier_as_rvalue (m_elements[i]));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_rvalue_from_array (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                           %s, /* gcc_jit_location *loc */\n"
+	   "                                           %s, /* gcc_jit_type *array_type */\n"
+	   "                                           %i, /* size_t num_elements  */ \n"
+	   "                                           %s); /* gcc_jit_rvalue **elements*/\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_array_type),
+	   m_elements.length (),
+	   elements_id);
+}
+
 /* The implementation of class gcc::jit::recording::unary_op.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 4a994fe7094..3ab2373cb9e 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -149,6 +149,10 @@ public:
 	      type *type,
 	      const char *name);
 
+  void
+  new_global_value_initializer (recording::lvalue *global,
+				recording::rvalue *value);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
@@ -162,6 +166,16 @@ public:
 			  vector_type *type,
 			  rvalue **elements);
 
+  rvalue *
+  new_rvalue_from_struct (location *loc,
+			  struct_ *type,
+			  rvalue **fields);
+
+  rvalue *
+  new_rvalue_from_array (location *loc,
+			 array_type *type,
+			 rvalue **elements);
+
   rvalue *
   new_unary_op (location *loc,
 		enum gcc_jit_unary_op op,
@@ -522,6 +536,7 @@ public:
   virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
   virtual struct_ *dyn_cast_struct () { return NULL; }
   virtual vector_type *dyn_cast_vector_type () { return NULL; }
+  virtual array_type *dyn_cast_array_type () { return NULL; }
 
   /* Is it typesafe to copy to this type from rtype?  */
   virtual bool accepts_writes_from (type *rtype)
@@ -773,6 +788,8 @@ class array_type : public type
 
   type *dereference () FINAL OVERRIDE;
 
+  array_type *dyn_cast_array_type () FINAL OVERRIDE { return this; }
+
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
@@ -1134,6 +1151,11 @@ public:
   const char *access_as_rvalue (reproducer &r) OVERRIDE;
   virtual const char *access_as_lvalue (reproducer &r);
   virtual bool is_global () const { return false; }
+
+  bool is_constant () const FINAL OVERRIDE
+  {
+      return is_global ();
+  }
 };
 
 class param : public lvalue
@@ -1367,6 +1389,7 @@ public:
     m_name (name)
   {
     m_initializer = NULL;
+    m_initializer_value = NULL;
     m_initializer_num_bytes = 0;
   }
   ~global ()
@@ -1393,6 +1416,14 @@ public:
     m_initializer_num_bytes = num_bytes;
   }
 
+  void
+  set_initializer_value (rvalue* value)
+  {
+    m_initializer_value = value;
+  }
+
+  enum gcc_jit_global_kind get_kind () const { return m_kind; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1407,9 +1438,30 @@ private:
   enum gcc_jit_global_kind m_kind;
   string *m_name;
   void *m_initializer;
+  rvalue *m_initializer_value;
   size_t m_initializer_num_bytes;
 };
 
+class global_initializer : public memento
+{
+public:
+  void write_to_dump (dump &d) FINAL OVERRIDE;
+  void replay_into (replayer *) FINAL OVERRIDE;
+
+  global_initializer (lvalue *global, rvalue *value)
+  : memento (global->m_ctxt),
+    m_global (global),
+    m_value (value) {}
+
+private:
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  string * make_debug_string () FINAL OVERRIDE;
+
+private:
+  lvalue *m_global;
+  rvalue *m_value;
+};
+
 template <typename HOST_TYPE>
 class memento_of_new_rvalue_from_const : public rvalue
 {
@@ -1454,6 +1506,8 @@ public:
 
   void visit_children (rvalue_visitor *) FINAL OVERRIDE {}
 
+  virtual bool is_constant () const { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1491,6 +1545,78 @@ private:
   auto_vec<rvalue *> m_elements;
 };
 
+class memento_of_new_rvalue_from_array : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_array (context *ctxt,
+				    location *loc,
+				    array_type *type,
+				    rvalue **elements);
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+  virtual bool is_constant () const {
+      for (rvalue *element : m_elements)
+      {
+	if (!element->is_constant ())
+	{
+	  return false;
+	}
+      }
+      return true;
+  }
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_PRIMARY;
+  }
+
+private:
+  array_type *m_array_type;
+  auto_vec<rvalue *> m_elements;
+};
+
+class memento_of_new_rvalue_from_struct : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_struct (context *ctxt,
+				     location *loc,
+				     struct_ *type,
+				     rvalue **fields);
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+  virtual bool is_constant () const {
+      for (rvalue *field : m_fields)
+      {
+	if (!field->is_constant ())
+	{
+	  return false;
+	}
+      }
+      return true;
+  }
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_PRIMARY;
+  }
+
+private:
+  struct_ *m_struct_type;
+  auto_vec<rvalue *> m_fields;
+};
+
 class unary_op : public rvalue
 {
 public:
@@ -1538,6 +1664,10 @@ public:
 
   void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
 
+  virtual bool is_constant () const {
+      return m_a->is_constant () && m_b->is_constant ();
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1592,6 +1722,10 @@ public:
 
   void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
 
+  virtual bool is_constant () const {
+      return m_rvalue->is_constant ();
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1830,6 +1964,10 @@ public:
 
   void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
 
+  virtual bool is_constant () const {
+      return m_lvalue->is_constant ();
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1856,6 +1994,8 @@ public:
 
   void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
 
+  virtual bool is_constant () const { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index c744b634f4b..f48636c844f 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -277,6 +277,17 @@ struct gcc_jit_extended_asm : public gcc::jit::recording::extended_asm
       }								\
   JIT_END_STMT
 
+#define RETURN_IF_FAIL_PRINTF5(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, \
+			       A4) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,			\
+		   __func__, (A0), (A1), (A2), (A3), (A4));		\
+	return;							\
+      }								\
+  JIT_END_STMT
+
 /* Check that BLOCK is non-NULL, and that it's OK to add statements to
    it.  This will fail if BLOCK has already been terminated by some
    kind of jump or a return.  */
@@ -1425,6 +1436,48 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
   return global;
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::global::set_initializer_value method, in
+   jit-recording.c.  */
+
+void
+gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,
+				      gcc_jit_rvalue *value)
+{
+  RETURN_IF_FAIL (global, NULL, NULL, "NULL global");
+  RETURN_IF_FAIL (value, NULL, NULL, "NULL value");
+  RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL,
+			       "lvalue \"%s\" not a global",
+			       global->get_debug_string ());
+
+  gcc::jit::recording::global *global_variable =
+    reinterpret_cast <gcc::jit::recording::global *> (global);
+  RETURN_IF_FAIL_PRINTF1 (global_variable->get_kind ()
+    != GCC_JIT_GLOBAL_IMPORTED, global->get_context (), NULL,
+    "global \"%s\" cannot be of imported kind",
+    global->get_debug_string ());
+
+      RETURN_IF_FAIL_PRINTF5 (
+	compatible_types (global->get_type (),
+			  value->get_type ()),
+	NULL, NULL,
+	"mismatching types for global \"%s\":"
+	" assignment to global %s (type: %s) from %s (type: %s)",
+	global->get_debug_string (),
+	global->get_debug_string (),
+	global->get_type ()->get_debug_string (),
+	value->get_debug_string (),
+	value->get_type ()->get_debug_string ());
+
+  RETURN_IF_FAIL_PRINTF1 (value->is_constant (), NULL, NULL,
+			       "rvalue \"%s\" not a constant",
+			       value->get_debug_string ());
+
+  global->get_context ()->new_global_value_initializer (global, value);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, this calls the trivial
@@ -1647,6 +1700,114 @@ gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
   return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_rvalue_from_struct method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_struct (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_struct *struct_type,
+					size_t num_fields,
+					gcc_jit_rvalue **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (struct_type, ctxt, loc, "NULL struct_type");
+
+  /* "num_fields" must match.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    num_fields == (size_t) struct_type->get_fields ()->length (), ctxt, loc,
+    "num_fields != %d", struct_type->get_fields ()->length ());
+
+  /* "fields must be non-NULL.  */
+  RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields");
+
+  /* Each of "fields" must be non-NULL and of the correct type.  */
+  for (size_t i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL_PRINTF1 (
+	fields[i], ctxt, loc, "NULL fields[%zi]", i);
+      gcc::jit::recording::type *field_type
+	= struct_type->get_fields ()->get_field (i)->get_type ();
+      RETURN_NULL_IF_FAIL_PRINTF4 (
+	compatible_types (field_type,
+			  fields[i]->get_type ()),
+	ctxt, loc,
+	"mismatching type for field[%zi] (expected type: %s): %s (type: %s)",
+	i,
+	field_type->get_debug_string (),
+	fields[i]->get_debug_string (),
+	fields[i]->get_type ()->get_debug_string ());
+      RETURN_NULL_IF_FAIL_PRINTF2 (fields[i]->is_constant (), ctxt, NULL,
+				   "fields[%ld] is not a constant: %s", i,
+				   fields[i]->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_struct (loc, struct_type,
+    (gcc::jit::recording::rvalue **)fields);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_rvalue_from_array method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_array (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_type *array_type,
+					size_t num_elements,
+					gcc_jit_rvalue **elements)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (array_type, ctxt, loc, "NULL type");
+
+  /* "array_type" must be an array type.  */
+  gcc::jit::recording::array_type *as_array_type
+    = array_type->dyn_cast_array_type ();
+  RETURN_NULL_IF_FAIL_PRINTF1 (as_array_type, ctxt, loc,
+			       "%s is not an array type",
+			       array_type->get_debug_string ());
+
+  /* "num_elements" must match.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    num_elements == (size_t) as_array_type->num_elements (), ctxt, loc,
+    "num_elements != %d", as_array_type->num_elements ());
+
+  /* "elements must be non-NULL.  */
+  RETURN_NULL_IF_FAIL (elements, ctxt, loc, "NULL elements");
+
+  /* Each of "elements" must be non-NULL and of the correct type.  */
+  gcc::jit::recording::type *element_type
+    = as_array_type->is_array ();
+  for (size_t i = 0; i < num_elements; i++)
+    {
+      RETURN_NULL_IF_FAIL_PRINTF1 (
+	elements[i], ctxt, loc, "NULL elements[%zi]", i);
+      RETURN_NULL_IF_FAIL_PRINTF4 (
+	compatible_types (element_type,
+			  elements[i]->get_type ()),
+	ctxt, loc,
+	"mismatching type for array[%zi] (expected type: %s): %s (type: %s)",
+	i,
+	element_type->get_debug_string (),
+	elements[i]->get_debug_string (),
+	elements[i]->get_type ()->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_array (loc, as_array_type,
+    (gcc::jit::recording::rvalue **)elements);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a1c9436c545..ee959d83c67 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -827,6 +827,19 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
 				const void *blob,
 				size_t num_bytes);
 
+#define LIBGCCJIT_HAVE_GLOBAL_INITIALIZER_VALUE
+
+/* Set an initial value for a global, which must be a constant.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_21; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_GLOBAL_INITIALIZER_VALUE
+*/
+
+extern void
+gcc_jit_global_set_initializer_value (gcc_jit_lvalue *global,
+				      gcc_jit_rvalue *value);
+
 /* Upcasting.  */
 extern gcc_jit_object *
 gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
@@ -880,6 +893,20 @@ extern gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 				    const char *value);
 
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_struct (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_struct *struct_type,
+					size_t num_fields,
+					gcc_jit_rvalue **fields);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_array (gcc_jit_context *ctxt,
+					gcc_jit_location *loc,
+					gcc_jit_type *array_type,
+					size_t num_elements,
+					gcc_jit_rvalue **elements);
+
 enum gcc_jit_unary_op
 {
   /* Negate an arithmetic value; analogous to:
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 64e790949e8..84059261845 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -226,3 +226,22 @@ LIBGCCJIT_ABI_16 {
     gcc_jit_type_is_struct;
     gcc_jit_struct_get_field_count;
 } LIBGCCJIT_ABI_15;
+
+LIBGCCJIT_ABI_17 {
+} LIBGCCJIT_ABI_16;
+
+LIBGCCJIT_ABI_18 {
+} LIBGCCJIT_ABI_17;
+
+LIBGCCJIT_ABI_19 {
+} LIBGCCJIT_ABI_18;
+
+LIBGCCJIT_ABI_20 {
+} LIBGCCJIT_ABI_19;
+
+LIBGCCJIT_ABI_21 {
+  global:
+    gcc_jit_global_set_initializer_value;
+    gcc_jit_context_new_rvalue_from_struct;
+    gcc_jit_context_new_rvalue_from_array;
+} LIBGCCJIT_ABI_20;
diff --git a/gcc/testsuite/jit.dg/test-error-imported-global-initializer.c b/gcc/testsuite/jit.dg/test-error-imported-global-initializer.c
new file mode 100644
index 00000000000..cfa3657e420
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-imported-global-initializer.c
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to import a global variable and set an initial value
+     and verify that the API complains about setting a value to an
+     imported variable.
+  */
+  gcc_jit_type *unsigned_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT);
+
+  gcc_jit_rvalue *forty_two = gcc_jit_context_new_rvalue_from_int (
+      ctxt, unsigned_type, 42);
+
+  gcc_jit_lvalue *glob =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_IMPORTED,
+      unsigned_type,
+      "integer");
+  gcc_jit_global_set_initializer_value (glob, forty_two);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  void *glob = gcc_jit_result_get_global (result, "integer");
+  CHECK_VALUE (glob, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_global_set_initializer_value: "
+		      "global \"integer\" cannot be of imported kind");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-global-set-initializer.c b/gcc/testsuite/jit.dg/test-global-set-initializer.c
index d38aba7d73f..2bbf72664ea 100644
--- a/gcc/testsuite/jit.dg/test-global-set-initializer.c
+++ b/gcc/testsuite/jit.dg/test-global-set-initializer.c
@@ -13,6 +13,11 @@ static signed char test_blob1[] = { 0xc, 0xa, 0xf, 0xf, 0xe };
 static unsigned test_blob2[] = { 0x3, 0x2, 0x1, 0x0, 0x1, 0x2, 0x3 };
 static unsigned char test_blob3[BIG_BLOB_SIZE];
 
+struct struct_of_integers {
+    int a;
+    int b;
+};
+
 void
 create_code (gcc_jit_context *ctxt, void *user_data)
 {
@@ -21,6 +26,13 @@ create_code (gcc_jit_context *ctxt, void *user_data)
      signed char bin_blob1[] = { 0xc, 0xa, 0xf, 0xf, 0xe };
      unsigned bin_blob2[] = { 0x3, 0x2, 0x1, 0x0, 0x1, 0x2, 0x3 };
      unsigned char bin_blob3[4096]...
+     unsigned int integer = 42;
+     unsigned int integers[] = {42, 43, 45};
+     struct struct_of_integers {
+        int a;
+        int b;
+     };
+     struct struct_of_integers integer_struct = {44, 40};
   */
   gcc_jit_type *unsigned_char_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
@@ -56,6 +68,58 @@ create_code (gcc_jit_context *ctxt, void *user_data)
 				      sizeof (test_blob3)),
       "bin_blob3");
   gcc_jit_global_set_initializer (glob, test_blob3, sizeof (test_blob3));
+
+  gcc_jit_rvalue *forty_two = gcc_jit_context_new_rvalue_from_int (
+      ctxt, unsigned_type, 42);
+
+  glob =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED,
+      unsigned_type,
+      "integer");
+  gcc_jit_global_set_initializer_value (glob, forty_two);
+
+  gcc_jit_type *array_type = gcc_jit_context_new_array_type (
+      ctxt, NULL, unsigned_type, 3);
+
+  gcc_jit_rvalue *elements[3] = {
+      forty_two,
+      gcc_jit_context_new_rvalue_from_int ( ctxt, unsigned_type, 43),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, unsigned_type, 45),
+  };
+
+  gcc_jit_rvalue *integers = gcc_jit_context_new_rvalue_from_array (
+      ctxt, NULL, array_type, 3, elements);
+
+  glob =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED,
+      array_type,
+      "integers");
+  gcc_jit_global_set_initializer_value (glob, integers);
+
+  gcc_jit_field *fields[2] = {
+      gcc_jit_context_new_field (ctxt, NULL, unsigned_type, "a"),
+      gcc_jit_context_new_field (ctxt, NULL, unsigned_type, "b"),
+  };
+
+  gcc_jit_struct *struct_type = gcc_jit_context_new_struct_type (
+      ctxt, NULL, "struct_of_integers", 2, fields);
+
+  gcc_jit_rvalue *struct_elements[2] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, unsigned_type, 44),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, unsigned_type, 40),
+  };
+
+  gcc_jit_rvalue *integer_fields = gcc_jit_context_new_rvalue_from_struct (
+      ctxt, NULL, struct_type, 2, struct_elements);
+
+  glob =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_struct_as_type (struct_type),
+      "integer_struct");
+  gcc_jit_global_set_initializer_value (glob, integer_fields);
 }
 
 void
@@ -75,4 +139,21 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
   CHECK_NON_NULL (glob);
   CHECK_VALUE (memcmp (test_blob3, glob, sizeof (test_blob3)), 0);
 
+  glob = gcc_jit_result_get_global (result, "integer");
+  CHECK_NON_NULL (glob);
+  int *value = glob;
+  CHECK_VALUE (*value, 42);
+
+  glob = gcc_jit_result_get_global (result, "integers");
+  CHECK_NON_NULL (glob);
+  int *values = glob;
+  CHECK_VALUE (values[0], 42);
+  CHECK_VALUE (values[1], 43);
+  CHECK_VALUE (values[2], 45);
+
+  glob = gcc_jit_result_get_global (result, "integer_struct");
+  CHECK_NON_NULL (glob);
+  struct struct_of_integers *struct_values = glob;
+  CHECK_VALUE (struct_values->a, 44);
+  CHECK_VALUE (struct_values->b, 40);
 }
-- 
2.26.2.7.g19db9cfb68.dirty


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

* SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-23  2:01   ` Antoni Boucher
@ 2021-11-23 10:51     ` Petter Tomner
  2021-11-23 14:10       ` Antoni Boucher
  2021-11-30  1:34       ` David Malcolm
  0 siblings, 2 replies; 12+ messages in thread
From: Petter Tomner @ 2021-11-23 10:51 UTC (permalink / raw)
  To: David Malcolm, Antoni Boucher, jit

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

Hi!

Does it work with pointers to other symbols and unions? I don't think constant symbols end
up in the .rdata section unless they are marked for that.

I did a similar patch that I just dropped in a RFC mail some time ago. (See attachment).

If I remember correctly there need to be alot of folding to not segfault deeper into gcc on
expressions that are not one literal, for e.g. pointer arithmetic.

Regards,
Petter 


Från: Gcc-patches <gcc-patches-bounces+tomner=kth.se@gcc.gnu.org> för Antoni Boucher via Gcc-patches <gcc-patches@gcc.gnu.org>
Skickat: den 23 november 2021 03:01
Till: David Malcolm
Kopia: jit@gcc.gnu.org; gcc-patches@gcc.gnu.org
Ämne: Re: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
    
Hi David!

I updated the patch to allow initializing global variables with values
of type array or struct.

I also fixed the bug I was talking in my previous message by using the
following workaround: I create a new memento for the action of setting
the global variable initial value and as such, both the global variable
and the initial value are bound to exist when setting the global
variable initializer.
Is that workaround good enough?
(I guess that workaround could be used to fix the same issue that we
have for inline assembly.)

Thanks for the review!

Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> David: this one wasn't reviewed yet by you, so you can review it.
> 
> Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > Hi.
> > 
> > I made this patch to set an arbitrary value to a global variable.
> > 
> > This patch suffers from the same issue as inline assembly
> > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > segfaults if the `rvalue` is created after the global variable.
> > It seems to be a design issue so I'm not sure what would be the fix
> > for
> > it and having it fixed would allow me to test this new function
> > much
> > more and see if things are missing (i.e. it might require a way to
> > create a constant struct).
> > See the link above for an explanation of this issue.
> > 
> > Thanks for the review.
> 

    

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

From e6850f3417bc0c35d9712e850e5274117527021c Mon Sep 17 00:00:00 2001
From: Petter Tomner <tomner@kth.se>
Date: Sun, 24 Oct 2021 21:13:44 +0200
Subject: [PATCH 3/5] Add suport for global rvalue initialization and ctors

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

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

gcc/testsuite/
	* jit.dg/test-error-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.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           |  117 ++
 gcc/jit/jit-common.h                          |    9 +
 gcc/jit/jit-playback.c                        |  267 +++-
 gcc/jit/jit-playback.h                        |   25 +-
 gcc/jit/jit-recording.c                       |  374 ++++-
 gcc/jit/jit-recording.h                       |  112 ++
 gcc/jit/libgccjit++.h                         |   44 +
 gcc/jit/libgccjit.c                           |  289 +++-
 gcc/jit/libgccjit.h                           |  107 ++
 gcc/jit/libgccjit.map                         |    4 +-
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |   14 +
 .../jit.dg/test-error-ctor-struct-too-big.c   |   86 ++
 .../test-error-ctor-struct-wrong-field-name.c |   83 ++
 .../test-error-ctor-struct-wrong-type.c       |   76 ++
 .../test-error-ctor-union-wrong-field-name.c  |   80 ++
 .../jit.dg/test-error-global-allready-init.c  |   46 +
 .../jit.dg/test-error-global-common-section.c |   54 +
 .../test-error-global-init-too-small-array.c  |   64 +
 .../jit.dg/test-error-global-lvalue-init.c    |   60 +
 .../jit.dg/test-error-global-nonconst-init.c  |   80 ++
 .../jit.dg/test-global-init-rvalue.c          | 1211 +++++++++++++++++
 gcc/testsuite/jit.dg/test-local-init-rvalue.c |  532 ++++++++
 22 files changed, 3709 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-allready-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-common-section.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
 create mode 100644 gcc/testsuite/jit.dg/test-global-init-rvalue.c
 create mode 100644 gcc/testsuite/jit.dg/test-local-init-rvalue.c

diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 30a3b9780f9..3b38cab025c 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -176,6 +176,91 @@ Simple expressions
    underlying string, so it is valid to pass in a pointer to an on-stack
    buffer.
 
+.. function:: gcc_jit_rvalue *\
+	      gcc_jit_context_new_constructor (gcc_jit_context *ctxt,\
+                                               gcc_jit_location *loc,\
+				               gcc_jit_type *type,\
+				               size_t arr_length,\
+				               gcc_jit_field **fields,\
+				               gcc_jit_rvalue **values)
+
+   Create a constructor for an array, union or struct as a rvalue.
+
+   Returns NULL on error. The two parameter arrays are copied and
+   do not have to outlive the context.
+
+   ``type`` specifies what the constructor will build.
+
+   ``arr_length`` specifies the number of elements in ``values``.
+   
+   Constructing structs
+   """"""""""""""""""""
+
+   For a struct, 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
+   and the pair need to have the same unqualified type.
+
+   A NULL value in ``values`` is a shorthand for zero initialization
+   of the corresponding field or array element.
+
+   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.
+
+   ``fields`` need to have the same length as ``values``. 
+   
+   If ``arr_length`` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+   
+
+   Constructing arrays
+   """""""""""""""""""
+   
+   For an array type, the ``fields`` parameter is ignored.
+
+   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 elements' type.
+
+   If ``arr_length`` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+
+   Constructing unions
+   """""""""""""""""""
+
+   For unions, ``arr_length`` need to be 1. There need to be one field
+   in ``fields`` and one value in ``values`` which specified which field
+   in the union to set to what value. The pair need to have the same
+   unqualified type.
+
+   The field in ``fields`` need to be one of the objects that were used
+   to create the union.
+
+   Remarks
+   """""""
+
+   The constructor rvalue can be used for assignment to locals.
+   It can be used to initialize global variables with
+   :func:`gcc_jit_global_set_initializer_rvalue`. It can also be used as a
+   temporary value for function calls and return values.
+
+   The constructor can contain nested constructors. Note that a string
+   literal rvalue can't be used to construct a char array. It need one
+   rvalue for each char.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presense using:
+
+   .. code-block:: c
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
 Vector expressions
 ******************
 
@@ -681,6 +766,38 @@ Global variables
 
       #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
+.. function:: gcc_jit_lvalue *\
+	      gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+	                                             gcc_jit_rvalue *init_value)
+
+   Set the initial value of a global with an rvalue.
+
+   The rvalue need to be a constant expression, i.e. no function calls.
+
+   The global can't have the ``kind`` :ref:`GCC_JIT_GLOBAL_IMPORTED`.
+
+   As a non-comprehensive example it is OK to do the equivalent of:
+
+   .. code-block:: c
+
+       int foo = 3 * 2; /* rvalue from gcc_jit_context_new_binary_op */
+       int arr[] = {1,2,3,4}; /* rvalue from gcc_jit_context_new_constructor */
+       int *bar = &arr[2] + 1; /* rvalue from nested "get address" of "array access" */
+       const int baz = 3; /* rvalue from gcc_jit_context_rvalue_from_int */
+       int boz = baz; /* rvalue from gcc_jit_lvalue_as_rvalue */
+
+   Use together with :ref:`gcc_jit_context_new_constructor` to
+   initialize structs, unions and arrays.
+
+   On success, returns the ``global`` parameter unchanged. Otherwise, ``NULL``.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
+   presence using:
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_CTORS
+
 Working with pointers, structs and unions
 -----------------------------------------
 
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index bc0453fba05..7c937478793 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -203,6 +203,15 @@ enum inner_bool_option
   NUM_INNER_BOOL_OPTIONS
 };
 
+/* Flags for global variables class. For when the playback of the
+   global need to know what will happen to it later. */
+enum global_var_flags
+{
+  GLOBAL_VAR_FLAGS_NONE = 0,
+  GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT = 1,
+  GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT = 2,
+};
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 1f4dc31a1c1..71f0e7283ba 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -107,6 +107,43 @@ namespace jit {
  Playback.
  **********************************************************************/
 
+/* Fold a readonly non-volatile variable with an initial constant value,
+   to that value.
+
+   Otherwise return the argument unchanged.
+
+   This fold is needed for setting a variable's DECL_INITIAL to the value
+   of a const variable. The c-frontend does this in its own special
+   fold(), so we lift this part out and do it explicitly where there is a
+   potential for variables to be used as rvalues. */
+static tree
+fold_const_var (tree node)
+{
+  /* See c_fully_fold_internal in c-fold.c and decl_constant_value_1
+     in c-typeck.c */
+  if (VAR_P (node)
+      && TREE_READONLY (node)
+      && !TREE_THIS_VOLATILE (node)
+      && DECL_INITIAL (node) != NULL_TREE
+      /* "This is invalid if initial value is not constant.
+	  If it has either a function call, a memory reference,
+	  or a variable, then re-evaluating it could give different
+	  results." */
+      && TREE_CONSTANT (DECL_INITIAL (node)))
+    {
+      tree ret = DECL_INITIAL (node);
+      /* "Avoid unwanted tree sharing between the initializer and current
+	  function's body where the tree can be modified e.g. by the
+	  gimplifier."  */
+      if (TREE_STATIC (node))
+	ret = unshare_expr (ret);
+
+      return ret;
+    }
+
+  return node;
+}
+
 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
    The TREE_TYPE is not initialized.  */
 
@@ -547,15 +584,28 @@ playback::context::
 global_new_decl (location *loc,
 		 enum gcc_jit_global_kind kind,
 		 type *type,
-		 const char *name)
+		 const char *name,
+		 enum global_var_flags flags)
 {
   gcc_assert (type);
   gcc_assert (name);
+
+  tree type_tree = type->as_tree ();
+
   tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
 			   get_identifier (name),
-			   type->as_tree ());
+			   type_tree);
+
   TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
-  DECL_COMMON (inner) = 1;
+
+
+  int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
+			      GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
+
+  /* A VAR_DECL with DECL_INITIAL will not end up in .common section */
+  if (!will_be_init)
+    DECL_COMMON (inner) = 1;
+
   switch (kind)
     {
     default:
@@ -574,6 +624,9 @@ global_new_decl (location *loc,
       break;
     }
 
+  if (TYPE_READONLY (type_tree))
+    TREE_READONLY(inner) = 1;
+
   if (loc)
     set_tree_location (inner, loc);
 
@@ -598,13 +651,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.*/
@@ -638,9 +843,10 @@ new_global_initialized (location *loc,
                         size_t element_size,
 			size_t initializer_num_elem,
 			const void *initializer,
-			const char *name)
+			const char *name,
+			enum global_var_flags flags)
 {
-  tree inner = global_new_decl (loc, kind, type, name);
+  tree inner = global_new_decl (loc, kind, type, name, flags);
 
   vec<constructor_elt, va_gc> *constructor_elements = NULL;
 
@@ -1109,7 +1315,8 @@ as_truth_value (tree expr, location *loc)
   if (loc)
     set_tree_location (typed_zero, loc);
 
-  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  expr = fold_build2_loc (UNKNOWN_LOCATION,
+    NE_EXPR, integer_type_node, expr, typed_zero);
   if (loc)
     set_tree_location (expr, loc);
 
@@ -1145,6 +1352,8 @@ new_unary_op (location *loc,
   gcc_assert (a);
 
   tree node = a->as_tree ();
+  node = fold_const_var (node);
+
   tree inner_result = NULL;
 
   switch (op)
@@ -1176,6 +1385,10 @@ new_unary_op (location *loc,
   inner_result = build1 (inner_op,
 			 result_type->as_tree (),
 			 node);
+
+  /* Try to fold */
+  inner_result = fold (inner_result);
+
   if (loc)
     set_tree_location (inner_result, loc);
 
@@ -1200,7 +1413,10 @@ new_binary_op (location *loc,
   gcc_assert (b);
 
   tree node_a = a->as_tree ();
+  node_a = fold_const_var (node_a);
+
   tree node_b = b->as_tree ();
+  node_b = fold_const_var (node_b);
 
   switch (op)
     {
@@ -1275,6 +1491,10 @@ new_binary_op (location *loc,
 			    result_type->as_tree (),
 			    node_a,
 			    node_b);
+
+  /* Try to fold the expression */
+  inner_expr = fold (inner_expr);
+
   if (loc)
     set_tree_location (inner_expr, loc);
 
@@ -1322,10 +1542,19 @@ new_comparison (location *loc,
       break;
     }
 
+  tree node_a = a->as_tree ();
+  node_a = fold_const_var (node_a);
+  tree node_b = b->as_tree ();
+  node_b = fold_const_var (node_b);
+
   tree inner_expr = build2 (inner_op,
 			    boolean_type_node,
-			    a->as_tree (),
-			    b->as_tree ());
+			    node_a,
+			    node_b);
+
+  /* Try to fold */
+  inner_expr = fold (inner_expr);
+
   if (loc)
     set_tree_location (inner_expr, loc);
   return new rvalue (this, inner_expr);
@@ -1425,6 +1654,8 @@ playback::context::build_cast (playback::location *loc,
 
      Only some kinds of cast are currently supported here.  */
   tree t_expr = expr->as_tree ();
+  t_expr = fold_const_var (t_expr);
+
   tree t_dst_type = type_->as_tree ();
   tree t_ret = NULL;
   t_ret = targetm.convert_to_type (t_dst_type, t_expr);
@@ -1507,7 +1738,10 @@ new_array_access (location *loc,
        c-family/c-common.c: pointer_int_sum
   */
   tree t_ptr = ptr->as_tree ();
+  t_ptr = fold_const_var (t_ptr);
   tree t_index = index->as_tree ();
+  t_index = fold_const_var (t_index);
+
   tree t_type_ptr = TREE_TYPE (t_ptr);
   tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
 
@@ -1515,6 +1749,7 @@ new_array_access (location *loc,
     {
       tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
 			      NULL_TREE, NULL_TREE);
+      t_result = fold (t_result);
       if (loc)
 	set_tree_location (t_result, loc);
       return new lvalue (this, t_result);
@@ -1524,12 +1759,14 @@ new_array_access (location *loc,
       /* Convert index to an offset in bytes.  */
       tree t_sizeof = size_in_bytes (t_type_star_ptr);
       t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
-      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+      tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
+	MULT_EXPR, sizetype, t_index, t_sizeof);
 
       /* Locate (ptr + offset).  */
-      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+      tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
+	POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
 
-      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
       if (loc)
 	{
 	  set_tree_location (t_sizeof, loc);
@@ -1577,7 +1814,7 @@ new_dereference (tree ptr,
   gcc_assert (ptr);
 
   tree type = TREE_TYPE (TREE_TYPE(ptr));
-  tree datum = build1 (INDIRECT_REF, type, ptr);
+  tree datum = fold_build1 (INDIRECT_REF, type, ptr);
   if (loc)
     set_tree_location (datum, loc);
   return datum;
@@ -1731,7 +1968,7 @@ get_address (location *loc)
   tree t_lvalue = as_tree ();
   tree t_thistype = TREE_TYPE (t_lvalue);
   tree t_ptrtype = build_pointer_type (t_thistype);
-  tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+  tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
   if (loc)
     get_context ()->set_tree_location (ptr, loc);
   if (mark_addressable (loc))
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index f670c9e81df..d445d7ccb95 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -109,7 +109,8 @@ public:
   new_global (location *loc,
 	      enum gcc_jit_global_kind kind,
 	      type *type,
-	      const char *name);
+	      const char *name,
+	      enum global_var_flags flags);
 
   lvalue *
   new_global_initialized (location *loc,
@@ -118,7 +119,19 @@ public:
                           size_t element_size,
                           size_t initializer_num_elem,
                           const void *initializer,
-                          const char *name);
+                          const char *name,
+			  enum global_var_flags flags);
+
+  rvalue *
+  new_ctor (location *log,
+	    type *type,
+	    const auto_vec<field*> *fields,
+	    const auto_vec<rvalue*> *rvalues);
+
+
+  void
+  global_set_init_rvalue (lvalue* variable,
+			  rvalue* init);
 
   template <typename HOST_TYPE>
   rvalue *
@@ -286,7 +299,8 @@ private:
   global_new_decl (location *loc,
                    enum gcc_jit_global_kind kind,
                    type *type,
-                   const char *name);
+		   const char *name,
+		   enum global_var_flags flags);
   lvalue *
   global_finalize_lvalue (tree inner);
 
@@ -635,7 +649,10 @@ public:
   rvalue *
   as_rvalue () { return this; }
 
-  tree as_tree () const { return m_inner; }
+  tree as_tree () const
+  {
+    return m_inner;
+  }
 
   context *get_context () const { return m_ctxt; }
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 8d34956fc67..9a5b735a40f 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1064,6 +1064,15 @@ recording::context::new_global (recording::location *loc,
   return result;
 }
 
+void
+recording::context::new_global_init_rvalue (lvalue *variable,
+					    rvalue *init)
+{
+  recording::global_init_rvalue *obj =
+    new recording::global_init_rvalue (this, variable, init);
+  record (obj);
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1096,6 +1105,46 @@ 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);
+
+  /* We need to copy fields and values into result's auto_vec:s. */
+  if (type->is_array () != NULL)
+    {
+      result->m_values.reserve (arr_length, false);
+
+      for (int i = 0; i < arr_length; i++)
+	result->m_values.quick_push (values[i]);
+    }
+  else if (type->is_union ())
+    {
+      result->m_values.safe_push (values[0]);
+      result->m_fields.safe_push (fields[0]);
+    }
+  else if (type->is_struct ())
+    {
+      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
+    gcc_unreachable();
+
+  record (result);
+  return result;
+}
+
 /* Create a recording::unary_op instance and add it to this context's
    list of mementos.
 
@@ -4652,11 +4701,13 @@ recording::global::replay_into (replayer *r)
 				 m_initializer_num_bytes
 				 / m_type->dereference ()->get_size (),
 				 m_initializer,
-				 playback_string (m_name))
+				 playback_string (m_name),
+				 flags)
     : r->new_global (playback_location (r, m_loc),
 		     m_kind,
 		     m_type->playback_type (),
-		     playback_string (m_name)));
+		     playback_string (m_name),
+		     flags));
 }
 
 /* Override the default implementation of
@@ -5583,6 +5634,125 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
 	   elements_id);
 }
 
+void
+recording::ctor::visit_children (rvalue_visitor *v)
+{
+  for (unsigned int i = 0; i < m_values.length (); i++)
+    v->visit (m_values[i]);
+}
+
+recording::string *
+recording::ctor::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "ctor");
+}
+
+void
+recording::ctor::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  type *type = get_type();
+
+  r.write ("  gcc_jit_rvalue *%s;\n", id);
+  r.write ("  {\n"); /* Open scope for locals */
+
+  /* Write the array of values */
+  r.write ("    gcc_jit_rvalue *values[] = {\n");
+  for (unsigned i = 0; i < m_values.length (); i++)
+    r.write ("        %s,\n", r.get_identifier (m_values[i]));
+  r.write ("      };\n");
+
+  /* Write the array of fields */
+  if (type->is_array ())
+    r.write ("    gcc_jit_field **fields = NULL;\n");
+  else
+    {
+      r.write ("    gcc_jit_field *fields[] = {\n");
+      for (unsigned i = 0; i < m_fields.length (); i++)
+	r.write ("        %s,\n", r.get_identifier (m_fields[i]));
+      r.write ("      };\n");
+    }
+  r.write (
+"    %s =\n"
+"      gcc_jit_context_new_constructor (%s,\n"
+"                                       %s, /* gcc_jit_location *loc */\n"
+"                                       %s, /* gcc_jit_type *type */\n"
+"                                       %i, /* int arr_length */\n"
+"                                       fields,\n"
+"                                       values);\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (get_type ()),
+	   m_values.length ());
+
+  r.write ("  }\n"); /* Close scope for locals */
+}
+
+void
+recording::ctor::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_values;
+  auto_vec<playback::field *> playback_fields;
+
+  int n = m_values.length();
+
+  type *type = get_type ();
+
+  /* Handle arrays, and return */
+  if (type->is_array ())
+    {
+      playback_values.reserve (n, false);
+
+      for (int i = 0; i < n; i++)
+	{
+	  /* null m_values element indicates zero ctor */
+	  playback_values.quick_push (m_values[i] ?
+				      m_values[i]->playback_rvalue () :
+				      NULL);
+	}
+      set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				     get_type ()->playback_type (),
+				     NULL,
+				     &playback_values));
+      return;
+    }
+  /* Handle unions, and return */
+  else if (type->is_union ())
+    {
+      playback_values.safe_push (m_values[0] ?
+				   m_values[0]->playback_rvalue () :
+				   NULL);
+      playback_fields.safe_push (m_fields[0]->playback_field ());
+
+      set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				     get_type ()->playback_type (),
+				     &playback_fields,
+				     &playback_values));
+
+      return;
+    }
+  /* ... else, handle structs */
+
+  playback_values.reserve (n, false);
+  playback_fields.reserve (n, false);
+
+  for (int i = 0; i < n; i++)
+    {
+      /* null m_values element indicates zero ctor */
+      playback_values.quick_push (m_values[i] ?
+				    m_values[i]->playback_rvalue () :
+				    NULL);
+      playback_fields.quick_push (m_fields[i]->playback_field ());
+    }
+
+  set_playback_obj (r->new_ctor (playback_location (r, m_loc),
+				 get_type ()->playback_type (),
+				 &playback_fields,
+				 &playback_values));
+}
+
 /* The implementation of class gcc::jit::recording::unary_op.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -7556,6 +7726,206 @@ 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;
+}
+
+recording::type *
+strip_outer_qualifiers (recording::type *type)
+{
+  while (true)
+    {
+      if (!type)
+	gcc_unreachable (); /* Should only happen on corrupt input */
+
+      /* unqualified() returns 'this' on base types, vector, arrays and
+	 pointers. */
+      recording::type *next = type->unqualified ();
+      if (next == type)
+	{
+	  break;
+	}
+      type = next;
+    }
+
+  return type;
+}
+
+recording::type *
+get_stripped_subtype (recording::type *type)
+{
+  recording::type *stripped = strip_outer_qualifiers (type);
+  recording::type *subtype;
+
+  if ((subtype = stripped->is_pointer()))
+    return strip_outer_qualifiers (subtype);
+
+  if ((subtype = stripped->is_array ()))
+    return strip_outer_qualifiers (subtype);
+
+  if ((subtype = stripped->dyn_cast_vector_type ()))
+    return strip_outer_qualifiers (subtype);
+
+  return NULL;
+}
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index d5e0c359a48..2e529f4bf52 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -149,6 +149,17 @@ public:
 	      type *type,
 	      const char *name);
 
+  rvalue *
+  new_ctor (location *loc,
+	    type *type,
+	    int arr_length,
+	    field **fields,
+	    rvalue **values);
+
+  void
+  new_global_init_rvalue (lvalue *variable,
+			  rvalue *init);
+
   template <typename HOST_TYPE>
   rvalue *
   new_rvalue_from_const (type *type,
@@ -547,6 +558,8 @@ public:
   virtual bool is_complex () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_array () = 0;
+  virtual bool is_struct () const { return false; }
+  virtual bool is_union () const { return false; }
   virtual bool is_void () const { return false; }
   virtual bool has_known_size () const { return true; }
   /* Used to pair complex float types with real float type
@@ -620,6 +633,8 @@ public:
       }
   }
 
+  type *get_base_type () { return this; }
+
   bool is_int () const FINAL OVERRIDE;
   bool is_float () const FINAL OVERRIDE;
   bool is_bool () const FINAL OVERRIDE;
@@ -873,6 +888,7 @@ public:
   {}
 
   type * get_type () const { return m_type; }
+  string * get_name () const { return m_name; }
 
   compound_type * get_container () const { return m_container; }
   void set_container (compound_type *c) { m_container = c; }
@@ -979,6 +995,8 @@ public:
 
   const char *access_as_type (reproducer &r) FINAL OVERRIDE;
 
+  virtual bool is_struct () const FINAL OVERRIDE { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1017,6 +1035,8 @@ public:
 
   void replay_into (replayer *r) FINAL OVERRIDE;
 
+  virtual bool is_union () const FINAL OVERRIDE { return true; }
+
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1414,6 +1434,21 @@ public:
     m_initializer_num_bytes = num_bytes;
   }
 
+  void set_flags (int flag_fields)
+  {
+    flags = (enum global_var_flags)(flags | flag_fields);
+  }
+  /* Returns true if any of the flags in the argument is set */
+  bool test_flags_anyof (int flag_fields) const
+  {
+    return flags & flag_fields;
+  }
+
+  enum gcc_jit_global_kind get_kind() const
+  {
+    return m_kind;
+  }
+
 private:
   string * make_debug_string () FINAL OVERRIDE { return m_name; }
   template <typename T>
@@ -1426,9 +1461,11 @@ private:
 
 private:
   enum gcc_jit_global_kind m_kind;
+  enum global_var_flags flags = GLOBAL_VAR_FLAGS_NONE;
   string *m_name;
   void *m_initializer;
   size_t m_initializer_num_bytes;
+  
 };
 
 template <typename HOST_TYPE>
@@ -1512,6 +1549,32 @@ private:
   auto_vec<rvalue *> m_elements;
 };
 
+class ctor : public rvalue
+{
+public:
+  ctor (context *ctxt,
+	location *loc,
+	type *type)
+  : rvalue (ctxt, loc, type)
+  { }
+
+  void replay_into (replayer *r) FINAL OVERRIDE;
+
+  void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_PRIMARY;
+  }
+
+public:
+  auto_vec<field *> m_fields;
+  auto_vec<rvalue *> m_values;
+};
+
 class unary_op : public rvalue
 {
 public:
@@ -2355,6 +2418,24 @@ private:
   string *m_asm_stmts;
 };
 
+class global_init_rvalue : public memento
+{
+public:
+  global_init_rvalue (context *ctxt, lvalue *variable, rvalue *init) :
+    memento(ctxt), m_variable (variable), m_init (init) {};
+
+  void write_to_dump (dump &d) FINAL OVERRIDE;
+
+private:
+  void replay_into (replayer *r) FINAL OVERRIDE;
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+  lvalue *m_variable;
+  rvalue *m_init;
+};
+
 } // namespace gcc::jit::recording
 
 /* Create a recording::memento_of_new_rvalue_from_const instance and add
@@ -2374,6 +2455,37 @@ recording::context::new_rvalue_from_const (recording::type *type,
   return result;
 }
 
+bool
+types_kinda_same_internal (recording::type *a,
+			   recording::type *b);
+
+/* Strip *all* qualifiers and count pointer depth, returning true
+   if the types and pointer depth are the same, otherwise false.
+
+   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);
+}
+
+/* Strips qualifiers down to a pointer, array, union, vector
+   or base type. */
+recording::type *
+strip_outer_qualifiers (recording::type *type);
+
+/* For a pointer, array or vector; returns its pointed to type
+   for pointers or element type for array or vectors.
+
+   The returned type is stripped of qualifiers.
+
+   If the argument is not a pointer, array or vector, NULL
+   is returned. */
+recording::type *
+get_stripped_subtype (recording::type *type);
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index b94cdc85c8e..019172854a7 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -206,6 +206,11 @@ namespace gccjit
     rvalue new_rvalue (type vector_type,
 		       std::vector<rvalue> elements) const;
 
+    rvalue new_constructor (type type_,
+			    std::vector<field> &fields,
+			    std::vector<rvalue> &values,
+			    location loc = location ());
+
     /* Generic unary operations...  */
     rvalue new_unary_op (enum gcc_jit_unary_op op,
 			 type result_type,
@@ -509,6 +514,7 @@ namespace gccjit
 
     rvalue get_address (location loc = location ());
     lvalue set_initializer (const void *blob, size_t num_bytes);
+    lvalue set_initializer_rvalue (rvalue init_value);
   };
 
   class param : public lvalue
@@ -1891,6 +1897,44 @@ lvalue::set_initializer (const void *blob, size_t num_bytes)
   return *this;
 }
 
+inline lvalue
+lvalue::set_initializer_rvalue (rvalue init_value)
+{
+  return lvalue (gcc_jit_global_set_initializer_rvalue (
+		   get_inner_lvalue (),
+		   init_value.get_inner_rvalue()));
+}
+
+inline rvalue
+context::new_constructor (type type_,
+			  std::vector<field> &fields,
+			  std::vector<rvalue> &values,
+			  location loc)
+{
+  field *pfields = nullptr;
+  if (fields.size())
+    pfields = &fields[0];
+
+  gcc_jit_field **fields_arr =
+    reinterpret_cast<gcc_jit_field **> (pfields);
+
+  rvalue *pvalues = nullptr;
+  if (values.size())
+    pvalues = &values[0];
+
+  gcc_jit_rvalue **values_arr =
+    reinterpret_cast<gcc_jit_rvalue **> (pvalues);
+
+  return rvalue (
+	   gcc_jit_context_new_constructor (m_inner_ctxt,
+					    loc.get_inner_location (),
+					    type_.get_inner_type(),
+					    (int)values.size(),
+					    fields_arr,
+					    values_arr));
+}
+
+
 // class param : public lvalue
 inline param::param () : lvalue () {}
 inline param::param (gcc_jit_param *inner)
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 97c5aba643e..fe9a321e6fc 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -335,7 +335,7 @@ jit_error (gcc::jit::recording::context *ctxt,
 
    This is implemented by calling the
    gcc::jit::recording::type::accepts_writes_from virtual function on
-   LTYPE.  */
+   LTYPE. For const types accepts_writes_from always returns false. */
 
 static bool
 compatible_types (gcc::jit::recording::type *ltype,
@@ -1130,6 +1130,275 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
   return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   Builds a ctor for arrays, unions and structs.
+
+   The way many entrypoints compare types for sameness is abit
+   broken, since they only strip one qualifier, making eg.
+   'const volatile int' and 'volatile const int' incompatible,
+   or 'const volatile int' and 'int' incompatible. Or
+   'const volatile int' incompatible with it self if the types
+   were built from two different function calls.
+
+   However, for the constructor we need to strip everything. */
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values)
+{
+  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");
+
+  bool is_union = type->is_union ();
+  bool is_struct = type->is_struct ();
+  bool is_array = type->is_array () != NULL; /* is_array() returns ptr */
+
+  RETURN_NULL_IF_FAIL (is_union || is_struct || is_array,
+		       ctxt, loc,
+		       "constructor type not an union, array or struct");
+
+  if (is_array)
+    fields = NULL; /* fields are ignored for array constructors */
+  if (!arr_length)
+    {
+      /* Ignore fields and values if arr_length is zero */
+      fields = NULL;
+      values = NULL;
+    }
+
+  if (is_union)
+    RETURN_NULL_IF_FAIL (arr_length == 1, ctxt, loc,
+			 "union constructor 'arr_length' not 1");
+
+  if (arr_length)
+    {
+      if (is_struct || is_union)
+	{
+	  RETURN_NULL_IF_FAIL (
+	    fields && values,
+	    ctxt, loc,
+	    "'fields' and/or 'values' NULL with non-zero 'arr_length'");
+
+	  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 (
+	    n_fields >= arr_length,
+	    ctxt, loc,
+	    "more fields in constructor than in the target struct or union");
+
+	  RETURN_NULL_IF_FAIL (
+	    ct->has_known_size(),
+	    ctxt, loc,
+	    "struct can't be opaque");
+	}
+      else if (is_array)
+	{
+	  RETURN_NULL_IF_FAIL (
+	    values,
+	    ctxt, loc,
+	    "'values' NULL with non-zero 'arr_length'");
+
+	  gcc::jit::recording::array_type *arr_type =
+	    reinterpret_cast<gcc::jit::recording::array_type*>(type);
+	  int n_el = arr_type->num_elements ();
+
+	  RETURN_NULL_IF_FAIL (
+	    n_el >= arr_length,
+	    ctxt, loc,
+	    "array constructor has more values than the array type's length");
+	}
+    }
+
+  if (fields && values) /* Union or struct */
+    {
+      int idx = 0; /* Runner index */
+
+      compound_type *ct = reinterpret_cast<compound_type *>(type);
+      gcc::jit::recording::fields *fields_struct = ct->get_fields ();
+      int n_fields_in_struct = fields_struct->length ();
+
+      for (int i = 0; i < arr_length; i++)
+	{
+	  gcc::jit::recording::field *f = fields[i];
+	  gcc::jit::recording::rvalue *rv = values[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 union or 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_in_struct; 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_in_struct,
+	    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 ());
+
+	  if (rv)
+	    {
+	      gcc::jit::recording::type *rv_type = rv->get_type ();
+
+	      RETURN_NULL_IF_FAIL_PRINTF1 (
+		!rv_type->is_void (),
+		ctxt, loc,
+		"can't construct the void type, at index %d", i);
+	      RETURN_NULL_IF_FAIL_PRINTF3 (
+		gcc::jit::types_kinda_same (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 ());
+	    }
+	}
+    }
+  else if (values) /* Array */
+    {
+      /* 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 */
+	type0 = values[i]->get_type ();
+
+      /* If we got a type0, check that all other values have
+	 the same type */
+      for (; i < arr_length; i++)
+	{
+	  if (values[i])
+	    RETURN_NULL_IF_FAIL_PRINTF3 (
+	      gcc::jit::types_kinda_same (type0,
+					  values[i]->get_type ()),
+	      ctxt, loc,
+	      "value type at index %d differ from first value type"
+	      " (first type: %s)(different type: %s)",
+	      i,
+	      type0->get_debug_string (),
+	      values[i]->get_type ()->get_debug_string ());
+	}
+
+      /* Compare type0 with the element type specified in the
+	 type of the array. */
+      if (type0)
+	{
+	  gcc::jit::recording::type *el_type =
+	    type->is_array ();
+
+	  RETURN_NULL_IF_FAIL_PRINTF2 (
+	    gcc::jit::types_kinda_same (type0, el_type),
+	    ctxt, loc,
+	    "array element value types differ from types in 'values'"
+	    " (element type: %s)('values' type: %s)",
+	    el_type->get_debug_string (),
+	    type0->get_debug_string ());
+	}
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_ctor (
+    loc,
+    type,
+    arr_length,
+    reinterpret_cast<gcc::jit::recording::field**>(fields),
+    reinterpret_cast<gcc::jit::recording::rvalue**>(values));
+}
+
+/* Public entrypoint.  See description in libgccjit.h. */
+
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_rvalue)
+{
+  RETURN_NULL_IF_FAIL (global, NULL, NULL,"NULL global");
+  
+  gcc::jit::recording::context *ctxt = global->get_context ();
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL,"NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (init_rvalue, ctxt, NULL,"NULL init_rvalue");
+
+  RETURN_NULL_IF_FAIL_PRINTF1 (global->is_global (),
+			       ctxt, NULL,
+			       "lvalue \"%s\" not a global",
+			       global->get_debug_string ());
+
+  gcc::jit::recording::global *gbl =
+    reinterpret_cast<gcc::jit::recording::global *> (global);
+  
+  RETURN_NULL_IF_FAIL_PRINTF1 (gbl->get_kind () !=
+			       GCC_JIT_GLOBAL_IMPORTED,
+			       ctxt, NULL,
+			       "can't initialize \"%s\", it is imported",
+			       global->get_debug_string ());
+
+  RETURN_NULL_IF_FAIL_PRINTF4 (gcc::jit::types_kinda_same (
+				 global->get_type (),
+				 init_rvalue->get_type()),
+			       ctxt, NULL,
+			       "mismatching types:"
+			       " initializing %s (type: %s) with %s (type: %s)",
+			       global->get_debug_string (),
+			       global->get_type ()->get_debug_string (),
+			       init_rvalue->get_debug_string (),
+			       init_rvalue->get_type ()->get_debug_string ());
+
+  /* Check that there are no initializers set for the global yet */
+  RETURN_NULL_IF_FAIL_PRINTF1 (!gbl->test_flags_anyof (
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT),
+			       ctxt, NULL,
+			       "global variable allready initialized: %s",
+			       global->get_debug_string ());
+
+  /* The global need to know during playback that it will be
+     initialized. */
+  gbl->set_flags (gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT);
+
+  ctxt->new_global_init_rvalue (global, init_rvalue);
+
+  return global;
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -1163,8 +1432,22 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
     " global \"%s\" has size %zu whereas initializer has size %zu",
     global->get_debug_string (), lvalue_size, num_bytes);
 
-  reinterpret_cast <gcc::jit::recording::global *> (global)
-    ->set_initializer (blob, num_bytes);
+  /* Check that the rvalue initializer is not set for this global.
+     Note that we do not check if this blob type initializer is
+     allready set, since that check was not present when the entrypoint
+     was initially written. */
+  gcc::jit::recording::global *gbl =
+    reinterpret_cast<gcc::jit::recording::global *> (global);
+  RETURN_NULL_IF_FAIL_PRINTF1 (!gbl->test_flags_anyof (
+				  gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT),
+			       NULL, NULL,
+			       "global variable allready initialized: %s",
+			       global->get_debug_string ());
+
+  gbl->set_initializer (blob, num_bytes);
+  /* The global need to know during playback that it will be
+     initialized. */  
+  gbl->set_flags (gcc::jit::GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
 
   return global;
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index c510c5cc902..0b3acd0b9fa 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -795,6 +795,113 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
 			    gcc_jit_type *type,
 			    const char *name);
 
+#define LIBGCCJIT_HAVE_CTORS
+
+/*
+   Create a constructor for an array, union or struct as a rvalue.
+
+   Returns NULL on error. The two parameter arrays are copied and
+   do not have to outlive the context.
+
+   `type` specifies what the constructor will build.
+
+   `arr_length` specifies the number of elements in `values`.
+
+   Constructing structs
+   """"""""""""""""""""
+
+   For a struct, 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
+   and the pair need to have the same unqualified type.
+
+   A NULL value 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.
+
+   `fields` need to have the same length as `values`.
+
+   If `arr_length` is 0, the array parameters will be
+   ignored and zero initialization will be used.
+
+   Constructing arrays
+   """""""""""""""""""
+
+   For an array type, the `fields` parameter is ignored.
+
+   `arr_length` specifies the number of elements in `values`.
+
+   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 array parameters will be
+   ignored and zero initialization will be used.
+
+   Constructing unions
+   """""""""""""""""""
+
+   For unions, `arr_length` need to be 1. There need to be one field
+   in `fields` and one value in `values` which specified which field
+   in the union to set to what value. The pair need to have the same
+   unqualified type.
+
+   The field in `fields` need to be one of the objects that were used
+   to create the union.
+
+   Remarks
+   """""""
+
+   The constructor rvalue can be used for assignment to locals.
+   It can be used to initialize global variables with
+   gcc_jit_global_set_initializer_rvalue. It can also be used as a
+   temporary value for function calls and return values.
+
+   The constructor can contain nested constructors. Note that a string
+   literal rvalue can't be used to construct a char array. It need one
+   rvalue for each char.
+
+   This entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presense using:
+     #ifdef LIBGCCJIT_HAVE_CTORS
+
+*/
+extern gcc_jit_rvalue *
+gcc_jit_context_new_constructor (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 gcc_jit_type *type,
+				 int arr_length,
+				 gcc_jit_field **fields,
+				 gcc_jit_rvalue **values);
+
+/* Set the initial value of a global with an rvalue.
+
+   The rvalue need to be a constant expression, i.e. no function calls.
+
+   The global can't have the 'kind' GCC_JIT_GLOBAL_IMPORTED.
+   
+   Use together with gcc_jit_context_new_constructor() to
+   initialize structs, unions and arrays.
+
+   On success, returns the 'global' parameter. Otherwise, NULL.
+
+   This entrypoint was added in LIBGCCJIT_ABI_16; you can test for its
+   presence using:
+     #ifdef LIBGCCJIT_HAVE_CTORS
+*/
+extern gcc_jit_lvalue *
+gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
+				       gcc_jit_rvalue *init_value);
+
 #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
 /* Set an initial value for a global, which must be an array of
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 4022dbb6fbc..c5a1afdeacf 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 {
 
 LIBGCCJIT_ABI_16 {
   global:
+    gcc_jit_context_new_constructor;
     gcc_jit_context_new_rvalue_from_complex_double;
     gcc_jit_context_new_rvalue_from_complex_long_double;
-    gcc_jit_context_set_bool_enable_complex_types;
     gcc_jit_context_new_rvalue_from_long_double;
     gcc_jit_context_new_rvalue_from_long_long;
+    gcc_jit_context_set_bool_enable_complex_types;
+    gcc_jit_global_set_initializer_rvalue;
 } LIBGCCJIT_ABI_15;
\ No newline at end of file
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 8416b312bad..26f45fe0811 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -211,6 +211,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-global-init-rvalue.c */
+#define create_code create_code_global_init_rvalue
+#define verify_code verify_code_global_init_rvalue
+#include "test-global-init-rvalue.c"
+#undef create_code
+#undef verify_code
+
 /* test-global-set-initializer.c */
 #define create_code create_code_global_set_initializer
 #define verify_code verify_code_global_set_initializer
@@ -232,6 +239,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-local-init-rvalue.c */
+#define create_code create_code_local_init_rvalue
+#define verify_code verify_code_local_init_rvalue
+#include "test-local-init-rvalue.c"
+#undef create_code
+#undef verify_code
+
 /* test-long-names.c */
 #define create_code create_code_long_names
 #define verify_code verify_code_long_names
diff --git a/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c b/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
new file mode 100644
index 00000000000..a66b894dfde
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-too-big.c
@@ -0,0 +1,86 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an struct type, but have too many fields.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *struct_bar_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt,
+				       0,
+				       "bar",
+				       3,
+				       fields_b));
+  
+  gcc_jit_field *b11 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "a");
+  gcc_jit_field *b22 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "b");
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+  gcc_jit_field *b44 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  int_type,
+						  "c");
+
+  gcc_jit_field *fields_ctor[] = {b11, b22, b33, b44};
+  gcc_jit_rvalue *values[] = {0,0,0,0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     4,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: more fields in "
+		      "constructor than in the target struct or union");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: more fields in "
+		      "constructor than in the target struct or union");
+}
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..2b31b2fc123
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
@@ -0,0 +1,83 @@
+/*
+
+  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_constructor
+    (ctxt, 0,
+     struct_bar_type,
+     4,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: field at index 2, was "
+		      "not used when creating the union or struct (d)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: field at index 2, was "
+		      "not used when creating the union or 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..987b6b8fcbd
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
@@ -0,0 +1,76 @@
+/*
+
+  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_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_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_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..65c85060f6f
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-ctor-union-wrong-field-name.c
@@ -0,0 +1,80 @@
+/*
+
+  Test that the proper error is triggered when we build a ctor
+  for an union type, but don't provide a correct field.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+
+  gcc_jit_field *b1 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 int_type,
+						 "a");
+  gcc_jit_field *b2 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 float_type,
+						 "b");
+  gcc_jit_field *b3 = gcc_jit_context_new_field (ctxt,
+						 0,
+						 double_type,
+						 "c");
+  gcc_jit_field *fields_b[] = {b1, b2, b3};
+
+  gcc_jit_type *union_bar_type =
+      gcc_jit_context_new_union_type (ctxt,
+				      0,
+				      "bar",
+				      3,
+				      fields_b);
+
+  gcc_jit_field *b33 = gcc_jit_context_new_field (ctxt,
+						  0,
+						  double_type,
+						  "cc"); /* wrong */
+
+
+  gcc_jit_field *fields_ctor[] = {b33};
+  gcc_jit_rvalue *values[] = {0};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+    (ctxt, 0,
+     union_bar_type,
+     1,
+     fields_ctor,
+     values);
+
+  CHECK_VALUE (ctor, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: field at "
+		      "index 0, was not used when creating the "
+		      "union or struct (cc)");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: field at "
+		      "index 0, was not used when creating the "
+		      "union or struct (cc)");
+}
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..137bae6c6b5
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
@@ -0,0 +1,64 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with another non-const global's rvalue.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{ /* float foo[1] = {1,2}; */
+
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							   0,
+							   float_type,
+							   1);
+  gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+    ctxt, float_type, 1);
+  gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+    ctxt, float_type, 2);
+
+  gcc_jit_rvalue *values[] = {rval_1, rval_2};
+
+  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							  0,
+							  arr_type,
+							  2,
+							  0,
+							  values);
+  if (!ctor)
+    return;
+  
+  gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+    ctxt, NULL,
+    GCC_JIT_GLOBAL_EXPORTED,
+    arr_type,
+    "global_floatarr_12");
+  gcc_jit_global_set_initializer_rvalue (foo, ctor);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_constructor: array constructor has"
+		      " more values than the array type's length");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "gcc_jit_context_new_constructor: array constructor has"
+		      " more values than the array type's length");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c b/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
new file mode 100644
index 00000000000..c6e1f0ea4fe
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-lvalue-init.c
@@ -0,0 +1,60 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with another non-const global's rvalue.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+
+  gcc_jit_lvalue *foo;
+  { /* int bar; */
+    foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int1");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* int foo = bar; */
+	     
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int2"); 
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_lvalueinit_int2 does not seem to be constant");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_lvalueinit_int2 does not seem to be constant");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c b/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
new file mode 100644
index 00000000000..d04db8ba8ab
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-global-nonconst-init.c
@@ -0,0 +1,80 @@
+/*
+
+  Test that the proper error is triggered when we initialize
+  a global with a function call.
+
+  Using gcc_jit_global_set_initializer_rvalue()
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  
+  gcc_jit_function *fn_int_3; 
+  { /* int foo () { int local = 3; return local;} */
+    fn_int_3 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_int_3",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn_int_3, "start");
+    gcc_jit_lvalue *local = gcc_jit_function_new_local (fn_int_3,
+							0,
+							int_type,
+							"local");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+
+    gcc_jit_block_add_assignment (block, 0, local, rval);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+							  
+  }
+
+  { /* int bar = foo(); */
+    gcc_jit_rvalue *rval =
+      gcc_jit_context_new_call (ctxt,
+			        0,
+				fn_int_3,
+				0,0);
+						     
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_nonconst_int"); 
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted. */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_nonconst_int does not seem to be constant");
+  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+		      "init rvalue for the global variable "
+		      "global_nonconst_int does not seem to be constant");
+}
diff --git a/gcc/testsuite/jit.dg/test-global-init-rvalue.c b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
new file mode 100644
index 00000000000..b7e8c9cf3e5
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-global-init-rvalue.c
@@ -0,0 +1,1211 @@
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+#include "harness.h"
+
+/* This testcase checks that gcc_jit_global_set_initializer_rvalue() works
+   with rvalues, especially with gcc_jit_context_new_constructor() for
+   struct, unions and arrays. */
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *short_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SHORT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_BOOL);
+  gcc_jit_type *char_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *cpchar_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *size_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SIZE_T);
+
+  /* Make a struct: struct fi { float f; int i;} */
+  gcc_jit_field *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 = {1, {2, 3}, 4};
+       I.e. nested ctors
+     */
+    gcc_jit_lvalue *bar = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_bar_type,
+      "global_struct_bar_2");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+
+    gcc_jit_rvalue *vals2[] = {fval, ctor, ival};
+    gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii};
+
+    gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_bar_type,
+       3,
+       fields2,
+       vals2);
+
+    gcc_jit_global_set_initializer_rvalue (bar, ctor_bar);
+  }
+  { /* struct fi foo = {2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_1");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+
+    gcc_jit_rvalue *vals[] = { fval, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {0, 0}; (null init) */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_4");
+
+    gcc_jit_rvalue *vals[] = { 0, 0};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {.i = 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_5");
+
+    gcc_jit_rvalue *vals[] = {0};
+    gcc_jit_field *fields[] = {fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       1,
+       fields,
+       vals);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {}; (null init)
+
+       Null fields and values. */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_6");
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       0,
+       0,
+       0);
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* struct fi foo = {2 * 2, 3}; */
+    gcc_jit_lvalue *foo = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      struct_fi_type,
+      "global_struct_fi_3");
+
+    gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *fval2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+    gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      float_type,
+      fval,
+      fval2);
+
+    gcc_jit_rvalue *vals[] = { rval_mul, ival};
+    gcc_jit_field *fields[] = {fi_f, fi_i};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    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 *vals[] = {fval};
+     gcc_jit_field *fields[] = {ubar_ff};
+
+     gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (
+       ctxt,
+       0,
+       ubar,
+       1,
+       fields,
+       vals);
+
+     gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int foo = 3; */
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int1_3");
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* Try the above, but with opposite order of global and literal calls */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int2_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+  }
+  { /* int foo = 3 * (3 + 3) */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int3_18");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      rval_plus,
+      rval3_2);
+
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_mul);
+  }
+  { /* int foo = 3; int *pfoo = &foo; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int4_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint5");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (foo, 0));
+  }
+  { /* int foo = 3; int *pfoo = &foo + 1; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_int6_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval);
+
+    gcc_jit_lvalue *pfoo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      pint_type,
+      "global_pint7");
+    gcc_jit_global_set_initializer_rvalue (pfoo,
+      gcc_jit_lvalue_get_address (
+	gcc_jit_context_new_array_access(
+	  ctxt,
+	  0,
+	  gcc_jit_lvalue_get_address(foo, 0),
+	  gcc_jit_context_one(ctxt, int_type)),
+	0));
+  }
+  { /* double foo = 3; */
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double1_3");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval);
+  }
+  { /* double foo = 3 * 3 + 3 */
+    gcc_jit_lvalue *double1 =  gcc_jit_context_new_global (
+	ctxt, NULL,
+	GCC_JIT_GLOBAL_EXPORTED,
+	double_type,
+	"global_double2_12");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, double_type, 3);
+    gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_MULT,
+      double_type,
+      rval,
+      rval);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0,
+      GCC_JIT_BINARY_OP_PLUS,
+      double_type,
+      rval_mul,
+      rval);
+    gcc_jit_global_set_initializer_rvalue (double1,
+      rval_plus);
+  }
+  { /* bool foo = 3 + 3 <= 6; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      bool_type,
+      "global_bool1_1");
+    gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 6);
+    gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt,
+      0,
+      GCC_JIT_BINARY_OP_PLUS,
+      int_type,
+      rval3_0,
+      rval3_1);
+    gcc_jit_rvalue *rval_le = gcc_jit_context_new_comparison (ctxt,
+      0,
+      GCC_JIT_COMPARISON_LE,
+      rval_plus,
+      rval6);
+
+    gcc_jit_global_set_initializer_rvalue (foo,
+      rval_le);
+  }
+  gcc_jit_lvalue *global_intarr_1234;
+  { /* int foo[] = {1,2,3,4}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_4 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, rval_3, rval_4};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    values);
+    global_intarr_1234 = gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_intarr_1234");
+    gcc_jit_global_set_initializer_rvalue (global_intarr_1234, ctor);
+  }
+  { /* float foo[4] = {1,2}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_12");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {1,2,0}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 2);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, 0};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_120");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     4);
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    0,
+							    0,
+							    0);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_0000");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* float foo[4] = {NULL , NULL, 3, NULL}; (null init) */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     float_type,
+							     8);
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 3);
+    gcc_jit_rvalue *rval5 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 5);
+    gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, float_type, 6);
+
+    gcc_jit_rvalue *values[] = {0, 0, rval3, 0, rval5, rval6, 0 };
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    7,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_floatarr_00305600");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int *foo[4] = {0, &global_intarr_1234[1]}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     pint_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_lvalue *arr_access = gcc_jit_context_new_array_access (
+      ctxt,
+      0,
+      gcc_jit_lvalue_as_rvalue (global_intarr_1234),
+      rval_1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_lvalue_get_address (arr_access, 0);
+
+    gcc_jit_rvalue *values[] = {0, rval_2};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    values);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_pintarr_x2xx");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* char foo[4] = {'q','w','e',0}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     char_type,
+							     4);
+
+
+    gcc_jit_rvalue *rvals[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'q'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'w'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 'e'),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, char_type, 0)
+    };
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    rvals);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_chararr_qwe");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* int foo[2][2] = {{1,2},{3,4}}; */
+
+    gcc_jit_type *row_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     2);
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     row_type,
+							     2);
+    gcc_jit_rvalue *rvals_row0[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 1),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 2)
+    };
+    gcc_jit_rvalue *rvals_row1[] = {
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 3),
+      gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 4)
+    };
+
+    gcc_jit_rvalue *ctor_row0 =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       row_type,
+				       2,
+				       0,
+				       rvals_row0);
+    gcc_jit_rvalue *ctor_row1 =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       row_type,
+				       2,
+				       0,
+				       rvals_row1);
+    gcc_jit_rvalue *ctors_row[] = {ctor_row0, ctor_row1};
+
+    gcc_jit_rvalue *ctor_arr =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       arr_type,
+				       2,
+				       0,
+				       ctors_row);
+
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_int2x2matrix_1234");
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor_arr);
+  }
+  { /* const char *foo[4] = {"qwe", "asd"}; */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     cpchar_type,
+							     4);
+
+
+    gcc_jit_rvalue *rvals[] = {
+      gcc_jit_context_new_string_literal (ctxt, "qwe"),
+      gcc_jit_context_new_string_literal (ctxt, "asd")
+    };
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    2,
+							    0,
+							    rvals);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      arr_type,
+      "global_cpchararr_qwe_asd");
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+  { /* const int foo = 3;
+       int bar = foo;
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_3");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int_3");
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+  { /* int foo = 3 * 2;
+       int arr[] = {1,2,3,4};
+       int *bar = &arr[2] + 1
+
+       Example in the docs.
+     */
+
+    gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
+							     0,
+							     int_type,
+							     4);
+    gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 1);
+    gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 2);
+    gcc_jit_rvalue *rval_3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_rvalue *rval_4 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+
+    gcc_jit_rvalue *values[] = {rval_1, rval_2, rval_3, rval_4};
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
+							    0,
+							    arr_type,
+							    4,
+							    0,
+							    values);
+    gcc_jit_lvalue *global_intarr_1234 =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  arr_type,
+				  "global_intarr_1234_2");
+
+    gcc_jit_global_set_initializer_rvalue (global_intarr_1234, ctor);
+
+    gcc_jit_lvalue *bar =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  int_type,
+				  "global_int_6");
+    gcc_jit_global_set_initializer_rvalue
+      (bar,
+       gcc_jit_context_new_binary_op
+	 (ctxt, 0, GCC_JIT_BINARY_OP_MULT,
+	  int_type,
+	  gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 3),
+	  gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2)));
+
+    gcc_jit_lvalue *pfoo =
+      gcc_jit_context_new_global (ctxt, NULL,
+				  GCC_JIT_GLOBAL_EXPORTED,
+				  gcc_jit_type_get_pointer (int_type),
+				  "global_pint_4");
+    /* int *bar = &arr[2] + 1;
+
+       In practice we could just do &foo[3]
+       but just prove folding this works. */
+    gcc_jit_global_set_initializer_rvalue (
+       pfoo,
+       gcc_jit_lvalue_get_address (
+	 gcc_jit_context_new_array_access (
+	   ctxt, 0,
+	   gcc_jit_lvalue_get_address (
+	     gcc_jit_context_new_array_access (
+	       ctxt, 0,
+	       gcc_jit_lvalue_as_rvalue (global_intarr_1234),
+	       gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2)),
+	       0),
+	   gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)),
+	   0));
+  }
+  { /*  static int bar = 11;
+	int foo () { return bar; } */
+
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_static_int_11");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 11);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_int_11",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(bar));
+  }
+  { /* static const int cbar = 11;
+       int cfoo () { return cbar; } */
+
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_static_cint_11");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 11);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "fn_cint_11",
+				    0,
+				    0,
+				    0);
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(bar));
+  }
+  { /* static const int cbar = 12;
+       const int* cfoo () { return &cbar; } */
+
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_static_cint_12");
+    gcc_jit_rvalue *rval1 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 12);
+    gcc_jit_global_set_initializer_rvalue (bar,
+	rval1);
+
+    gcc_jit_function *fn11 =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    gcc_jit_type_get_pointer(int_type),
+				    "fn_cint_12",
+				    0,
+				    0,
+				    0);
+
+    gcc_jit_block *block = gcc_jit_function_new_block (fn11, "start");
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_get_address (bar, 0));
+  }
+  { /* const int foo = 3;
+       short bar = (short)foo;
+
+       Assure casts fold
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_4");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      short_type,
+      "global_lvalueinit_short_3");
+    gcc_jit_global_set_initializer_rvalue (
+      bar,
+      gcc_jit_context_new_cast( ctxt, 0,
+				gcc_jit_lvalue_as_rvalue (foo),
+				short_type));
+  }
+  { /* const int foo = 3;
+       const int const *bar = &foo; */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (int_type),
+      "global_const_int_6");
+    gcc_jit_rvalue *rval3 = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 3);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval3);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (
+	gcc_jit_type_get_pointer (
+	  gcc_jit_type_get_const (
+	    int_type))),
+      "global_lvalueinit_cpcint_3");
+    gcc_jit_global_set_initializer_rvalue (
+      bar,
+      gcc_jit_lvalue_get_address (foo, 0));
+  }
+  { /* const int __attribute__ ((aligned (64))) foo = 3;
+       int bar = foo;
+
+       Assure alignement does not make the constant "miss"
+       or something strange.
+     */
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (gcc_jit_type_get_aligned (int_type, 64)),
+      "global_const_int_7");
+    gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int (
+      ctxt, int_type, 4);
+    gcc_jit_global_set_initializer_rvalue (foo,
+	rval);
+    gcc_jit_lvalue *bar =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      int_type,
+      "global_lvalueinit_int_4");
+    gcc_jit_global_set_initializer_rvalue (bar,
+					   gcc_jit_lvalue_as_rvalue (foo));
+  }
+  {
+    /* union upintsize { size_t s; int *p } u = {.s = 0x0EEFBEEF}; */
+    gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   size_type,
+						   "s");
+    gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt,
+						   0,
+						   pint_type,
+						   "p");
+    gcc_jit_field *fields1[] = {f1, f2};
+
+    gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt,
+							 0,
+							 "upintsize",
+							 2,
+							 fields1);
+    gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
+      ctxt, NULL,
+      GCC_JIT_GLOBAL_EXPORTED,
+      gcc_jit_type_get_const (ubar),
+      "global_const_upintsize_1");
+
+    gcc_jit_rvalue *val = gcc_jit_context_new_rvalue_from_long_long (
+      ctxt, size_type, 0xBAAAABBEEEEFBEEF);
+
+    gcc_jit_rvalue *vals[] = {val};
+    gcc_jit_field *fields2[] = {f1};
+
+    gcc_jit_rvalue *ctor =
+      gcc_jit_context_new_constructor (ctxt,
+				       0,
+				       ubar,
+				       1,
+				       fields2,
+				       vals);
+
+    gcc_jit_global_set_initializer_rvalue (foo, ctor);
+  }
+}
+
+struct fi {
+  float f;
+  int i;
+};
+
+struct bar1 {
+  float ff;
+  struct fi fi;
+  int ii;
+};
+
+union ubar1 {
+  float ff;
+  int ii;
+};
+
+union upintsize {
+  size_t s;
+  int *p;
+};
+
+int test_aligned64_works_in_linker_1 __attribute__ ((aligned (64))) = 0;
+int test_aligned64_works_in_linker_2 __attribute__ ((aligned (64))) = 0;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_1");
+
+    CHECK_VALUE (fi->f, 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_3");
+
+    CHECK_VALUE (fi->f, 2 * 2);
+    CHECK_VALUE (fi->i, 3);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_4");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_5");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_6");
+
+    CHECK_VALUE (fi->f, 0);
+    CHECK_VALUE (fi->i, 0);
+  }
+  {
+    union ubar1 *foo = gcc_jit_result_get_global (result,
+						 "global_union_ufoo_ff3");
+    CHECK_VALUE (foo->ff, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int2_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int3_18");
+
+    CHECK_VALUE (*foo, 18);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int4_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint5");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo, *pfoo);
+    CHECK_VALUE (**pfoo, 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int6_3");
+    int **pfoo = gcc_jit_result_get_global (result, "global_pint7");
+
+    CHECK_VALUE (*foo, 3);
+    CHECK_VALUE (foo + 1, *pfoo);
+    CHECK_VALUE (*(*pfoo - 1), 3);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_lvalueinit_int_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double1_3");
+
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    double *foo = gcc_jit_result_get_global (result, "global_double2_12");
+
+    CHECK_VALUE (*foo, 12);
+  }
+  {
+    _Bool *foo = gcc_jit_result_get_global (result, "global_bool1_1");
+
+    CHECK_VALUE (*foo, 1);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_intarr_1234");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 3);
+    CHECK_VALUE (foo[3], 4);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_12");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_120");
+
+    CHECK_VALUE (foo[0], 1);
+    CHECK_VALUE (foo[1], 2);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_0000");
+
+    CHECK_VALUE (foo[0], 0);
+    CHECK_VALUE (foo[1], 0);
+    CHECK_VALUE (foo[2], 0);
+    CHECK_VALUE (foo[3], 0);
+  }
+  {
+    float *foo = gcc_jit_result_get_global (result, "global_floatarr_00305600");
+
+    float key[] = {0,0,3,0,5,6,0,0};
+
+    CHECK_VALUE (memcmp (foo, key, sizeof key), 0);
+  }
+  {
+    int **foo = gcc_jit_result_get_global (result, "global_pintarr_x2xx");
+
+    CHECK_VALUE (foo[0], 0);
+    CHECK_VALUE (*foo[1], 2);
+  }
+  {
+    char *foo = gcc_jit_result_get_global (result, "global_chararr_qwe");
+    const char *key = "qwe";
+    CHECK_VALUE (strcmp (foo, key), 0);
+  }
+  {
+    int *foo = gcc_jit_result_get_global (result, "global_int2x2matrix_1234");
+
+    for (int i = 0; i < 4; i++)
+      CHECK_VALUE (foo[i], i + 1);
+  }
+  {
+    const char **foo =
+      gcc_jit_result_get_global (result, "global_cpchararr_qwe_asd");
+
+    CHECK_VALUE (strcmp (foo[0], "qwe"), 0);
+    CHECK_VALUE (strcmp (foo[1], "asd"), 0);
+  }
+  {
+    int **pint =
+      gcc_jit_result_get_global (result, "global_pint_4");
+    int *foo =
+      gcc_jit_result_get_global (result, "global_int_6");
+    CHECK_VALUE (**pint, 4);
+    CHECK_VALUE (*foo, 6);
+  }
+  {
+    int (*fn)(void) = gcc_jit_result_get_code (result, "fn_int_11");
+    CHECK_VALUE (fn (), 11);
+  }
+  {
+    int (*fn)(void) = gcc_jit_result_get_code (result, "fn_cint_11");
+    CHECK_VALUE (fn (), 11);
+  }
+  {
+    short *foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_short_3");
+    CHECK_VALUE (*foo, 3);
+  }
+  {
+    int **foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_cpcint_3");
+    CHECK_VALUE (**foo, 3);
+  }
+  {
+    int *foo =
+      gcc_jit_result_get_code (result, "global_lvalueinit_int_4");
+    CHECK_VALUE (*foo, 4);
+
+    int *bar =
+      gcc_jit_result_get_code (result, "global_const_int_7");
+    CHECK_VALUE (*bar, 4);
+    /* The linker does not have to support up to 64 alignment, so test that
+       it does before testing that it works in libgccjit. */
+    if ((size_t) &test_aligned64_works_in_linker_1 % 64 == 0 &&
+	(size_t) &test_aligned64_works_in_linker_2 % 64 == 0)
+      CHECK_VALUE ((size_t) bar % 64, 0); /* __attribute__ ((aligned (64))) */
+  }
+  {
+    union upintsize *foo =
+      gcc_jit_result_get_code (result, "global_const_upintsize_1");
+    CHECK_VALUE (foo->p, (void*)0xBAAAABBEEEEFBEEF);
+  }
+}
diff --git a/gcc/testsuite/jit.dg/test-local-init-rvalue.c b/gcc/testsuite/jit.dg/test-local-init-rvalue.c
new file mode 100644
index 00000000000..443666aaba4
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-local-init-rvalue.c
@@ -0,0 +1,532 @@
+
+
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* This testcase checks that gcc_jit_context_new_constructor() works
+   with locals. Tests that constructors can be used as return
+   values or function call values. Test that constructors can have side
+   effects and be assigned to locals.
+ */
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_INT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type);
+  gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_BOOL);
+  gcc_jit_type *size_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *voidptr_type = gcc_jit_context_get_type (ctxt,
+    GCC_JIT_TYPE_VOID_PTR);
+
+  /* Make a struct: struct fi { float f; int i;} */
+  gcc_jit_field *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;
+     }
+  */
+  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_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};
+
+  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);
+
+  (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_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_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_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_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_constructor
+      (ctxt, 0,
+       struct_fi_type,
+       2,
+       fields,
+       vals);
+
+    gcc_jit_rvalue *call = gcc_jit_context_new_call (ctxt, 0, fn0, 1, &ctor);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   call);
+  }
+  { /* struct bar foo() { struct bar local = {};
+			  return local;}
+     */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_bar_type,
+				    "fn_bar_0s",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (fn,
+				  0,
+				  struct_bar_type,
+				  "local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 struct_bar_type,
+	 0,
+	 0,
+	 0);
+    gcc_jit_block_add_assignment (block, 0, local, ctor);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+  { /* struct bar foo() { struct bar local;
+			  local.arr = (int [50]){1,2,3,4,5,6};
+			  return local;}
+     */
+    gcc_jit_function *fn =
+      gcc_jit_context_new_function (ctxt,
+				    0,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    struct_bar_type,
+				    "fn_bar_123s",
+				    0,
+				    0,
+				    0);
+    gcc_jit_lvalue *local =
+      gcc_jit_function_new_local (fn,
+				  0,
+				  struct_bar_type,
+				  "local");
+    gcc_jit_block *block = gcc_jit_function_new_block (fn, "start");
+
+    gcc_jit_rvalue *values[6];
+
+    for (int i = 0; i < 6; i++)
+      values[i] = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, i + 1);
+
+    gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
+	(ctxt, 0,
+	 int50arr_type,
+	 6,
+	 0,
+	 values);
+
+    gcc_jit_lvalue *arr_lv = gcc_jit_lvalue_access_field (local,
+							  0,
+							  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_constructor
+	(ctxt, 0,
+	 int50arr_type,
+	 6,
+	 0,
+	 values);
+
+    gcc_jit_block_add_assignment (block, 0, local, ctor);
+
+    gcc_jit_block_end_with_return (block,
+				   0,
+				   gcc_jit_lvalue_as_rvalue(local));
+  }
+}
+
+struct fi2 {
+  float f;
+  int i;
+};
+
+struct bar2 {
+  float ff;
+  int arr[50];
+  int ii;
+};
+
+union ubar2 {
+  float ff;
+  int ii;
+};
+
+struct int50arr {
+  int arr[50];
+};
+
+void
+scramble_stack(void)
+  {
+    char *p = alloca(100);
+    for (int i = 0; i < 100; i++)
+      *p++ = 0xF0;
+    asm(""); /* Don't touch my code, optimizers. */
+  }
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_2");
+    scramble_stack();
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 1);
+    CHECK_VALUE (fi.i, 2);
+  }
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_5_6");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 5);
+    CHECK_VALUE (fi.i, 6);
+  }
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_3");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 1);
+    CHECK_VALUE (fi.i, 3);
+  }  
+  {
+    struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_3_4");
+    struct fi2 fi = fn();
+    CHECK_VALUE (fi.f, 3);
+    CHECK_VALUE (fi.i, 4);
+  }
+  {
+    scramble_stack();
+    struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_0s");
+    struct bar2 bar = fn();
+    struct bar2 key = {};
+
+    CHECK_VALUE (bar.ff, 0);
+    CHECK_VALUE (bar.ii, 0);
+    CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0);
+  }
+  {
+    scramble_stack();
+    struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_123s");
+    struct bar2 bar = fn();
+    struct bar2 key = {.arr = {1,2,3,4,5,6} };
+
+    CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0);
+  }
+  {
+    scramble_stack();
+    /* This is abit shady. Lets just pretend that array returns à la Fortran
+       is the same thing as returning a struct with an array in it in C. */
+    struct int50arr (*fn) (void) =
+      gcc_jit_result_get_code (result, "fn_int50arr_123s");
+    struct int50arr ans = fn();
+    int key[50] = {1,2,3,4,5,6};
+
+    CHECK_VALUE (memcmp (ans.arr, key, sizeof (key)), 0);
+  }
+}
-- 
2.30.2


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

* Re: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-23 10:51     ` SV: " Petter Tomner
@ 2021-11-23 14:10       ` Antoni Boucher
  2021-11-24 13:38         ` SV: " Petter Tomner
  2021-11-30  1:34       ` David Malcolm
  1 sibling, 1 reply; 12+ messages in thread
From: Antoni Boucher @ 2021-11-23 14:10 UTC (permalink / raw)
  To: Petter Tomner, David Malcolm, jit

Le mardi 23 novembre 2021 à 10:51 +0000, Petter Tomner a écrit :
> Hi!
> 
> Does it work with pointers to other symbols and unions? I don't think
> constant symbols end
> up in the .rdata section unless they are marked for that.

Since I don't provide a constructor for unions, it doesn't work for
them.
I believe it works for an address of a global variable, but I can't
remember.

> 
> I did a similar patch that I just dropped in a RFC mail some time ago.
> (See attachment).

That looks indeed much more complete than my patch.
I'm gonna try your patch for rustc_codegen_gcc when I'm back from
vacation in December and tell you if it works or if it misses
something.
David, could you please take a look at Petter's patch?

> 
> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.
> 
> Regards,
> Petter 
> 
> 
> Från: Gcc-patches <gcc-patches-bounces+tomner=kth.se@gcc.gnu.org> för
> Antoni Boucher via Gcc-patches <gcc-patches@gcc.gnu.org>
> Skickat: den 23 november 2021 03:01
> Till: David Malcolm
> Kopia: jit@gcc.gnu.org; gcc-patches@gcc.gnu.org
> Ämne: Re: [PATCH] libgccjit: Add function to set the initial value of a
> global variable [PR96089]
>     
> Hi David!
> 
> I updated the patch to allow initializing global variables with values
> of type array or struct.
> 
> I also fixed the bug I was talking in my previous message by using the
> following workaround: I create a new memento for the action of setting
> the global variable initial value and as such, both the global variable
> and the initial value are bound to exist when setting the global
> variable initializer.
> Is that workaround good enough?
> (I guess that workaround could be used to fix the same issue that we
> have for inline assembly.)
> 
> Thanks for the review!
> 
> Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> > David: this one wasn't reviewed yet by you, so you can review it.
> > 
> > Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > > Hi.
> > > 
> > > I made this patch to set an arbitrary value to a global variable.
> > > 
> > > This patch suffers from the same issue as inline assembly
> > > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > > segfaults if the `rvalue` is created after the global variable.
> > > It seems to be a design issue so I'm not sure what would be the fix
> > > for
> > > it and having it fixed would allow me to test this new function
> > > much
> > > more and see if things are missing (i.e. it might require a way to
> > > create a constant struct).
> > > See the link above for an explanation of this issue.
> > > 
> > > Thanks for the review.
> > 
> 
>     


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

* SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-23 14:10       ` Antoni Boucher
@ 2021-11-24 13:38         ` Petter Tomner
  0 siblings, 0 replies; 12+ messages in thread
From: Petter Tomner @ 2021-11-24 13:38 UTC (permalink / raw)
  To: Antoni Boucher, David Malcolm, jit

Ok cool I'll wrap up the patch for review. I think I will redo the entrypoint like you did with

separate entrypoints for union, struct and array. It seems less contrived than cramming it all

into one entrypoint.


Regards, Petter

________________________________
Från: Antoni Boucher <bouanto@zoho.com>
Skickat: den 23 november 2021 15:10
Till: Petter Tomner; David Malcolm; jit@gcc.gnu.org
Ämne: Re: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]

Le mardi 23 novembre 2021 à 10:51 +0000, Petter Tomner a écrit :
> Hi!
>
> Does it work with pointers to other symbols and unions? I don't think
> constant symbols end
> up in the .rdata section unless they are marked for that.

Since I don't provide a constructor for unions, it doesn't work for
them.
I believe it works for an address of a global variable, but I can't
remember.

>
> I did a similar patch that I just dropped in a RFC mail some time ago.
> (See attachment).

That looks indeed much more complete than my patch.
I'm gonna try your patch for rustc_codegen_gcc when I'm back from
vacation in December and tell you if it works or if it misses
something.
David, could you please take a look at Petter's patch?

>
> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.
>
> Regards,
> Petter
>
>
> Från: Gcc-patches <gcc-patches-bounces+tomner=kth.se@gcc.gnu.org> för
> Antoni Boucher via Gcc-patches <gcc-patches@gcc.gnu.org>
> Skickat: den 23 november 2021 03:01
> Till: David Malcolm
> Kopia: jit@gcc.gnu.org; gcc-patches@gcc.gnu.org
> Ämne: Re: [PATCH] libgccjit: Add function to set the initial value of a
> global variable [PR96089]
>
> Hi David!
>
> I updated the patch to allow initializing global variables with values
> of type array or struct.
>
> I also fixed the bug I was talking in my previous message by using the
> following workaround: I create a new memento for the action of setting
> the global variable initial value and as such, both the global variable
> and the initial value are bound to exist when setting the global
> variable initializer.
> Is that workaround good enough?
> (I guess that workaround could be used to fix the same issue that we
> have for inline assembly.)
>
> Thanks for the review!
>
> Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> > David: this one wasn't reviewed yet by you, so you can review it.
> >
> > Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > > Hi.
> > >
> > > I made this patch to set an arbitrary value to a global variable.
> > >
> > > This patch suffers from the same issue as inline assembly
> > > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > > segfaults if the `rvalue` is created after the global variable.
> > > It seems to be a design issue so I'm not sure what would be the fix
> > > for
> > > it and having it fixed would allow me to test this new function
> > > much
> > > more and see if things are missing (i.e. it might require a way to
> > > create a constant struct).
> > > See the link above for an explanation of this issue.
> > >
> > > Thanks for the review.
> >
>
>


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

* Re: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-23 10:51     ` SV: " Petter Tomner
  2021-11-23 14:10       ` Antoni Boucher
@ 2021-11-30  1:34       ` David Malcolm
  2021-11-30 14:37         ` SV: " Petter Tomner
  1 sibling, 1 reply; 12+ messages in thread
From: David Malcolm @ 2021-11-30  1:34 UTC (permalink / raw)
  To: Petter Tomner, Antoni Boucher, jit

On Tue, 2021-11-23 at 10:51 +0000, Petter Tomner wrote:
> Hi!
> 
> Does it work with pointers to other symbols and unions? I don't think
> constant symbols end
> up in the .rdata section unless they are marked for that.
> 
> I did a similar patch that I just dropped in a RFC mail some time ago.
> (See attachment).

Petter and Antoni, thanks for the patches.

It sounds like I should review Petter's patch, but obviously I want
Antoni's input to be sure that it works for the rustc backend.

Also, Antoni has much more experience than me of creating initializers
in libgccjit.

> 
> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.
> 
> Regards,
> Petter 
> 
> 
> Från: Gcc-patches <gcc-patches-bounces+tomner=kth.se@gcc.gnu.org> för
> Antoni Boucher via Gcc-patches <gcc-patches@gcc.gnu.org>
> Skickat: den 23 november 2021 03:01
> Till: David Malcolm
> Kopia: jit@gcc.gnu.org; gcc-patches@gcc.gnu.org
> Ämne: Re: [PATCH] libgccjit: Add function to set the initial value of a
> global variable [PR96089]
>     
> Hi David!
> 
> I updated the patch to allow initializing global variables with values
> of type array or struct.
> 
> I also fixed the bug I was talking in my previous message by using the
> following workaround: I create a new memento for the action of setting
> the global variable initial value and as such, both the global variable
> and the initial value are bound to exist when setting the global
> variable initializer.
> Is that workaround good enough?
> (I guess that workaround could be used to fix the same issue that we
> have for inline assembly.)
> 
> Thanks for the review!
> 
> Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> > David: this one wasn't reviewed yet by you, so you can review it.
> > 
> > Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > > Hi.
> > > 
> > > I made this patch to set an arbitrary value to a global variable.
> > > 
> > > This patch suffers from the same issue as inline assembly
> > > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > > segfaults if the `rvalue` is created after the global variable.
> > > It seems to be a design issue so I'm not sure what would be the fix
> > > for
> > > it and having it fixed would allow me to test this new function
> > > much
> > > more and see if things are missing (i.e. it might require a way to
> > > create a constant struct).
> > > See the link above for an explanation of this issue.
> > > 
> > > Thanks for the review.
> > 
> 
>     

> From e6850f3417bc0c35d9712e850e5274117527021c Mon Sep 17 00:00:00 2001
> From: Petter Tomner <tomner@kth.se>
> Date: Sun, 24 Oct 2021 21:13:44 +0200
> Subject: [PATCH 3/5] Add suport for global rvalue initialization and ctors
> 
> This patch adds support for initialization of global variables
> with rvalues and creating constructors for array, struct and
> union types which can be used as rvalues.
>

[...snip...]

Review comments follow inline throughout below...

> diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
> index 30a3b9780f9..3b38cab025c 100644
> --- a/gcc/jit/docs/topics/expressions.rst
> +++ b/gcc/jit/docs/topics/expressions.rst
> @@ -176,6 +176,91 @@ Simple expressions
>     underlying string, so it is valid to pass in a pointer to an on-stack
>     buffer.
>  
> +.. function:: gcc_jit_rvalue *\
> +	      gcc_jit_context_new_constructor (gcc_jit_context *ctxt,\
> +                                               gcc_jit_location *loc,\
> +				               gcc_jit_type *type,\
> +				               size_t arr_length,\

It's a size_t in the docs, but an "int" in the header.  Let's make it a
size_t.

> +				               gcc_jit_field **fields,\
> +				               gcc_jit_rvalue **values)
> +
> +   Create a constructor for an array, union or struct as a rvalue.
> +
> +   Returns NULL on error. The two parameter arrays are copied and
> +   do not have to outlive the context.
> +
> +   ``type`` specifies what the constructor will build.
> +
> +   ``arr_length`` specifies the number of elements in ``values``.
> +   
> +   Constructing structs
> +   """"""""""""""""""""
> +
> +   For a struct, 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
> +   and the pair need to have the same unqualified type.
> +
> +   A NULL value in ``values`` is a shorthand for zero initialization
> +   of the corresponding field or array element.
> +
> +   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.
> +
> +   ``fields`` need to have the same length as ``values``. 
> +   
> +   If ``arr_length`` is 0, the array parameters will be
> +   ignored and zero initialization will be used.
> +   
> +
> +   Constructing arrays
> +   """""""""""""""""""
> +   
> +   For an array type, the ``fields`` parameter is ignored.
> +
> +   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 elements' type.
> +
> +   If ``arr_length`` is 0, the array parameters will be
> +   ignored and zero initialization will be used.
> +
> +   Constructing unions
> +   """""""""""""""""""
> +
> +   For unions, ``arr_length`` need to be 1. There need to be one field
> +   in ``fields`` and one value in ``values`` which specified which field
> +   in the union to set to what value. The pair need to have the same
> +   unqualified type.
> +
> +   The field in ``fields`` need to be one of the objects that were used
> +   to create the union.
> +
> +   Remarks
> +   """""""
> +
> +   The constructor rvalue can be used for assignment to locals.
> +   It can be used to initialize global variables with
> +   :func:`gcc_jit_global_set_initializer_rvalue`. It can also be used as a
> +   temporary value for function calls and return values.
> +
> +   The constructor can contain nested constructors. Note that a string
> +   literal rvalue can't be used to construct a char array. It need one
> +   rvalue for each char.
> +
> +   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
> +   presense using:
> +
> +   .. code-block:: c
> +     #ifdef LIBGCCJIT_HAVE_CTORS
> +

Reading the docs, it seems that this function seems to be doing 3
different things.

Would it be better to have 3 different API entrypoints?

Perhaps something like:

extern gcc_jit_rvalue *
gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
                                        gcc_jit_location *loc,
                                        gcc_jit_struct *type,
                                        size_t num_fields, // and values
                                        gcc_jit_field **fields,
                                        gcc_jit_rvalue **values);

extern gcc_jit_rvalue *
gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
                                       gcc_jit_location *loc,
                                       gcc_jit_type *element_type,
                                       size_t num_values,
                                       gcc_jit_rvalue **values);

extern gcc_jit_rvalue *
gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
                                       gcc_jit_location *loc,
                                       gcc_jit_type *union_type,
                                       gcc_jit_field *field,
                                       gcc_jit_rvalue *value);

Would that be better?  I'm not sure, but I think it's clearer.

They could potentially share the memento class internally, or be split
out.

Would "initializer" be better than "constructor"?  (I'm not sure)


[...snip...]

> +/* Flags for global variables class. For when the playback of the
> +   global need to know what will happen to it later. */
> +enum global_var_flags
> +{
> +  GLOBAL_VAR_FLAGS_NONE = 0,
> +  GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT = 1,
> +  GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT = 2,
> +};
> +
>  } // namespace gcc::jit
>  
>  } // namespace gcc
> diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
> index 1f4dc31a1c1..71f0e7283ba 100644
> --- a/gcc/jit/jit-playback.c
> +++ b/gcc/jit/jit-playback.c
> @@ -107,6 +107,43 @@ namespace jit {
>   Playback.
>   **********************************************************************/
>  
> +/* Fold a readonly non-volatile variable with an initial constant value,
> +   to that value.
> +
> +   Otherwise return the argument unchanged.
> +
> +   This fold is needed for setting a variable's DECL_INITIAL to the value
> +   of a const variable. The c-frontend does this in its own special
> +   fold(), so we lift this part out and do it explicitly where there is a
> +   potential for variables to be used as rvalues. */
> +static tree
> +fold_const_var (tree node)
> +{
> +  /* See c_fully_fold_internal in c-fold.c and decl_constant_value_1
> +     in c-typeck.c */
> +  if (VAR_P (node)
> +      && TREE_READONLY (node)
> +      && !TREE_THIS_VOLATILE (node)
> +      && DECL_INITIAL (node) != NULL_TREE
> +      /* "This is invalid if initial value is not constant.
> +	  If it has either a function call, a memory reference,
> +	  or a variable, then re-evaluating it could give different
> +	  results." */
> +      && TREE_CONSTANT (DECL_INITIAL (node)))
> +    {
> +      tree ret = DECL_INITIAL (node);
> +      /* "Avoid unwanted tree sharing between the initializer and current
> +	  function's body where the tree can be modified e.g. by the
> +	  gimplifier."  */
> +      if (TREE_STATIC (node))
> +	ret = unshare_expr (ret);
> +
> +      return ret;
> +    }
> +
> +  return node;
> +}

You mentioned above:

> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.

Can we fail to fold to a const?  If so, should this function return
NULL_TREE instead? (and the callers be adjusted accordingly)

[...snip...]

> +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",

What is "it" in this message?  Is it "the latter"?

> +		 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",

Maybe reword to
  "unable to convert initial value for the global variable %s to a compile-time constant"
or somesuch?

[...snip...]

> +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,

Can the type be made const?

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

Likewise, can these types be made const?

> +{
> +  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;
> +}
> +
> +recording::type *
> +strip_outer_qualifiers (recording::type *type)

...and again, can the return type and input type be const?

> +{
> +  while (true)
> +    {
> +      if (!type)
> +	gcc_unreachable (); /* Should only happen on corrupt input */
> +
> +      /* unqualified() returns 'this' on base types, vector, arrays and
> +	 pointers. */
> +      recording::type *next = type->unqualified ();
> +      if (next == type)
> +	{
> +	  break;
> +	}
> +      type = next;
> +    }
> +
> +  return type;
> +}
> +
> +recording::type *
> +get_stripped_subtype (recording::type *type)

...and again.

> +{
> +  recording::type *stripped = strip_outer_qualifiers (type);
> +  recording::type *subtype;
> +
> +  if ((subtype = stripped->is_pointer()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  if ((subtype = stripped->is_array ()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  if ((subtype = stripped->dyn_cast_vector_type ()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  return NULL;
> +}
> +
>  } // namespace gcc::jit
>

[...snip...]

> diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
> index b94cdc85c8e..019172854a7 100644
> --- a/gcc/jit/libgccjit++.h
> +++ b/gcc/jit/libgccjit++.h
> @@ -206,6 +206,11 @@ namespace gccjit
>      rvalue new_rvalue (type vector_type,
>  		       std::vector<rvalue> elements) const;
>  
> +    rvalue new_constructor (type type_,
> +			    std::vector<field> &fields,
> +			    std::vector<rvalue> &values,
> +			    location loc = location ());

Similar considerations as per the C API.

[...snip...]

>  /* Set an initial value for a global, which must be an array of
> diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
> index 4022dbb6fbc..c5a1afdeacf 100644
> --- a/gcc/jit/libgccjit.map
> +++ b/gcc/jit/libgccjit.map
> @@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 {
>  
>  LIBGCCJIT_ABI_16 {
>    global:
> +    gcc_jit_context_new_constructor;
>      gcc_jit_context_new_rvalue_from_complex_double;
>      gcc_jit_context_new_rvalue_from_complex_long_double;
> -    gcc_jit_context_set_bool_enable_complex_types;
>      gcc_jit_context_new_rvalue_from_long_double;
>      gcc_jit_context_new_rvalue_from_long_long;
> +    gcc_jit_context_set_bool_enable_complex_types;
> +    gcc_jit_global_set_initializer_rvalue;
>  } LIBGCCJIT_ABI_15;

LIBGCCJIT_ABI_16 is in trunk, so we'll need a new ID for this.

> \ No newline at end of file
> diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> index 8416b312bad..26f45fe0811 100644
> --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> @@ -211,6 +211,13 @@
>  #undef create_code
>  #undef verify_code
>  
> +/* test-global-init-rvalue.c */
> +#define create_code create_code_global_init_rvalue
> +#define verify_code verify_code_global_init_rvalue
> +#include "test-global-init-rvalue.c"
> +#undef create_code
> +#undef verify_code
> +
>  /* test-global-set-initializer.c */
>  #define create_code create_code_global_set_initializer
>  #define verify_code verify_code_global_set_initializer
> @@ -232,6 +239,13 @@
>  #undef create_code
>  #undef verify_code
>  
> +/* test-local-init-rvalue.c */
> +#define create_code create_code_local_init_rvalue
> +#define verify_code verify_code_local_init_rvalue
> +#include "test-local-init-rvalue.c"
> +#undef create_code
> +#undef verify_code
> +
>  /* test-long-names.c */
>  #define create_code create_code_long_names
>  #define verify_code verify_code_long_names

You should add entries for the above to the "testcases" array at the
bottom of the file.

Thanks for all the error-handling test coverage...

> 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..a66b894dfde
> --- /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");

Two fields called "c" here, FWIW.
But given that these are different field instances, it should complain
about that, also.

> +
> +  gcc_jit_field *fields_ctor[] = {b11, b22, b33, b44};
> +  gcc_jit_rvalue *values[] = {0,0,0,0};
> +
> +  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
> +    (ctxt, 0,
> +     struct_bar_type,
> +     4,
> +     fields_ctor,
> +     values);
> +
> +  CHECK_VALUE (ctor, NULL);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +		      "gcc_jit_context_new_constructor: more fields in "
> +		      "constructor than in the target struct or union");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +		      "gcc_jit_context_new_constructor: more fields in "
> +		      "constructor than in the target struct or union");
> +}
> 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..2b31b2fc123
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
> @@ -0,0 +1,83 @@
> +/*
> +
> +  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");

Should this be named "e"?

> +  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");

Maybe call this "something_else" for clarity?

> +
> +  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_constructor
> +    (ctxt, 0,
> +     struct_bar_type,
> +     4,
> +     fields_ctor,
> +     values);
> +
> +  CHECK_VALUE (ctor, NULL);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +		      "gcc_jit_context_new_constructor: field at index 2, was "
> +		      "not used when creating the union or struct (d)");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +		      "gcc_jit_context_new_constructor: field at index 2, was "
> +		      "not used when creating the union or struct (d)");

Ideally the error message should contain both the struct/union name,
and the bad field name
e.g.:
  gcc_jit_context_new_constructor: field at index 2 (d) is not an
element of struct "bar"


> 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..987b6b8fcbd
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
> @@ -0,0 +1,76 @@
> +/*
> +
> +  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_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_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_constructor: value and field not "
> +		      "the same unqualified type, "
> +		      "at index 0 (field type: int)(value type: float)");

This is good; even better would be to also give the name of the field
and name of the struct.


[...snip...]

> 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");

"allready" -> "already" (in the implementation, of course)

> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +		      "gcc_jit_global_set_initializer_rvalue: global variable "
> +		      "allready initialized: global_lvalueinit_int_0");
> +}

[...snip...]

> diff --git a/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
> new file mode 100644
> index 00000000000..137bae6c6b5
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
> @@ -0,0 +1,64 @@
> +/*
> +
> +  Test that the proper error is triggered when we initialize
> +  a global with another non-const global's rvalue.
> +
> +  Using gcc_jit_global_set_initializer_rvalue()
> +
> +*/
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "libgccjit.h"
> +#include "harness.h"
> +
> +void
> +create_code (gcc_jit_context *ctxt, void *user_data)
> +{ /* float foo[1] = {1,2}; */
> +
> +  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
> +    GCC_JIT_TYPE_FLOAT);
> +  gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
> +							   0,
> +							   float_type,
> +							   1);
> +  gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
> +    ctxt, float_type, 1);
> +  gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
> +    ctxt, float_type, 2);
> +
> +  gcc_jit_rvalue *values[] = {rval_1, rval_2};
> +
> +  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
> +							  0,
> +							  arr_type,
> +							  2,
> +							  0,
> +							  values);
> +  if (!ctor)
> +    return;
> +  
> +  gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
> +    ctxt, NULL,
> +    GCC_JIT_GLOBAL_EXPORTED,
> +    arr_type,
> +    "global_floatarr_12");
> +  gcc_jit_global_set_initializer_rvalue (foo, ctor);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +		      "gcc_jit_context_new_constructor: array constructor has"
> +		      " more values than the array type's length");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +		      "gcc_jit_context_new_constructor: array constructor has"
> +		      " more values than the array type's length");
> +}

Ideally would also tell the user the specific values.

[...snip...]

Thanks again for the patches; hope this is constructive.  As noted
above, I'm keen on hearing Antoni's opinion of the patch.

Dave


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

* SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-30  1:34       ` David Malcolm
@ 2021-11-30 14:37         ` Petter Tomner
  2021-12-02  0:07           ` David Malcolm
  0 siblings, 1 reply; 12+ messages in thread
From: Petter Tomner @ 2021-11-30 14:37 UTC (permalink / raw)
  To: David Malcolm, Antoni Boucher, jit

Hi!

> It sounds like I should review Petter's patch, but obviously I want
> Antoni's input to be sure that it works for the rustc backend.

He asked you to review my patch and wrote that he would check if it worked 
for his work when back from a vacation, in a follow up mail. Maybe you missed it:
https://gcc.gnu.org/pipermail/jit/2021q4/001394.html

I tidied up the patch and mailed it for review to the list:
https://gcc.gnu.org/pipermail/jit/2021q4/001399.html

but it is about the same code as you reviewed so your points still appy,
except that I fixed some docs, whitespace etc and split up the entry points and
made them compatible with how Antoni used them. I.e. the user can 
leave out the fields arg and just have the values being applied in 
struct field definition order.

> It's a size_t in the docs, but an "int" in the header.  Let's make it a
> size_t.

Ye need to sync those. Are you sure you want size_t though? Neither
array or struct types can have more elements/fields than int due to the
entrypoints for making those have int args (which were the reason I 
changed to int, forgot to change the docs). 

> Reading the docs, it seems that this function seems to be doing 3
> different things.
>
> Would it be better to have 3 different API entrypoints?
>
>Perhaps something like:
>
>extern gcc_jit_rvalue *
>gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
...
>extern gcc_jit_rvalue *
>gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
...
>extern gcc_jit_rvalue *
>gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
>
> Would that be better?  I'm not sure, but I think it's clearer.

Funnely enough the exact signature I chose. But with
gcc_jit_type instead of gcc_jit_struct.

Ye it is way clearer. One entrypoint made it too crammed and
the documentation got very confusing.

> They could potentially share the memento class internally, or be split
> out.

The code is very similair for arrays and UNION are kinda RECORDs with 
no offsets, so I guess it makes sense to keep the internal class together.

> Would "initializer" be better than "constructor"?  (I'm not sure)

They can be used for assigning to variables at any time, so
initializer would probably be confusing, if people think in C or
C++ terms.

>> If I remember correctly there need to be alot of folding to not
>> segfault deeper into gcc on
>> expressions that are not one literal, for e.g. pointer arithmetic.
>
>Can we fail to fold to a const?  If so, should this function return
>NULL_TREE instead? (and the callers be adjusted accordingly)

I could not construct something that failed to fold 
"enough" so that varasm.c coulnd't handle it and that also was 
TREE_CONSTANT.

playback::context::global_set_init_rvalue searches for variables
without DECL_INITIAL set (which would make downstream code
unhappy) and checks that the rvalue is also TREE_CONSTANT.

fold_const_var () just lets things it can't fold through, like fold () does.
I guess returning NULL_TREE on failing to fold would add alot of
checking everywhere it is used.

> Two fields called "c" here, FWIW.
> But given that these are different field instances, it should complain
> about that, also.

Ye the name of that "c" field doesn't really matter since the the size
check is before the "is this field object one of the field objects that created
the type"-check. That is checked in:
test-error-ctor-struct-wrong-field-name.c

I'll fix the other comments too, and prepare a new patch.

Regards,


Från: David Malcolm <dmalcolm@redhat.com>
Skickat: den 30 november 2021 02:34
Till: Petter Tomner; Antoni Boucher; jit@gcc.gnu.org
Ämne: Re: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
    
On Tue, 2021-11-23 at 10:51 +0000, Petter Tomner wrote:
> Hi!
> 
> Does it work with pointers to other symbols and unions? I don't think
> constant symbols end
> up in the .rdata section unless they are marked for that.
> 
> I did a similar patch that I just dropped in a RFC mail some time ago.
> (See attachment).

Petter and Antoni, thanks for the patches.

It sounds like I should review Petter's patch, but obviously I want
Antoni's input to be sure that it works for the rustc backend.

Also, Antoni has much more experience than me of creating initializers
in libgccjit.

> 
> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.
> 
> Regards,
> Petter 
> 
> 
> Från: Gcc-patches <gcc-patches-bounces+tomner=kth.se@gcc.gnu.org> för
> Antoni Boucher via Gcc-patches <gcc-patches@gcc.gnu.org>
> Skickat: den 23 november 2021 03:01
> Till: David Malcolm
> Kopia: jit@gcc.gnu.org; gcc-patches@gcc.gnu.org
> Ämne: Re: [PATCH] libgccjit: Add function to set the initial value of a
> global variable [PR96089]
>     
> Hi David!
> 
> I updated the patch to allow initializing global variables with values
> of type array or struct.
> 
> I also fixed the bug I was talking in my previous message by using the
> following workaround: I create a new memento for the action of setting
> the global variable initial value and as such, both the global variable
> and the initial value are bound to exist when setting the global
> variable initializer.
> Is that workaround good enough?
> (I guess that workaround could be used to fix the same issue that we
> have for inline assembly.)
> 
> Thanks for the review!
> 
> Le vendredi 11 juin 2021 à 16:44 -0400, Antoni Boucher a écrit :
> > David: this one wasn't reviewed yet by you, so you can review it.
> > 
> > Le jeudi 20 mai 2021 à 21:27 -0400, Antoni Boucher a écrit :
> > > Hi.
> > > 
> > > I made this patch to set an arbitrary value to a global variable.
> > > 
> > > This patch suffers from the same issue as inline assembly
> > > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100380), i.e. it
> > > segfaults if the `rvalue` is created after the global variable.
> > > It seems to be a design issue so I'm not sure what would be the fix
> > > for
> > > it and having it fixed would allow me to test this new function
> > > much
> > > more and see if things are missing (i.e. it might require a way to
> > > create a constant struct).
> > > See the link above for an explanation of this issue.
> > > 
> > > Thanks for the review.
> > 
> 
>     

> From e6850f3417bc0c35d9712e850e5274117527021c Mon Sep 17 00:00:00 2001
> From: Petter Tomner <tomner@kth.se>
> Date: Sun, 24 Oct 2021 21:13:44 +0200
> Subject: [PATCH 3/5] Add suport for global rvalue initialization and ctors
> 
> This patch adds support for initialization of global variables
> with rvalues and creating constructors for array, struct and
> union types which can be used as rvalues.
>

[...snip...]

Review comments follow inline throughout below...

> diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
> index 30a3b9780f9..3b38cab025c 100644
> --- a/gcc/jit/docs/topics/expressions.rst
> +++ b/gcc/jit/docs/topics/expressions.rst
> @@ -176,6 +176,91 @@ Simple expressions
>     underlying string, so it is valid to pass in a pointer to an on-stack
>     buffer.
>  
> +.. function:: gcc_jit_rvalue *\
> +           gcc_jit_context_new_constructor (gcc_jit_context *ctxt,\
> +                                               gcc_jit_location *loc,\
> +                                            gcc_jit_type *type,\
> +                                            size_t arr_length,\

It's a size_t in the docs, but an "int" in the header.  Let's make it a
size_t.

> +                                            gcc_jit_field **fields,\
> +                                            gcc_jit_rvalue **values)
> +
> +   Create a constructor for an array, union or struct as a rvalue.
> +
> +   Returns NULL on error. The two parameter arrays are copied and
> +   do not have to outlive the context.
> +
> +   ``type`` specifies what the constructor will build.
> +
> +   ``arr_length`` specifies the number of elements in ``values``.
> +   
> +   Constructing structs
> +   """"""""""""""""""""
> +
> +   For a struct, 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
> +   and the pair need to have the same unqualified type.
> +
> +   A NULL value in ``values`` is a shorthand for zero initialization
> +   of the corresponding field or array element.
> +
> +   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.
> +
> +   ``fields`` need to have the same length as ``values``. 
> +   
> +   If ``arr_length`` is 0, the array parameters will be
> +   ignored and zero initialization will be used.
> +   
> +
> +   Constructing arrays
> +   """""""""""""""""""
> +   
> +   For an array type, the ``fields`` parameter is ignored.
> +
> +   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 elements' type.
> +
> +   If ``arr_length`` is 0, the array parameters will be
> +   ignored and zero initialization will be used.
> +
> +   Constructing unions
> +   """""""""""""""""""
> +
> +   For unions, ``arr_length`` need to be 1. There need to be one field
> +   in ``fields`` and one value in ``values`` which specified which field
> +   in the union to set to what value. The pair need to have the same
> +   unqualified type.
> +
> +   The field in ``fields`` need to be one of the objects that were used
> +   to create the union.
> +
> +   Remarks
> +   """""""
> +
> +   The constructor rvalue can be used for assignment to locals.
> +   It can be used to initialize global variables with
> +   :func:`gcc_jit_global_set_initializer_rvalue`. It can also be used as a
> +   temporary value for function calls and return values.
> +
> +   The constructor can contain nested constructors. Note that a string
> +   literal rvalue can't be used to construct a char array. It need one
> +   rvalue for each char.
> +
> +   This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its
> +   presense using:
> +
> +   .. code-block:: c
> +     #ifdef LIBGCCJIT_HAVE_CTORS
> +

Reading the docs, it seems that this function seems to be doing 3
different things.

Would it be better to have 3 different API entrypoints?

Perhaps something like:

extern gcc_jit_rvalue *
gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
                                        gcc_jit_location *loc,
                                        gcc_jit_struct *type,
                                        size_t num_fields, // and values
                                        gcc_jit_field **fields,
                                        gcc_jit_rvalue **values);

extern gcc_jit_rvalue *
gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
                                       gcc_jit_location *loc,
                                       gcc_jit_type *element_type,
                                       size_t num_values,
                                       gcc_jit_rvalue **values);

extern gcc_jit_rvalue *
gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
                                       gcc_jit_location *loc,
                                       gcc_jit_type *union_type,
                                       gcc_jit_field *field,
                                       gcc_jit_rvalue *value);

Would that be better?  I'm not sure, but I think it's clearer.

They could potentially share the memento class internally, or be split
out.

Would "initializer" be better than "constructor"?  (I'm not sure)


[...snip...]

> +/* Flags for global variables class. For when the playback of the
> +   global need to know what will happen to it later. */
> +enum global_var_flags
> +{
> +  GLOBAL_VAR_FLAGS_NONE = 0,
> +  GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT = 1,
> +  GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT = 2,
> +};
> +
>  } // namespace gcc::jit
>  
>  } // namespace gcc
> diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
> index 1f4dc31a1c1..71f0e7283ba 100644
> --- a/gcc/jit/jit-playback.c
> +++ b/gcc/jit/jit-playback.c
> @@ -107,6 +107,43 @@ namespace jit {
>   Playback.
>   **********************************************************************/
>  
> +/* Fold a readonly non-volatile variable with an initial constant value,
> +   to that value.
> +
> +   Otherwise return the argument unchanged.
> +
> +   This fold is needed for setting a variable's DECL_INITIAL to the value
> +   of a const variable. The c-frontend does this in its own special
> +   fold(), so we lift this part out and do it explicitly where there is a
> +   potential for variables to be used as rvalues. */
> +static tree
> +fold_const_var (tree node)
> +{
> +  /* See c_fully_fold_internal in c-fold.c and decl_constant_value_1
> +     in c-typeck.c */
> +  if (VAR_P (node)
> +      && TREE_READONLY (node)
> +      && !TREE_THIS_VOLATILE (node)
> +      && DECL_INITIAL (node) != NULL_TREE
> +      /* "This is invalid if initial value is not constant.
> +       If it has either a function call, a memory reference,
> +       or a variable, then re-evaluating it could give different
> +       results." */
> +      && TREE_CONSTANT (DECL_INITIAL (node)))
> +    {
> +      tree ret = DECL_INITIAL (node);
> +      /* "Avoid unwanted tree sharing between the initializer and current
> +       function's body where the tree can be modified e.g. by the
> +       gimplifier."  */
> +      if (TREE_STATIC (node))
> +     ret = unshare_expr (ret);
> +
> +      return ret;
> +    }
> +
> +  return node;
> +}

You mentioned above:

> If I remember correctly there need to be alot of folding to not
> segfault deeper into gcc on
> expressions that are not one literal, for e.g. pointer arithmetic.

Can we fail to fold to a const?  If so, should this function return
NULL_TREE instead? (and the callers be adjusted accordingly)

[...snip...]

> +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",

What is "it" in this message?  Is it "the latter"?

> +              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",

Maybe reword to
  "unable to convert initial value for the global variable %s to a compile-time constant"
or somesuch?

[...snip...]

> +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,

Can the type be made const?

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

Likewise, can these types be made const?

> +{
> +  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;
> +}
> +
> +recording::type *
> +strip_outer_qualifiers (recording::type *type)

...and again, can the return type and input type be const?

> +{
> +  while (true)
> +    {
> +      if (!type)
> +     gcc_unreachable (); /* Should only happen on corrupt input */
> +
> +      /* unqualified() returns 'this' on base types, vector, arrays and
> +      pointers. */
> +      recording::type *next = type->unqualified ();
> +      if (next == type)
> +     {
> +       break;
> +     }
> +      type = next;
> +    }
> +
> +  return type;
> +}
> +
> +recording::type *
> +get_stripped_subtype (recording::type *type)

...and again.

> +{
> +  recording::type *stripped = strip_outer_qualifiers (type);
> +  recording::type *subtype;
> +
> +  if ((subtype = stripped->is_pointer()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  if ((subtype = stripped->is_array ()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  if ((subtype = stripped->dyn_cast_vector_type ()))
> +    return strip_outer_qualifiers (subtype);
> +
> +  return NULL;
> +}
> +
>  } // namespace gcc::jit
>

[...snip...]

> diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
> index b94cdc85c8e..019172854a7 100644
> --- a/gcc/jit/libgccjit++.h
> +++ b/gcc/jit/libgccjit++.h
> @@ -206,6 +206,11 @@ namespace gccjit
>      rvalue new_rvalue (type vector_type,
>                       std::vector<rvalue> elements) const;
>  
> +    rvalue new_constructor (type type_,
> +                         std::vector<field> &fields,
> +                         std::vector<rvalue> &values,
> +                         location loc = location ());

Similar considerations as per the C API.

[...snip...]

>  /* Set an initial value for a global, which must be an array of
> diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
> index 4022dbb6fbc..c5a1afdeacf 100644
> --- a/gcc/jit/libgccjit.map
> +++ b/gcc/jit/libgccjit.map
> @@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 {
>  
>  LIBGCCJIT_ABI_16 {
>    global:
> +    gcc_jit_context_new_constructor;
>      gcc_jit_context_new_rvalue_from_complex_double;
>      gcc_jit_context_new_rvalue_from_complex_long_double;
> -    gcc_jit_context_set_bool_enable_complex_types;
>      gcc_jit_context_new_rvalue_from_long_double;
>      gcc_jit_context_new_rvalue_from_long_long;
> +    gcc_jit_context_set_bool_enable_complex_types;
> +    gcc_jit_global_set_initializer_rvalue;
>  } LIBGCCJIT_ABI_15;

LIBGCCJIT_ABI_16 is in trunk, so we'll need a new ID for this.

> \ No newline at end of file
> diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> index 8416b312bad..26f45fe0811 100644
> --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
> +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
> @@ -211,6 +211,13 @@
>  #undef create_code
>  #undef verify_code
>  
> +/* test-global-init-rvalue.c */
> +#define create_code create_code_global_init_rvalue
> +#define verify_code verify_code_global_init_rvalue
> +#include "test-global-init-rvalue.c"
> +#undef create_code
> +#undef verify_code
> +
>  /* test-global-set-initializer.c */
>  #define create_code create_code_global_set_initializer
>  #define verify_code verify_code_global_set_initializer
> @@ -232,6 +239,13 @@
>  #undef create_code
>  #undef verify_code
>  
> +/* test-local-init-rvalue.c */
> +#define create_code create_code_local_init_rvalue
> +#define verify_code verify_code_local_init_rvalue
> +#include "test-local-init-rvalue.c"
> +#undef create_code
> +#undef verify_code
> +
>  /* test-long-names.c */
>  #define create_code create_code_long_names
>  #define verify_code verify_code_long_names

You should add entries for the above to the "testcases" array at the
bottom of the file.

Thanks for all the error-handling test coverage...

> 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..a66b894dfde
> --- /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");

Two fields called "c" here, FWIW.
But given that these are different field instances, it should complain
about that, also.

> +
> +  gcc_jit_field *fields_ctor[] = {b11, b22, b33, b44};
> +  gcc_jit_rvalue *values[] = {0,0,0,0};
> +
> +  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor
> +    (ctxt, 0,
> +     struct_bar_type,
> +     4,
> +     fields_ctor,
> +     values);
> +
> +  CHECK_VALUE (ctor, NULL);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +                   "gcc_jit_context_new_constructor: more fields in "
> +                   "constructor than in the target struct or union");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +                   "gcc_jit_context_new_constructor: more fields in "
> +                   "constructor than in the target struct or union");
> +}
> 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..2b31b2fc123
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-field-name.c
> @@ -0,0 +1,83 @@
> +/*
> +
> +  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");

Should this be named "e"?

> +  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");

Maybe call this "something_else" for clarity?

> +
> +  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_constructor
> +    (ctxt, 0,
> +     struct_bar_type,
> +     4,
> +     fields_ctor,
> +     values);
> +
> +  CHECK_VALUE (ctor, NULL);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +                   "gcc_jit_context_new_constructor: field at index 2, was "
> +                   "not used when creating the union or struct (d)");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +                   "gcc_jit_context_new_constructor: field at index 2, was "
> +                   "not used when creating the union or struct (d)");

Ideally the error message should contain both the struct/union name,
and the bad field name
e.g.:
  gcc_jit_context_new_constructor: field at index 2 (d) is not an
element of struct "bar"


> 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..987b6b8fcbd
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-ctor-struct-wrong-type.c
> @@ -0,0 +1,76 @@
> +/*
> +
> +  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_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_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_constructor: value and field not "
> +                   "the same unqualified type, "
> +                   "at index 0 (field type: int)(value type: float)");

This is good; even better would be to also give the name of the field
and name of the struct.


[...snip...]

> 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");

"allready" -> "already" (in the implementation, of course)

> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +                   "gcc_jit_global_set_initializer_rvalue: global variable "
> +                   "allready initialized: global_lvalueinit_int_0");
> +}

[...snip...]

> diff --git a/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
> new file mode 100644
> index 00000000000..137bae6c6b5
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-error-global-init-too-small-array.c
> @@ -0,0 +1,64 @@
> +/*
> +
> +  Test that the proper error is triggered when we initialize
> +  a global with another non-const global's rvalue.
> +
> +  Using gcc_jit_global_set_initializer_rvalue()
> +
> +*/
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "libgccjit.h"
> +#include "harness.h"
> +
> +void
> +create_code (gcc_jit_context *ctxt, void *user_data)
> +{ /* float foo[1] = {1,2}; */
> +
> +  gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt,
> +    GCC_JIT_TYPE_FLOAT);
> +  gcc_jit_type *arr_type = gcc_jit_context_new_array_type (ctxt,
> +                                                        0,
> +                                                        float_type,
> +                                                        1);
> +  gcc_jit_rvalue *rval_1 = gcc_jit_context_new_rvalue_from_int (
> +    ctxt, float_type, 1);
> +  gcc_jit_rvalue *rval_2 = gcc_jit_context_new_rvalue_from_int (
> +    ctxt, float_type, 2);
> +
> +  gcc_jit_rvalue *values[] = {rval_1, rval_2};
> +
> +  gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor (ctxt,
> +                                                       0,
> +                                                       arr_type,
> +                                                       2,
> +                                                       0,
> +                                                       values);
> +  if (!ctor)
> +    return;
> +  
> +  gcc_jit_lvalue *foo =  gcc_jit_context_new_global (
> +    ctxt, NULL,
> +    GCC_JIT_GLOBAL_EXPORTED,
> +    arr_type,
> +    "global_floatarr_12");
> +  gcc_jit_global_set_initializer_rvalue (foo, ctor);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> +  /* Ensure that the bad API usage prevents the API giving a bogus
> +     result back.  */
> +  CHECK_VALUE (result, NULL);
> +
> +  /* Verify that the correct error message was emitted. */
> +  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
> +                   "gcc_jit_context_new_constructor: array constructor has"
> +                   " more values than the array type's length");
> +  CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
> +                   "gcc_jit_context_new_constructor: array constructor has"
> +                   " more values than the array type's length");
> +}

Ideally would also tell the user the specific values.

[...snip...]

Thanks again for the patches; hope this is constructive.  As noted
above, I'm keen on hearing Antoni's opinion of the patch.

Dave

    

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

* Re: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-11-30 14:37         ` SV: " Petter Tomner
@ 2021-12-02  0:07           ` David Malcolm
  2021-12-02 22:58             ` Antoni Boucher
  2021-12-06 10:51             ` Petter Tomner
  0 siblings, 2 replies; 12+ messages in thread
From: David Malcolm @ 2021-12-02  0:07 UTC (permalink / raw)
  To: Petter Tomner, Antoni Boucher, jit

On Tue, 2021-11-30 at 14:37 +0000, Petter Tomner wrote:
> Hi!
> 
> > It sounds like I should review Petter's patch, but obviously I want
> > Antoni's input to be sure that it works for the rustc backend.
> 
> He asked you to review my patch and wrote that he would check if it
> worked 
> for his work when back from a vacation, in a follow up mail. Maybe you
> missed it:
> https://gcc.gnu.org/pipermail/jit/2021q4/001394.html

Thanks.  What I mean is that I want to be sure that this approach will
work for the rustc backend and gives all the expressiveness that's
needed - I'm hoping that by release, GCC 12's libgccjit will have all
of the functionality needed by the rustc backend.

> 
> I tidied up the patch and mailed it for review to the list:
> https://gcc.gnu.org/pipermail/jit/2021q4/001399.html
> 
> but it is about the same code as you reviewed so your points still
> appy,
> except that I fixed some docs, whitespace etc and split up the entry
> points and
> made them compatible with how Antoni used them. I.e. the user can 
> leave out the fields arg and just have the values being applied in 
> struct field definition order.
> 
> > It's a size_t in the docs, but an "int" in the header.  Let's make it
> > a
> > size_t.
> 
> Ye need to sync those. Are you sure you want size_t though? Neither
> array or struct types can have more elements/fields than int due to the
> entrypoints for making those have int args (which were the reason I 
> changed to int, forgot to change the docs). 

I think that was a historical error on my part, and I should have used
size_t.  size_t is shorter to type than "unsigned"; it seems that the
type's signedness should be unsigned given that < 0 makes no sense.

> 
> > Reading the docs, it seems that this function seems to be doing 3
> > different things.
> > 
> > Would it be better to have 3 different API entrypoints?
> > 
> > Perhaps something like:
> > 
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
> ...
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
> ...
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
> > 
> > Would that be better?  I'm not sure, but I think it's clearer.
> 
> Funnely enough the exact signature I chose. But with
> gcc_jit_type instead of gcc_jit_struct.
> 
> Ye it is way clearer. One entrypoint made it too crammed and
> the documentation got very confusing.
> 
> > They could potentially share the memento class internally, or be
> > split
> > out.
> 
> The code is very similair for arrays and UNION are kinda RECORDs with
> no offsets, so I guess it makes sense to keep the internal class
> together.

Whichever is easier from an implementation point of view (it's much
easier to change the implementation, compared to the user-facing API).

> 
> > Would "initializer" be better than "constructor"?  (I'm not sure)
> 
> They can be used for assigning to variables at any time, so
> initializer would probably be confusing, if people think in C or
> C++ terms.

Fair enough.

> 
> > > If I remember correctly there need to be alot of folding to not
> > > segfault deeper into gcc on
> > > expressions that are not one literal, for e.g. pointer arithmetic.
> > 
> > Can we fail to fold to a const?  If so, should this function return
> > NULL_TREE instead? (and the callers be adjusted accordingly)
> 
> I could not construct something that failed to fold 
> "enough" so that varasm.c coulnd't handle it and that also was 
> TREE_CONSTANT.
> 
> playback::context::global_set_init_rvalue searches for variables
> without DECL_INITIAL set (which would make downstream code
> unhappy) and checks that the rvalue is also TREE_CONSTANT.
> 
> fold_const_var () just lets things it can't fold through, like fold ()
> does.
> I guess returning NULL_TREE on failing to fold would add alot of
> checking everywhere it is used.

My goal here is that it shouldn't be possible to generate a crash
inside libgccjit via API calls from client code; as noted in 
  https://gcc.gnu.org/onlinedocs/jit/internals/index.html#design-notes
we should add additional checking to gracefully reject bad inputs
rather than crasing. The checking ideally should be within the
libgccjit API entrypoints in libgccjit.c, since this is as close as
possible to the error; failing that, a good place is within
recording::context::validate () in jit-recording.c.  That said, if we
can only detect the problem when a tree is generated during playback,
then we should at least fail gracefully at that point, rather than
crashing.

On re-reading what you wrote above, you needed to add a lot of folding
to prevent a crash, but it sounds like you might have already added
enough, and fixed things by now.  So hopefully the folding code is good
enough as-is, and we can revisit this if someone manages to generate
crashing inputs.


> 
> > Two fields called "c" here, FWIW.
> > But given that these are different field instances, it should
> > complain
> > about that, also.
> 
> Ye the name of that "c" field doesn't really matter since the the size
> check is before the "is this field object one of the field objects that
> created
> the type"-check. That is checked in:
> test-error-ctor-struct-wrong-field-name.c
> 
> I'll fix the other comments too, and prepare a new patch.

Thanks!  Please can you crosspost libgccjit patches to both the jit and
gcc-patches mailing lists.

Dave

[...snip...]


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

* Re: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-12-02  0:07           ` David Malcolm
@ 2021-12-02 22:58             ` Antoni Boucher
  2021-12-06 10:56               ` SV: " Petter Tomner
  2021-12-06 10:51             ` Petter Tomner
  1 sibling, 1 reply; 12+ messages in thread
From: Antoni Boucher @ 2021-12-02 22:58 UTC (permalink / raw)
  To: David Malcolm, Petter Tomner, jit

Hi Petter!
I tried your patch with rustc_codegen_gcc and here's the first issue I
got:
when initializing a global variable to the address of another global
variable, I get the following error:

libgccjit.so: error: can't initialize
_RNvNvCsMJfZecVzJR_21mini_core_hello_world4main14ANOTHER_STATIC with
_RNvCs3Hdp5GKxhqH_9mini_core8A_STATIC since it has no initial value set

It looks like I can't take the address of an uninitialized global
variable (maybe it's initialized after, but from a quick look, it seems
like it's an imported global variable).

Also, I'd appreciate if the function
gcc_jit_context_new_struct_constructor would not need the fields
parameter.

After that, I removed this check to see if there was any other error
later, but everything was fine!

Thanks for your work!

Le mercredi 01 décembre 2021 à 19:07 -0500, David Malcolm a écrit :
> On Tue, 2021-11-30 at 14:37 +0000, Petter Tomner wrote:
> > Hi!
> > 
> > > It sounds like I should review Petter's patch, but obviously I
> > > want
> > > Antoni's input to be sure that it works for the rustc backend.
> > 
> > He asked you to review my patch and wrote that he would check if it
> > worked 
> > for his work when back from a vacation, in a follow up mail. Maybe
> > you
> > missed it:
> > https://gcc.gnu.org/pipermail/jit/2021q4/001394.html
> 
> Thanks.  What I mean is that I want to be sure that this approach
> will
> work for the rustc backend and gives all the expressiveness that's
> needed - I'm hoping that by release, GCC 12's libgccjit will have all
> of the functionality needed by the rustc backend.
> 
> > 
> > I tidied up the patch and mailed it for review to the list:
> > https://gcc.gnu.org/pipermail/jit/2021q4/001399.html
> > 
> > but it is about the same code as you reviewed so your points still
> > appy,
> > except that I fixed some docs, whitespace etc and split up the
> > entry
> > points and
> > made them compatible with how Antoni used them. I.e. the user can 
> > leave out the fields arg and just have the values being applied in 
> > struct field definition order.
> > 
> > > It's a size_t in the docs, but an "int" in the header.  Let's
> > > make it
> > > a
> > > size_t.
> > 
> > Ye need to sync those. Are you sure you want size_t though? Neither
> > array or struct types can have more elements/fields than int due to
> > the
> > entrypoints for making those have int args (which were the reason I
> > changed to int, forgot to change the docs). 
> 
> I think that was a historical error on my part, and I should have
> used
> size_t.  size_t is shorter to type than "unsigned"; it seems that the
> type's signedness should be unsigned given that < 0 makes no sense.
> 
> > 
> > > Reading the docs, it seems that this function seems to be doing 3
> > > different things.
> > > 
> > > Would it be better to have 3 different API entrypoints?
> > > 
> > > Perhaps something like:
> > > 
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
> > ...
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
> > ...
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
> > > 
> > > Would that be better?  I'm not sure, but I think it's clearer.
> > 
> > Funnely enough the exact signature I chose. But with
> > gcc_jit_type instead of gcc_jit_struct.
> > 
> > Ye it is way clearer. One entrypoint made it too crammed and
> > the documentation got very confusing.
> > 
> > > They could potentially share the memento class internally, or be
> > > split
> > > out.
> > 
> > The code is very similair for arrays and UNION are kinda RECORDs
> > with
> > no offsets, so I guess it makes sense to keep the internal class
> > together.
> 
> Whichever is easier from an implementation point of view (it's much
> easier to change the implementation, compared to the user-facing
> API).
> 
> > 
> > > Would "initializer" be better than "constructor"?  (I'm not sure)
> > 
> > They can be used for assigning to variables at any time, so
> > initializer would probably be confusing, if people think in C or
> > C++ terms.
> 
> Fair enough.
> 
> > 
> > > > If I remember correctly there need to be alot of folding to not
> > > > segfault deeper into gcc on
> > > > expressions that are not one literal, for e.g. pointer
> > > > arithmetic.
> > > 
> > > Can we fail to fold to a const?  If so, should this function
> > > return
> > > NULL_TREE instead? (and the callers be adjusted accordingly)
> > 
> > I could not construct something that failed to fold 
> > "enough" so that varasm.c coulnd't handle it and that also was 
> > TREE_CONSTANT.
> > 
> > playback::context::global_set_init_rvalue searches for variables
> > without DECL_INITIAL set (which would make downstream code
> > unhappy) and checks that the rvalue is also TREE_CONSTANT.
> > 
> > fold_const_var () just lets things it can't fold through, like fold
> > ()
> > does.
> > I guess returning NULL_TREE on failing to fold would add alot of
> > checking everywhere it is used.
> 
> My goal here is that it shouldn't be possible to generate a crash
> inside libgccjit via API calls from client code; as noted in 
>  
> https://gcc.gnu.org/onlinedocs/jit/internals/index.html#design-notes
> we should add additional checking to gracefully reject bad inputs
> rather than crasing. The checking ideally should be within the
> libgccjit API entrypoints in libgccjit.c, since this is as close as
> possible to the error; failing that, a good place is within
> recording::context::validate () in jit-recording.c.  That said, if we
> can only detect the problem when a tree is generated during playback,
> then we should at least fail gracefully at that point, rather than
> crashing.
> 
> On re-reading what you wrote above, you needed to add a lot of
> folding
> to prevent a crash, but it sounds like you might have already added
> enough, and fixed things by now.  So hopefully the folding code is
> good
> enough as-is, and we can revisit this if someone manages to generate
> crashing inputs.
> 
> 
> > 
> > > Two fields called "c" here, FWIW.
> > > But given that these are different field instances, it should
> > > complain
> > > about that, also.
> > 
> > Ye the name of that "c" field doesn't really matter since the the
> > size
> > check is before the "is this field object one of the field objects
> > that
> > created
> > the type"-check. That is checked in:
> > test-error-ctor-struct-wrong-field-name.c
> > 
> > I'll fix the other comments too, and prepare a new patch.
> 
> Thanks!  Please can you crosspost libgccjit patches to both the jit
> and
> gcc-patches mailing lists.
> 
> Dave
> 
> [...snip...]
> 


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

* SV: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-12-02  0:07           ` David Malcolm
  2021-12-02 22:58             ` Antoni Boucher
@ 2021-12-06 10:51             ` Petter Tomner
  1 sibling, 0 replies; 12+ messages in thread
From: Petter Tomner @ 2021-12-06 10:51 UTC (permalink / raw)
  To: David Malcolm, Antoni Boucher, jit

Hi!

Thanks for the review. An updated patch has been submitted to the list.

https://gcc.gnu.org/pipermail/jit/2021q4/001409.html

Regards,
Petter


Från: David Malcolm <dmalcolm@redhat.com>
Skickat: den 2 december 2021 01:07
Till: Petter Tomner; Antoni Boucher; jit@gcc.gnu.org
Ämne: Re: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
    
On Tue, 2021-11-30 at 14:37 +0000, Petter Tomner wrote:
> Hi!
> 
> > It sounds like I should review Petter's patch, but obviously I want
> > Antoni's input to be sure that it works for the rustc backend.
> 
> He asked you to review my patch and wrote that he would check if it
> worked 
> for his work when back from a vacation, in a follow up mail. Maybe you
> missed it:
> https://gcc.gnu.org/pipermail/jit/2021q4/001394.html

Thanks.  What I mean is that I want to be sure that this approach will
work for the rustc backend and gives all the expressiveness that's
needed - I'm hoping that by release, GCC 12's libgccjit will have all
of the functionality needed by the rustc backend.

> 
> I tidied up the patch and mailed it for review to the list:
> https://gcc.gnu.org/pipermail/jit/2021q4/001399.html
> 
> but it is about the same code as you reviewed so your points still
> appy,
> except that I fixed some docs, whitespace etc and split up the entry
> points and
> made them compatible with how Antoni used them. I.e. the user can 
> leave out the fields arg and just have the values being applied in 
> struct field definition order.
> 
> > It's a size_t in the docs, but an "int" in the header.  Let's make it
> > a
> > size_t.
> 
> Ye need to sync those. Are you sure you want size_t though? Neither
> array or struct types can have more elements/fields than int due to the
> entrypoints for making those have int args (which were the reason I 
> changed to int, forgot to change the docs). 

I think that was a historical error on my part, and I should have used
size_t.  size_t is shorter to type than "unsigned"; it seems that the
type's signedness should be unsigned given that < 0 makes no sense.

> 
> > Reading the docs, it seems that this function seems to be doing 3
> > different things.
> > 
> > Would it be better to have 3 different API entrypoints?
> > 
> > Perhaps something like:
> > 
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
> ...
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
> ...
> > extern gcc_jit_rvalue *
> > gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
> > 
> > Would that be better?  I'm not sure, but I think it's clearer.
> 
> Funnely enough the exact signature I chose. But with
> gcc_jit_type instead of gcc_jit_struct.
> 
> Ye it is way clearer. One entrypoint made it too crammed and
> the documentation got very confusing.
> 
> > They could potentially share the memento class internally, or be
> > split
> > out.
> 
> The code is very similair for arrays and UNION are kinda RECORDs with
> no offsets, so I guess it makes sense to keep the internal class
> together.

Whichever is easier from an implementation point of view (it's much
easier to change the implementation, compared to the user-facing API).

> 
> > Would "initializer" be better than "constructor"?  (I'm not sure)
> 
> They can be used for assigning to variables at any time, so
> initializer would probably be confusing, if people think in C or
> C++ terms.

Fair enough.

> 
> > > If I remember correctly there need to be alot of folding to not
> > > segfault deeper into gcc on
> > > expressions that are not one literal, for e.g. pointer arithmetic.
> > 
> > Can we fail to fold to a const?  If so, should this function return
> > NULL_TREE instead? (and the callers be adjusted accordingly)
> 
> I could not construct something that failed to fold 
> "enough" so that varasm.c coulnd't handle it and that also was 
> TREE_CONSTANT.
> 
> playback::context::global_set_init_rvalue searches for variables
> without DECL_INITIAL set (which would make downstream code
> unhappy) and checks that the rvalue is also TREE_CONSTANT.
> 
> fold_const_var () just lets things it can't fold through, like fold ()
> does.
> I guess returning NULL_TREE on failing to fold would add alot of
> checking everywhere it is used.

My goal here is that it shouldn't be possible to generate a crash
inside libgccjit via API calls from client code; as noted in 
   https://gcc.gnu.org/onlinedocs/jit/internals/index.html#design-notes
we should add additional checking to gracefully reject bad inputs
rather than crasing. The checking ideally should be within the
libgccjit API entrypoints in libgccjit.c, since this is as close as
possible to the error; failing that, a good place is within
recording::context::validate () in jit-recording.c.  That said, if we
can only detect the problem when a tree is generated during playback,
then we should at least fail gracefully at that point, rather than
crashing.

On re-reading what you wrote above, you needed to add a lot of folding
to prevent a crash, but it sounds like you might have already added
enough, and fixed things by now.  So hopefully the folding code is good
enough as-is, and we can revisit this if someone manages to generate
crashing inputs.


> 
> > Two fields called "c" here, FWIW.
> > But given that these are different field instances, it should
> > complain
> > about that, also.
> 
> Ye the name of that "c" field doesn't really matter since the the size
> check is before the "is this field object one of the field objects that
> created
> the type"-check. That is checked in:
> test-error-ctor-struct-wrong-field-name.c
> 
> I'll fix the other comments too, and prepare a new patch.

Thanks!  Please can you crosspost libgccjit patches to both the jit and
gcc-patches mailing lists.

Dave

[...snip...]

    

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

* SV: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
  2021-12-02 22:58             ` Antoni Boucher
@ 2021-12-06 10:56               ` Petter Tomner
  0 siblings, 0 replies; 12+ messages in thread
From: Petter Tomner @ 2021-12-06 10:56 UTC (permalink / raw)
  To: Antoni Boucher, David Malcolm, jit

Hi Antoni!
          
> when initializing a global variable to the address of another global
> variable, I get the following error:

Oh ye that need to work. I removed that check since it is redundant with the TREE_CONSTANT
check. Also added a testcase for it. Updated patch: https://gcc.gnu.org/pipermail/jit/2021q4/001409.html

> Also, I'd appreciate if the function
> gcc_jit_context_new_struct_constructor would not need the fields
> parameter.

If the fields parameter is set to NULL the values will be applied in struct definition order. Did
you try that?

Regards,
Petter

Från: Antoni Boucher <bouanto@zoho.com>
Skickat: den 2 december 2021 23:58
Till: David Malcolm; Petter Tomner; jit@gcc.gnu.org
Ämne: Re: SV: SV: [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089]
    
Hi Petter!
I tried your patch with rustc_codegen_gcc and here's the first issue I
got:
when initializing a global variable to the address of another global
variable, I get the following error:

libgccjit.so: error: can't initialize
_RNvNvCsMJfZecVzJR_21mini_core_hello_world4main14ANOTHER_STATIC with
_RNvCs3Hdp5GKxhqH_9mini_core8A_STATIC since it has no initial value set

It looks like I can't take the address of an uninitialized global
variable (maybe it's initialized after, but from a quick look, it seems
like it's an imported global variable).

Also, I'd appreciate if the function
gcc_jit_context_new_struct_constructor would not need the fields
parameter.

After that, I removed this check to see if there was any other error
later, but everything was fine!

Thanks for your work!

Le mercredi 01 décembre 2021 à 19:07 -0500, David Malcolm a écrit :
> On Tue, 2021-11-30 at 14:37 +0000, Petter Tomner wrote:
> > Hi!
> > 
> > > It sounds like I should review Petter's patch, but obviously I
> > > want
> > > Antoni's input to be sure that it works for the rustc backend.
> > 
> > He asked you to review my patch and wrote that he would check if it
> > worked 
> > for his work when back from a vacation, in a follow up mail. Maybe
> > you
> > missed it:
> > https://gcc.gnu.org/pipermail/jit/2021q4/001394.html
> 
> Thanks.  What I mean is that I want to be sure that this approach
> will
> work for the rustc backend and gives all the expressiveness that's
> needed - I'm hoping that by release, GCC 12's libgccjit will have all
> of the functionality needed by the rustc backend.
> 
> > 
> > I tidied up the patch and mailed it for review to the list:
> > https://gcc.gnu.org/pipermail/jit/2021q4/001399.html
> > 
> > but it is about the same code as you reviewed so your points still
> > appy,
> > except that I fixed some docs, whitespace etc and split up the
> > entry
> > points and
> > made them compatible with how Antoni used them. I.e. the user can 
> > leave out the fields arg and just have the values being applied in 
> > struct field definition order.
> > 
> > > It's a size_t in the docs, but an "int" in the header.  Let's
> > > make it
> > > a
> > > size_t.
> > 
> > Ye need to sync those. Are you sure you want size_t though? Neither
> > array or struct types can have more elements/fields than int due to
> > the
> > entrypoints for making those have int args (which were the reason I
> > changed to int, forgot to change the docs). 
> 
> I think that was a historical error on my part, and I should have
> used
> size_t.  size_t is shorter to type than "unsigned"; it seems that the
> type's signedness should be unsigned given that < 0 makes no sense.
> 
> > 
> > > Reading the docs, it seems that this function seems to be doing 3
> > > different things.
> > > 
> > > Would it be better to have 3 different API entrypoints?
> > > 
> > > Perhaps something like:
> > > 
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_struct_constructor (gcc_jit_context *ctxt,
> > ...
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
> > ...
> > > extern gcc_jit_rvalue *
> > > gcc_jit_context_new_union_constructor (gcc_jit_context *ctxt,
> > > 
> > > Would that be better?  I'm not sure, but I think it's clearer.
> > 
> > Funnely enough the exact signature I chose. But with
> > gcc_jit_type instead of gcc_jit_struct.
> > 
> > Ye it is way clearer. One entrypoint made it too crammed and
> > the documentation got very confusing.
> > 
> > > They could potentially share the memento class internally, or be
> > > split
> > > out.
> > 
> > The code is very similair for arrays and UNION are kinda RECORDs
> > with
> > no offsets, so I guess it makes sense to keep the internal class
> > together.
> 
> Whichever is easier from an implementation point of view (it's much
> easier to change the implementation, compared to the user-facing
> API).
> 
> > 
> > > Would "initializer" be better than "constructor"?  (I'm not sure)
> > 
> > They can be used for assigning to variables at any time, so
> > initializer would probably be confusing, if people think in C or
> > C++ terms.
> 
> Fair enough.
> 
> > 
> > > > If I remember correctly there need to be alot of folding to not
> > > > segfault deeper into gcc on
> > > > expressions that are not one literal, for e.g. pointer
> > > > arithmetic.
> > > 
> > > Can we fail to fold to a const?  If so, should this function
> > > return
> > > NULL_TREE instead? (and the callers be adjusted accordingly)
> > 
> > I could not construct something that failed to fold 
> > "enough" so that varasm.c coulnd't handle it and that also was 
> > TREE_CONSTANT.
> > 
> > playback::context::global_set_init_rvalue searches for variables
> > without DECL_INITIAL set (which would make downstream code
> > unhappy) and checks that the rvalue is also TREE_CONSTANT.
> > 
> > fold_const_var () just lets things it can't fold through, like fold
> > ()
> > does.
> > I guess returning NULL_TREE on failing to fold would add alot of
> > checking everywhere it is used.
> 
> My goal here is that it shouldn't be possible to generate a crash
> inside libgccjit via API calls from client code; as noted in 
>  
>  https://gcc.gnu.org/onlinedocs/jit/internals/index.html#design-notes
> we should add additional checking to gracefully reject bad inputs
> rather than crasing. The checking ideally should be within the
> libgccjit API entrypoints in libgccjit.c, since this is as close as
> possible to the error; failing that, a good place is within
> recording::context::validate () in jit-recording.c.  That said, if we
> can only detect the problem when a tree is generated during playback,
> then we should at least fail gracefully at that point, rather than
> crashing.
> 
> On re-reading what you wrote above, you needed to add a lot of
> folding
> to prevent a crash, but it sounds like you might have already added
> enough, and fixed things by now.  So hopefully the folding code is
> good
> enough as-is, and we can revisit this if someone manages to generate
> crashing inputs.
> 
> 
> > 
> > > Two fields called "c" here, FWIW.
> > > But given that these are different field instances, it should
> > > complain
> > > about that, also.
> > 
> > Ye the name of that "c" field doesn't really matter since the the
> > size
> > check is before the "is this field object one of the field objects
> > that
> > created
> > the type"-check. That is checked in:
> > test-error-ctor-struct-wrong-field-name.c
> > 
> > I'll fix the other comments too, and prepare a new patch.
> 
> Thanks!  Please can you crosspost libgccjit patches to both the jit
> and
> gcc-patches mailing lists.
> 
> Dave
> 
> [...snip...]
> 

    

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

end of thread, other threads:[~2021-12-06 10:56 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-21  1:27 [PATCH] libgccjit: Add function to set the initial value of a global variable [PR96089] Antoni Boucher
2021-06-11 20:44 ` Antoni Boucher
2021-11-23  2:01   ` Antoni Boucher
2021-11-23 10:51     ` SV: " Petter Tomner
2021-11-23 14:10       ` Antoni Boucher
2021-11-24 13:38         ` SV: " Petter Tomner
2021-11-30  1:34       ` David Malcolm
2021-11-30 14:37         ` SV: " Petter Tomner
2021-12-02  0:07           ` David Malcolm
2021-12-02 22:58             ` Antoni Boucher
2021-12-06 10:56               ` SV: " Petter Tomner
2021-12-06 10:51             ` 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).