summaryrefslogtreecommitdiff
path: root/gcc/jit/jit-recording.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-04-22 10:21:45 +0000
committer <>2015-04-25 21:44:09 +0000
commitf80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch)
treebb7eafaa81fc4b8c5c215bc08d517fd158db234a /gcc/jit/jit-recording.c
parentc27a97d04853380f1e80525391b3f0d156ed4c84 (diff)
downloadgcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'gcc/jit/jit-recording.c')
-rw-r--r--gcc/jit/jit-recording.c5391
1 files changed, 5391 insertions, 0 deletions
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
new file mode 100644
index 0000000000..32d7f31a8c
--- /dev/null
+++ b/gcc/jit/jit-recording.c
@@ -0,0 +1,5391 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+ Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "pretty-print.h"
+#include "hash-map.h"
+#include "toplev.h"
+
+#include <pthread.h>
+
+#include "jit-common.h"
+#include "jit-builtins.h"
+#include "jit-logging.h"
+#include "jit-recording.h"
+#include "jit-playback.h"
+
+namespace gcc {
+namespace jit {
+
+// class dump
+
+dump::dump (recording::context &ctxt,
+ const char *filename,
+ bool update_locations)
+: m_ctxt (ctxt),
+ m_filename (filename),
+ m_update_locations (update_locations),
+ m_line (0),
+ m_column (0)
+{
+ m_file = fopen (filename, "w");
+ if (!m_file)
+ ctxt.add_error (NULL,
+ "error opening dump file %s for writing: %s",
+ filename,
+ xstrerror (errno));
+}
+
+dump::~dump ()
+{
+ if (m_file)
+ {
+ int err = fclose (m_file);
+ if (err)
+ m_ctxt.add_error (NULL,
+ "error closing dump file %s: %s",
+ m_filename,
+ xstrerror (errno));
+ }
+}
+
+/* Write the given message to the dump, using printf-formatting
+ conventions, updating the line/column within the dump.
+
+ Emit an error on the context if a failure occurs. */
+
+void
+dump::write (const char *fmt, ...)
+{
+ int len;
+ va_list ap;
+ char *buf;
+
+ /* If there was an error opening the file, we've already reported it.
+ Don't attempt further work. */
+ if (!m_file)
+ return;
+
+ va_start (ap, fmt);
+ len = vasprintf (&buf, fmt, ap);
+ va_end (ap);
+
+ if (buf == NULL || len < 0)
+ {
+ m_ctxt.add_error (NULL, "malloc failure writing to dumpfile %s",
+ m_filename);
+ return;
+ }
+
+ if (fwrite (buf, strlen (buf), 1, m_file) != 1)
+ m_ctxt.add_error (NULL, "error writing to dump file %s",
+ m_filename);
+
+ /* Flush after each line, to ease debugging crashes. */
+ fflush (m_file);
+
+ /* Update line/column: */
+ for (const char *ptr = buf; *ptr; ptr++)
+ {
+ if ('\n' == *ptr)
+ {
+ m_line++;
+ m_column = 0;
+ }
+ else
+ m_column++;
+ }
+
+ free (buf);
+}
+
+/* Construct a gcc::jit::recording::location instance for the current
+ location within the dump. */
+
+recording::location *
+dump::make_location () const
+{
+ return m_ctxt.new_location (m_filename, m_line, m_column,
+ /* We need to flag such locations as *not*
+ created by the user, so that
+ reproducer::get_identifier can cope with
+ them appearing *after* the memento that
+ refers to them. */
+ false);
+}
+
+/* A collection of allocations, all of which can be released together, to
+ avoid needing to track and release them individually. */
+
+class allocator
+{
+ public:
+ ~allocator ();
+
+ char *
+ xstrdup_printf (const char *, ...)
+ ATTRIBUTE_RETURNS_NONNULL
+ GNU_PRINTF(2, 3);
+
+ char *
+ xstrdup_printf_va (const char *, va_list ap)
+ ATTRIBUTE_RETURNS_NONNULL
+ GNU_PRINTF(2, 0);
+
+ private:
+ auto_vec <void *> m_buffers;
+};
+
+/* allocator's destructor. Call "free" on all of the allocations. */
+
+allocator::~allocator ()
+{
+ unsigned i;
+ void *buffer;
+ FOR_EACH_VEC_ELT (m_buffers, i, buffer)
+ free (buffer);
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+ the allocation fails).
+
+ The buffer exists until the allocator is cleaned up, and is freed at
+ that point, so the caller doesn't need to track the result. */
+
+char *
+allocator::xstrdup_printf (const char *fmt, ...)
+{
+ char *result;
+ va_list ap;
+ va_start (ap, fmt);
+ result = xstrdup_printf_va (fmt, ap);
+ va_end (ap);
+ return result;
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+ the allocation fails).
+
+ The buffer exists until the allocator is cleaned up, and is freed at
+ that point, so the caller doesn't need to track the result. */
+
+char *
+allocator::xstrdup_printf_va (const char *fmt, va_list ap)
+{
+ char *result = xvasprintf (fmt, ap);
+ m_buffers.safe_push (result);
+ return result;
+}
+
+/* gcc::jit::reproducer is a subclass of gcc::jit::dump, used for
+ implementing gcc_jit_context_dump_reproducer_to_file. */
+
+class reproducer : public dump
+{
+ public:
+ reproducer (recording::context &ctxt,
+ const char *filename);
+
+ void
+ write_params (const vec <recording::context *> &contexts);
+
+ void
+ write_args (const vec <recording::context *> &contexts);
+
+ const char *
+ make_identifier (recording::memento *m, const char *prefix);
+
+ const char *
+ make_tmp_identifier (const char *prefix, recording::memento *m);
+
+ const char *
+ get_identifier (recording::context *ctxt);
+
+ const char *
+ get_identifier (recording::memento *m);
+
+ const char *
+ get_identifier_as_rvalue (recording::rvalue *m);
+
+ const char *
+ get_identifier_as_lvalue (recording::lvalue *m);
+
+ const char *
+ get_identifier_as_type (recording::type *m);
+
+ char *
+ xstrdup_printf (const char *, ...)
+ ATTRIBUTE_RETURNS_NONNULL
+ GNU_PRINTF(2, 3);
+
+ private:
+ hash_map<recording::memento *, const char *> m_identifiers;
+ allocator m_allocator;
+};
+
+/* gcc::jit::reproducer's constructor. */
+
+reproducer::reproducer (recording::context &ctxt,
+ const char *filename) :
+ dump (ctxt, filename, 0),
+ m_identifiers (),
+ m_allocator ()
+{
+}
+
+/* Write out a list of contexts as a set of parameters within a
+ C function declaration. */
+
+void
+reproducer::write_params (const vec <recording::context *> &contexts)
+{
+ unsigned i;
+ recording::context *ctxt;
+ FOR_EACH_VEC_ELT (contexts, i, ctxt)
+ {
+ write ("gcc_jit_context *%s",
+ get_identifier (ctxt));
+ if (i < contexts.length () - 1)
+ write (",\n"
+ " ");
+ }
+}
+
+/* Write out a list of contexts as a set of arguments within a call
+ to a C function. */
+
+void
+reproducer::write_args (const vec <recording::context *> &contexts)
+{
+ unsigned i;
+ recording::context *ctxt;
+ FOR_EACH_VEC_ELT (contexts, i, ctxt)
+ {
+ write ("%s",
+ get_identifier (ctxt));
+ if (i < contexts.length () - 1)
+ write (",\n"
+ " ");
+ }
+}
+
+/* Generate a C identifier for the given memento, associating the generated
+ buffer with the memento (for future calls to get_identifier et al).
+
+ The reproducer will eventually clean up the buffer in its dtor. */
+const char *
+reproducer::make_identifier (recording::memento *m, const char *prefix)
+{
+ char *result;
+ if (strlen (m->get_debug_string ()) < 100)
+ {
+ result = m_allocator.xstrdup_printf ("%s_%s_%p",
+ prefix,
+ m->get_debug_string (),
+ (void *) m);
+ for (char *p = result; *p; p++)
+ if (!ISALNUM (*p))
+ *p = '_';
+ }
+ else
+ result = m_allocator.xstrdup_printf ("%s_%p",
+ prefix, (void *) m);
+ m_identifiers.put (m, result);
+ return result;
+}
+
+/* Generate a C identifier for a temporary variable.
+ The reproducer will eventually clean up the buffer in its dtor. */
+
+const char *
+reproducer::make_tmp_identifier (const char *prefix, recording::memento *m)
+{
+ return m_allocator.xstrdup_printf ("%s_%s",
+ prefix, get_identifier (m));
+}
+
+/* Generate a C identifier for the given context.
+ The reproducer will eventually clean up the buffer in its dtor. */
+
+const char *
+reproducer::get_identifier (recording::context *ctxt)
+{
+ return m_allocator.xstrdup_printf ("ctxt_%p",
+ (void *)ctxt);
+}
+
+/* Locate the C identifier for the given memento, which is assumed to
+ have already been created via make_identifier. */
+
+const char *
+reproducer::get_identifier (recording::memento *m)
+{
+ if (!m)
+ return "NULL";
+
+ /* gcc_jit_context_dump_to_file (, , 1) generates and writes locations,
+ and hence these locations appear in the context's memento list
+ out-of-order: they appear in the context's memento list *after*
+ the memento that refers to them. For this case, it's simplest to
+ pretend that they're NULL when writing out the code to recreate the
+ memento that uses them. */
+ if (recording::location *loc = m->dyn_cast_location ())
+ if (!loc->created_by_user ())
+ return "NULL";
+
+ const char **slot = m_identifiers.get (m);
+ if (!slot)
+ {
+ get_context ().add_error (NULL,
+ "unable to find identifier for %p: %s",
+ (void *)m,
+ m->get_debug_string ());
+ gcc_unreachable ();
+ }
+ return *slot;
+}
+
+/* Locate the C identifier for the given rvalue, wrapping it within
+ a gcc_*_as_rvalue upcast if necessary. */
+
+const char *
+reproducer::get_identifier_as_rvalue (recording::rvalue *m)
+{
+ return m->access_as_rvalue (*this);
+}
+
+/* Locate the C identifier for the given lvalue, wrapping it within
+ a gcc_*_as_lvalue upcast if necessary. */
+
+const char *
+reproducer::get_identifier_as_lvalue (recording::lvalue *m)
+{
+ return m->access_as_lvalue (*this);
+}
+
+/* Locate the C identifier for the given type, wrapping it within
+ a gcc_*_as_type upcast if necessary. */
+
+const char *
+reproducer::get_identifier_as_type (recording::type *m)
+{
+ return m->access_as_type (*this);
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+ the allocation fails).
+
+ The buffer exists until the allocator is cleaned up, and is freed at
+ that point, so the caller doesn't need to track the result.
+
+ Note that we can't use ggc_printf since we're not within the compiler
+ proper (when within gcc_jit_context_dump_reproducer_to_file). */
+
+char *
+reproducer::xstrdup_printf (const char *fmt, ...)
+{
+ char *result;
+ va_list ap;
+ va_start (ap, fmt);
+ result = m_allocator.xstrdup_printf_va (fmt, ap);
+ va_end (ap);
+ return result;
+}
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+/* Get the playback::location for the given recording::location,
+ handling a NULL input with a NULL output. */
+
+playback::location *
+recording::playback_location (replayer *r, recording::location *loc)
+{
+ if (loc)
+ return loc->playback_location (r);
+ else
+ return NULL;
+}
+
+/* Get a const char * for the given recording::string
+ handling a NULL input with a NULL output. */
+
+const char *
+recording::playback_string (recording::string *str)
+{
+ if (str)
+ return str->c_str ();
+ else
+ return NULL;
+}
+
+/* Get the playback::block for the given recording::block,
+ handling a NULL input with a NULL output. */
+
+playback::block *
+recording::playback_block (recording::block *b)
+{
+ if (b)
+ return b->playback_block ();
+ else
+ return NULL;
+}
+
+/* Methods of cc::jit::recording::context. */
+
+/* The constructor for gcc::jit::recording::context, used by
+ gcc_jit_context_acquire and gcc_jit_context_new_child_context. */
+
+recording::context::context (context *parent_ctxt)
+ : log_user (NULL),
+ m_parent_ctxt (parent_ctxt),
+ m_toplevel_ctxt (m_parent_ctxt ? m_parent_ctxt->m_toplevel_ctxt : this),
+ m_error_count (0),
+ m_first_error_str (NULL),
+ m_owns_first_error_str (false),
+ m_last_error_str (NULL),
+ m_owns_last_error_str (false),
+ m_mementos (),
+ m_compound_types (),
+ m_globals (),
+ m_functions (),
+ m_FILE_type (NULL),
+ m_builtins_manager(NULL)
+{
+ if (parent_ctxt)
+ {
+ /* Inherit options from parent. */
+ for (unsigned i = 0;
+ i < sizeof (m_str_options) / sizeof (m_str_options[0]);
+ i++)
+ {
+ const char *parent_opt = parent_ctxt->m_str_options[i];
+ m_str_options[i] = parent_opt ? xstrdup (parent_opt) : NULL;
+ }
+ memcpy (m_int_options,
+ parent_ctxt->m_int_options,
+ sizeof (m_int_options));
+ memcpy (m_bool_options,
+ parent_ctxt->m_bool_options,
+ sizeof (m_bool_options));
+ set_logger (parent_ctxt->get_logger ());
+ }
+ else
+ {
+ memset (m_str_options, 0, sizeof (m_str_options));
+ memset (m_int_options, 0, sizeof (m_int_options));
+ memset (m_bool_options, 0, sizeof (m_bool_options));
+ }
+
+ memset (m_basic_types, 0, sizeof (m_basic_types));
+}
+
+/* The destructor for gcc::jit::recording::context, implicitly used by
+ gcc_jit_context_release. */
+
+recording::context::~context ()
+{
+ JIT_LOG_SCOPE (get_logger ());
+ int i;
+ memento *m;
+ FOR_EACH_VEC_ELT (m_mementos, i, m)
+ {
+ delete m;
+ }
+
+ for (i = 0; i < GCC_JIT_NUM_STR_OPTIONS; ++i)
+ free (m_str_options[i]);
+
+ if (m_builtins_manager)
+ delete m_builtins_manager;
+
+ if (m_owns_first_error_str)
+ free (m_first_error_str);
+
+ if (m_owns_last_error_str)
+ if (m_last_error_str != m_first_error_str)
+ free (m_last_error_str);
+}
+
+/* Add the given mememto to the list of those tracked by this
+ gcc::jit::recording::context, so that e.g. it can be deleted
+ when this context is released. */
+
+void
+recording::context::record (memento *m)
+{
+ gcc_assert (m);
+
+ m_mementos.safe_push (m);
+}
+
+/* Replay this context (and any parents) into the given replayer. */
+
+void
+recording::context::replay_into (replayer *r)
+{
+ JIT_LOG_SCOPE (get_logger ());
+ int i;
+ memento *m;
+
+ /* If we have a parent context, we must replay it. This will
+ recursively walk backwards up the historical tree, then replay things
+ forwards "in historical order", starting with the ultimate parent
+ context, until we reach the "this" context.
+
+ Note that we fully replay the parent, then fully replay the child,
+ which means that inter-context references can only exist from child
+ to parent, not the other way around.
+
+ All of this replaying is suboptimal - it would be better to do the
+ work for the parent context *once*, rather than replaying the parent
+ every time we replay each child. However, fixing this requires deep
+ surgery to lifetime-management: we'd need every context family tree
+ to have its own GC heap, and to initialize the GCC code to use that
+ heap (with a mutex on such a heap). */
+ if (m_parent_ctxt)
+ m_parent_ctxt->replay_into (r);
+
+ if (r->errors_occurred ())
+ return;
+
+ /* Replay this context's saved operations into r. */
+ FOR_EACH_VEC_ELT (m_mementos, i, m)
+ {
+ /* Disabled low-level debugging, here if we need it: print what
+ we're replaying.
+ Note that the calls to get_debug_string might lead to more
+ mementos being created for the strings.
+ This can also be used to exercise the debug_string
+ machinery. */
+ if (0)
+ printf ("context %p replaying (%p): %s\n",
+ (void *)this, (void *)m, m->get_debug_string ());
+
+ m->replay_into (r);
+
+ if (r->errors_occurred ())
+ return;
+ }
+}
+
+/* During a playback, we associate objects from the recording with
+ their counterparts during this playback.
+
+ For simplicity, we store this within the recording objects.
+
+ The following method cleans away these associations, to ensure that
+ we never have out-of-date associations lingering on subsequent
+ playbacks (the objects pointed to are GC-managed, but the
+ recording objects don't own refs to them). */
+
+void
+recording::context::disassociate_from_playback ()
+{
+ JIT_LOG_SCOPE (get_logger ());
+ int i;
+ memento *m;
+
+ if (m_parent_ctxt)
+ m_parent_ctxt->disassociate_from_playback ();
+
+ FOR_EACH_VEC_ELT (m_mementos, i, m)
+ {
+ m->set_playback_obj (NULL);
+ }
+}
+
+/* Create a recording::string instance and add it to this context's list
+ of mementos.
+
+ This creates a fresh copy of the given 0-terminated buffer. */
+
+recording::string *
+recording::context::new_string (const char *text)
+{
+ if (!text)
+ return NULL;
+
+ recording::string *result = new string (this, text);
+ record (result);
+ return result;
+}
+
+/* Create a recording::location instance and add it to this context's
+ list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_location. */
+
+recording::location *
+recording::context::new_location (const char *filename,
+ int line,
+ int column,
+ bool created_by_user)
+{
+ recording::location *result =
+ new recording::location (this,
+ new_string (filename),
+ line, column,
+ created_by_user);
+ record (result);
+ return result;
+}
+
+/* If we haven't seen this enum value yet, create a recording::type
+ instance and add it to this context's list of mementos.
+
+ If we have seen it before, reuse our cached value, so that repeated
+ calls on the context give the same object.
+
+ If we have a parent context, the cache is within the ultimate
+ ancestor context.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_type. */
+
+recording::type *
+recording::context::get_type (enum gcc_jit_types kind)
+{
+ if (!m_basic_types[kind])
+ {
+ if (m_parent_ctxt)
+ m_basic_types[kind] = m_parent_ctxt->get_type (kind);
+ else
+ {
+ recording::type *result = new memento_of_get_type (this, kind);
+ record (result);
+ m_basic_types[kind] = result;
+ }
+ }
+
+ return m_basic_types[kind];
+}
+
+/* Get a recording::type instance for the given size and signedness.
+ This is implemented in terms of recording::context::get_type
+ above.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_int_type. */
+
+recording::type *
+recording::context::get_int_type (int num_bytes, int is_signed)
+{
+ /* We can't use a switch here since some of the values are macros affected
+ by options; e.g. i386.h has
+ #define LONG_TYPE_SIZE (TARGET_X32 ? 32 : BITS_PER_WORD)
+ Compare with tree.c's make_or_reuse_type. Note that the _SIZE macros
+ are in bits, rather than bytes.
+ */
+ const int num_bits = num_bytes * 8;
+ if (num_bits == INT_TYPE_SIZE)
+ return get_type (is_signed
+ ? GCC_JIT_TYPE_INT
+ : GCC_JIT_TYPE_UNSIGNED_INT);
+ if (num_bits == CHAR_TYPE_SIZE)
+ return get_type (is_signed
+ ? GCC_JIT_TYPE_SIGNED_CHAR
+ : GCC_JIT_TYPE_UNSIGNED_CHAR);
+ if (num_bits == SHORT_TYPE_SIZE)
+ return get_type (is_signed
+ ? GCC_JIT_TYPE_SHORT
+ : GCC_JIT_TYPE_UNSIGNED_SHORT);
+ if (num_bits == LONG_TYPE_SIZE)
+ return get_type (is_signed
+ ? GCC_JIT_TYPE_LONG
+ : GCC_JIT_TYPE_UNSIGNED_LONG);
+ if (num_bits == LONG_LONG_TYPE_SIZE)
+ return get_type (is_signed
+ ? GCC_JIT_TYPE_LONG_LONG
+ : GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+
+ /* Some other size, not corresponding to the C int types. */
+ /* To be written: support arbitrary other sizes, sharing by
+ memoizing at the recording::context level? */
+ gcc_unreachable ();
+}
+
+/* Create a recording::type instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_array_type. */
+
+recording::type *
+recording::context::new_array_type (recording::location *loc,
+ recording::type *element_type,
+ int num_elements)
+{
+ if (struct_ *s = element_type->dyn_cast_struct ())
+ if (!s->get_fields ())
+ {
+ add_error (NULL,
+ "cannot create an array of type %s"
+ " until the fields have been set",
+ s->get_name ()->c_str ());
+ return NULL;
+ }
+ recording::type *result =
+ new recording::array_type (this, loc, element_type, num_elements);
+ record (result);
+ return result;
+}
+
+/* Create a recording::field instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_field. */
+
+recording::field *
+recording::context::new_field (recording::location *loc,
+ recording::type *type,
+ const char *name)
+{
+ recording::field *result =
+ new recording::field (this, loc, type, new_string (name));
+ record (result);
+ return result;
+}
+
+/* Create a recording::struct_ instance and add it to this context's
+ list of mementos and list of compound types.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_struct_type. */
+
+recording::struct_ *
+recording::context::new_struct_type (recording::location *loc,
+ const char *name)
+{
+ recording::struct_ *result = new struct_ (this, loc, new_string (name));
+ record (result);
+ m_compound_types.safe_push (result);
+ return result;
+}
+
+/* Create a recording::union_ instance and add it to this context's
+ list of mementos and list of compound types.
+
+ Implements the first post-error-checking part of
+ gcc_jit_context_new_union_type. */
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+ const char *name)
+{
+ recording::union_ *result = new union_ (this, loc, new_string (name));
+ record (result);
+ m_compound_types.safe_push (result);
+ return result;
+}
+
+/* Create a recording::function_type instance and add it to this context's
+ list of mementos.
+
+ Used by new_function_ptr_type and by builtins_manager::make_fn_type. */
+
+recording::function_type *
+recording::context::new_function_type (recording::type *return_type,
+ int num_params,
+ recording::type **param_types,
+ int is_variadic)
+{
+ recording::function_type *fn_type
+ = new function_type (this,
+ return_type,
+ num_params,
+ param_types,
+ is_variadic);
+ record (fn_type);
+ return fn_type;
+}
+
+/* Create a recording::type instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_function_ptr_type. */
+
+recording::type *
+recording::context::new_function_ptr_type (recording::location *, /* unused loc */
+ recording::type *return_type,
+ int num_params,
+ recording::type **param_types,
+ int is_variadic)
+{
+ recording::function_type *fn_type
+ = new_function_type (return_type,
+ num_params,
+ param_types,
+ is_variadic);
+
+ /* Return a pointer-type to the the function type. */
+ return fn_type->get_pointer ();
+}
+
+/* Create a recording::param instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_param. */
+
+recording::param *
+recording::context::new_param (recording::location *loc,
+ recording::type *type,
+ const char *name)
+{
+ recording::param *result = new recording::param (this, loc, type, new_string (name));
+ record (result);
+ return result;
+}
+
+/* Create a recording::function instance and add it to this context's list
+ of mementos and list of functions.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_function. */
+
+recording::function *
+recording::context::new_function (recording::location *loc,
+ enum gcc_jit_function_kind kind,
+ recording::type *return_type,
+ const char *name,
+ int num_params,
+ recording::param **params,
+ int is_variadic,
+ enum built_in_function builtin_id)
+{
+ recording::function *result =
+ new recording::function (this,
+ loc, kind, return_type,
+ new_string (name),
+ num_params, params, is_variadic,
+ builtin_id);
+ record (result);
+ m_functions.safe_push (result);
+
+ return result;
+}
+
+/* Locate the builtins_manager (if any) for this family of contexts,
+ creating it if it doesn't exist already.
+
+ All of the recording contexts in a family share one builtins_manager:
+ if we have a child context, follow the parent links to get the
+ ultimate ancestor context, and look for it/store it there. */
+
+builtins_manager *
+recording::context::get_builtins_manager ()
+{
+ if (m_parent_ctxt)
+ return m_parent_ctxt->get_builtins_manager ();
+
+ if (!m_builtins_manager)
+ m_builtins_manager = new builtins_manager (this);
+
+ return m_builtins_manager;
+}
+
+/* Get a recording::function instance, which is lazily-created and added
+ to the context's lists of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_builtin_function. */
+
+recording::function *
+recording::context::get_builtin_function (const char *name)
+{
+ builtins_manager *bm = get_builtins_manager ();
+ return bm->get_builtin_function (name);
+}
+
+/* Create a recording::global instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_global. */
+
+recording::lvalue *
+recording::context::new_global (recording::location *loc,
+ enum gcc_jit_global_kind kind,
+ recording::type *type,
+ const char *name)
+{
+ recording::global *result =
+ new recording::global (this, loc, kind, type, new_string (name));
+ record (result);
+ m_globals.safe_push (result);
+
+ return result;
+}
+
+/* Create a recording::memento_of_new_string_literal instance and add it
+ to this context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_string_literal. */
+
+recording::rvalue *
+recording::context::new_string_literal (const char *value)
+{
+ recording::rvalue *result =
+ new memento_of_new_string_literal (this, NULL, new_string (value));
+ record (result);
+ return result;
+}
+
+/* Create a recording::unary_op instance and add it to this context's
+ list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_unary_op. */
+
+recording::rvalue *
+recording::context::new_unary_op (recording::location *loc,
+ enum gcc_jit_unary_op op,
+ recording::type *result_type,
+ recording::rvalue *a)
+{
+ recording::rvalue *result =
+ new unary_op (this, loc, op, result_type, a);
+ record (result);
+ return result;
+}
+
+/* Create a recording::binary_op instance and add it to this context's
+ list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_binary_op. */
+
+recording::rvalue *
+recording::context::new_binary_op (recording::location *loc,
+ enum gcc_jit_binary_op op,
+ recording::type *result_type,
+ recording::rvalue *a,
+ recording::rvalue *b)
+{
+ recording::rvalue *result =
+ new binary_op (this, loc, op, result_type, a, b);
+ record (result);
+ return result;
+}
+
+/* Create a recording::comparison instance and add it to this context's
+ list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_comparison. */
+
+recording::rvalue *
+recording::context::new_comparison (recording::location *loc,
+ enum gcc_jit_comparison op,
+ recording::rvalue *a,
+ recording::rvalue *b)
+{
+ recording::rvalue *result = new comparison (this, loc, op, a, b);
+ record (result);
+ return result;
+}
+
+/* Create a recording::cast instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_cast. */
+
+recording::rvalue *
+recording::context::new_cast (recording::location *loc,
+ recording::rvalue *expr,
+ recording::type *type_)
+{
+ recording::rvalue *result = new cast (this, loc, expr, type_);
+ record (result);
+ return result;
+}
+
+/* Create a recording::call instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_call. */
+
+recording::rvalue *
+recording::context::new_call (recording::location *loc,
+ function *func,
+ int numargs , recording::rvalue **args)
+{
+ recording::rvalue *result = new call (this, loc, func, numargs, args);
+ record (result);
+ return result;
+}
+
+/* Create a recording::call_through_ptr instance and add it to this
+ context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_call_through_ptr. */
+
+recording::rvalue *
+recording::context::new_call_through_ptr (recording::location *loc,
+ recording::rvalue *fn_ptr,
+ int numargs,
+ recording::rvalue **args)
+ {
+ recording::rvalue *result = new call_through_ptr (this, loc, fn_ptr, numargs, args);
+ record (result);
+ return result;
+}
+
+/* Create a recording::array_access instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_array_access. */
+
+recording::lvalue *
+recording::context::new_array_access (recording::location *loc,
+ recording::rvalue *ptr,
+ recording::rvalue *index)
+{
+ recording::lvalue *result = new array_access (this, loc, ptr, index);
+ record (result);
+ return result;
+}
+
+/* Set the given string option for this context, or add an error if
+ it's not recognized.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_set_str_option. */
+
+void
+recording::context::set_str_option (enum gcc_jit_str_option opt,
+ const char *value)
+{
+ if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
+ {
+ add_error (NULL,
+ "unrecognized (enum gcc_jit_str_option) value: %i", opt);
+ return;
+ }
+ free (m_str_options[opt]);
+ m_str_options[opt] = value ? xstrdup (value) : NULL;
+ log_str_option (opt);
+}
+
+/* Set the given integer option for this context, or add an error if
+ it's not recognized.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_set_int_option. */
+
+void
+recording::context::set_int_option (enum gcc_jit_int_option opt,
+ int value)
+{
+ if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
+ {
+ add_error (NULL,
+ "unrecognized (enum gcc_jit_int_option) value: %i", opt);
+ return;
+ }
+ m_int_options[opt] = value;
+ log_int_option (opt);
+}
+
+/* Set the given boolean option for this context, or add an error if
+ it's not recognized.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_set_bool_option. */
+
+void
+recording::context::set_bool_option (enum gcc_jit_bool_option opt,
+ int value)
+{
+ if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
+ {
+ add_error (NULL,
+ "unrecognized (enum gcc_jit_bool_option) value: %i", opt);
+ return;
+ }
+ m_bool_options[opt] = value ? true : false;
+ log_bool_option (opt);
+}
+
+/* Add the given dumpname/out_ptr pair to this context's list of requested
+ dumps.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_enable_dump. */
+
+void
+recording::context::enable_dump (const char *dumpname,
+ char **out_ptr)
+{
+ requested_dump d;
+ gcc_assert (dumpname);
+ gcc_assert (out_ptr);
+
+ d.m_dumpname = dumpname;
+ d.m_out_ptr = out_ptr;
+ *out_ptr = NULL;
+ m_requested_dumps.safe_push (d);
+}
+
+/* Validate this context, and if it passes, compile it to memory
+ (within a mutex).
+
+ Implements the post-error-checking part of
+ gcc_jit_context_compile. */
+
+result *
+recording::context::compile ()
+{
+ JIT_LOG_SCOPE (get_logger ());
+
+ log_all_options ();
+
+ validate ();
+
+ if (errors_occurred ())
+ return NULL;
+
+ /* Set up a compile_to_memory playback context. */
+ ::gcc::jit::playback::compile_to_memory replayer (this);
+
+ /* Use it. */
+ replayer.compile ();
+
+ /* Get the jit::result (or NULL) from the
+ compile_to_memory playback context. */
+ return replayer.get_result_obj ();
+}
+
+/* Validate this context, and if it passes, compile it to a file
+ (within a mutex).
+
+ Implements the post-error-checking part of
+ gcc_jit_context_compile_to_file. */
+
+void
+recording::context::compile_to_file (enum gcc_jit_output_kind output_kind,
+ const char *output_path)
+{
+ JIT_LOG_SCOPE (get_logger ());
+
+ log_all_options ();
+
+ validate ();
+
+ if (errors_occurred ())
+ return;
+
+ /* Set up a compile_to_file playback context. */
+ ::gcc::jit::playback::compile_to_file replayer (this,
+ output_kind,
+ output_path);
+
+ /* Use it. */
+ replayer.compile ();
+}
+
+/* Format the given error using printf's conventions, print
+ it to stderr, and add it to the context. */
+
+void
+recording::context::add_error (location *loc, const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ add_error_va (loc, fmt, ap);
+ va_end (ap);
+}
+
+/* Format the given error using printf's conventions, print
+ it to stderr, and add it to the context. */
+
+void
+recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
+{
+ int len;
+ char *malloced_msg;
+ const char *errmsg;
+ bool has_ownership;
+
+ JIT_LOG_SCOPE (get_logger ());
+
+ len = vasprintf (&malloced_msg, fmt, ap);
+ if (malloced_msg == NULL || len < 0)
+ {
+ errmsg = "out of memory generating error message";
+ has_ownership = false;
+ }
+ else
+ {
+ errmsg = malloced_msg;
+ has_ownership = true;
+ }
+ if (get_logger ())
+ get_logger ()->log ("error %i: %s", m_error_count, errmsg);
+
+ const char *ctxt_progname =
+ get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+ if (!ctxt_progname)
+ ctxt_progname = "libgccjit.so";
+
+ if (loc)
+ fprintf (stderr, "%s: %s: error: %s\n",
+ ctxt_progname,
+ loc->get_debug_string (),
+ errmsg);
+ else
+ fprintf (stderr, "%s: error: %s\n",
+ ctxt_progname,
+ errmsg);
+
+ if (!m_error_count)
+ {
+ m_first_error_str = const_cast <char *> (errmsg);
+ m_owns_first_error_str = has_ownership;
+ }
+
+ if (m_owns_last_error_str)
+ if (m_last_error_str != m_first_error_str)
+ free (m_last_error_str);
+ m_last_error_str = const_cast <char *> (errmsg);
+ m_owns_last_error_str = has_ownership;
+
+ m_error_count++;
+}
+
+/* Get the message for the first error that occurred on this context, or
+ NULL if no errors have occurred on it.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_first_error. */
+
+const char *
+recording::context::get_first_error () const
+{
+ return m_first_error_str;
+}
+
+/* Get the message for the last error that occurred on this context, or
+ NULL if no errors have occurred on it.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_last_error. */
+
+const char *
+recording::context::get_last_error () const
+{
+ return m_last_error_str;
+}
+
+/* Lazily generate and record a recording::type representing an opaque
+ struct named "FILE".
+
+ For use if client code tries to dereference the result of
+ get_type (GCC_JIT_TYPE_FILE_PTR). */
+
+recording::type *
+recording::context::get_opaque_FILE_type ()
+{
+ if (!m_FILE_type)
+ m_FILE_type = new_struct_type (NULL, "FILE");
+ return m_FILE_type;
+}
+
+/* Dump a C-like representation of the given context to the given path.
+ If UPDATE_LOCATIONS is true, update the locations within the
+ context's mementos to point to the dumpfile.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_dump_to_file. */
+
+void
+recording::context::dump_to_file (const char *path, bool update_locations)
+{
+ int i;
+ dump d (*this, path, update_locations);
+
+ /* Forward declaration of structs and unions. */
+ compound_type *st;
+ FOR_EACH_VEC_ELT (m_compound_types, i, st)
+ {
+ d.write ("%s;\n\n", st->get_debug_string ());
+ }
+
+ /* Content of structs, where set. */
+ FOR_EACH_VEC_ELT (m_compound_types, i, st)
+ if (st->get_fields ())
+ {
+ st->get_fields ()->write_to_dump (d);
+ d.write ("\n");
+ }
+
+ /* Globals. */
+ global *g;
+ FOR_EACH_VEC_ELT (m_globals, i, g)
+ {
+ g->write_to_dump (d);
+ }
+ if (!m_globals.is_empty ())
+ d.write ("\n");
+
+ function *fn;
+ FOR_EACH_VEC_ELT (m_functions, i, fn)
+ {
+ fn->write_to_dump (d);
+ }
+}
+
+static const char * const
+ str_option_reproducer_strings[GCC_JIT_NUM_STR_OPTIONS] = {
+ "GCC_JIT_STR_OPTION_PROGNAME"
+};
+
+static const char * const
+ int_option_reproducer_strings[GCC_JIT_NUM_INT_OPTIONS] = {
+ "GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL"
+};
+
+static const char * const
+ bool_option_reproducer_strings[GCC_JIT_NUM_BOOL_OPTIONS] = {
+ "GCC_JIT_BOOL_OPTION_DEBUGINFO",
+ "GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE",
+ "GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE",
+ "GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE",
+ "GCC_JIT_BOOL_OPTION_DUMP_SUMMARY",
+ "GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING",
+ "GCC_JIT_BOOL_OPTION_SELFCHECK_GC",
+ "GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES"
+};
+
+
+/* Write the current value of all options to the log file (if any). */
+
+void
+recording::context::log_all_options () const
+{
+ int opt_idx;
+
+ if (!get_logger ())
+ return;
+
+ for (opt_idx = 0; opt_idx < GCC_JIT_NUM_STR_OPTIONS; opt_idx++)
+ log_str_option ((enum gcc_jit_str_option)opt_idx);
+
+ for (opt_idx = 0; opt_idx < GCC_JIT_NUM_INT_OPTIONS; opt_idx++)
+ log_int_option ((enum gcc_jit_int_option)opt_idx);
+
+ for (opt_idx = 0; opt_idx < GCC_JIT_NUM_BOOL_OPTIONS; opt_idx++)
+ log_bool_option ((enum gcc_jit_bool_option)opt_idx);
+}
+
+/* Write the current value of the given string option to the
+ log file (if any). */
+
+void
+recording::context::log_str_option (enum gcc_jit_str_option opt) const
+{
+ gcc_assert (opt < GCC_JIT_NUM_STR_OPTIONS);
+ if (get_logger ())
+ {
+ if (m_str_options[opt])
+ log ("%s: \"%s\"",
+ str_option_reproducer_strings[opt],
+ m_str_options[opt]);
+ else
+ log ("%s: NULL",
+ str_option_reproducer_strings[opt]);
+ }
+}
+
+/* Write the current value of the given int option to the
+ log file (if any). */
+
+void
+recording::context::log_int_option (enum gcc_jit_int_option opt) const
+{
+ gcc_assert (opt < GCC_JIT_NUM_INT_OPTIONS);
+ if (get_logger ())
+ log ("%s: %i",
+ int_option_reproducer_strings[opt],
+ m_int_options[opt]);
+}
+
+/* Write the current value of the given bool option to the
+ log file (if any). */
+
+void
+recording::context::log_bool_option (enum gcc_jit_bool_option opt) const
+{
+ gcc_assert (opt < GCC_JIT_NUM_BOOL_OPTIONS);
+ if (get_logger ())
+ log ("%s: %s",
+ bool_option_reproducer_strings[opt],
+ m_bool_options[opt] ? "true" : "false");
+}
+
+/* Write C source code to PATH that attempts to replay the API
+ calls made to this context (and its parents), for use in
+ minimizing test cases for libgccjit.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_dump_reproducer_to_file. */
+
+void
+recording::context::dump_reproducer_to_file (const char *path)
+{
+ JIT_LOG_SCOPE (get_logger ());
+ reproducer r (*this, path);
+
+ /* Generate the "ancestry" of this context, as a list. */
+ auto_vec <context *> ascending_contexts;
+ for (context *ctxt = this; ctxt; ctxt = ctxt->m_parent_ctxt)
+ ascending_contexts.safe_push (ctxt);
+
+ /* Reverse the list, giving a list of contexts from
+ top-most parent context down through to youngest child context.
+ We will use this list as the parameters of the functions in
+ our generated file. */
+ unsigned num_ctxts = ascending_contexts.length ();
+ auto_vec <context *> contexts (num_ctxts);
+ for (unsigned i = 0; i < num_ctxts; i++)
+ contexts.safe_push (ascending_contexts[num_ctxts - (i + 1)]);
+
+ /* contexts[0] should be the top-level context. */
+ gcc_assert (contexts[0]);
+ gcc_assert (contexts[0]->m_toplevel_ctxt == contexts[0]);
+
+ /* The final element in contexts should be "this". */
+ gcc_assert (contexts[contexts.length () - 1] == this);
+ gcc_assert (contexts[contexts.length () - 1]->m_toplevel_ctxt
+ == contexts[0]);
+
+ r.write ("/* This code was autogenerated by"
+ " gcc_jit_context_dump_reproducer_to_file.\n\n");
+ print_version (r.get_file (), " ", false);
+ r.write ("*/\n");
+ r.write ("#include <libgccjit.h>\n\n");
+ r.write ("static void\nset_options (");
+ r.write_params (contexts);
+ r.write (");\n\n");
+ r.write ("static void\ncreate_code (");
+ r.write_params (contexts);
+ r.write (");\n\n");
+ r.write ("int\nmain (int argc, const char **argv)\n");
+ r.write ("{\n");
+ for (unsigned i = 0; i < num_ctxts; i++)
+ r.write (" gcc_jit_context *%s;\n",
+ r.get_identifier (contexts[i]));
+ r.write (" gcc_jit_result *result;\n"
+ "\n");
+
+ /* Create the contexts.
+ The top-level context is acquired from a clean slate, the others as
+ children of the prior context. */
+ r.write (" %s = gcc_jit_context_acquire ();\n",
+ r.get_identifier (contexts[0]));
+ for (unsigned i = 1; i < num_ctxts; i++)
+ r.write (" %s = gcc_jit_context_new_child_context (%s);\n",
+ r.get_identifier (contexts[i]),
+ r.get_identifier (contexts[i - 1]));
+ r.write (" set_options (");
+ r.write_args (contexts);
+ r.write (");\n");
+ r.write (" create_code (");
+ r.write_args (contexts);
+ r.write (");\n");
+
+ r.write (" result = gcc_jit_context_compile (%s);\n",
+ r.get_identifier (this));
+
+ for (unsigned i = num_ctxts; i > 0; i--)
+ r.write (" gcc_jit_context_release (%s);\n",
+ r.get_identifier (contexts[i - 1]));
+
+ r.write (" gcc_jit_result_release (result);\n"
+ " return 0;\n"
+ "}\n\n");
+
+ /* Define (char *) variables for use in calls to
+ gcc_jit_context_enable_dump. */
+ for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+ {
+ if (m_requested_dumps.length ())
+ {
+ r.write ("/* Requested dumps for %s. */\n",
+ r.get_identifier (contexts[ctxt_idx]));
+ for (unsigned i = 0; i < m_requested_dumps.length (); i++)
+ r.write ("static char *dump_%p;\n",
+ (void *)&m_requested_dumps[i]);
+ r.write ("\n");
+ }
+ }
+
+ /* Write out values of options. */
+ r.write ("static void\nset_options (");
+ r.write_params (contexts);
+ r.write (")\n{\n");
+ for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+ {
+ if (ctxt_idx > 0)
+ r.write ("\n");
+
+ r.write (" /* Set options for %s. */\n",
+ r.get_identifier (contexts[ctxt_idx]));
+
+ r.write (" /* String options. */\n");
+ for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_STR_OPTIONS; opt_idx++)
+ r.write (" gcc_jit_context_set_str_option (%s,\n"
+ " %s,\n"
+ " \"%s\");\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ str_option_reproducer_strings[opt_idx],
+ m_str_options[opt_idx] ? m_str_options[opt_idx] : "NULL");
+ r.write (" /* Int options. */\n");
+ for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_INT_OPTIONS; opt_idx++)
+ r.write (" gcc_jit_context_set_int_option (%s,\n"
+ " %s,\n"
+ " %i);\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ int_option_reproducer_strings[opt_idx],
+ m_int_options[opt_idx]);
+ r.write (" /* Boolean options. */\n");
+ for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_BOOL_OPTIONS; opt_idx++)
+ r.write (" gcc_jit_context_set_bool_option (%s,\n"
+ " %s,\n"
+ " %i);\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ bool_option_reproducer_strings[opt_idx],
+ m_bool_options[opt_idx]);
+
+ if (m_requested_dumps.length ())
+ {
+ r.write (" /* Requested dumps. */\n");
+ /* Dumpfiles that were requested via gcc_jit_context_enable_dump. */
+ for (unsigned i = 0; i < m_requested_dumps.length (); i++)
+ {
+ r.write (" gcc_jit_context_enable_dump (%s,\n"
+ " \"%s\",\n"
+ " &dump_%p);\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ m_requested_dumps[i].m_dumpname,
+ (void *)&m_requested_dumps[i]);
+ }
+ }
+ }
+ r.write ("}\n\n");
+
+ r.write ("static void\ncreate_code (");
+ r.write_params (contexts);
+ r.write (")\n"
+ "{\n");
+ for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+ {
+ memento *m;
+ int i;
+ if (ctxt_idx > 0)
+ r.write ("\n\n");
+
+ r.write (" /* Replay of API calls for %s. */\n",
+ r.get_identifier (contexts[ctxt_idx]));
+ FOR_EACH_VEC_ELT (contexts[ctxt_idx]->m_mementos, i, m)
+ m->write_reproducer (r);
+ }
+ r.write ("}\n");
+}
+
+/* Copy the requested dumps within this context and all ancestors into
+ OUT. */
+
+void
+recording::context::get_all_requested_dumps (vec <recording::requested_dump> *out)
+{
+ if (m_parent_ctxt)
+ m_parent_ctxt->get_all_requested_dumps (out);
+
+ out->reserve (m_requested_dumps.length ());
+ out->splice (m_requested_dumps);
+}
+
+/* This is a pre-compilation check for the context (and any parents).
+
+ Detect errors within the context, adding errors if any are found. */
+
+void
+recording::context::validate ()
+{
+ JIT_LOG_SCOPE (get_logger ());
+
+ if (m_parent_ctxt)
+ m_parent_ctxt->validate ();
+
+ int i;
+ function *fn;
+ FOR_EACH_VEC_ELT (m_functions, i, fn)
+ fn->validate ();
+}
+
+/* The implementation of class gcc::jit::recording::memento. */
+
+/* Get a (const char *) debug description of the given memento, by
+ calling the pure-virtual make_debug_string hook, caching the
+ result.
+
+ It is intended that this should only be called in debugging and
+ error-handling paths, so this doesn't need to be particularly
+ optimized. */
+
+const char *
+recording::memento::get_debug_string ()
+{
+ if (!m_debug_string)
+ m_debug_string = make_debug_string ();
+ return m_debug_string->c_str ();
+}
+
+/* Default implementation of recording::memento::write_to_dump, writing
+ an indented form of the memento's debug string to the dump. */
+
+void
+recording::memento::write_to_dump (dump &d)
+{
+ d.write(" %s\n", get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::string. */
+
+/* Constructor for gcc::jit::recording::string::string, allocating a
+ copy of the given text using new char[]. */
+
+recording::string::string (context *ctxt, const char *text)
+ : memento (ctxt)
+{
+ m_len = strlen (text);
+ m_buffer = new char[m_len + 1];
+ strcpy (m_buffer, text);
+}
+
+/* Destructor for gcc::jit::recording::string::string. */
+
+recording::string::~string ()
+{
+ delete[] m_buffer;
+}
+
+/* Function for making gcc::jit::recording::string instances on a
+ context via printf-style formatting.
+
+ It is intended that this should only be called in debugging and
+ error-handling paths, so this doesn't need to be particularly
+ optimized, hence the double-copy of the string is acceptable. */
+
+recording::string *
+recording::string::from_printf (context *ctxt, const char *fmt, ...)
+{
+ int len;
+ va_list ap;
+ char *buf;
+ recording::string *result;
+
+ va_start (ap, fmt);
+ len = vasprintf (&buf, fmt, ap);
+ va_end (ap);
+
+ if (buf == NULL || len < 0)
+ {
+ ctxt->add_error (NULL, "malloc failure");
+ return NULL;
+ }
+
+ result = ctxt->new_string (buf);
+ free (buf);
+ return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for strings,
+ wrapping the given string in quotes and escaping as necessary. */
+
+recording::string *
+recording::string::make_debug_string ()
+{
+ /* Hack to avoid infinite recursion into strings when logging all
+ mementos: don't re-escape strings: */
+ if (m_buffer[0] == '"')
+ return this;
+
+ /* Wrap in quotes and do escaping etc */
+
+ size_t sz = (1 /* opening quote */
+ + (m_len * 2) /* each char might get escaped */
+ + 1 /* closing quote */
+ + 1); /* nil termintator */
+ char *tmp = new char[sz];
+ size_t len = 0;
+
+#define APPEND(CH) do { gcc_assert (len < sz); tmp[len++] = (CH); } while (0)
+ APPEND('"'); /* opening quote */
+ for (size_t i = 0; i < m_len ; i++)
+ {
+ char ch = m_buffer[i];
+ if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
+ APPEND('\\');
+ APPEND(ch);
+ }
+ APPEND('"'); /* closing quote */
+#undef APPEND
+ tmp[len] = '\0'; /* nil termintator */
+
+ string *result = m_ctxt->new_string (tmp);
+
+ delete[] tmp;
+ return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for strings. */
+
+void
+recording::string::write_reproducer (reproducer &)
+{
+ /* Empty. */
+}
+
+/* The implementation of class gcc::jit::recording::location. */
+
+/* Implementation of recording::memento::replay_into for locations.
+
+ Create a new playback::location and store it into the
+ recording::location's m_playback_obj field. */
+
+void
+recording::location::replay_into (replayer *r)
+{
+ m_playback_obj = r->new_location (this,
+ m_filename->c_str (),
+ m_line,
+ m_column);
+}
+
+/* Implementation of recording::memento::make_debug_string for locations,
+ turning them into the usual form:
+ FILENAME:LINE:COLUMN
+ like we do when emitting diagnostics. */
+
+recording::string *
+recording::location::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s:%i:%i",
+ m_filename->c_str (), m_line, m_column);
+}
+
+/* Implementation of recording::memento::write_reproducer for locations. */
+
+void
+recording::location::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "loc");
+ r.write (" gcc_jit_location *%s =\n"
+ " gcc_jit_context_new_location (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* const char *filename */\n"
+ " %i, /* int line */\n"
+ " %i);/* int column */\n",
+ id,
+ r.get_identifier (get_context ()),
+ m_filename->get_debug_string (),
+ m_line, m_column);
+}
+
+/* The implementation of class gcc::jit::recording::type. */
+
+/* Given a type T, get the type T*.
+
+ If this doesn't already exist, generate a new memento_of_get_pointer
+ instance and add it to this type's context's list of mementos.
+
+ Otherwise, use the cached type.
+
+ Implements the post-error-checking part of
+ gcc_jit_type_get_pointer. */
+
+recording::type *
+recording::type::get_pointer ()
+{
+ if (!m_pointer_to_this_type)
+ {
+ m_pointer_to_this_type = new memento_of_get_pointer (this);
+ m_ctxt->record (m_pointer_to_this_type);
+ }
+ return m_pointer_to_this_type;
+}
+
+/* Given a type T, get the type const T.
+
+ Implements the post-error-checking part of
+ gcc_jit_type_get_const. */
+
+recording::type *
+recording::type::get_const ()
+{
+ recording::type *result = new memento_of_get_const (this);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* Given a type T, get the type volatile T.
+
+ Implements the post-error-checking part of
+ gcc_jit_type_get_volatile. */
+
+recording::type *
+recording::type::get_volatile ()
+{
+ recording::type *result = new memento_of_get_volatile (this);
+ m_ctxt->record (result);
+ return result;
+}
+
+const char *
+recording::type::access_as_type (reproducer &r)
+{
+ return r.get_identifier (this);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+ recording::memento_of_get_type. */
+
+recording::type *
+recording::memento_of_get_type::dereference ()
+{
+ switch (m_kind)
+ {
+ default: gcc_unreachable ();
+
+ case GCC_JIT_TYPE_VOID:
+ return NULL;
+
+ case GCC_JIT_TYPE_VOID_PTR:
+ return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+
+ case GCC_JIT_TYPE_BOOL:
+ case GCC_JIT_TYPE_CHAR:
+ case GCC_JIT_TYPE_SIGNED_CHAR:
+ case GCC_JIT_TYPE_UNSIGNED_CHAR:
+ case GCC_JIT_TYPE_SHORT:
+ case GCC_JIT_TYPE_UNSIGNED_SHORT:
+ case GCC_JIT_TYPE_INT:
+ case GCC_JIT_TYPE_UNSIGNED_INT:
+ case GCC_JIT_TYPE_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG:
+ case GCC_JIT_TYPE_LONG_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+ case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_DOUBLE:
+ case GCC_JIT_TYPE_LONG_DOUBLE:
+ case GCC_JIT_TYPE_COMPLEX_FLOAT:
+ case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+ case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+ /* Not a pointer: */
+ return NULL;
+
+ case GCC_JIT_TYPE_CONST_CHAR_PTR:
+ return m_ctxt->get_type (GCC_JIT_TYPE_CHAR)->get_const ();
+
+ case GCC_JIT_TYPE_SIZE_T:
+ /* Not a pointer: */
+ return NULL;
+
+ case GCC_JIT_TYPE_FILE_PTR:
+ /* Give the client code back an opaque "struct FILE". */
+ return m_ctxt->get_opaque_FILE_type ();
+ }
+}
+
+/* Implementation of pure virtual hook recording::type::is_int for
+ recording::memento_of_get_type. */
+
+bool
+recording::memento_of_get_type::is_int () const
+{
+ switch (m_kind)
+ {
+ default: gcc_unreachable ();
+
+ case GCC_JIT_TYPE_VOID:
+ return false;
+
+ case GCC_JIT_TYPE_VOID_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_BOOL:
+ return false;
+
+ case GCC_JIT_TYPE_CHAR:
+ case GCC_JIT_TYPE_SIGNED_CHAR:
+ case GCC_JIT_TYPE_UNSIGNED_CHAR:
+ case GCC_JIT_TYPE_SHORT:
+ case GCC_JIT_TYPE_UNSIGNED_SHORT:
+ case GCC_JIT_TYPE_INT:
+ case GCC_JIT_TYPE_UNSIGNED_INT:
+ case GCC_JIT_TYPE_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG:
+ case GCC_JIT_TYPE_LONG_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+ return true;
+
+ case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_DOUBLE:
+ case GCC_JIT_TYPE_LONG_DOUBLE:
+ return false;
+
+ case GCC_JIT_TYPE_CONST_CHAR_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_SIZE_T:
+ return true;
+
+ case GCC_JIT_TYPE_FILE_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_COMPLEX_FLOAT:
+ case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+ case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+ return false;
+ }
+}
+
+/* Implementation of pure virtual hook recording::type::is_float for
+ recording::memento_of_get_type. */
+
+bool
+recording::memento_of_get_type::is_float () const
+{
+ switch (m_kind)
+ {
+ default: gcc_unreachable ();
+
+ case GCC_JIT_TYPE_VOID:
+ return false;
+
+ case GCC_JIT_TYPE_VOID_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_BOOL:
+ return false;
+
+ case GCC_JIT_TYPE_CHAR:
+ case GCC_JIT_TYPE_SIGNED_CHAR:
+ case GCC_JIT_TYPE_UNSIGNED_CHAR:
+ case GCC_JIT_TYPE_SHORT:
+ case GCC_JIT_TYPE_UNSIGNED_SHORT:
+ case GCC_JIT_TYPE_INT:
+ case GCC_JIT_TYPE_UNSIGNED_INT:
+ case GCC_JIT_TYPE_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG:
+ case GCC_JIT_TYPE_LONG_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+ return false;
+
+ case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_DOUBLE:
+ case GCC_JIT_TYPE_LONG_DOUBLE:
+ return true;
+
+ case GCC_JIT_TYPE_CONST_CHAR_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_SIZE_T:
+ return false;
+
+ case GCC_JIT_TYPE_FILE_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_COMPLEX_FLOAT:
+ case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+ case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+ return true;
+ }
+}
+
+/* Implementation of pure virtual hook recording::type::is_bool for
+ recording::memento_of_get_type. */
+
+bool
+recording::memento_of_get_type::is_bool () const
+{
+ switch (m_kind)
+ {
+ default: gcc_unreachable ();
+
+ case GCC_JIT_TYPE_VOID:
+ return false;
+
+ case GCC_JIT_TYPE_VOID_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_BOOL:
+ return true;
+
+ case GCC_JIT_TYPE_CHAR:
+ case GCC_JIT_TYPE_SIGNED_CHAR:
+ case GCC_JIT_TYPE_UNSIGNED_CHAR:
+ case GCC_JIT_TYPE_SHORT:
+ case GCC_JIT_TYPE_UNSIGNED_SHORT:
+ case GCC_JIT_TYPE_INT:
+ case GCC_JIT_TYPE_UNSIGNED_INT:
+ case GCC_JIT_TYPE_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG:
+ case GCC_JIT_TYPE_LONG_LONG:
+ case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+ return false;
+
+ case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_DOUBLE:
+ case GCC_JIT_TYPE_LONG_DOUBLE:
+ return false;
+
+ case GCC_JIT_TYPE_CONST_CHAR_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_SIZE_T:
+ return false;
+
+ case GCC_JIT_TYPE_FILE_PTR:
+ return false;
+
+ case GCC_JIT_TYPE_COMPLEX_FLOAT:
+ case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+ case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+ return false;
+ }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_get_type. */
+
+void
+recording::memento_of_get_type::replay_into (replayer *r)
+{
+ set_playback_obj (r->get_type (m_kind));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_type. */
+
+/* Descriptive strings for each of enum gcc_jit_types. */
+
+static const char * const get_type_strings[] = {
+ "void", /* GCC_JIT_TYPE_VOID */
+ "void *", /* GCC_JIT_TYPE_VOID_PTR */
+
+ "bool", /* GCC_JIT_TYPE_BOOL */
+
+ "char", /* GCC_JIT_TYPE_CHAR */
+ "signed char", /* GCC_JIT_TYPE_SIGNED_CHAR */
+ "unsigned char", /* GCC_JIT_TYPE_UNSIGNED_CHAR */
+
+ "short", /* GCC_JIT_TYPE_SHORT */
+ "unsigned short", /* GCC_JIT_TYPE_UNSIGNED_SHORT */
+
+ "int", /* GCC_JIT_TYPE_INT */
+ "unsigned int", /* GCC_JIT_TYPE_UNSIGNED_INT */
+
+ "long", /* GCC_JIT_TYPE_LONG */
+ "unsigned long", /* GCC_JIT_TYPE_UNSIGNED_LONG, */
+
+ "long long", /* GCC_JIT_TYPE_LONG_LONG */
+ "unsigned long long", /* GCC_JIT_TYPE_UNSIGNED_LONG_LONG */
+
+ "float", /* GCC_JIT_TYPE_FLOAT */
+ "double", /* GCC_JIT_TYPE_DOUBLE */
+ "long double", /* GCC_JIT_TYPE_LONG_DOUBLE */
+
+ "const char *", /* GCC_JIT_TYPE_CONST_CHAR_PTR */
+
+ "size_t", /* GCC_JIT_TYPE_SIZE_T */
+
+ "FILE *", /* GCC_JIT_TYPE_FILE_PTR */
+
+ "complex float", /* GCC_JIT_TYPE_COMPLEX_FLOAT */
+ "complex double", /* GCC_JIT_TYPE_COMPLEX_DOUBLE */
+ "complex long double" /* GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE */
+
+};
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_type, using a simple table of type names. */
+
+recording::string *
+recording::memento_of_get_type::make_debug_string ()
+{
+ return m_ctxt->new_string (get_type_strings[m_kind]);
+}
+
+static const char * const get_type_enum_strings[] = {
+ "GCC_JIT_TYPE_VOID",
+ "GCC_JIT_TYPE_VOID_PTR",
+ "GCC_JIT_TYPE_BOOL",
+ "GCC_JIT_TYPE_CHAR",
+ "GCC_JIT_TYPE_SIGNED_CHAR",
+ "GCC_JIT_TYPE_UNSIGNED_CHAR",
+ "GCC_JIT_TYPE_SHORT",
+ "GCC_JIT_TYPE_UNSIGNED_SHORT",
+ "GCC_JIT_TYPE_INT",
+ "GCC_JIT_TYPE_UNSIGNED_INT",
+ "GCC_JIT_TYPE_LONG",
+ "GCC_JIT_TYPE_UNSIGNED_LONG",
+ "GCC_JIT_TYPE_LONG_LONG",
+ "GCC_JIT_TYPE_UNSIGNED_LONG_LONG",
+ "GCC_JIT_TYPE_FLOAT",
+ "GCC_JIT_TYPE_DOUBLE",
+ "GCC_JIT_TYPE_LONG_DOUBLE",
+ "GCC_JIT_TYPE_CONST_CHAR_PTR",
+ "GCC_JIT_TYPE_SIZE_T",
+ "GCC_JIT_TYPE_FILE_PTR",
+ "GCC_JIT_TYPE_COMPLEX_FLOAT",
+ "GCC_JIT_TYPE_COMPLEX_DOUBLE",
+ "GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE"
+};
+
+void
+recording::memento_of_get_type::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s = gcc_jit_context_get_type (%s, %s);\n",
+ id,
+ r.get_identifier (get_context ()),
+ get_type_enum_strings[m_kind]);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_pointer. */
+
+/* Override of default implementation of
+ recording::type::accepts_writes_from for get_pointer.
+
+ Require a pointer type, and allowing writes to
+ (const T *) from a (T*), but not the other way around. */
+
+bool
+recording::memento_of_get_pointer::accepts_writes_from (type *rtype)
+{
+ /* Must be a pointer type: */
+ type *rtype_points_to = rtype->is_pointer ();
+ if (!rtype_points_to)
+ return false;
+
+ /* It's OK to assign to a (const T *) from a (T *). */
+ return m_other_type->unqualified ()
+ ->accepts_writes_from (rtype_points_to);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_get_pointer. */
+
+void
+recording::memento_of_get_pointer::replay_into (replayer *)
+{
+ set_playback_obj (m_other_type->playback_type ()->get_pointer ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_pointer, adding " *" to the underlying type,
+ with special-casing to handle function pointer types. */
+
+recording::string *
+recording::memento_of_get_pointer::make_debug_string ()
+{
+ /* Special-case function pointer types, to put the "*" in parens between
+ the return type and the params (for one level of dereferencing, at
+ least). */
+ if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+ return fn_type->make_debug_string_with_ptr ();
+
+ return string::from_printf (m_ctxt,
+ "%s *", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for get_pointer. */
+
+void
+recording::memento_of_get_pointer::write_reproducer (reproducer &r)
+{
+ /* We need to special-case function pointer types; see the notes in
+ recording::function_type::write_deferred_reproducer. */
+ if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+ {
+ fn_type->write_deferred_reproducer (r, this);
+ return;
+ }
+
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_type_get_pointer (%s);\n",
+ id,
+ r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_const. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_get_const. */
+
+void
+recording::memento_of_get_const::replay_into (replayer *)
+{
+ set_playback_obj (m_other_type->playback_type ()->get_const ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_const, prepending "const ". */
+
+recording::string *
+recording::memento_of_get_const::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "const %s", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for const types. */
+
+void
+recording::memento_of_get_const::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_type_get_const (%s);\n",
+ id,
+ r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_volatile. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_get_volatile. */
+
+void
+recording::memento_of_get_volatile::replay_into (replayer *)
+{
+ set_playback_obj (m_other_type->playback_type ()->get_volatile ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_volatile, prepending "volatile ". */
+
+recording::string *
+recording::memento_of_get_volatile::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "volatile %s", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for volatile
+ types. */
+
+void
+recording::memento_of_get_volatile::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_type_get_volatile (%s);\n",
+ id,
+ r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::array_type */
+
+/* Implementation of pure virtual hook recording::type::dereference for
+ recording::array_type. */
+
+recording::type *
+recording::array_type::dereference ()
+{
+ return m_element_type;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::array_type. */
+
+void
+recording::array_type::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_array_type (playback_location (r, m_loc),
+ m_element_type->playback_type (),
+ m_num_elements));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of new_array_type. */
+
+recording::string *
+recording::array_type::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s[%d]",
+ m_element_type->get_debug_string (),
+ m_num_elements);
+}
+
+/* Implementation of recording::memento::write_reproducer for array
+ types. */
+
+void
+recording::array_type::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "array_type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_context_new_array_type (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *element_type */\n"
+ " %i); /* int num_elements */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_type (m_element_type),
+ m_num_elements);
+}
+
+/* The implementation of class gcc::jit::recording::function_type */
+
+/* Constructor for gcc::jit::recording::function_type. */
+
+recording::function_type::function_type (context *ctxt,
+ type *return_type,
+ int num_params,
+ type **param_types,
+ int is_variadic)
+: type (ctxt),
+ m_return_type (return_type),
+ m_param_types (),
+ m_is_variadic (is_variadic)
+{
+ for (int i = 0; i< num_params; i++)
+ m_param_types.safe_push (param_types[i]);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+ recording::function_type. */
+
+recording::type *
+recording::function_type::dereference ()
+{
+ return NULL;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::function_type. */
+
+void
+recording::function_type::replay_into (replayer *r)
+{
+ /* Convert m_param_types to a vec of playback type. */
+ auto_vec <playback::type *> param_types;
+ int i;
+ recording::type *type;
+ param_types.create (m_param_types.length ());
+ FOR_EACH_VEC_ELT (m_param_types, i, type)
+ param_types.safe_push (type->playback_type ());
+
+ set_playback_obj (r->new_function_type (m_return_type->playback_type (),
+ &param_types,
+ m_is_variadic));
+}
+
+/* Special-casing for make_debug_string for get_pointer results for
+ handling (one level) of pointers to functions. */
+
+recording::string *
+recording::function_type::make_debug_string_with_ptr ()
+{
+ return make_debug_string_with ("(*) ");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of new_function_type. */
+
+recording::string *
+recording::function_type::make_debug_string ()
+{
+ return make_debug_string_with ("");
+}
+
+/* Build a debug string representation of the form:
+
+ RESULT_TYPE INSERT (PARAM_TYPES)
+
+ for use when handling 0 and 1 level of indirection to this
+ function type. */
+
+recording::string *
+recording::function_type::make_debug_string_with (const char *insert)
+{
+ /* First, build a buffer for the arguments. */
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< m_param_types.length (); i++)
+ {
+ sz += strlen (m_param_types[i]->get_debug_string ());
+ sz += 2; /* ", " separator */
+ }
+ if (m_is_variadic)
+ sz += 5; /* ", ..." separator and ellipsis */
+
+ /* Now allocate and populate the buffer. */
+ char *argbuf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< m_param_types.length (); i++)
+ {
+ strcpy (argbuf + len, m_param_types[i]->get_debug_string ());
+ len += strlen (m_param_types[i]->get_debug_string ());
+ if (i + 1 < m_param_types.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ }
+ if (m_is_variadic)
+ {
+ if (m_param_types.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ strcpy (argbuf + len, "...");
+ len += 3;
+ }
+ argbuf[len] = '\0';
+
+ /* ...and use it to get the string for the call as a whole. */
+ string *result = string::from_printf (m_ctxt,
+ "%s %s(%s)",
+ m_return_type->get_debug_string (),
+ insert,
+ argbuf);
+
+ delete[] argbuf;
+
+ return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for function
+ types. */
+
+void
+recording::function_type::write_reproducer (reproducer &)
+{
+ /* see notes below. */
+}
+
+/* There's a get_pointer within context::new_function_ptr_type:
+ the type received by client code isn't the memento for the
+ function_type, but instead the result of get_pointer on it.
+
+ Hence we can't directly write a reproducer that gives function_type.
+ Instead we special-case things within get_pointer, detecting this
+ case, calling the following function. */
+
+void
+recording::function_type::write_deferred_reproducer (reproducer &r,
+ memento *ptr_type)
+{
+ gcc_assert (ptr_type);
+ r.make_identifier (this, "function_type");
+ const char *ptr_id = r.make_identifier (ptr_type, "ptr_to");
+ const char *param_types_id = r.make_tmp_identifier ("params_for", this);
+ r.write (" gcc_jit_type *%s[%i] = {\n",
+ param_types_id,
+ m_param_types.length ());
+ int i;
+ type *param_type;
+ FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+ r.write (" %s,\n", r.get_identifier_as_type (param_type));
+ r.write (" };\n");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_context_new_function_ptr_type (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *return_type */\n"
+ " %i, /* int num_params */\n"
+ " %s, /* gcc_jit_type **param_types */\n"
+ " %i); /* int is_variadic */\n",
+ ptr_id,
+ r.get_identifier (get_context ()),
+ "NULL", /* location is not stored */
+ r.get_identifier_as_type (m_return_type),
+ m_param_types.length (),
+ param_types_id,
+ m_is_variadic);
+}
+
+/* The implementation of class gcc::jit::recording::field. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::field. */
+
+void
+recording::field::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_field (playback_location (r, m_loc),
+ m_type->playback_type (),
+ playback_string (m_name)));
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump. Dump each field
+ by dumping a line of the form:
+ TYPE NAME;
+ so that we can build up a struct/union field-byfield. */
+
+void
+recording::field::write_to_dump (dump &d)
+{
+ d.write (" %s %s;\n",
+ m_type->get_debug_string (),
+ m_name->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of new_field. */
+
+recording::string *
+recording::field::make_debug_string ()
+{
+ return m_name;
+}
+
+/* Implementation of recording::memento::write_reproducer for fields. */
+
+void
+recording::field::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "field");
+ r.write(" gcc_jit_field *%s =\n"
+ " gcc_jit_context_new_field (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *type, */\n"
+ " %s); /* const char *name */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_type (m_type),
+ m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::compound_type */
+
+/* The constructor for gcc::jit::recording::compound_type. */
+
+recording::compound_type::compound_type (context *ctxt,
+ location *loc,
+ string *name)
+: type (ctxt),
+ m_loc (loc),
+ m_name (name),
+ m_fields (NULL)
+{
+}
+
+/* Set the fields of a compound type.
+
+ Implements the post-error-checking part of
+ gcc_jit_struct_set_fields, and is also used by
+ gcc_jit_context_new_union_type. */
+
+void
+recording::compound_type::set_fields (location *loc,
+ int num_fields,
+ field **field_array)
+{
+ m_loc = loc;
+ gcc_assert (NULL == m_fields);
+
+ m_fields = new fields (this, num_fields, field_array);
+ m_ctxt->record (m_fields);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+ recording::compound_type. */
+
+recording::type *
+recording::compound_type::dereference ()
+{
+ return NULL; /* not a pointer */
+}
+
+/* The implementation of class gcc::jit::recording::struct_. */
+
+/* The constructor for gcc::jit::recording::struct_. */
+
+recording::struct_::struct_ (context *ctxt,
+ location *loc,
+ string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::struct_. */
+
+void
+recording::struct_::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->new_compound_type (playback_location (r, get_loc ()),
+ get_name ()->c_str (),
+ true /* is_struct */));
+}
+
+const char *
+recording::struct_::access_as_type (reproducer &r)
+{
+ return r.xstrdup_printf ("gcc_jit_struct_as_type (%s)",
+ r.get_identifier (this));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ structs. */
+
+recording::string *
+recording::struct_::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "struct %s", get_name ()->c_str ());
+}
+
+void
+recording::struct_::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "struct");
+ r.write (" gcc_jit_struct *%s =\n"
+ " gcc_jit_context_new_opaque_struct (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* const char *name */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (get_loc ()),
+ get_name ()->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::union_. */
+
+/* The constructor for gcc::jit::recording::union_. */
+
+recording::union_::union_ (context *ctxt,
+ location *loc,
+ string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::union_. */
+
+void
+recording::union_::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->new_compound_type (playback_location (r, get_loc ()),
+ get_name ()->c_str (),
+ false /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ unions. */
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "union %s", get_name ()->c_str ());
+}
+
+/* Implementation of recording::memento::write_reproducer for unions. */
+
+void
+recording::union_::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "union");
+
+ const char *fields_id = r.make_tmp_identifier ("fields_for", this);
+ r.write (" gcc_jit_field *%s[%i] = {\n",
+ fields_id,
+ get_fields ()->length ());
+ for (int i = 0; i < get_fields ()->length (); i++)
+ r.write (" %s,\n", r.get_identifier (get_fields ()->get_field (i)));
+ r.write (" };\n");
+
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_context_new_union_type (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* const char *name */\n"
+ " %i, /* int num_fields */\n"
+ " %s); /* gcc_jit_field **fields */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (get_loc ()),
+ get_name ()->get_debug_string (),
+ get_fields ()->length (),
+ fields_id);
+}
+
+/* The implementation of class gcc::jit::recording::fields. */
+
+/* The constructor for gcc::jit::recording::fields. */
+
+recording::fields::fields (compound_type *struct_or_union,
+ int num_fields,
+ field **fields)
+: memento (struct_or_union->m_ctxt),
+ m_struct_or_union (struct_or_union),
+ m_fields ()
+{
+ for (int i = 0; i < num_fields; i++)
+ {
+ gcc_assert (fields[i]->get_container () == NULL);
+ fields[i]->set_container (m_struct_or_union);
+ m_fields.safe_push (fields[i]);
+ }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::fields. */
+
+void
+recording::fields::replay_into (replayer *)
+{
+ auto_vec<playback::field *> 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_field ());
+ m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields);
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump by writing a union/struct
+ declaration of this form:
+
+ struct/union NAME {
+ TYPE_1 NAME_1;
+ TYPE_2 NAME_2;
+ ....
+ TYPE_N NAME_N;
+ };
+
+ to the dump. */
+
+void
+recording::fields::write_to_dump (dump &d)
+{
+ int i;
+ field *f;
+
+ d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
+ FOR_EACH_VEC_ELT (m_fields, i, f)
+ f->write_to_dump (d);
+ d.write ("};\n");
+}
+
+/* Implementation of recording::memento::write_reproducer for the fields
+ subclass. */
+
+void
+recording::fields::write_reproducer (reproducer &r)
+{
+ if (m_struct_or_union)
+ if (NULL == m_struct_or_union->dyn_cast_struct ())
+ /* We have a union; the fields have already been written by
+ union::write_reproducer. */
+ return;
+
+ const char *fields_id = r.make_identifier (this, "fields");
+ r.write (" gcc_jit_field *%s[%i] = {\n",
+ fields_id,
+ m_fields.length ());
+ int i;
+ field *field;
+ FOR_EACH_VEC_ELT (m_fields, i, field)
+ r.write (" %s,\n", r.get_identifier (field));
+ r.write (" };\n");
+
+ r.write (" gcc_jit_struct_set_fields (%s, /* gcc_jit_struct *struct_type */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %i, /* int num_fields */\n"
+ " %s); /* gcc_jit_field **fields */\n",
+ r.get_identifier (m_struct_or_union),
+ r.get_identifier ((memento *)NULL),
+ m_fields.length (),
+ fields_id);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ field tables. */
+
+recording::string *
+recording::fields::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "fields");
+}
+
+/* The implementation of class gcc::jit::recording::rvalue. */
+
+/* Create a recording::access_field_rvalue instance and add it to
+ the rvalue's context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_rvalue_access_field. */
+
+recording::rvalue *
+recording::rvalue::access_field (recording::location *loc,
+ field *field)
+{
+ recording::rvalue *result =
+ new access_field_rvalue (m_ctxt, loc, this, field);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* Create a recording::dereference_field_rvalue instance and add it to
+ the rvalue's context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_rvalue_dereference_field. */
+
+recording::lvalue *
+recording::rvalue::dereference_field (recording::location *loc,
+ field *field)
+{
+ recording::lvalue *result =
+ new dereference_field_rvalue (m_ctxt, loc, this, field);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* Create a recording::dereference_rvalue instance and add it to the
+ rvalue's context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_rvalue_dereference. */
+
+recording::lvalue *
+recording::rvalue::dereference (recording::location *loc)
+{
+ recording::lvalue *result =
+ new dereference_rvalue (m_ctxt, loc, this);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* An rvalue visitor, for validating that every rvalue within an expression
+ trees within "STMT" has the correct scope (e.g. no access to locals
+ of a different function). */
+
+class rvalue_usage_validator : public recording::rvalue_visitor
+{
+ public:
+ rvalue_usage_validator (const char *api_funcname,
+ recording::context *ctxt,
+ recording::statement *stmt);
+
+ void
+ visit (recording::rvalue *rvalue);
+
+ private:
+ const char *m_api_funcname;
+ recording::context *m_ctxt;
+ recording::statement *m_stmt;
+};
+
+/* The trivial constructor for rvalue_usage_validator. */
+
+rvalue_usage_validator::rvalue_usage_validator (const char *api_funcname,
+ recording::context *ctxt,
+ recording::statement *stmt)
+ : m_api_funcname (api_funcname),
+ m_ctxt (ctxt),
+ m_stmt (stmt)
+{
+}
+
+/* Verify that the given rvalue is in the correct scope. */
+
+void
+rvalue_usage_validator::visit (recording::rvalue *rvalue)
+{
+ gcc_assert (m_stmt->get_block ());
+ recording::function *stmt_scope = m_stmt->get_block ()->get_function ();
+
+ /* Most rvalues don't have a scope (only locals and params). */
+ if (rvalue->get_scope ())
+ {
+ if (rvalue->get_scope () != stmt_scope)
+ m_ctxt->add_error
+ (rvalue->get_loc (),
+ "%s:"
+ " rvalue %s (type: %s)"
+ " has scope limited to function %s"
+ " but was used within function %s"
+ " (in statement: %s)",
+ m_api_funcname,
+ rvalue->get_debug_string (),
+ rvalue->get_type ()->get_debug_string (),
+ rvalue->get_scope ()->get_debug_string (),
+ stmt_scope->get_debug_string (),
+ m_stmt->get_debug_string ());
+ }
+ else
+ {
+ if (rvalue->dyn_cast_param ())
+ m_ctxt->add_error
+ (rvalue->get_loc (),
+ "%s:"
+ " param %s (type: %s)"
+ " was used within function %s"
+ " (in statement: %s)"
+ " but is not associated with any function",
+ m_api_funcname,
+ rvalue->get_debug_string (),
+ rvalue->get_type ()->get_debug_string (),
+ stmt_scope->get_debug_string (),
+ m_stmt->get_debug_string ());
+ }
+}
+
+/* Verify that it's valid to use this rvalue (and all expressions
+ in the tree below it) within the given statement.
+
+ For example, we must reject attempts to use a local from one
+ function within a different function here, or we'll get
+ an ICE deep inside toplev::main. */
+
+void
+recording::rvalue::verify_valid_within_stmt (const char *api_funcname, statement *s)
+{
+ rvalue_usage_validator v (api_funcname,
+ s->get_context (),
+ s);
+
+ /* Verify that it's OK to use this rvalue within s. */
+ v.visit (this);
+
+ /* Traverse the expression tree below "this", verifying all rvalues
+ within it. */
+ visit_children (&v);
+}
+
+/* Set the scope of this rvalue to be the given function. This can only
+ be done once on a given rvalue. */
+
+void
+recording::rvalue::set_scope (function *scope)
+{
+ gcc_assert (scope);
+ gcc_assert (NULL == m_scope);
+ m_scope = scope;
+}
+
+
+/* Implementation of recording::rvalue::access_as_rvalue for rvalues
+ themselves.
+ Instances of rvalue don't need an upcast call. */
+
+const char *
+recording::rvalue::access_as_rvalue (reproducer &r)
+{
+ return r.get_identifier (this);
+}
+
+
+/* The implementation of class gcc::jit::recording::lvalue. */
+
+/* Create a recording::new_access_field_of_lvalue instance and add it to
+ the lvalue's context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_lvalue_access_field. */
+
+recording::lvalue *
+recording::lvalue::access_field (recording::location *loc,
+ field *field)
+{
+ recording::lvalue *result =
+ new access_field_of_lvalue (m_ctxt, loc, this, field);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* Implementation of recording::rvalue::access_as_rvalue for lvalues.
+ Instances of lvalue need to be wrapped in a gcc_jit_lvalue_as_rvalue
+ upcast call. */
+
+const char *
+recording::lvalue::access_as_rvalue (reproducer &r)
+{
+ return r.xstrdup_printf ("gcc_jit_lvalue_as_rvalue (%s)",
+ r.get_identifier (this));
+}
+
+/* Implementation of recording::lvalue::access_as_lvalue for lvalues.
+ Instances of lvalue don't need to be upcast. */
+
+const char *
+recording::lvalue::access_as_lvalue (reproducer &r)
+{
+ return r.get_identifier (this);
+}
+
+/* Create a recording::get_address_of_lvalue instance and add it to
+ the lvalue's context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_lvalue_get_address. */
+
+recording::rvalue *
+recording::lvalue::get_address (recording::location *loc)
+{
+ recording::rvalue *result =
+ new get_address_of_lvalue (m_ctxt, loc, this);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* The implementation of class gcc::jit::recording::param. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::param. */
+
+void
+recording::param::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_param (playback_location (r, m_loc),
+ m_type->playback_type (),
+ m_name->c_str ()));
+}
+
+/* Implementation of recording::rvalue::access_as_rvalue for params.
+ Instances of param need to be wrapped in a gcc_jit_param_as_rvalue
+ upcast call. */
+
+const char *
+recording::param::access_as_rvalue (reproducer &r)
+{
+ return r.xstrdup_printf ("gcc_jit_param_as_rvalue (%s)",
+ r.get_identifier (this));
+}
+
+/* Implementation of recording::lvalue::access_as_lvalue for params.
+ Instances of param need to be wrapped in a gcc_jit_param_as_lvalue
+ upcast call. */
+
+const char *
+recording::param::access_as_lvalue (reproducer &r)
+{
+ return r.xstrdup_printf ("gcc_jit_param_as_lvalue (%s)",
+ r.get_identifier (this));
+}
+
+/* Implementation of recording::memento::write_reproducer for params. */
+
+void
+recording::param::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "param");
+ r.write (" gcc_jit_param *%s =\n"
+ " gcc_jit_context_new_param (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /*gcc_jit_type *type */\n"
+ " %s); /* const char *name */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_type (m_type),
+ m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::function. */
+
+/* gcc::jit::recording::function's constructor. */
+
+recording::function::function (context *ctxt,
+ recording::location *loc,
+ enum gcc_jit_function_kind kind,
+ type *return_type,
+ recording::string *name,
+ int num_params,
+ recording::param **params,
+ int is_variadic,
+ enum built_in_function builtin_id)
+: memento (ctxt),
+ m_loc (loc),
+ m_kind (kind),
+ m_return_type (return_type),
+ m_name (name),
+ m_params (),
+ m_is_variadic (is_variadic),
+ m_builtin_id (builtin_id),
+ m_locals (),
+ m_blocks ()
+{
+ for (int i = 0; i< num_params; i++)
+ {
+ param *param = params[i];
+ gcc_assert (param);
+
+ /* Associate each param with this function.
+
+ Verify that the param doesn't already have a function. */
+ if (param->get_scope ())
+ {
+ /* We've already rejected attempts to reuse a param between
+ different functions (within gcc_jit_context_new_function), so
+ if the param *does* already have a function, it must be being
+ reused within the params array for this function. We must
+ produce an error for this reuse (blocking the compile), since
+ otherwise we'd have an ICE later on. */
+ gcc_assert (this == param->get_scope ());
+ ctxt->add_error
+ (loc,
+ "gcc_jit_context_new_function:"
+ " parameter %s (type: %s)"
+ " is used more than once when creating function %s",
+ param->get_debug_string (),
+ param->get_type ()->get_debug_string (),
+ name->c_str ());
+ }
+ else
+ {
+ /* The normal, non-error case: associate this function with the
+ param. */
+ param->set_scope (this);
+ }
+
+ m_params.safe_push (param);
+ }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::function. */
+
+void
+recording::function::replay_into (replayer *r)
+{
+ /* Convert m_params to a vec of playback param. */
+ auto_vec <playback::param *> params;
+ int i;
+ recording::param *param;
+ params.create (m_params.length ());
+ FOR_EACH_VEC_ELT (m_params, i, param)
+ params.safe_push (param->playback_param ());
+
+ set_playback_obj (r->new_function (playback_location (r, m_loc),
+ m_kind,
+ m_return_type->playback_type (),
+ m_name->c_str (),
+ &params,
+ m_is_variadic,
+ m_builtin_id));
+}
+
+/* Create a recording::local instance and add it to
+ the functions's context's list of mementos, and to the function's
+ list of locals.
+
+ Implements the post-error-checking part of
+ gcc_jit_function_new_local. */
+
+recording::lvalue *
+recording::function::new_local (recording::location *loc,
+ type *type,
+ const char *name)
+{
+ local *result = new local (this, loc, type, new_string (name));
+ m_ctxt->record (result);
+ m_locals.safe_push (result);
+ return result;
+}
+
+/* Create a recording::block instance and add it to
+ the functions's context's list of mementos, and to the function's
+ list of blocks.
+
+ Implements the post-error-checking part of
+ gcc_jit_function_new_block. */
+
+recording::block*
+recording::function::new_block (const char *name)
+{
+ gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+ recording::block *result =
+ new recording::block (this, m_blocks.length (), new_string (name));
+ m_ctxt->record (result);
+ m_blocks.safe_push (result);
+ return result;
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump by dumping a C-like
+ representation of the function; either like a prototype
+ for GCC_JIT_FUNCTION_IMPORTED, or like a full definition for
+ all other kinds of function. */
+
+void
+recording::function::write_to_dump (dump &d)
+{
+ switch (m_kind)
+ {
+ default: gcc_unreachable ();
+ case GCC_JIT_FUNCTION_EXPORTED:
+ case GCC_JIT_FUNCTION_IMPORTED:
+ d.write ("extern ");
+ break;
+ case GCC_JIT_FUNCTION_INTERNAL:
+ d.write ("static ");
+ break;
+ case GCC_JIT_FUNCTION_ALWAYS_INLINE:
+ d.write ("static inline ");
+ break;
+ }
+ d.write ("%s\n", m_return_type->get_debug_string ());
+
+ if (d.update_locations ())
+ m_loc = d.make_location ();
+
+ d.write ("%s (", get_debug_string ());
+
+ int i;
+ recording::param *param;
+ FOR_EACH_VEC_ELT (m_params, i, param)
+ {
+ if (i > 0)
+ d.write (", ");
+ d.write ("%s %s",
+ param->get_type ()->get_debug_string (),
+ param->get_debug_string ());
+ }
+ d.write (")");
+ if (m_kind == GCC_JIT_FUNCTION_IMPORTED)
+ {
+ d.write ("; /* (imported) */\n\n");
+ }
+ else
+ {
+ int i;
+ local *var = NULL;
+ block *b;
+ d.write ("\n{\n");
+
+ /* Write locals: */
+ FOR_EACH_VEC_ELT (m_locals, i, var)
+ var->write_to_dump (d);
+ if (m_locals.length ())
+ d.write ("\n");
+
+ /* Write each block: */
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ {
+ if (i > 0)
+ d.write ("\n");
+ b->write_to_dump (d);
+ }
+
+ d.write ("}\n\n");
+ }
+}
+
+/* Pre-compilation validation of a function, for those things we can't
+ check until the context is (supposedly) fully-populated. */
+
+void
+recording::function::validate ()
+{
+ /* Complain about empty functions with non-void return type. */
+ if (m_kind != GCC_JIT_FUNCTION_IMPORTED
+ && m_return_type != m_ctxt->get_type (GCC_JIT_TYPE_VOID))
+ if (0 == m_blocks.length ())
+ m_ctxt->add_error (m_loc,
+ "function %s returns non-void (type: %s)"
+ " but has no blocks",
+ get_debug_string (),
+ m_return_type->get_debug_string ());
+
+ /* Check that all blocks are terminated. */
+ int num_invalid_blocks = 0;
+ {
+ int i;
+ block *b;
+
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ if (!b->validate ())
+ num_invalid_blocks++;
+ }
+
+ /* Check that all blocks are reachable. */
+ if (m_blocks.length () > 0 && 0 == num_invalid_blocks)
+ {
+ /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
+ flag, starting at the initial block. */
+ auto_vec<block *> worklist (m_blocks.length ());
+ worklist.safe_push (m_blocks[0]);
+ while (worklist.length () > 0)
+ {
+ block *b = worklist.pop ();
+ b->m_is_reachable = true;
+
+ /* Add successor blocks that aren't yet marked to the worklist. */
+ /* We checked that each block has a terminating statement above . */
+ block *next1, *next2;
+ int n = b->get_successor_blocks (&next1, &next2);
+ switch (n)
+ {
+ default:
+ gcc_unreachable ();
+ case 2:
+ if (!next2->m_is_reachable)
+ worklist.safe_push (next2);
+ /* fallthrough */
+ case 1:
+ if (!next1->m_is_reachable)
+ worklist.safe_push (next1);
+ break;
+ case 0:
+ break;
+ }
+ }
+
+ /* Now complain about any blocks that haven't been marked. */
+ {
+ int i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ if (!b->m_is_reachable)
+ m_ctxt->add_error (b->get_loc (),
+ "unreachable block: %s",
+ b->get_debug_string ());
+ }
+ }
+}
+
+/* Implements the post-error-checking part of
+ gcc_jit_function_dump_to_dot. */
+
+void
+recording::function::dump_to_dot (const char *path)
+{
+ FILE *fp = fopen (path, "w");
+ if (!fp)
+ return;
+
+ pretty_printer the_pp;
+ the_pp.buffer->stream = fp;
+
+ pretty_printer *pp = &the_pp;
+
+ pp_printf (pp,
+ "digraph %s {\n", get_debug_string ());
+
+ /* Blocks: */
+ {
+ int i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ b->dump_to_dot (pp);
+ }
+
+ /* Edges: */
+ {
+ int i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ b->dump_edges_to_dot (pp);
+ }
+
+ pp_printf (pp, "}\n");
+ pp_flush (pp);
+ fclose (fp);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ functions. */
+
+recording::string *
+recording::function::make_debug_string ()
+{
+ return m_name;
+}
+
+/* A table of enum gcc_jit_function_kind values expressed in string
+ form. */
+
+static const char * const names_of_function_kinds[] = {
+ "GCC_JIT_FUNCTION_EXPORTED",
+ "GCC_JIT_FUNCTION_INTERNAL",
+ "GCC_JIT_FUNCTION_IMPORTED",
+ "GCC_JIT_FUNCTION_ALWAYS_INLINE"
+};
+
+/* Implementation of recording::memento::write_reproducer for functions. */
+
+void
+recording::function::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "func");
+
+ if (m_builtin_id)
+ {
+ r.write (" gcc_jit_function *%s =\n"
+ " gcc_jit_context_get_builtin_function (%s,\n"
+ " %s);\n",
+ id,
+ r.get_identifier (get_context ()),
+ m_name->get_debug_string ());
+ return;
+ }
+ const char *params_id = r.make_tmp_identifier ("params_for", this);
+ r.write (" gcc_jit_param *%s[%i] = {\n",
+ params_id,
+ m_params.length ());
+ int i;
+ param *param;
+ FOR_EACH_VEC_ELT (m_params, i, param)
+ r.write (" %s,\n", r.get_identifier (param));
+ r.write (" };\n");
+ r.write (" gcc_jit_function *%s =\n"
+ " gcc_jit_context_new_function (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* enum gcc_jit_function_kind kind */\n"
+ " %s, /* gcc_jit_type *return_type */\n"
+ " %s, /* const char *name */\n"
+ " %i, /* int num_params */\n"
+ " %s, /* gcc_jit_param **params */\n"
+ " %i); /* int is_variadic */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ names_of_function_kinds[m_kind],
+ r.get_identifier_as_type (m_return_type),
+ m_name->get_debug_string (),
+ m_params.length (),
+ params_id,
+ m_is_variadic);
+}
+
+
+/* The implementation of class gcc::jit::recording::block. */
+
+/* Create a recording::eval instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_eval. */
+
+recording::statement *
+recording::block::add_eval (recording::location *loc,
+ recording::rvalue *rvalue)
+{
+ statement *result = new eval (this, loc, rvalue);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
+/* Create a recording::assignment instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_assignment. */
+
+recording::statement *
+recording::block::add_assignment (recording::location *loc,
+ recording::lvalue *lvalue,
+ recording::rvalue *rvalue)
+{
+ statement *result = new assignment (this, loc, lvalue, rvalue);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
+/* Create a recording::assignment_op instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_assignment_op. */
+
+recording::statement *
+recording::block::add_assignment_op (recording::location *loc,
+ recording::lvalue *lvalue,
+ enum gcc_jit_binary_op op,
+ recording::rvalue *rvalue)
+{
+ statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
+/* Create a recording::comment instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_comment. */
+
+recording::statement *
+recording::block::add_comment (recording::location *loc,
+ const char *text)
+{
+ statement *result = new comment (this, loc, new_string (text));
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
+/* Create a recording::end_with_conditional instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_end_with_conditional. */
+
+recording::statement *
+recording::block::end_with_conditional (recording::location *loc,
+ recording::rvalue *boolval,
+ recording::block *on_true,
+ recording::block *on_false)
+{
+ statement *result = new conditional (this, loc, boolval, on_true, on_false);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ m_has_been_terminated = true;
+ return result;
+}
+
+/* Create a recording::end_with_jump instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_end_with_jump. */
+
+recording::statement *
+recording::block::end_with_jump (recording::location *loc,
+ recording::block *target)
+{
+ statement *result = new jump (this, loc, target);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ m_has_been_terminated = true;
+ return result;
+}
+
+/* Create a recording::end_with_return instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the post-error-checking parts of
+ gcc_jit_block_end_with_return and
+ gcc_jit_block_end_with_void_return. */
+
+recording::statement *
+recording::block::end_with_return (recording::location *loc,
+ recording::rvalue *rvalue)
+{
+ /* This is used by both gcc_jit_function_add_return and
+ gcc_jit_function_add_void_return; rvalue will be non-NULL for
+ the former and NULL for the latter. */
+ statement *result = new return_ (this, loc, rvalue);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ m_has_been_terminated = true;
+ return result;
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump for blocks by writing
+ an unindented block name as a label, followed by the indented
+ statements:
+
+ BLOCK_NAME:
+ STATEMENT_1;
+ STATEMENT_2;
+ ...
+ STATEMENT_N; */
+
+void
+recording::block::write_to_dump (dump &d)
+{
+ d.write ("%s:\n", get_debug_string ());
+
+ int i;
+ statement *s;
+ FOR_EACH_VEC_ELT (m_statements, i, s)
+ s->write_to_dump (d);
+}
+
+/* Validate a block by ensuring that it has been terminated. */
+
+bool
+recording::block::validate ()
+{
+ /* Check for termination. */
+ if (!has_been_terminated ())
+ {
+ statement *stmt = get_last_statement ();
+ location *loc = stmt ? stmt->get_loc () : NULL;
+ m_func->get_context ()->add_error (loc,
+ "unterminated block in %s: %s",
+ m_func->get_debug_string (),
+ get_debug_string ());
+ return false;
+ }
+
+ return true;
+}
+
+/* Get the source-location of a block by using that of the first
+ statement within it, if any. */
+
+recording::location *
+recording::block::get_loc () const
+{
+ recording::statement *stmt = get_first_statement ();
+ if (stmt)
+ return stmt->get_loc ();
+ else
+ return NULL;
+}
+
+/* Get the first statement within a block, if any. */
+
+recording::statement *
+recording::block::get_first_statement () const
+{
+ if (m_statements.length ())
+ return m_statements[0];
+ else
+ return NULL;
+}
+
+/* Get the last statement within a block, if any. */
+
+recording::statement *
+recording::block::get_last_statement () const
+{
+ if (m_statements.length ())
+ return m_statements[m_statements.length () - 1];
+ else
+ return NULL;
+}
+
+/* Assuming that this block has been terminated, get the number of
+ successor blocks, which will be 0, 1 or 2, for return, unconditional
+ jump, and conditional jump respectively.
+ NEXT1 and NEXT2 must be non-NULL. The first successor block (if any)
+ is written to NEXT1, and the second (if any) to NEXT2.
+
+ Used when validating functions, and when dumping dot representations
+ of them. */
+
+int
+recording::block::get_successor_blocks (block **next1, block **next2) const
+{
+ gcc_assert (m_has_been_terminated);
+ gcc_assert (next1);
+ gcc_assert (next2);
+ statement *last_statement = get_last_statement ();
+ gcc_assert (last_statement);
+ return last_statement->get_successor_blocks (next1, next2);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::block. */
+
+void
+recording::block::replay_into (replayer *)
+{
+ set_playback_obj (m_func->playback_function ()
+ ->new_block (playback_string (m_name)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ blocks. */
+
+recording::string *
+recording::block::make_debug_string ()
+{
+ if (m_name)
+ return m_name;
+ else
+ return string::from_printf (m_ctxt,
+ "<UNNAMED BLOCK %p>",
+ (void *)this);
+}
+
+/* Implementation of recording::memento::write_reproducer for blocks. */
+
+void
+recording::block::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "block");
+ r.write (" gcc_jit_block *%s =\n"
+ " gcc_jit_function_new_block (%s, %s);\n",
+ id,
+ r.get_identifier (m_func),
+ m_name ? m_name->get_debug_string () : "NULL");
+}
+
+/* Dump a block in graphviz form into PP, capturing the block name (if
+ any) and the statements. */
+
+void
+recording::block::dump_to_dot (pretty_printer *pp)
+{
+ pp_printf (pp,
+ ("\tblock_%d "
+ "[shape=record,style=filled,fillcolor=white,label=\"{"),
+ m_index);
+ pp_write_text_to_stream (pp);
+ if (m_name)
+ {
+ pp_string (pp, m_name->c_str ());
+ pp_string (pp, ":");
+ pp_newline (pp);
+ pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+ }
+
+ int i;
+ statement *s;
+ FOR_EACH_VEC_ELT (m_statements, i, s)
+ {
+ pp_string (pp, s->get_debug_string ());
+ pp_newline (pp);
+ pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+ }
+
+ pp_printf (pp,
+ "}\"];\n\n");
+ pp_flush (pp);
+}
+
+/* Dump the out-edges of the block in graphviz form into PP. */
+
+void
+recording::block::dump_edges_to_dot (pretty_printer *pp)
+{
+ block *next[2];
+ int num_succs = get_successor_blocks (&next[0], &next[1]);
+ for (int i = 0; i < num_succs; i++)
+ pp_printf (pp,
+ "\tblock_%d:s -> block_%d:n;\n",
+ m_index, next[i]->m_index);
+}
+
+/* The implementation of class gcc::jit::recording::global. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::global. */
+
+void
+recording::global::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_global (playback_location (r, m_loc),
+ m_kind,
+ m_type->playback_type (),
+ playback_string (m_name)));
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump for globals.
+ This will be of the form:
+
+ GCC_JIT_GLOBAL_EXPORTED:
+ "TYPE NAME;"
+ e.g. "int foo;"
+
+ GCC_JIT_GLOBAL_INTERNAL:
+ "static TYPE NAME;"
+ e.g. "static int foo;"
+
+ GCC_JIT_GLOBAL_IMPORTED:
+ "extern TYPE NAME;"
+ e.g. "extern int foo;"
+
+ These are written to the top of the dump by
+ recording::context::dump_to_file. */
+
+void
+recording::global::write_to_dump (dump &d)
+{
+ if (d.update_locations ())
+ m_loc = d.make_location ();
+
+ switch (m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case GCC_JIT_GLOBAL_EXPORTED:
+ break;
+
+ case GCC_JIT_GLOBAL_INTERNAL:
+ d.write ("static ");
+ break;
+
+ case GCC_JIT_GLOBAL_IMPORTED:
+ d.write ("extern ");
+ break;
+ }
+ d.write ("%s %s;\n",
+ m_type->get_debug_string (),
+ get_debug_string ());
+}
+
+/* A table of enum gcc_jit_global_kind values expressed in string
+ form. */
+
+static const char * const global_kind_reproducer_strings[] = {
+ "GCC_JIT_GLOBAL_EXPORTED",
+ "GCC_JIT_GLOBAL_INTERNAL",
+ "GCC_JIT_GLOBAL_IMPORTED"
+};
+
+/* Implementation of recording::memento::write_reproducer for globals. */
+
+void
+recording::global::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "block");
+ r.write (" gcc_jit_lvalue *%s =\n"
+ " gcc_jit_context_new_global (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* enum gcc_jit_global_kind kind */\n"
+ " %s, /* gcc_jit_type *type */\n"
+ " %s); /* const char *name */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ global_kind_reproducer_strings[m_kind],
+ r.get_identifier_as_type (get_type ()),
+ m_name->get_debug_string ());
+}
+
+/* The implementation of the various const-handling classes:
+ gcc::jit::recording::memento_of_new_rvalue_from_const <HOST_TYPE>. */
+
+/* Explicit specialization of the various mementos we're interested in. */
+template class recording::memento_of_new_rvalue_from_const <int>;
+template class recording::memento_of_new_rvalue_from_const <long>;
+template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <void *>;
+
+/* Implementation of the pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_rvalue_from_const <HOST_TYPE>. */
+
+template <typename HOST_TYPE>
+void
+recording::
+memento_of_new_rvalue_from_const <HOST_TYPE>::replay_into (replayer *r)
+{
+ set_playback_obj
+ (r->new_rvalue_from_const <HOST_TYPE> (m_type->playback_type (),
+ m_value));
+}
+
+/* The make_debug_string and write_reproducer methods vary between the
+ various
+ memento_of_new_rvalue_from_const <HOST_TYPE>
+ classes, so we explicitly write specializations of them.
+
+ I (dmalcolm) find the code to be clearer if the "recording" vs "playback"
+ namespaces are written out explicitly, which is why most of this file
+ doesn't abbreviate things by entering the "recording" namespace.
+
+ However, these specializations are required to be in the same namespace
+ as the template, hence we now have to enter the gcc::jit::recording
+ namespace. */
+
+namespace recording
+{
+
+/* The make_debug_string specialization for <int>, which renders it as
+ (TARGET_TYPE)LITERAL
+ e.g.
+ "(int)42". */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <int>::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "(%s)%i",
+ m_type->get_debug_string (),
+ m_value);
+}
+
+/* The write_reproducer specialization for <int>. */
+
+template <>
+void
+memento_of_new_rvalue_from_const <int>::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_int (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_type *numeric_type */\n"
+ " %i); /* int value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type),
+ m_value);
+}
+
+/* The make_debug_string specialization for <long>, rendering it as
+ (TARGET_TYPE)LITERAL
+ e.g.
+ "(long)42". */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <long>::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "(%s)%li",
+ m_type->get_debug_string (),
+ m_value);
+}
+
+/* The write_reproducer specialization for <long>. */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <long>::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+
+ /* We have to special-case LONG_MIN, since e.g.
+ -9223372036854775808L
+ is parsed as
+ -(9223372036854775808L)
+ and hence we'd get:
+ error: integer constant is so large that it is unsigned [-Werror]
+ Workaround this by writing (LONG_MIN + 1) - 1. */
+ if (m_value == LONG_MIN)
+ {
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_long (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_type *numeric_type */\n"
+ " %ldL - 1); /* long value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type),
+ m_value + 1);;
+ return;
+ }
+
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_long (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_type *numeric_type */\n"
+ " %ldL); /* long value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type),
+ m_value);
+ }
+
+/* The make_debug_string specialization for <double>, rendering it as
+ (TARGET_TYPE)LITERAL
+ e.g.
+ "(float)42.0". */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <double>::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "(%s)%f",
+ m_type->get_debug_string (),
+ m_value);
+}
+
+/* The write_reproducer specialization for <double>. */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_type *numeric_type */\n"
+ " %f); /* double value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type),
+ m_value);
+}
+
+/* The make_debug_string specialization for <void *>, rendering it as
+ (TARGET_TYPE)HEX
+ e.g.
+ "(int *)0xdeadbeef"
+
+ Zero is rendered as NULL e.g.
+ "(int *)NULL". */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <void *>::make_debug_string ()
+{
+ if (m_value != NULL)
+ return string::from_printf (m_ctxt,
+ "(%s)%p",
+ m_type->get_debug_string (), m_value);
+ else
+ return string::from_printf (m_ctxt,
+ "(%s)NULL",
+ m_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for <void *>
+ values. */
+
+template <>
+void
+memento_of_new_rvalue_from_const <void *>::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ if (m_value)
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_ptr (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_type *pointer_type */\n"
+ " (void *)%p); /* void *value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type),
+ m_value);
+ else
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_null (%s, /* gcc_jit_context *ctxt */\n"
+ " %s); /* gcc_jit_type *pointer_type */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_type (m_type));
+}
+
+/* We're done specializing make_debug_string and write_reproducer, so we
+ can exit the gcc::jit::recording namespace. */
+
+} // namespace recording
+
+/* The implementation of class gcc::jit::recording::memento_of_new_string_literal. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_string_literal. */
+
+void
+recording::memento_of_new_string_literal::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_string_literal (m_value->c_str ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ string literals. */
+
+recording::string *
+recording::memento_of_new_string_literal::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s",
+ m_value->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for string literal
+ values. */
+
+void
+recording::memento_of_new_string_literal::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_string_literal (%s, /* gcc_jit_context *ctxt */\n"
+ " %s); /* const char *value */\n",
+ id,
+ r.get_identifier (get_context ()),
+ m_value->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::unary_op. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::unary_op. */
+
+void
+recording::unary_op::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_unary_op (playback_location (r, m_loc),
+ m_op,
+ get_type ()->playback_type (),
+ m_a->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::unary_op. */
+void
+recording::unary_op::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_a);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ unary ops. */
+
+static const char * const unary_op_strings[] = {
+ "-", /* GCC_JIT_UNARY_OP_MINUS */
+ "~", /* GCC_JIT_UNARY_OP_BITWISE_NEGATE */
+ "!", /* GCC_JIT_UNARY_OP_LOGICAL_NEGATE */
+ "abs ", /* GCC_JIT_UNARY_OP_ABS */
+};
+
+recording::string *
+recording::unary_op::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s(%s)",
+ unary_op_strings[m_op],
+ m_a->get_debug_string ());
+}
+
+static const char * const unary_op_reproducer_strings[] = {
+ "GCC_JIT_UNARY_OP_MINUS",
+ "GCC_JIT_UNARY_OP_BITWISE_NEGATE",
+ "GCC_JIT_UNARY_OP_LOGICAL_NEGATE",
+ "GCC_JIT_UNARY_OP_ABS"
+};
+
+/* Implementation of recording::memento::write_reproducer for unary ops. */
+
+void
+recording::unary_op::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_unary_op (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* enum gcc_jit_unary_op op */\n"
+ " %s, /* gcc_jit_type *result_type */\n"
+ " %s); /* gcc_jit_rvalue *a */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ unary_op_reproducer_strings[m_op],
+ r.get_identifier_as_type (get_type ()),
+ r.get_identifier_as_rvalue (m_a));
+}
+
+/* The implementation of class gcc::jit::recording::binary_op. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::binary_op. */
+
+void
+recording::binary_op::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_binary_op (playback_location (r, m_loc),
+ m_op,
+ get_type ()->playback_type (),
+ m_a->playback_rvalue (),
+ m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::binary_op. */
+void
+recording::binary_op::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_a);
+ v->visit (m_b);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ binary ops. */
+
+static const char * const binary_op_strings[] = {
+ "+", /* GCC_JIT_BINARY_OP_PLUS */
+ "-", /* GCC_JIT_BINARY_OP_MINUS */
+ "*", /* GCC_JIT_BINARY_OP_MULT */
+ "/", /* GCC_JIT_BINARY_OP_DIVIDE */
+ "%", /* GCC_JIT_BINARY_OP_MODULO */
+ "&", /* GCC_JIT_BINARY_OP_BITWISE_AND */
+ "^", /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+ "|", /* GCC_JIT_BINARY_OP_BITWISE_OR */
+ "&&", /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+ "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+ "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
+ ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+
+recording::string *
+recording::binary_op::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s %s %s",
+ m_a->get_debug_string (),
+ binary_op_strings[m_op],
+ m_b->get_debug_string ());
+}
+
+static const char * const binary_op_reproducer_strings[] = {
+ "GCC_JIT_BINARY_OP_PLUS",
+ "GCC_JIT_BINARY_OP_MINUS",
+ "GCC_JIT_BINARY_OP_MULT",
+ "GCC_JIT_BINARY_OP_DIVIDE",
+ "GCC_JIT_BINARY_OP_MODULO",
+ "GCC_JIT_BINARY_OP_BITWISE_AND",
+ "GCC_JIT_BINARY_OP_BITWISE_XOR",
+ "GCC_JIT_BINARY_OP_BITWISE_OR",
+ "GCC_JIT_BINARY_OP_LOGICAL_AND",
+ "GCC_JIT_BINARY_OP_LOGICAL_OR",
+ "GCC_JIT_BINARY_OP_LSHIFT",
+ "GCC_JIT_BINARY_OP_RSHIFT"
+};
+
+/* Implementation of recording::memento::write_reproducer for binary ops. */
+
+void
+recording::binary_op::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_binary_op (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* enum gcc_jit_binary_op op */\n"
+ " %s, /* gcc_jit_type *result_type */\n"
+ " %s, /* gcc_jit_rvalue *a */\n"
+ " %s); /* gcc_jit_rvalue *b */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ binary_op_reproducer_strings[m_op],
+ r.get_identifier_as_type (get_type ()),
+ r.get_identifier_as_rvalue (m_a),
+ r.get_identifier_as_rvalue (m_b));
+}
+
+/* The implementation of class gcc::jit::recording::comparison. */
+
+/* Implementation of recording::memento::make_debug_string for
+ comparisons. */
+
+static const char * const comparison_strings[] =
+{
+ "==", /* GCC_JIT_COMPARISON_EQ */
+ "!=", /* GCC_JIT_COMPARISON_NE */
+ "<", /* GCC_JIT_COMPARISON_LT */
+ "<=", /* GCC_JIT_COMPARISON_LE */
+ ">", /* GCC_JIT_COMPARISON_GT */
+ ">=", /* GCC_JIT_COMPARISON_GE */
+};
+
+recording::string *
+recording::comparison::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s %s %s",
+ m_a->get_debug_string (),
+ comparison_strings[m_op],
+ m_b->get_debug_string ());
+}
+
+/* A table of enum gcc_jit_comparison values expressed in string
+ form. */
+
+static const char * const comparison_reproducer_strings[] =
+{
+ "GCC_JIT_COMPARISON_EQ",
+ "GCC_JIT_COMPARISON_NE",
+ "GCC_JIT_COMPARISON_LT",
+ "GCC_JIT_COMPARISON_LE",
+ "GCC_JIT_COMPARISON_GT",
+ "GCC_JIT_COMPARISON_GE"
+};
+
+/* Implementation of recording::memento::write_reproducer for comparisons. */
+
+void
+recording::comparison::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_comparison (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* enum gcc_jit_comparison op */\n"
+ " %s, /* gcc_jit_rvalue *a */\n"
+ " %s); /* gcc_jit_rvalue *b */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ comparison_reproducer_strings[m_op],
+ r.get_identifier_as_rvalue (m_a),
+ r.get_identifier_as_rvalue (m_b));
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::comparison. */
+
+void
+recording::comparison::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_comparison (playback_location (r, m_loc),
+ m_op,
+ m_a->playback_rvalue (),
+ m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::comparison. */
+
+void
+recording::comparison::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_a);
+ v->visit (m_b);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::cast. */
+
+void
+recording::cast::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_cast (playback_location (r, m_loc),
+ m_rvalue->playback_rvalue (),
+ get_type ()->playback_type ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::cast. */
+void
+recording::cast::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ casts. */
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "(%s)%s",
+ get_type ()->get_debug_string (),
+ m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for casts. */
+
+void
+recording::cast::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_cast (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *rvalue */\n"
+ " %s); /* gcc_jit_type *type */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_rvalue),
+ r.get_identifier_as_type (get_type ()));
+}
+
+/* The implementation of class gcc::jit::recording::call. */
+
+/* The constructor for gcc::jit::recording::call. */
+
+recording::call::call (recording::context *ctxt,
+ recording::location *loc,
+ recording::function *func,
+ int numargs,
+ rvalue **args)
+: rvalue (ctxt, loc, func->get_return_type ()),
+ m_func (func),
+ m_args ()
+{
+ for (int i = 0; i< numargs; i++)
+ m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::call. */
+
+void
+recording::call::replay_into (replayer *r)
+{
+ auto_vec<playback::rvalue *> playback_args;
+ playback_args.create (m_args.length ());
+ for (unsigned i = 0; i< m_args.length (); i++)
+ playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+ set_playback_obj (r->new_call (playback_location (r, m_loc),
+ m_func->playback_function (),
+ &playback_args));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::call. */
+
+void
+recording::call::visit_children (rvalue_visitor *v)
+{
+ for (unsigned i = 0; i< m_args.length (); i++)
+ v->visit (m_args[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ function calls. */
+
+recording::string *
+recording::call::make_debug_string ()
+{
+ /* First, build a buffer for the arguments. */
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ sz += strlen (m_args[i]->get_debug_string ());
+ sz += 2; /* ", " separator */
+ }
+
+ /* Now allocate and populate the buffer. */
+ char *argbuf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ strcpy (argbuf + len, m_args[i]->get_debug_string ());
+ len += strlen (m_args[i]->get_debug_string ());
+ if (i + 1 < m_args.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ }
+ argbuf[len] = '\0';
+
+ /* ...and use it to get the string for the call as a whole. */
+ string *result = string::from_printf (m_ctxt,
+ "%s (%s)",
+ m_func->get_debug_string (),
+ argbuf);
+
+ delete[] argbuf;
+
+ return result;
+}
+
+void
+recording::call::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "call");
+ const char *args_id = r.make_tmp_identifier ("args_for_", this);
+ r.write (" gcc_jit_rvalue *%s[%i] = {\n",
+ args_id,
+ m_args.length ());
+ for (unsigned i = 0; i< m_args.length (); i++)
+ r.write (" %s,\n", r.get_identifier_as_rvalue (m_args[i]));
+ r.write (" };\n");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_call (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_function *func */\n"
+ " %i, /* int numargs */ \n"
+ " %s); /* gcc_jit_rvalue **args*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_func),
+ m_args.length (),
+ args_id);
+}
+
+/* The implementation of class gcc::jit::recording::call_through_ptr. */
+
+/* The constructor for recording::call_through_ptr. */
+
+recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
+ recording::location *loc,
+ recording::rvalue *fn_ptr,
+ int numargs,
+ rvalue **args)
+: rvalue (ctxt, loc,
+ fn_ptr->get_type ()->dereference ()
+ ->as_a_function_type ()->get_return_type ()),
+ m_fn_ptr (fn_ptr),
+ m_args ()
+{
+ for (int i = 0; i< numargs; i++)
+ m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::call_through_ptr. */
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+ auto_vec<playback::rvalue *> playback_args;
+ playback_args.create (m_args.length ());
+ for (unsigned i = 0; i< m_args.length (); i++)
+ playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+ set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
+ m_fn_ptr->playback_rvalue (),
+ &playback_args));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::call_through_ptr. */
+
+void
+recording::call_through_ptr::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_fn_ptr);
+ for (unsigned i = 0; i< m_args.length (); i++)
+ v->visit (m_args[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ calls through function ptrs. */
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+ /* First, build a buffer for the arguments. */
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ sz += strlen (m_args[i]->get_debug_string ());
+ sz += 2; /* ", " separator */
+ }
+
+ /* Now allocate and populate the buffer. */
+ char *argbuf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< m_args.length (); i++)
+ {
+ strcpy (argbuf + len, m_args[i]->get_debug_string ());
+ len += strlen (m_args[i]->get_debug_string ());
+ if (i + 1 < m_args.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ }
+ argbuf[len] = '\0';
+
+ /* ...and use it to get the string for the call as a whole. */
+ string *result = string::from_printf (m_ctxt,
+ "%s (%s)",
+ m_fn_ptr->get_debug_string (),
+ argbuf);
+
+ delete[] argbuf;
+
+ return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ call_through_ptr. */
+
+void
+recording::call_through_ptr::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "call");
+ const char *args_id = r.make_tmp_identifier ("args_for_", this);
+ r.write (" gcc_jit_rvalue *%s[%i] = {\n",
+ args_id,
+ m_args.length ());
+ for (unsigned i = 0; i< m_args.length (); i++)
+ r.write (" %s,\n", r.get_identifier_as_rvalue (m_args[i]));
+ r.write (" };\n");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_call_through_ptr (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *fn_ptr */\n"
+ " %i, /* int numargs */ \n"
+ " %s); /* gcc_jit_rvalue **args*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_fn_ptr),
+ m_args.length (),
+ args_id);
+}
+
+/* The implementation of class gcc::jit::recording::array_access. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::array_access. */
+
+void
+recording::array_access::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->new_array_access (playback_location (r, m_loc),
+ m_ptr->playback_rvalue (),
+ m_index->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::array_access. */
+
+void
+recording::array_access::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_ptr);
+ v->visit (m_index);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ array accesses. */
+
+recording::string *
+recording::array_access::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s[%s]",
+ m_ptr->get_debug_string (),
+ m_index->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ array_access. */
+
+void
+recording::array_access::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s = \n"
+ " gcc_jit_context_new_array_access (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *ptr */\n"
+ " %s); /* gcc_jit_rvalue *index */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_ptr),
+ r.get_identifier_as_rvalue (m_index));
+}
+
+/* The implementation of class gcc::jit::recording::access_field_of_lvalue. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::access_field_of_lvalue. */
+
+void
+recording::access_field_of_lvalue::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_lvalue->playback_lvalue ()
+ ->access_field (playback_location (r, m_loc),
+ m_field->playback_field ()));
+
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::access_field_of_lvalue. */
+
+void
+recording::access_field_of_lvalue::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_lvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ accessing a field of an lvalue. */
+
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s.%s",
+ m_lvalue->get_debug_string (),
+ m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ access_field_of_lvalue. */
+
+void
+recording::access_field_of_lvalue::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s = \n"
+ " gcc_jit_lvalue_access_field (%s, /*gcc_jit_lvalue *struct_or_union */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s);\n",
+ id,
+ r.get_identifier_as_lvalue (m_lvalue),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_field));
+}
+
+/* The implementation of class gcc::jit::recording::access_field_rvalue. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::access_field_rvalue. */
+
+void
+recording::access_field_rvalue::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_rvalue->playback_rvalue ()
+ ->access_field (playback_location (r, m_loc),
+ m_field->playback_field ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::access_field_rvalue. */
+
+void
+recording::access_field_rvalue::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ accessing a field of an rvalue. */
+
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s.%s",
+ m_rvalue->get_debug_string (),
+ m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ access_field_rvalue. */
+
+void
+recording::access_field_rvalue::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "rvalue");
+ r.write (" gcc_jit_rvalue *%s = \n"
+ " gcc_jit_rvalue_access_field (%s, /*gcc_jit_rvalue *struct_or_union */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s);\n",
+ id,
+ r.get_identifier_as_rvalue (m_rvalue),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_field));
+}
+
+/* The implementation of class
+ gcc::jit::recording::dereference_field_rvalue. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::dereference_field_rvalue. */
+
+void
+recording::dereference_field_rvalue::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_rvalue->playback_rvalue ()->
+ dereference_field (playback_location (r, m_loc),
+ m_field->playback_field ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::dereference_field_rvalue. */
+
+void
+recording::dereference_field_rvalue::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ dereferencing a field of an rvalue. */
+
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s->%s",
+ m_rvalue->get_debug_string (),
+ m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ dereference_field_rvalue. */
+
+void
+recording::dereference_field_rvalue::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s=\n"
+ " gcc_jit_rvalue_dereference_field (%s, /* gcc_jit_rvalue *ptr */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* gcc_jit_field *field */\n",
+ id,
+ r.get_identifier_as_rvalue (m_rvalue),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_field));
+}
+
+/* The implementation of class gcc::jit::recording::dereference_rvalue. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::dereference_rvalue. */
+
+void
+recording::dereference_rvalue::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_rvalue->playback_rvalue ()->
+ dereference (playback_location (r, m_loc)));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::dereference_rvalue. */
+
+void
+recording::dereference_rvalue::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ dereferencing an rvalue. */
+
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "*%s",
+ m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ dereference_rvalue. */
+
+void
+recording::dereference_rvalue::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "dereference");
+ r.write (" gcc_jit_lvalue *%s =\n"
+ " gcc_jit_rvalue_dereference (%s, /* gcc_jit_rvalue *rvalue */\n"
+ " %s); /* gcc_jit_location *loc */\n",
+ id,
+ r.get_identifier_as_rvalue (m_rvalue),
+ r.get_identifier (m_loc));
+}
+
+/* The implementation of class gcc::jit::recording::get_address_of_lvalue. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::get_address_of_lvalue. */
+
+void
+recording::get_address_of_lvalue::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_lvalue->playback_lvalue ()->
+ get_address (playback_location (r, m_loc)));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::get_address_of_lvalue. */
+
+void
+recording::get_address_of_lvalue::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_lvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ getting the address of an lvalue. */
+
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "&%s",
+ m_lvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ get_address_of_lvalue. */
+
+void
+recording::get_address_of_lvalue::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "address_of");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_lvalue_get_address (%s, /* gcc_jit_lvalue *lvalue */\n"
+ " %s); /* gcc_jit_location *loc */\n",
+ id,
+ r.get_identifier_as_lvalue (m_lvalue),
+ r.get_identifier (m_loc));
+}
+
+/* The implementation of class gcc::jit::recording::local. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::local. */
+
+void
+recording::local::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_func->playback_function ()
+ ->new_local (playback_location (r, m_loc),
+ m_type->playback_type (),
+ playback_string (m_name)));
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump for locals by writing
+ TYPE NAME;
+ for use at the top of the function body as if it were a
+ declaration. */
+
+void
+recording::local::write_to_dump (dump &d)
+{
+ if (d.update_locations ())
+ m_loc = d.make_location ();
+ d.write(" %s %s;\n",
+ m_type->get_debug_string (),
+ get_debug_string ());
+}
+
+void
+recording::local::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "local");
+ r.write (" gcc_jit_lvalue *%s =\n"
+ " gcc_jit_function_new_local (%s, /* gcc_jit_function *func */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *type */\n"
+ " %s); /* const char *name */\n",
+ id,
+ r.get_identifier (m_func),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_type (m_type),
+ m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::statement. */
+
+/* We poison the default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+ since this vfunc must only ever be called on terminator
+ statements. */
+
+int
+recording::statement::get_successor_blocks (block **/*out_next1*/,
+ block **/*out_next2*/) const
+{
+ /* The base class implementation is for non-terminating statements,
+ and thus should never be called. */
+ gcc_unreachable ();
+ return 0;
+}
+
+/* Extend the default implementation of
+ recording::memento::write_to_dump for statements by (if requested)
+ updating the location of the statement to the current location in
+ the dumpfile. */
+
+void
+recording::statement::write_to_dump (dump &d)
+{
+ memento::write_to_dump (d);
+ if (d.update_locations ())
+ m_loc = d.make_location ();
+}
+
+/* The implementation of class gcc::jit::recording::eval. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::eval. */
+
+void
+recording::eval::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_eval (playback_location (r),
+ m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an eval statement. */
+
+recording::string *
+recording::eval::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "(void)%s;",
+ m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ eval statements. */
+
+void
+recording::eval::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_add_eval (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* gcc_jit_rvalue *rvalue */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::assignment. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::assignment. */
+
+void
+recording::assignment::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_assignment (playback_location (r),
+ m_lvalue->playback_lvalue (),
+ m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an assignment statement. */
+
+recording::string *
+recording::assignment::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s = %s;",
+ m_lvalue->get_debug_string (),
+ m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ assignment statements. */
+
+void
+recording::assignment::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_add_assignment (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_lvalue *lvalue */\n"
+ " %s); /* gcc_jit_rvalue *rvalue */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_lvalue (m_lvalue),
+ r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::assignment_op. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::assignment_op. */
+
+void
+recording::assignment_op::replay_into (replayer *r)
+{
+ playback::type *result_type =
+ m_lvalue->playback_lvalue ()->get_type ();
+
+ playback::rvalue *binary_op =
+ r->new_binary_op (playback_location (r),
+ m_op,
+ result_type,
+ m_lvalue->playback_rvalue (),
+ m_rvalue->playback_rvalue ());
+
+ playback_block (get_block ())
+ ->add_assignment (playback_location (r),
+ m_lvalue->playback_lvalue (),
+ binary_op);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an assignment_op statement. */
+
+recording::string *
+recording::assignment_op::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s %s= %s;",
+ m_lvalue->get_debug_string (),
+ binary_op_strings[m_op],
+ m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ assignment_op statements. */
+
+void
+recording::assignment_op::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_add_assignment_op (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_lvalue *lvalue */\n"
+ " %s, /* enum gcc_jit_binary_op op */\n"
+ " %s); /* gcc_jit_rvalue *rvalue */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_lvalue (m_lvalue),
+ binary_op_reproducer_strings[m_op],
+ r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::comment. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::comment. */
+
+void
+recording::comment::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_comment (playback_location (r),
+ m_text->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ a comment "statement". */
+
+recording::string *
+recording::comment::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "/* %s */",
+ m_text->c_str ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ comments. */
+
+void
+recording::comment::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_add_comment (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* const char *text */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ m_text->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::conditional. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::conditional. */
+
+void
+recording::conditional::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_conditional (playback_location (r),
+ m_boolval->playback_rvalue (),
+ playback_block (m_on_true),
+ playback_block (m_on_false));
+}
+
+/* Override the poisoned default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+
+ A conditional jump has 2 successor blocks. */
+
+int
+recording::conditional::get_successor_blocks (block **out_next1,
+ block **out_next2) const
+{
+ *out_next1 = m_on_true;
+ *out_next2 = m_on_false;
+ return 2;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ a conditional jump statement. */
+
+recording::string *
+recording::conditional::make_debug_string ()
+{
+ if (m_on_false)
+ return string::from_printf (m_ctxt,
+ "if (%s) goto %s; else goto %s;",
+ m_boolval->get_debug_string (),
+ m_on_true->get_debug_string (),
+ m_on_false->get_debug_string ());
+ else
+ return string::from_printf (m_ctxt,
+ "if (%s) goto %s;",
+ m_boolval->get_debug_string (),
+ m_on_true->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ conditional statements. */
+
+void
+recording::conditional::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_end_with_conditional (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *boolval */\n"
+ " %s, /* gcc_jit_block *on_true */\n"
+ " %s); /* gcc_jit_block *on_false */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_rvalue (m_boolval),
+ r.get_identifier (m_on_true),
+ r.get_identifier (m_on_false));
+}
+
+/* The implementation of class gcc::jit::recording::jump. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::jump. */
+
+void
+recording::jump::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_jump (playback_location (r),
+ m_target->playback_block ());
+}
+
+/* Override the poisoned default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+
+ An unconditional jump has 1 successor block. */
+
+int
+recording::jump::get_successor_blocks (block **out_next1,
+ block **/*out_next2*/) const
+{
+ *out_next1 = m_target;
+ return 1;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ a unconditional jump statement. */
+
+recording::string *
+recording::jump::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "goto %s;",
+ m_target->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ jump statements. */
+
+void
+recording::jump::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_end_with_jump (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* gcc_jit_block *target */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier (m_target));
+}
+
+/* The implementation of class gcc::jit::recording::return_. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::return_. */
+
+void
+recording::return_::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_return (playback_location (r),
+ m_rvalue ? m_rvalue->playback_rvalue () : NULL);
+}
+
+/* Override the poisoned default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+
+ A return statement has no successor block. */
+
+int
+recording::return_::get_successor_blocks (block **/*out_next1*/,
+ block **/*out_next2*/) const
+{
+ return 0;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ a return statement (covers both those with and without rvalues). */
+
+recording::string *
+recording::return_::make_debug_string ()
+{
+ if (m_rvalue)
+ return string::from_printf (m_ctxt,
+ "return %s;",
+ m_rvalue->get_debug_string ());
+ else
+ return string::from_printf (m_ctxt,
+ "return;");
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ return statements. */
+
+void
+recording::return_::write_reproducer (reproducer &r)
+{
+ if (m_rvalue)
+ r.write (" gcc_jit_block_end_with_return (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* gcc_jit_rvalue *rvalue */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_rvalue (m_rvalue));
+ else
+ r.write (" gcc_jit_block_end_with_void_return (%s, /*gcc_jit_block *block */\n"
+ " %s); /* gcc_jit_location *loc */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()));
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc