/* Internals of libgccjit: classes for recording calls made to the JIT API.
- Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ Copyright (C) 2013-2020 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "opts.h"
-#include "tree.h"
#include "pretty-print.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"
void
dump::write (const char *fmt, ...)
{
+ int len;
va_list ap;
- char *buf = NULL;
+ char *buf;
/* If there was an error opening the file, we've already reported it.
Don't attempt further work. */
return;
va_start (ap, fmt);
- vasprintf (&buf, fmt, ap);
+ len = vasprintf (&buf, fmt, ap);
va_end (ap);
- if (!buf)
+ if (buf == NULL || len < 0)
{
m_ctxt.add_error (NULL, "malloc failure writing to dumpfile %s",
m_filename);
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++)
{
recording::location *
dump::make_location () const
{
- return m_ctxt.new_location (m_filename, m_line, m_column);
+ 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:
+ const char * ensure_identifier_is_unique (const char *candidate, void *ptr);
+
+ private:
+ hash_map<recording::memento *, const char *> m_map_memento_to_identifier;
+
+ struct hash_traits : public string_hash
+ {
+ static void remove (const char *) {}
+ };
+ hash_set<const char *, false, hash_traits> m_set_identifiers;
+ allocator m_allocator;
+};
+
+/* gcc::jit::reproducer's constructor. */
+
+reproducer::reproducer (recording::context &ctxt,
+ const char *filename) :
+ dump (ctxt, filename, 0),
+ m_map_memento_to_identifier (),
+ m_set_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"
+ " ");
+ }
+}
+
+/* Ensure that STR is a valid C identifier by overwriting
+ any invalid chars in-place with underscores.
+
+ This doesn't special-case the first character. */
+
+static void
+convert_to_identifier (char *str)
+{
+ for (char *p = str; *p; p++)
+ if (!ISALNUM (*p))
+ *p = '_';
+}
+
+/* Given CANDIDATE, a possible C identifier for use in a reproducer,
+ ensure that it is unique within the generated source file by
+ appending PTR to it if necessary. Return the resulting string.
+
+ The reproducer will eventually clean up the buffer in its dtor. */
+
+const char *
+reproducer::ensure_identifier_is_unique (const char *candidate, void *ptr)
+{
+ if (m_set_identifiers.contains (candidate))
+ candidate = m_allocator.xstrdup_printf ("%s_%p", candidate, ptr);
+ gcc_assert (!m_set_identifiers.contains (candidate));
+ m_set_identifiers.add (candidate);
+ return candidate;
+}
+
+/* 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)
+{
+ const char *result;
+ if (strlen (m->get_debug_string ()) < 100)
+ {
+ char *buf = m_allocator.xstrdup_printf ("%s_%s",
+ prefix,
+ m->get_debug_string ());
+ convert_to_identifier (buf);
+ result = buf;
+ }
+ else
+ result = m_allocator.xstrdup_printf ("%s_%p",
+ prefix, (void *) m);
+ result = ensure_identifier_is_unique (result, m);
+ m_map_memento_to_identifier.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_map_memento_to_identifier.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;
+}
+
+/* A helper class for implementing make_debug_string, for building
+ a temporary string from a vec of rvalues. */
+
+class comma_separated_string
+{
+ public:
+ comma_separated_string (const auto_vec<recording::rvalue *> &rvalues,
+ enum recording::precedence prec);
+ ~comma_separated_string ();
+
+ const char *as_char_ptr () const { return m_buf; }
+
+ private:
+ char *m_buf;
+};
+
+/* comma_separated_string's ctor
+ Build m_buf. */
+
+comma_separated_string::comma_separated_string
+ (const auto_vec<recording::rvalue *> &rvalues,
+ enum recording::precedence prec)
+: m_buf (NULL)
+{
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< rvalues.length (); i++)
+ {
+ sz += strlen (rvalues[i]->get_debug_string_parens (prec));
+ sz += 2; /* ", " separator */
+ }
+
+ /* Now allocate and populate the buffer. */
+ m_buf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< rvalues.length (); i++)
+ {
+ strcpy (m_buf + len, rvalues[i]->get_debug_string_parens (prec));
+ len += strlen (rvalues[i]->get_debug_string_parens (prec));
+ if (i + 1 < rvalues.length ())
+ {
+ strcpy (m_buf + len, ", ");
+ len += 2;
+ }
+ }
+ m_buf[len] = '\0';
+}
+
+/* comma_separated_string's dtor. */
+
+comma_separated_string::~comma_separated_string ()
+{
+ delete[] m_buf;
}
/**********************************************************************
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_timer (NULL),
m_error_count (0),
m_first_error_str (NULL),
m_owns_first_error_str (false),
m_owns_last_error_str (false),
m_mementos (),
m_compound_types (),
+ m_globals (),
m_functions (),
m_FILE_type (NULL),
m_builtins_manager(NULL)
memcpy (m_bool_options,
parent_ctxt->m_bool_options,
sizeof (m_bool_options));
+ memcpy (m_inner_bool_options,
+ parent_ctxt->m_inner_bool_options,
+ sizeof (m_inner_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_inner_bool_options, 0, sizeof (m_inner_bool_options));
}
memset (m_basic_types, 0, sizeof (m_basic_types));
for (i = 0; i < GCC_JIT_NUM_STR_OPTIONS; ++i)
free (m_str_options[i]);
+ char *optname;
+ FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+ free (optname);
+ FOR_EACH_VEC_ELT (m_driver_options, i, optname)
+ free (optname);
+
if (m_builtins_manager)
delete m_builtins_manager;
recording::location *
recording::context::new_location (const char *filename,
- int line,
- int column)
+ int line,
+ int column,
+ bool created_by_user)
{
recording::location *result =
new recording::location (this,
- new_string (filename),
- line, column);
+ new_string (filename),
+ line, column,
+ created_by_user);
record (result);
return result;
}
return result;
}
+/* Create a recording::bitfield instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_bitfield. */
+
+recording::field *
+recording::context::new_bitfield (recording::location *loc,
+ recording::type *type,
+ int width,
+ const char *name)
+{
+ recording::field *result =
+ new recording::bitfield (this, loc, type, width, 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.
param_types,
is_variadic);
- /* Return a pointer-type to the the function type. */
+ /* Return a pointer-type to the function type. */
return fn_type->get_pointer ();
}
recording::lvalue *
recording::context::new_global (recording::location *loc,
+ enum gcc_jit_global_kind kind,
recording::type *type,
const char *name)
{
- recording::lvalue *result =
- new recording::global (this, loc, type, new_string (name));
- record (result);
- return result;
-}
-
-/* Create a recording::memento_of_new_rvalue_from_int instance and add
- it to this context's list of mementos.
-
- Implements the post-error-checking part of
- gcc_jit_context_new_rvalue_from_int. */
-
-recording::rvalue *
-recording::context::new_rvalue_from_int (recording::type *type,
- int value)
-{
- recording::rvalue *result =
- new memento_of_new_rvalue_from_int (this, NULL, type, value);
+ recording::global *result =
+ new recording::global (this, loc, kind, type, new_string (name));
record (result);
- return result;
-}
-
-/* Create a recording::memento_of_new_rvalue_from_double instance and
- add it to this context's list of mementos.
-
- Implements the post-error-checking part of
- gcc_jit_context_new_rvalue_from_double. */
+ m_globals.safe_push (result);
-recording::rvalue *
-recording::context::new_rvalue_from_double (recording::type *type,
- double value)
-{
- recording::rvalue *result =
- new memento_of_new_rvalue_from_double (this, NULL, type, value);
- record (result);
return result;
}
-/* Create a recording::memento_of_new_rvalue_from_ptr instance and add
- it to this context's list of mementos.
+/* 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_rvalue_from_ptr. */
+ gcc_jit_context_new_string_literal. */
recording::rvalue *
-recording::context::new_rvalue_from_ptr (recording::type *type,
- void *value)
+recording::context::new_string_literal (const char *value)
{
recording::rvalue *result =
- new memento_of_new_rvalue_from_ptr (this, NULL, type, value);
+ new memento_of_new_string_literal (this, NULL, new_string (value));
record (result);
return result;
}
-/* Create a recording::memento_of_new_string_literal instance and add it
+/* Create a recording::memento_of_new_rvalue_from_vector instance and add it
to this context's list of mementos.
Implements the post-error-checking part of
- gcc_jit_context_new_string_literal. */
+ gcc_jit_context_new_rvalue_from_vector. */
recording::rvalue *
-recording::context::new_string_literal (const char *value)
+recording::context::new_rvalue_from_vector (location *loc,
+ vector_type *type,
+ rvalue **elements)
{
- recording::rvalue *result =
- new memento_of_new_string_literal (this, NULL, new_string (value));
+ recording::rvalue *result
+ = new memento_of_new_rvalue_from_vector (this, loc, type, elements);
record (result);
return result;
}
return result;
}
+/* Create a recording::case_ instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_case. */
+
+recording::case_ *
+recording::context::new_case (recording::rvalue *min_value,
+ recording::rvalue *max_value,
+ recording::block *block)
+{
+ recording::case_ *result = new case_ (this, min_value, max_value, block);
+ record (result);
+ return result;
+}
+
/* Set the given string option for this context, or add an error if
it's not recognized.
}
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
return;
}
m_int_options[opt] = value;
+ log_int_option (opt);
}
/* Set the given boolean option for this context, or add an error if
return;
}
m_bool_options[opt] = value ? true : false;
+ log_bool_option (opt);
+}
+
+void
+recording::context::set_inner_bool_option (enum inner_bool_option inner_opt,
+ int value)
+{
+ gcc_assert (inner_opt >= 0 && inner_opt < NUM_INNER_BOOL_OPTIONS);
+ m_inner_bool_options[inner_opt] = value ? true : false;
+ log_inner_bool_option (inner_opt);
+}
+
+
+/* Add the given optname to this context's list of extra options.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_add_command_line_option. */
+
+void
+recording::context::add_command_line_option (const char *optname)
+{
+ m_command_line_options.safe_push (xstrdup (optname));
+}
+
+/* Add any user-provided extra options, starting with any from
+ parent contexts.
+ Called by playback::context::make_fake_args. */
+
+void
+recording::context::append_command_line_options (vec <char *> *argvec)
+{
+ if (m_parent_ctxt)
+ m_parent_ctxt->append_command_line_options (argvec);
+
+ int i;
+ char *optname;
+ FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+ argvec->safe_push (xstrdup (optname));
+}
+
+/* Add the given optname to this context's list of extra driver options. */
+
+void
+recording::context::add_driver_option (const char *optname)
+{
+ m_driver_options.safe_push (xstrdup (optname));
+}
+
+/* Add any user-provided driver options, starting with any from
+ parent contexts.
+ Called by playback::context::invoke_driver. */
+
+void
+recording::context::append_driver_options (auto_string_vec *argvec)
+{
+ if (m_parent_ctxt)
+ m_parent_ctxt->append_driver_options (argvec);
+
+ int i;
+ char *optname;
+
+ FOR_EACH_VEC_ELT (m_driver_options, i, optname)
+ argvec->safe_push (xstrdup (optname));
}
/* Add the given dumpname/out_ptr pair to this context's list of requested
m_requested_dumps.safe_push (d);
}
-/* Validate this context, and if it passes, compile it within a
- mutex.
+/* 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. */
{
JIT_LOG_SCOPE (get_logger ());
+ log_all_options ();
+
validate ();
if (errors_occurred ())
return NULL;
- /* Set up a playback context. */
- ::gcc::jit::playback::context replayer (this);
+ /* Set up a compile_to_memory playback context. */
+ ::gcc::jit::playback::compile_to_memory replayer (this);
/* Use it. */
- result *result_obj = replayer.compile ();
+ replayer.compile ();
+
+ /* Get the jit::result (or NULL) from the
+ compile_to_memory playback context. */
+ return replayer.get_result_obj ();
+}
- return 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
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 ());
- vasprintf (&malloced_msg, fmt, ap);
- if (malloced_msg)
+ len = vasprintf (&malloced_msg, fmt, ap);
+ if (malloced_msg == NULL || len < 0)
{
- errmsg = malloced_msg;
- has_ownership = true;
+ errmsg = "out of memory generating error message";
+ has_ownership = false;
}
else
{
- errmsg = "out of memory generating error message";
- has_ownership = false;
+ errmsg = malloced_msg;
+ has_ownership = true;
}
if (get_logger ())
get_logger ()->log ("error %i: %s", m_error_count, errmsg);
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)
{
}
}
+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"
+};
+
+static const char * const
+ inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = {
+ "gcc_jit_context_set_bool_allow_unreachable_blocks",
+ "gcc_jit_context_set_bool_use_external_driver"
+};
+
+/* 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);
+ for (opt_idx = 0; opt_idx < NUM_INNER_BOOL_OPTIONS; opt_idx++)
+ log_inner_bool_option ((enum inner_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 the current value of the given "inner" bool option to the
+ log file (if any). */
+
+void
+recording::context::log_inner_bool_option (enum inner_bool_option opt) const
+{
+ gcc_assert (opt < NUM_INNER_BOOL_OPTIONS);
+ if (get_logger ())
+ log ("%s: %s",
+ inner_bool_option_reproducer_strings[opt],
+ m_inner_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 ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\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",
+ r.get_identifier (contexts[ctxt_idx]),
+ str_option_reproducer_strings[opt_idx]);
+ if (m_str_options[opt_idx])
+ r.write (" \"%s\");\n",
+ m_str_options[opt_idx]);
+ else
+ r.write (" NULL);\n");
+ }
+ 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]);
+ for (int opt_idx = 0; opt_idx < NUM_INNER_BOOL_OPTIONS; opt_idx++)
+ r.write (" %s (%s, %i);\n",
+ inner_bool_option_reproducer_strings[opt_idx],
+ r.get_identifier (contexts[ctxt_idx]),
+ m_inner_bool_options[opt_idx]);
+
+ if (!m_command_line_options.is_empty ())
+ {
+ int i;
+ char *optname;
+ r.write (" /* User-provided command-line options. */\n");
+ FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+ r.write (" gcc_jit_context_add_command_line_option (%s, \"%s\");\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ optname);
+ }
+
+ if (!m_driver_options.is_empty ())
+ {
+ int i;
+ char *optname;
+ r.write (" /* User-provided driver options. */\n");
+ FOR_EACH_VEC_ELT (m_driver_options, i, optname)
+ r.write (" gcc_jit_context_add_driver_option (%s, \"%s\");\n",
+ r.get_identifier (contexts[ctxt_idx]),
+ optname);
+ }
+
+ 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. */
recording::string *
recording::string::from_printf (context *ctxt, const char *fmt, ...)
{
+ int len;
va_list ap;
- char *buf = NULL;
+ char *buf;
recording::string *result;
va_start (ap, fmt);
- vasprintf (&buf, fmt, ap);
+ len = vasprintf (&buf, fmt, ap);
va_end (ap);
- if (!buf)
+ if (buf == NULL || len < 0)
{
ctxt->add_error (NULL, "malloc failure");
return NULL;
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.
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*.
return result;
}
+/* Given a type, get an aligned version of the type.
+
+ Implements the post-error-checking part of
+ gcc_jit_type_get_aligned. */
+
+recording::type *
+recording::type::get_aligned (size_t alignment_in_bytes)
+{
+ recording::type *result
+ = new memento_of_get_aligned (this, alignment_in_bytes);
+ m_ctxt->record (result);
+ return result;
+}
+
+/* Given a type, get a vector version of the type.
+
+ Implements the post-error-checking part of
+ gcc_jit_type_get_vector. */
+
+recording::type *
+recording::type::get_vector (size_t num_units)
+{
+ recording::type *result
+ = new vector_type (this, num_units);
+ 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. */
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
"%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
"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
"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::memento_of_get_aligned. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_get_aligned. */
+
+void
+recording::memento_of_get_aligned::replay_into (replayer *)
+{
+ set_playback_obj
+ (m_other_type->playback_type ()->get_aligned (m_alignment_in_bytes));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_aligned. */
+
+recording::string *
+recording::memento_of_get_aligned::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s __attribute__((aligned(%zi)))",
+ m_other_type->get_debug_string (),
+ m_alignment_in_bytes);
+}
+
+/* Implementation of recording::memento::write_reproducer for aligned
+ types. */
+
+void
+recording::memento_of_get_aligned::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_type_get_aligned (%s, %zi);\n",
+ id,
+ r.get_identifier_as_type (m_other_type),
+ m_alignment_in_bytes);
+}
+
+/* The implementation of class gcc::jit::recording::vector_type. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::vector_type. */
+
+void
+recording::vector_type::replay_into (replayer *)
+{
+ set_playback_obj
+ (m_other_type->playback_type ()->get_vector (m_num_units));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of get_vector. */
+
+recording::string *
+recording::vector_type::make_debug_string ()
+{
+ return string::from_printf
+ (m_ctxt,
+ "%s __attribute__((vector_size(sizeof (%s) * %zi)))",
+ m_other_type->get_debug_string (),
+ m_other_type->get_debug_string (),
+ m_num_units);
+}
+
+/* Implementation of recording::memento::write_reproducer for vector types. */
+
+void
+recording::vector_type::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "type");
+ r.write (" gcc_jit_type *%s =\n"
+ " gcc_jit_type_get_vector (%s, %zi);\n",
+ id,
+ r.get_identifier_as_type (m_other_type),
+ m_num_units);
+}
+
/* The implementation of class gcc::jit::recording::array_type */
/* Implementation of pure virtual hook recording::type::dereference for
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. */
return NULL;
}
+/* Implementation of virtual hook recording::type::is_same_type_as for
+ recording::function_type.
+
+ We override this to avoid requiring identity of function pointer types,
+ so that if client code has obtained the same signature in
+ different ways (e.g. via gcc_jit_context_new_function_ptr_type
+ vs gcc_jit_function_get_address), the different function_type
+ instances are treated as compatible.
+
+ We can't use type::accepts_writes_from for this as we need a stronger
+ notion of "sameness": if we have a fn_ptr type that has args that are
+ themselves fn_ptr types, then those args still need to match exactly.
+
+ Alternatively, we could consolidate attempts to create identical
+ function_type instances so that pointer equality works, but that runs
+ into issues about the lifetimes of the cache (w.r.t. nested contexts). */
+
+bool
+recording::function_type::is_same_type_as (type *other)
+{
+ gcc_assert (other);
+
+ function_type *other_fn_type = other->dyn_cast_function_type ();
+ if (!other_fn_type)
+ return false;
+
+ /* Everything must match. */
+
+ if (!m_return_type->is_same_type_as (other_fn_type->m_return_type))
+ return false;
+
+ if (m_param_types.length () != other_fn_type->m_param_types.length ())
+ return false;
+
+ unsigned i;
+ type *param_type;
+ FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+ if (!param_type->is_same_type_as (other_fn_type->m_param_types[i]))
+ return false;
+
+ if (m_is_variadic != other_fn_type->m_is_variadic)
+ return false;
+
+ /* Passed all tests. */
+ return true;
+}
+
/* Implementation of pure virtual hook recording::memento::replay_into
for recording::function_type. */
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
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. */
+ so that we can build up a struct/union field by field. */
void
recording::field::write_to_dump (dump &d)
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::bitfield. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::bitfield. */
+
+void
+recording::bitfield::replay_into (replayer *r)
+{
+ set_playback_obj (r->new_bitfield (playback_location (r, m_loc),
+ m_type->playback_type (),
+ m_width,
+ playback_string (m_name)));
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump. Dump each bit field
+ by dumping a line of the form:
+ TYPE NAME:WIDTH;
+ so that we can build up a struct/union field by field. */
+
+void
+recording::bitfield::write_to_dump (dump &d)
+{
+ d.write (" %s %s:%d;\n",
+ m_type->get_debug_string (),
+ m_name->c_str (),
+ m_width);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ results of new_bitfield. */
+
+recording::string *
+recording::bitfield::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s:%d",
+ m_name->c_str (), m_width);
+}
+
+/* Implementation of recording::memento::write_reproducer for bitfields. */
+
+void
+recording::bitfield::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "bitfield");
+ r.write (" gcc_jit_field *%s =\n"
+ " gcc_jit_context_new_bitfield (%s,\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *type, */\n"
+ " %d, /* int width, */\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_width,
+ m_name->get_debug_string ());
+}
+
/* The implementation of class gcc::jit::recording::compound_type */
/* The constructor for gcc::jit::recording::compound_type. */
field **field_array)
{
m_loc = loc;
- gcc_assert (NULL == m_fields);
+ gcc_assert (m_fields == NULL);
m_fields = new fields (this, num_fields, field_array);
m_ctxt->record (m_fields);
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. */
"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_. */
"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. */
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 (m_struct_or_union->dyn_cast_struct () == NULL)
+ /* 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. */
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) FINAL OVERRIDE;
+
+ 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 (m_scope == NULL);
+ 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);
+}
+
+/* Return a debug string for the given rvalue, wrapping it in parentheses
+ if needed to mimic C's precedence rules, i.e. if OUTER_PREC is of
+ stronger precedence that this rvalue's precedence.
+
+ For example, given:
+
+ MULT
+ / \
+ PLUS MINUS
+ / \ / \
+ A B C D
+
+ we want to emit:
+
+ (A + B) * (C - D)
+
+ since MULT has strong precedence than PLUS and MINUS, whereas for:
+
+ PLUS
+ / \
+ MULT DIVIDE
+ / \ / \
+ A B C D
+
+ we can simply emit:
+
+ A * B + C / D
+
+ since PLUS has weaker precedence than MULT and DIVIDE. */
+
+const char *
+recording::rvalue::get_debug_string_parens (enum precedence outer_prec)
+{
+ enum precedence this_prec = get_precedence ();
+
+ /* If this_prec has stronger precedence than outer_prec, we don't
+ need to wrap this in parens within the outer debug string.
+ Stronger precedences occur earlier than weaker within the enum,
+ so this is a less than test. Equal precedences don't need
+ parentheses. */
+ if (this_prec <= outer_prec)
+ return get_debug_string();
+
+ /* Otherwise, we need parentheses. */
+
+ /* Lazily-build and cache m_parenthesized_string. */
+ if (!m_parenthesized_string)
+ {
+ const char *debug_string = get_debug_string ();
+ m_parenthesized_string = string::from_printf (get_context (),
+ "(%s)",
+ debug_string);
+ }
+ gcc_assert (m_parenthesized_string);
+ return m_parenthesized_string->c_str ();
+}
+
+
/* The implementation of class gcc::jit::recording::lvalue. */
/* Create a recording::new_access_field_of_lvalue instance and add it to
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.
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. */
m_is_variadic (is_variadic),
m_builtin_id (builtin_id),
m_locals (),
- m_blocks ()
+ m_blocks (),
+ m_fn_ptr_type (NULL)
{
for (int i = 0; i< num_params; i++)
- m_params.safe_push (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
/* 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 ())
+ if (m_blocks.length () == 0)
m_ctxt->add_error (m_loc,
"function %s returns non-void (type: %s)"
" but has no blocks",
}
/* Check that all blocks are reachable. */
- if (m_blocks.length () > 0 && 0 == num_invalid_blocks)
+ if (!m_ctxt->get_inner_bool_option
+ (INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS)
+ && m_blocks.length () > 0 && num_invalid_blocks == 0)
{
/* Iteratively walk the graph of blocks, marking their "m_is_reachable"
flag, starting at the initial block. */
/* 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;
- }
+ vec <block *> successors = b->get_successor_blocks ();
+ int i;
+ block *succ;
+ FOR_EACH_VEC_ELT (successors, i, succ)
+ if (!succ->m_is_reachable)
+ worklist.safe_push (succ);
+ successors.release ();
}
/* Now complain about any blocks that haven't been marked. */
fclose (fp);
}
+/* Implements the post-error-checking part of
+ gcc_jit_function_get_address. */
+
+recording::rvalue *
+recording::function::get_address (recording::location *loc)
+{
+ /* Lazily create and cache the function pointer type. */
+ if (!m_fn_ptr_type)
+ {
+ /* Make a recording::function_type for this function. */
+ auto_vec <recording::type *> param_types (m_params.length ());
+ unsigned i;
+ recording::param *param;
+ FOR_EACH_VEC_ELT (m_params, i, param)
+ param_types.safe_push (param->get_type ());
+ recording::function_type *fn_type
+ = m_ctxt->new_function_type (m_return_type,
+ m_params.length (),
+ param_types.address (),
+ m_is_variadic);
+ m_fn_ptr_type = fn_type->get_pointer ();
+ }
+ gcc_assert (m_fn_ptr_type);
+
+ rvalue *result = new function_pointer (get_context (), loc, this, m_fn_ptr_type);
+ m_ctxt->record (result);
+ return result;
+}
+
/* Implementation of recording::memento::make_debug_string for
functions. */
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 post-error-checking part of
- gcc_jit_block_add_eval. */
+ Implements the heart of gcc_jit_block_add_eval. */
-void
+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 post-error-checking part of
- gcc_jit_block_add_assignment. */
+ Implements the heart of gcc_jit_block_add_assignment. */
-void
+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 post-error-checking part of
- gcc_jit_block_add_assignment_op. */
+ Implements the heart of gcc_jit_block_add_assignment_op. */
-void
+recording::statement *
recording::block::add_assignment_op (recording::location *loc,
recording::lvalue *lvalue,
enum gcc_jit_binary_op op,
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 post-error-checking part of
- gcc_jit_block_add_comment. */
+ Implements the heart of gcc_jit_block_add_comment. */
-void
+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 post-error-checking part of
- gcc_jit_block_end_with_conditional. */
+ Implements the heart of gcc_jit_block_end_with_conditional. */
-void
+recording::statement *
recording::block::end_with_conditional (recording::location *loc,
recording::rvalue *boolval,
recording::block *on_true,
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 post-error-checking part of
- gcc_jit_block_end_with_jump. */
+ Implements the heart of gcc_jit_block_end_with_jump. */
-void
+recording::statement *
recording::block::end_with_jump (recording::location *loc,
recording::block *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
gcc_jit_block_end_with_return and
gcc_jit_block_end_with_void_return. */
-void
+recording::statement *
recording::block::end_with_return (recording::location *loc,
recording::rvalue *rvalue)
{
m_ctxt->record (result);
m_statements.safe_push (result);
m_has_been_terminated = true;
+ return result;
+}
+
+/* Create a recording::switch_ 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_switch. */
+
+recording::statement *
+recording::block::end_with_switch (recording::location *loc,
+ recording::rvalue *expr,
+ recording::block *default_block,
+ int num_cases,
+ recording::case_ **cases)
+{
+ statement *result = new switch_ (this, loc,
+ expr,
+ default_block,
+ num_cases,
+ cases);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ m_has_been_terminated = true;
+ return result;
}
/* Override the default implementation of
bool
recording::block::validate ()
{
+ /* Check for termination. */
if (!has_been_terminated ())
{
statement *stmt = get_last_statement ();
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.
+/* Assuming that this block has been terminated, get the successor blocks
+ as a vector. Ownership of the vector transfers to the caller, which
+ must call its release () method.
Used when validating functions, and when dumping dot representations
of them. */
-int
-recording::block::get_successor_blocks (block **next1, block **next2) const
+vec <recording::block *>
+recording::block::get_successor_blocks () 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);
+ return last_statement->get_successor_blocks ();
}
/* Implementation of pure virtual hook recording::memento::replay_into
(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_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++)
+ vec <block *> successors = get_successor_blocks ();
+ int i;
+ block *succ;
+ FOR_EACH_VEC_ELT (successors, i, succ)
pp_printf (pp,
"\tblock_%d:s -> block_%d:n;\n",
- m_index, next[i]->m_index);
+ m_index, succ->m_index);
+ successors.release ();
}
/* The implementation of class gcc::jit::recording::global. */
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)));
}
-/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_int. */
+/* 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;"
-/* Implementation of pure virtual hook recording::memento::replay_into
- for recording::memento_of_new_rvalue_from_int. */
+ 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_int::replay_into (replayer *r)
+recording::
+memento_of_new_rvalue_from_const <HOST_TYPE>::replay_into (replayer *r)
{
- set_playback_obj (r->new_rvalue_from_int (m_type->playback_type (),
- m_value));
+ set_playback_obj
+ (r->new_rvalue_from_const <HOST_TYPE> (m_type->playback_type (),
+ m_value));
}
-/* Implementation of recording::memento::make_debug_string for
- rvalue_from_int, rendering it as
- (TYPE)LITERAL
+/* 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". */
-recording::string *
-recording::memento_of_new_rvalue_from_int::make_debug_string ()
+template <>
+string *
+memento_of_new_rvalue_from_const <int>::make_debug_string ()
{
return string::from_printf (m_ctxt,
"(%s)%i",
m_value);
}
-/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_double. */
+/* The get_wide_int specialization for <int>. */
-/* Implementation of pure virtual hook recording::memento::replay_into
- for recording::memento_of_new_rvalue_from_double. */
+template <>
+bool
+memento_of_new_rvalue_from_const <int>::get_wide_int (wide_int *out) const
+{
+ *out = wi::shwi (m_value, sizeof (m_value) * 8);
+ return true;
+}
+/* The write_reproducer specialization for <int>. */
+
+template <>
void
-recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
+memento_of_new_rvalue_from_const <int>::write_reproducer (reproducer &r)
{
- set_playback_obj (r->new_rvalue_from_double (m_type->playback_type (),
- m_value));
+ 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);
}
-/* Implementation of recording::memento::make_debug_string for
- rvalue_from_double, rendering it as
- (TYPE)LITERAL
+/* 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 get_wide_int specialization for <long>. */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <long>::get_wide_int (wide_int *out) const
+{
+ *out = wi::shwi (m_value, sizeof (m_value) * 8);
+ return true;
+}
+
+/* The write_reproducer specialization for <long>. */
+
+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". */
-recording::string *
-recording::memento_of_new_rvalue_from_double::make_debug_string ()
+template <>
+string *
+memento_of_new_rvalue_from_const <double>::make_debug_string ()
{
return string::from_printf (m_ctxt,
"(%s)%f",
m_value);
}
-/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_ptr. */
+/* The get_wide_int specialization for <double>. */
-/* Implementation of pure virtual hook recording::memento::replay_into
- for recording::memento_of_new_rvalue_from_ptr. */
+template <>
+bool
+memento_of_new_rvalue_from_const <double>::get_wide_int (wide_int *) const
+{
+ return false;
+}
+
+/* The write_reproducer specialization for <double>. */
+template <>
void
-recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
+recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproducer &r)
{
- set_playback_obj (r->new_rvalue_from_ptr (m_type->playback_type (),
- m_value));
+ 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);
}
-/* Implementation of recording::memento::make_debug_string for
- rvalue_from_ptr, rendering it as
- (TYPE)HEX
+/* 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". */
-recording::string *
-recording::memento_of_new_rvalue_from_ptr::make_debug_string ()
+template <>
+string *
+memento_of_new_rvalue_from_const <void *>::make_debug_string ()
{
if (m_value != NULL)
return string::from_printf (m_ctxt,
m_type->get_debug_string ());
}
-/* The implementation of class gcc::jit::recording::memento_of_new_string_literal. */
+/* The get_wide_int specialization for <void *>. */
-/* Implementation of pure virtual hook recording::memento::replay_into
+template <>
+bool
+memento_of_new_rvalue_from_const <void *>::get_wide_int (wide_int *) const
+{
+ return false;
+}
+
+/* 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::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::memento_of_new_rvalue_from_vector. */
+
+/* The constructor for
+ gcc::jit::recording::memento_of_new_rvalue_from_vector. */
+
+recording::memento_of_new_rvalue_from_vector::
+memento_of_new_rvalue_from_vector (context *ctxt,
+ location *loc,
+ vector_type *type,
+ rvalue **elements)
+: rvalue (ctxt, loc, type),
+ m_vector_type (type),
+ m_elements ()
+{
+ for (unsigned i = 0; i < type->get_num_units (); i++)
+ m_elements.safe_push (elements[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_rvalue_from_vector. */
+
+void
+recording::memento_of_new_rvalue_from_vector::replay_into (replayer *r)
+{
+ auto_vec<playback::rvalue *> playback_elements;
+ playback_elements.create (m_elements.length ());
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ playback_elements.safe_push (m_elements[i]->playback_rvalue ());
+
+ set_playback_obj (r->new_rvalue_from_vector (playback_location (r, m_loc),
+ m_type->playback_type (),
+ playback_elements));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::memento_of_new_rvalue_from_vector. */
+
+void
+recording::memento_of_new_rvalue_from_vector::visit_children (rvalue_visitor *v)
+{
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ v->visit (m_elements[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ vectors. */
+
+recording::string *
+recording::memento_of_new_rvalue_from_vector::make_debug_string ()
+{
+ comma_separated_string elements (m_elements, get_precedence ());
+
+ /* Now build a string. */
+ string *result = string::from_printf (m_ctxt,
+ "{%s}",
+ elements.as_char_ptr ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vectors. */
+
+void
+recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "vector");
+ const char *elements_id = r.make_tmp_identifier ("elements_for_", this);
+ r.write (" gcc_jit_rvalue *%s[%i] = {\n",
+ elements_id,
+ m_elements.length ());
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ r.write (" %s,\n", r.get_identifier_as_rvalue (m_elements[i]));
+ r.write (" };\n");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_vector (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *vec_type */\n"
+ " %i, /* size_t num_elements */ \n"
+ " %s); /* gcc_jit_rvalue **elements*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_vector_type),
+ m_elements.length (),
+ elements_id);
+}
+
/* The implementation of class gcc::jit::recording::unary_op. */
/* Implementation of pure virtual hook recording::memento::replay_into
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. */
m_a->get_debug_string ());
}
+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
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. */
recording::string *
recording::binary_op::make_debug_string ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s %s %s",
- m_a->get_debug_string (),
+ m_a->get_debug_string_parens (prec),
binary_op_strings[m_op],
- m_b->get_debug_string ());
+ m_b->get_debug_string_parens (prec));
+}
+
+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));
+}
+
+namespace recording {
+static const enum precedence binary_op_precedence[] = {
+ PRECEDENCE_ADDITIVE, /* GCC_JIT_BINARY_OP_PLUS */
+ PRECEDENCE_ADDITIVE, /* GCC_JIT_BINARY_OP_MINUS */
+
+ PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_MULT */
+ PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_DIVIDE */
+ PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_MODULO */
+
+ PRECEDENCE_BITWISE_AND, /* GCC_JIT_BINARY_OP_BITWISE_AND */
+ PRECEDENCE_BITWISE_XOR, /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+ PRECEDENCE_BITWISE_IOR, /* GCC_JIT_BINARY_OP_BITWISE_OR */
+ PRECEDENCE_LOGICAL_AND, /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+ PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */
+ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+} /* namespace recording */
+
+enum recording::precedence
+recording::binary_op::get_precedence () const
+{
+ return binary_op_precedence[m_op];
}
/* The implementation of class gcc::jit::recording::comparison. */
recording::string *
recording::comparison::make_debug_string ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s %s %s",
- m_a->get_debug_string (),
+ m_a->get_debug_string_parens (prec),
comparison_strings[m_op],
- m_b->get_debug_string ());
+ m_b->get_debug_string_parens (prec));
+}
+
+/* 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
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);
+}
+
+namespace recording {
+static const enum precedence comparison_precedence[] =
+{
+ PRECEDENCE_EQUALITY, /* GCC_JIT_COMPARISON_EQ */
+ PRECEDENCE_EQUALITY, /* GCC_JIT_COMPARISON_NE */
+
+ PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_LT */
+ PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_LE */
+ PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_GT */
+ PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_GE */
+};
+} /* namespace recording */
+
+enum recording::precedence
+recording::comparison::get_precedence () const
+{
+ return comparison_precedence[m_op];
+}
+
/* Implementation of pure virtual hook recording::memento::replay_into
for recording::cast. */
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"(%s)%s",
get_type ()->get_debug_string (),
- m_rvalue->get_debug_string ());
+ m_rvalue->get_debug_string_parens (prec));
+}
+
+/* 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::base_call. */
+
+/* The constructor for gcc::jit::recording::base_call. */
+
+recording::base_call::base_call (context *ctxt,
+ location *loc,
+ type *type_,
+ int numargs,
+ rvalue **args)
+: rvalue (ctxt, loc, type_),
+ m_args (),
+ m_require_tail_call (0)
+{
+ for (int i = 0; i< numargs; i++)
+ m_args.safe_push (args[i]);
+}
+
+/* Subroutine for use by call and call_though_ptr's write_reproducer
+ methods. */
+
+void
+recording::base_call::write_reproducer_tail_call (reproducer &r,
+ const char *id)
+{
+ if (m_require_tail_call)
+ {
+ r.write (" gcc_jit_rvalue_set_bool_require_tail_call (%s, /* gcc_jit_rvalue *call*/\n"
+ " %i); /* int require_tail_call*/\n",
+ id,
+ 1);
+ }
}
/* The implementation of class gcc::jit::recording::call. */
recording::function *func,
int numargs,
rvalue **args)
-: rvalue (ctxt, loc, func->get_return_type ()),
- m_func (func),
- m_args ()
+: base_call (ctxt, loc, func->get_return_type (), numargs, args),
+ m_func (func)
{
- for (int i = 0; i< numargs; i++)
- m_args.safe_push (args[i]);
}
/* Implementation of pure virtual hook recording::memento::replay_into
set_playback_obj (r->new_call (playback_location (r, m_loc),
m_func->playback_function (),
- &playback_args));
+ &playback_args,
+ m_require_tail_call));
+}
+
+/* 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
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';
+ comma_separated_string args (m_args, get_precedence ());
/* ...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;
+ args.as_char_ptr ());
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);
+ write_reproducer_tail_call (r, id);
+}
+
/* The implementation of class gcc::jit::recording::call_through_ptr. */
/* The constructor for recording::call_through_ptr. */
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 ()
+: base_call (ctxt, loc,
+ fn_ptr->get_type ()->dereference ()
+ ->as_a_function_type ()->get_return_type (),
+ numargs, args),
+ m_fn_ptr (fn_ptr)
{
- for (int i = 0; i< numargs; i++)
- m_args.safe_push (args[i]);
}
/* Implementation of pure virtual hook recording::memento::replay_into
set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
m_fn_ptr->playback_rvalue (),
- &playback_args));
+ &playback_args,
+ m_require_tail_call));
+}
+
+/* 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
recording::string *
recording::call_through_ptr::make_debug_string ()
{
+ enum precedence prec = get_precedence ();
/* 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 += strlen (m_args[i]->get_debug_string_parens (prec));
sz += 2; /* ", " separator */
}
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 ());
+ strcpy (argbuf + len, m_args[i]->get_debug_string_parens (prec));
+ len += strlen (m_args[i]->get_debug_string_parens (prec));
if (i + 1 < m_args.length ())
{
strcpy (argbuf + len, ", ");
/* ...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 (),
+ m_fn_ptr->get_debug_string_parens (prec),
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);
+ write_reproducer_tail_call (r, id);
+}
+
/* The implementation of class gcc::jit::recording::array_access. */
/* Implementation of pure virtual hook recording::memento::replay_into
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s[%s]",
- m_ptr->get_debug_string (),
- m_index->get_debug_string ());
+ m_ptr->get_debug_string_parens (prec),
+ m_index->get_debug_string_parens (prec));
+}
+
+/* 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::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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s.%s",
- m_lvalue->get_debug_string (),
+ m_lvalue->get_debug_string_parens (prec),
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
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s.%s",
- m_rvalue->get_debug_string (),
+ m_rvalue->get_debug_string_parens (prec),
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. */
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"%s->%s",
- m_rvalue->get_debug_string (),
+ m_rvalue->get_debug_string_parens (prec),
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
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"*%s",
- m_rvalue->get_debug_string ());
+ m_rvalue->get_debug_string_parens (prec));
+}
+
+/* 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. */
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 ()
{
+ enum precedence prec = get_precedence ();
return string::from_printf (m_ctxt,
"&%s",
- m_lvalue->get_debug_string ());
+ m_lvalue->get_debug_string_parens (prec));
+}
+
+/* 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::function_pointer. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::function_pointer. */
+
+void
+recording::function_pointer::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_fn->playback_function ()->
+ get_address (playback_location (r, m_loc)));
+}
+
+void
+recording::function_pointer::visit_children (rvalue_visitor *)
+{
+ /* Empty. */
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ getting the address of an lvalue. */
+
+recording::string *
+recording::function_pointer::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s",
+ m_fn->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ function_pointer. */
+
+void
+recording::function_pointer::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "address_of");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_function_get_address (%s, /* gcc_jit_function *fn */\n"
+ " %s); /* gcc_jit_location *loc */\n",
+ id,
+ r.get_identifier (m_fn),
+ r.get_identifier (m_loc));
}
/* The implementation of class gcc::jit::recording::local. */
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
since this vfunc must only ever be called on terminator
statements. */
-int
-recording::statement::get_successor_blocks (block **/*out_next1*/,
- block **/*out_next2*/) const
+vec <recording::block *>
+recording::statement::get_successor_blocks () const
{
/* The base class implementation is for non-terminating statements,
and thus should never be called. */
gcc_unreachable ();
- return 0;
+ vec <block *> result;
+ result.create (0);
+ return result;
}
/* Extend the default implementation of
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
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
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
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
A conditional jump has 2 successor blocks. */
-int
-recording::conditional::get_successor_blocks (block **out_next1,
- block **out_next2) const
+vec <recording::block *>
+recording::conditional::get_successor_blocks () const
{
- *out_next1 = m_on_true;
- *out_next2 = m_on_false;
- return 2;
+ vec <block *> result;
+ result.create (2);
+ result.quick_push (m_on_true);
+ result.quick_push (m_on_false);
+ return result;
}
/* Implementation of recording::memento::make_debug_string for
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
An unconditional jump has 1 successor block. */
-int
-recording::jump::get_successor_blocks (block **out_next1,
- block **/*out_next2*/) const
+vec <recording::block *>
+recording::jump::get_successor_blocks () const
{
- *out_next1 = m_target;
- return 1;
+ vec <block *> result;
+ result.create (1);
+ result.quick_push (m_target);
+ return result;
}
/* Implementation of recording::memento::make_debug_string for
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
A return statement has no successor block. */
-int
-recording::return_::get_successor_blocks (block **/*out_next1*/,
- block **/*out_next2*/) const
+vec <recording::block *>
+recording::return_::get_successor_blocks () const
{
- return 0;
+ vec <block *> result;
+ result.create (0);
+ return result;
}
/* Implementation of recording::memento::make_debug_string for
"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 ()));
+}
+
+/* The implementation of class gcc::jit::recording::case_. */
+
+void
+recording::case_::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "case");
+ const char *fmt =
+ " gcc_jit_case *%s = \n"
+ " gcc_jit_context_new_case (%s, /*gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_rvalue *min_value */\n"
+ " %s, /* gcc_jit_rvalue *max_value */\n"
+ " %s); /* gcc_jit_block *dest_block */\n";
+ r.write (fmt,
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier_as_rvalue (m_min_value),
+ r.get_identifier_as_rvalue (m_max_value),
+ r.get_identifier (m_dest_block));
+}
+
+recording::string *
+recording::case_::make_debug_string ()
+{
+ return string::from_printf (get_context (),
+ "case %s ... %s: goto %s;",
+ m_min_value->get_debug_string (),
+ m_max_value->get_debug_string (),
+ m_dest_block->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::switch_. */
+
+/* gcc::jit::recording::switch_'s constructor. */
+
+recording::switch_::switch_ (block *b,
+ location *loc,
+ rvalue *expr,
+ block *default_block,
+ int num_cases,
+ case_ **cases)
+: statement (b, loc),
+ m_expr (expr),
+ m_default_block (default_block)
+{
+ m_cases.reserve_exact (num_cases);
+ for (int i = 0; i< num_cases; i++)
+ m_cases.quick_push (cases[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::switch_. */
+
+void
+recording::switch_::replay_into (replayer *r)
+{
+ auto_vec <playback::case_> pcases;
+ int i;
+ recording::case_ *rcase;
+ pcases.reserve_exact (m_cases.length ());
+ FOR_EACH_VEC_ELT (m_cases, i, rcase)
+ {
+ playback::case_ pcase (rcase->get_min_value ()->playback_rvalue (),
+ rcase->get_max_value ()->playback_rvalue (),
+ rcase->get_dest_block ()->playback_block ());
+ pcases.safe_push (pcase);
+ }
+ playback_block (get_block ())
+ ->add_switch (playback_location (r),
+ m_expr->playback_rvalue (),
+ m_default_block->playback_block (),
+ &pcases);
+}
+
+/* Override the poisoned default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+
+ A switch statement has (NUM_CASES + 1) successor blocks. */
+
+vec <recording::block *>
+recording::switch_::get_successor_blocks () const
+{
+ vec <block *> result;
+ result.create (m_cases.length () + 1);
+ result.quick_push (m_default_block);
+ int i;
+ case_ *c;
+ FOR_EACH_VEC_ELT (m_cases, i, c)
+ result.quick_push (c->get_dest_block ());
+ return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ a switch statement. */
+
+recording::string *
+recording::switch_::make_debug_string ()
+{
+ auto_vec <char> cases_str;
+ int i;
+ case_ *c;
+ FOR_EACH_VEC_ELT (m_cases, i, c)
+ {
+ size_t len = strlen (c->get_debug_string ());
+ unsigned idx = cases_str.length ();
+ cases_str.safe_grow (idx + 1 + len);
+ cases_str[idx] = ' ';
+ memcpy (&(cases_str[idx + 1]),
+ c->get_debug_string (),
+ len);
+ }
+ cases_str.safe_push ('\0');
+
+ return string::from_printf (m_ctxt,
+ "switch (%s) {default: goto %s;%s}",
+ m_expr->get_debug_string (),
+ m_default_block->get_debug_string (),
+ &cases_str[0]);
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ switch statements. */
+
+void
+recording::switch_::write_reproducer (reproducer &r)
+{
+ r.make_identifier (this, "switch");
+ int i;
+ case_ *c;
+ const char *cases_id =
+ r.make_tmp_identifier ("cases_for", this);
+ r.write (" gcc_jit_case *%s[%i] = {\n",
+ cases_id,
+ m_cases.length ());
+ FOR_EACH_VEC_ELT (m_cases, i, c)
+ r.write (" %s,\n", r.get_identifier (c));
+ r.write (" };\n");
+ const char *fmt =
+ " gcc_jit_block_end_with_switch (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *expr */\n"
+ " %s, /* gcc_jit_block *default_block */\n"
+ " %i, /* int num_cases */\n"
+ " %s); /* gcc_jit_case **cases */\n";
+ r.write (fmt,
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier_as_rvalue (m_expr),
+ r.get_identifier (m_default_block),
+ m_cases.length (),
+ cases_id);
+}
+
} // namespace gcc::jit
} // namespace gcc