Committed to branch dmalcolm/jit:

Add a new "gcc_jit_context_dump_to_file", which dumps a C-like
representation of the context's IR to a given path.

There is also a flag "update_locations", which, when true, will set up
gcc_jit_location information throughout the context, pointing at the dump
file as if it were a source file.

I've been using this in conjunction with GCC_JIT_BOOL_OPTION_DEBUGINFO to
step through generated code in the debugger (when trying to debug my port
of GNU Octave's JIT to libgccjit).

gcc/jit/
        * libgccjit.h (gcc_jit_context_dump_to_file): New.
        * libgccjit.map (gcc_jit_context_dump_to_file): New.
        * libgccjit.c (gcc_jit_context_dump_to_file): New.
        * libgccjit++.h (gccjit::context::dump_to_file): New.

        * internal-api.h (gcc::jit::dump): New class.
        (gcc::jit::recording::playback_location): Add a replayer argument,
        so that playback locations can be created before playback statements.
        (gcc::jit::recording::location::playback_location): Likewise.
        (gcc::jit::recording::statement::playback_location): Likewise.
        (gcc::jit::recording::context::dump_to_file): New.
        (gcc::jit::recording::context::m_structs): New field, for use by
        dump_to_file.
        (gcc::jit::recording::context::m_functions): Likewise.
        (gcc::jit::recording::memento::write_to_dump): New virtual function.
        (gcc::jit::recording::field::write_to_dump): New.
        (gcc::jit::recording::fields::write_to_dump): New.
        (gcc::jit::recording::function::write_to_dump): New.
        (gcc::jit::recording::function::m_locals): New field for use by
        write_to_dump.
        (gcc::jit::recording::function::m_activity): Likewise.
        (gcc::jit::recording::local::write_to_dump): New.
        (gcc::jit::recording::statement::write_to_dump): New.
        (gcc::jit::recording::place_label::write_to_dump): New.

        * internal-api.c (gcc::jit::dump::dump): New.
        (gcc::jit::dump::~dump): New.
        (gcc::jit::dump::write): New.
        (gcc::jit::dump::make_location): New.
        (gcc::jit::recording::playback_location): Add a replayer argument,
        so that playback locations can be created before playback statements.

        (gcc::jit::recording::context::context): Initialize new fields.
        (gcc::jit::recording::function::function): Likewise.

        (gcc::jit::recording::context::new_struct_type): Add struct to the
        context's m_structs vector.
        (gcc::jit::recording::context::new_function): Add function to the
        context's m_functions vector.
        (gcc::jit::recording::context::dump_to_file): New.
        (gcc::jit::recording::memento::write_to_dump): New.
        (gcc::jit::recording::field::write_to_dump): New.
        (gcc::jit::recording::fields::write_to_dump): New.
        (gcc::jit::recording::function::write_to_dump): New.
        (gcc::jit::recording::local::write_to_dump): New.
        (gcc::jit::recording::statement::write_to_dump): New.
        (gcc::jit::recording::place_label::write_to_dump): New.

        (gcc::jit::recording::array_type::replay_into): Pass on replayer
        to call to playback_location.
        (gcc::jit::recording::field::replay_into): Likewise.
        (gcc::jit::recording::struct_::replay_into): Likewise.
        (gcc::jit::recording::param::replay_into): Likewise.
        (gcc::jit::recording::function::replay_into): Likewise.
        (gcc::jit::recording::global::replay_into): Likewise.
        (gcc::jit::recording::unary_op::replay_into): Likewise.
        (gcc::jit::recording::binary_op::replay_into): Likewise.
        (gcc::jit::recording::comparison::replay_into): Likewise.
        (gcc::jit::recording::call::replay_into): Likewise.
        (gcc::jit::recording::array_access::replay_into): Likewise.
        (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
        (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
        (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
        (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
        (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
        (gcc::jit::recording::local::replay_into): Likewise.
        (gcc::jit::recording::eval::replay_into): Likewise.
        (gcc::jit::recording::assignment::replay_into): Likewise.
        (gcc::jit::recording::assignment_op::replay_into): Likewise.
        (gcc::jit::recording::comment::replay_into): Likewise.
        (gcc::jit::recording::conditional::replay_into): Likewise.
        (gcc::jit::recording::place_label::replay_into): Likewise.
        (gcc::jit::recording::jump::replay_into): Likewise.
        (gcc::jit::recording::return_::replay_into): Likewise.
        (gcc::jit::recording::loop::replay_into): Likewise.
        (gcc::jit::recording::loop_end::replay_into): Likewise.

        (gcc::jit::recording::function::new_local): Add to the function's
        vector of locals.
        (gcc::jit::recording::function::add_eval): Add to the function's
        m_activity field.
        (gcc::jit::recording::function::add_assignment): Likewise.
        (gcc::jit::recording::function::add_assignment_op): Likewise.
        (gcc::jit::recording::function::add_comment): Likewise.
        (gcc::jit::recording::function::add_conditional): Likewise.
        (gcc::jit::recording::function::place_forward_label): Likewise.
        (gcc::jit::recording::function::add_jump): Likewise.
        (gcc::jit::recording::function::add_return): Likewise.
        (gcc::jit::recording::function::new_loop): Likewise.

        (gcc::jit::recording::conditional::make_debug_string): Add missing
        semicolon.
---
 gcc/jit/ChangeLog.jit  |  95 ++++++++++++++++
 gcc/jit/internal-api.c | 298 +++++++++++++++++++++++++++++++++++++++++--------
 gcc/jit/internal-api.h |  80 ++++++++++++-
 gcc/jit/libgccjit++.h  |  12 ++
 gcc/jit/libgccjit.c    |  10 ++
 gcc/jit/libgccjit.h    |  13 +++
 gcc/jit/libgccjit.map  |   1 +
 7 files changed, 458 insertions(+), 51 deletions(-)

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 0978a9c..006881d 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,98 @@
+2014-02-21  David Malcolm  <dmalc...@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_dump_to_file): New.
+       * libgccjit.map (gcc_jit_context_dump_to_file): New.
+       * libgccjit.c (gcc_jit_context_dump_to_file): New.
+       * libgccjit++.h (gccjit::context::dump_to_file): New.
+
+       * internal-api.h (gcc::jit::dump): New class.
+       (gcc::jit::recording::playback_location): Add a replayer argument,
+       so that playback locations can be created before playback statements.
+       (gcc::jit::recording::location::playback_location): Likewise.
+       (gcc::jit::recording::statement::playback_location): Likewise.
+       (gcc::jit::recording::context::dump_to_file): New.
+       (gcc::jit::recording::context::m_structs): New field, for use by
+       dump_to_file.
+       (gcc::jit::recording::context::m_functions): Likewise.
+       (gcc::jit::recording::memento::write_to_dump): New virtual function.
+       (gcc::jit::recording::field::write_to_dump): New.
+       (gcc::jit::recording::fields::write_to_dump): New.
+       (gcc::jit::recording::function::write_to_dump): New.
+       (gcc::jit::recording::function::m_locals): New field for use by
+       write_to_dump.
+       (gcc::jit::recording::function::m_activity): Likewise.
+       (gcc::jit::recording::local::write_to_dump): New.
+       (gcc::jit::recording::statement::write_to_dump): New.
+       (gcc::jit::recording::place_label::write_to_dump): New.
+
+       * internal-api.c (gcc::jit::dump::dump): New.
+       (gcc::jit::dump::~dump): New.
+       (gcc::jit::dump::write): New.
+       (gcc::jit::dump::make_location): New.
+       (gcc::jit::recording::playback_location): Add a replayer argument,
+       so that playback locations can be created before playback statements.
+
+       (gcc::jit::recording::context::context): Initialize new fields.
+       (gcc::jit::recording::function::function): Likewise.
+
+       (gcc::jit::recording::context::new_struct_type): Add struct to the
+       context's m_structs vector.
+       (gcc::jit::recording::context::new_function): Add function to the
+       context's m_functions vector.
+       (gcc::jit::recording::context::dump_to_file): New.
+       (gcc::jit::recording::memento::write_to_dump): New.
+       (gcc::jit::recording::field::write_to_dump): New.
+       (gcc::jit::recording::fields::write_to_dump): New.
+       (gcc::jit::recording::function::write_to_dump): New.
+       (gcc::jit::recording::local::write_to_dump): New.
+       (gcc::jit::recording::statement::write_to_dump): New.
+       (gcc::jit::recording::place_label::write_to_dump): New.
+
+       (gcc::jit::recording::array_type::replay_into): Pass on replayer
+       to call to playback_location.
+       (gcc::jit::recording::field::replay_into): Likewise.
+       (gcc::jit::recording::struct_::replay_into): Likewise.
+       (gcc::jit::recording::param::replay_into): Likewise.
+       (gcc::jit::recording::function::replay_into): Likewise.
+       (gcc::jit::recording::global::replay_into): Likewise.
+       (gcc::jit::recording::unary_op::replay_into): Likewise.
+       (gcc::jit::recording::binary_op::replay_into): Likewise.
+       (gcc::jit::recording::comparison::replay_into): Likewise.
+       (gcc::jit::recording::call::replay_into): Likewise.
+       (gcc::jit::recording::array_access::replay_into): Likewise.
+       (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::local::replay_into): Likewise.
+       (gcc::jit::recording::eval::replay_into): Likewise.
+       (gcc::jit::recording::assignment::replay_into): Likewise.
+       (gcc::jit::recording::assignment_op::replay_into): Likewise.
+       (gcc::jit::recording::comment::replay_into): Likewise.
+       (gcc::jit::recording::conditional::replay_into): Likewise.
+       (gcc::jit::recording::place_label::replay_into): Likewise.
+       (gcc::jit::recording::jump::replay_into): Likewise.
+       (gcc::jit::recording::return_::replay_into): Likewise.
+       (gcc::jit::recording::loop::replay_into): Likewise.
+       (gcc::jit::recording::loop_end::replay_into): Likewise.
+
+       (gcc::jit::recording::function::new_local): Add to the function's
+       vector of locals.
+       (gcc::jit::recording::function::add_eval): Add to the function's
+       m_activity field.
+       (gcc::jit::recording::function::add_assignment): Likewise.
+       (gcc::jit::recording::function::add_assignment_op): Likewise.
+       (gcc::jit::recording::function::add_comment): Likewise.
+       (gcc::jit::recording::function::add_conditional): Likewise.
+       (gcc::jit::recording::function::place_forward_label): Likewise.
+       (gcc::jit::recording::function::add_jump): Likewise.
+       (gcc::jit::recording::function::add_return): Likewise.
+       (gcc::jit::recording::function::new_loop): Likewise.
+
+       (gcc::jit::recording::conditional::make_debug_string): Add missing
+       semicolon.
+
 2014-02-19  David Malcolm  <dmalc...@redhat.com>
 
        * libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Verify that
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index 37fe70b..957edb7 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -25,15 +25,65 @@
 namespace gcc {
 namespace jit {
 
+// class dump
+
+dump::dump (recording::context &ctxt,
+           const char *filename,
+           bool update_locations)
+: m_ctxt (ctxt),
+  m_filename (filename),
+  m_update_locations (update_locations),
+  m_line (0),
+  m_column (0)
+{
+  m_file  = fopen (filename, "w");
+}
+
+dump::~dump ()
+{
+  if (m_file)
+    fclose (m_file);
+}
+
+void
+dump::write (const char *fmt, ...)
+{
+  char buf[4096];
+  va_list ap;
+  va_start (ap, fmt);
+  vsnprintf (buf, sizeof (buf), fmt, ap);
+  va_end (ap);
+
+  fwrite (buf, strlen (buf), 1, m_file);
+
+  /* Update line/column: */
+  for (const char *ptr = buf; *ptr; ptr++)
+    {
+      if ('\n' == *ptr)
+       {
+         m_line++;
+         m_column = 0;
+       }
+      else
+       m_column++;
+    }
+}
+
+recording::location *
+dump::make_location () const
+{
+  return m_ctxt.new_location (m_filename, m_line, m_column);
+}
+
 /**********************************************************************
  Recording.
  **********************************************************************/
 
 playback::location *
-recording::playback_location (recording::location *loc)
+recording::playback_location (replayer *r, recording::location *loc)
 {
   if (loc)
-    return loc->playback_location ();
+    return loc->playback_location (r);
   else
     return NULL;
 }
@@ -62,6 +112,8 @@ recording::context::context (context *parent_ctxt)
   : m_parent_ctxt (parent_ctxt),
     m_error_count (0),
     m_mementos (),
+    m_structs (),
+    m_functions (),
     m_FILE_type (NULL),
     m_builtins_manager(NULL)
 {
@@ -290,6 +342,7 @@ recording::context::new_struct_type (recording::location 
*loc,
 {
   recording::struct_ *result = new struct_ (this, loc, new_string (name));
   record (result);
+  m_structs.safe_push (result);
   return result;
 }
 
@@ -321,6 +374,8 @@ recording::context::new_function (recording::location *loc,
                             num_params, params, is_variadic,
                             builtin_id);
   record (result);
+  m_functions.safe_push (result);
+
   return result;
 }
 
@@ -548,6 +603,34 @@ recording::context::get_opaque_FILE_type ()
   return m_FILE_type;
 }
 
+void
+recording::context::dump_to_file (const char *path, bool update_locations)
+{
+  int i;
+  dump d (*this, path, update_locations);
+
+  /* Forward declaration of structs.  */
+  struct_ *st;
+  FOR_EACH_VEC_ELT (m_structs, i, st)
+    {
+      d.write ("%s;\n\n", st->get_debug_string ());
+    }
+
+  /* Content of structs, where set.  */
+  FOR_EACH_VEC_ELT (m_structs, i, st)
+    if (st->get_fields ())
+      {
+       st->get_fields ()->write_to_dump (d);
+       d.write ("\n");
+      }
+
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    {
+      fn->write_to_dump (d);
+    }
+}
+
 /* gcc::jit::recording::memento:: */
 
 const char *
@@ -558,6 +641,12 @@ recording::memento::get_debug_string ()
   return m_debug_string->c_str ();
 }
 
+void
+recording::memento::write_to_dump (dump &d)
+{
+  d.write("  %s\n", get_debug_string ());
+}
+
 /* gcc::jit::recording::string:: */
 recording::string::string (context *ctxt, const char *text)
   : memento (ctxt)
@@ -797,7 +886,7 @@ recording::array_type::dereference ()
 void
 recording::array_type::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_array_type (playback_location (m_loc),
+  set_playback_obj (r->new_array_type (playback_location (r, m_loc),
                                       m_element_type->playback_type (),
                                       m_num_elements));
 }
@@ -903,11 +992,19 @@ recording::function_type::make_debug_string ()
 void
 recording::field::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_field (playback_location (m_loc),
+  set_playback_obj (r->new_field (playback_location (r, m_loc),
                                  m_type->playback_type (),
                                  playback_string (m_name)));
 }
 
+void
+recording::field::write_to_dump (dump &d)
+{
+  d.write ("  %s %s;\n",
+          m_type->get_debug_string (),
+          m_name->c_str ());
+}
+
 recording::string *
 recording::field::make_debug_string ()
 {
@@ -947,7 +1044,7 @@ void
 recording::struct_::replay_into (replayer *r)
 {
   set_playback_obj (
-    r->new_struct_type (playback_location (m_loc),
+    r->new_struct_type (playback_location (r, m_loc),
                        m_name->c_str ()));
 }
 
@@ -984,6 +1081,18 @@ recording::fields::replay_into (replayer *)
   m_struct->playback_struct ()->set_fields (playback_fields);
 }
 
+void
+recording::fields::write_to_dump (dump &d)
+{
+  int i;
+  field *f;
+
+  d.write ("%s\n{\n", m_struct->get_debug_string ());
+  FOR_EACH_VEC_ELT (m_fields, i, f)
+    f->write_to_dump (d);
+  d.write ("};\n");
+}
+
 recording::string *
 recording::fields::make_debug_string ()
 {
@@ -1047,7 +1156,7 @@ recording::lvalue::get_address (recording::location *loc)
 void
 recording::param::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_param (playback_location (m_loc),
+  set_playback_obj (r->new_param (playback_location (r, m_loc),
                                  m_type->playback_type (),
                                  m_name->c_str ()));
 }
@@ -1071,7 +1180,9 @@ recording::function::function (context *ctxt,
   m_name (name),
   m_params (),
   m_is_variadic (is_variadic),
-  m_builtin_id (builtin_id)
+  m_builtin_id (builtin_id),
+  m_locals (),
+  m_activity ()
 {
   for (int i = 0; i< num_params; i++)
     m_params.safe_push (params[i]);
@@ -1088,7 +1199,7 @@ recording::function::replay_into (replayer *r)
   FOR_EACH_VEC_ELT (m_params, i, param)
     params.safe_push (param->playback_param ());
 
-  set_playback_obj (r->new_function (playback_location (m_loc),
+  set_playback_obj (r->new_function (playback_location (r, m_loc),
                                     m_kind,
                                     m_return_type->playback_type (),
                                     m_name->c_str (),
@@ -1104,6 +1215,7 @@ recording::function::new_local (recording::location *loc,
 {
   local *result = new local (this, loc, type, new_string (name));
   m_ctxt->record (result);
+  m_locals.safe_push (result);
   return result;
 }
 
@@ -1122,6 +1234,7 @@ recording::function::add_eval (recording::location *loc,
 {
   statement *result = new eval (this, loc, rvalue);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1131,6 +1244,7 @@ recording::function::add_assignment (recording::location 
*loc,
 {
   statement *result = new assignment (this, loc, lvalue, rvalue);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1141,6 +1255,7 @@ recording::function::add_assignment_op 
(recording::location *loc,
 {
   statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1149,6 +1264,7 @@ recording::function::add_comment (recording::location 
*loc,
 {
   statement *result = new comment (this, loc, new_string (text));
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1159,6 +1275,7 @@ recording::function::add_conditional (recording::location 
*loc,
 {
   statement *result = new conditional (this, loc, boolval, on_true, on_false);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 recording::label *
@@ -1176,6 +1293,7 @@ recording::function::place_forward_label 
(recording::location *loc,
 {
   statement *result = new place_label (this, loc, lab);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1184,6 +1302,7 @@ recording::function::add_jump (recording::location *loc,
 {
   statement *result = new jump (this, loc, target);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 void
@@ -1192,6 +1311,7 @@ recording::function::add_return (recording::location *loc,
 {
   statement *result = new return_ (this, loc, rvalue);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
 }
 
 recording::loop *
@@ -1203,9 +1323,67 @@ recording::function::new_loop (recording::location *loc,
   recording::loop *result = new recording::loop (this, loc, boolval,
                                                 iteration_var, step);
   m_ctxt->record (result);
+  m_activity.safe_push (result);
   return result;
 }
 
+void
+recording::function::write_to_dump (dump &d)
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_FUNCTION_EXPORTED:
+    case GCC_JIT_FUNCTION_IMPORTED:
+      d.write ("extern ");
+      break;
+    case GCC_JIT_FUNCTION_INTERNAL:
+      d.write ("static ");
+      break;
+     }
+  d.write ("%s\n", m_return_type->get_debug_string ());
+
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+
+  d.write ("%s (", get_debug_string ());
+
+  int i;
+  recording::param *param;
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    {
+      if (i > 0)
+       d.write (", ");
+      d.write ("%s %s",
+              param->get_type ()->get_debug_string (),
+              param->get_debug_string ());
+    }
+  d.write (")");
+  if (m_kind == GCC_JIT_FUNCTION_IMPORTED)
+    {
+      d.write ("; /* (imported) */\n\n");
+    }
+  else
+    {
+      int i;
+      local *var = NULL;
+      memento *m;
+      d.write ("\n{\n");
+
+      /* Write locals: */
+      FOR_EACH_VEC_ELT (m_locals, i, var)
+       var->write_to_dump (d);
+      if (m_locals.length ())
+       d.write ("\n");
+
+      /* Write statements and labels: */
+      FOR_EACH_VEC_ELT (m_activity, i, m)
+       m->write_to_dump (d);
+
+      d.write ("}\n\n");
+    }
+}
+
 recording::string *
 recording::function::make_debug_string ()
 {
@@ -1243,7 +1421,7 @@ recording::label::make_debug_string ()
 void
 recording::global::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_global (playback_location (m_loc),
+  set_playback_obj (r->new_global (playback_location (r, m_loc),
                                   m_type->playback_type (),
                                   playback_string (m_name)));
 }
@@ -1321,7 +1499,7 @@ 
recording::memento_of_new_string_literal::make_debug_string ()
 void
 recording::unary_op::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_unary_op (playback_location (m_loc),
+  set_playback_obj (r->new_unary_op (playback_location (r, m_loc),
                                     m_op,
                                     get_type ()->playback_type (),
                                     m_a->playback_rvalue ()));
@@ -1346,7 +1524,7 @@ recording::unary_op::make_debug_string ()
 void
 recording::binary_op::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_binary_op (playback_location (m_loc),
+  set_playback_obj (r->new_binary_op (playback_location (r, m_loc),
                                      m_op,
                                      get_type ()->playback_type (),
                                      m_a->playback_rvalue (),
@@ -1400,7 +1578,7 @@ recording::comparison::make_debug_string ()
 void
 recording::comparison::replay_into (replayer *r)
 {
-  set_playback_obj (r->new_comparison (playback_location (m_loc),
+  set_playback_obj (r->new_comparison (playback_location (r, m_loc),
                                       m_op,
                                       m_a->playback_rvalue (),
                                       m_b->playback_rvalue ()));
@@ -1427,7 +1605,7 @@ recording::call::replay_into (replayer *r)
   for (unsigned i = 0; i< m_args.length (); i++)
     playback_args.safe_push (m_args[i]->playback_rvalue ());
 
-  set_playback_obj (r->new_call (playback_location (m_loc),
+  set_playback_obj (r->new_call (playback_location (r, m_loc),
                                 m_func->playback_function (),
                                 playback_args));
 }
@@ -1475,7 +1653,7 @@ void
 recording::array_access::replay_into (replayer *r)
 {
   set_playback_obj (
-    r->new_array_access (playback_location (m_loc),
+    r->new_array_access (playback_location (r, m_loc),
                         m_ptr->playback_rvalue (),
                         m_index->playback_rvalue ()));
 }
@@ -1490,11 +1668,11 @@ recording::array_access::make_debug_string ()
 }
 
 void
-recording::access_field_of_lvalue::replay_into (replayer *)
+recording::access_field_of_lvalue::replay_into (replayer *r)
 {
   set_playback_obj (
     m_lvalue->playback_lvalue ()
-      ->access_field (playback_location (m_loc),
+      ->access_field (playback_location (r, m_loc),
                      m_field->playback_field ()));
 
 }
@@ -1509,11 +1687,11 @@ recording::access_field_of_lvalue::make_debug_string ()
 }
 
 void
-recording::access_field_rvalue::replay_into (replayer *)
+recording::access_field_rvalue::replay_into (replayer *r)
 {
   set_playback_obj (
     m_rvalue->playback_rvalue ()
-      ->access_field (playback_location (m_loc),
+      ->access_field (playback_location (r, m_loc),
                      m_field->playback_field ()));
 }
 
@@ -1527,11 +1705,11 @@ recording::access_field_rvalue::make_debug_string ()
 }
 
 void
-recording::dereference_field_rvalue::replay_into (replayer *)
+recording::dereference_field_rvalue::replay_into (replayer *r)
 {
   set_playback_obj (
     m_rvalue->playback_rvalue ()->
-      dereference_field (playback_location (m_loc),
+      dereference_field (playback_location (r, m_loc),
                         m_field->playback_field ()));
 }
 
@@ -1545,11 +1723,11 @@ recording::dereference_field_rvalue::make_debug_string 
()
 }
 
 void
-recording::dereference_rvalue::replay_into (replayer *)
+recording::dereference_rvalue::replay_into (replayer *r)
 {
   set_playback_obj (
     m_rvalue->playback_rvalue ()->
-      dereference (playback_location (m_loc)));
+      dereference (playback_location (r, m_loc)));
 }
 
 recording::string *
@@ -1561,11 +1739,11 @@ recording::dereference_rvalue::make_debug_string ()
 }
 
 void
-recording::get_address_of_lvalue::replay_into (replayer *)
+recording::get_address_of_lvalue::replay_into (replayer *r)
 {
   set_playback_obj (
     m_lvalue->playback_lvalue ()->
-      get_address (playback_location (m_loc)));
+      get_address (playback_location (r, m_loc)));
 }
 
 recording::string *
@@ -1577,20 +1755,40 @@ recording::get_address_of_lvalue::make_debug_string ()
 }
 
 void
-recording::local::replay_into (replayer *)
+recording::local::replay_into (replayer *r)
 {
   set_playback_obj (
     m_func->playback_function ()
-      ->new_local (playback_location (m_loc),
+      ->new_local (playback_location (r, m_loc),
                   m_type->playback_type (),
                   playback_string (m_name)));
 }
 
 void
-recording::eval::replay_into (replayer *)
+recording::local::write_to_dump (dump &d)
+{
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+  d.write("  %s %s;\n",
+         m_type->get_debug_string (),
+         get_debug_string ());
+}
+
+// gcc::jit::recording::statement
+
+void
+recording::statement::write_to_dump (dump &d)
+{
+  memento::write_to_dump (d);
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+}
+
+void
+recording::eval::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_eval (playback_location (),
+    ->add_eval (playback_location (r),
                m_rvalue->playback_rvalue ());
 }
 
@@ -1603,10 +1801,10 @@ recording::eval::make_debug_string ()
 }
 
 void
-recording::assignment::replay_into (replayer *)
+recording::assignment::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_assignment (playback_location (),
+    ->add_assignment (playback_location (r),
                      m_lvalue->playback_lvalue (),
                      m_rvalue->playback_rvalue ());
 }
@@ -1627,14 +1825,14 @@ recording::assignment_op::replay_into (replayer *r)
     m_lvalue->playback_lvalue ()->get_type ();
 
   playback::rvalue *binary_op =
-    r->new_binary_op (playback_location (),
+    r->new_binary_op (playback_location (r),
                      m_op,
                      result_type,
                      m_lvalue->playback_rvalue (),
                      m_rvalue->playback_rvalue ());
 
   playback_function ()
-    ->add_assignment (playback_location (),
+    ->add_assignment (playback_location (r),
                      m_lvalue->playback_lvalue (),
                      binary_op);
 }
@@ -1650,10 +1848,10 @@ recording::assignment_op::make_debug_string ()
 }
 
 void
-recording::comment::replay_into (replayer *)
+recording::comment::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_comment (playback_location (),
+    ->add_comment (playback_location (r),
                   m_text->c_str ());
 }
 
@@ -1666,10 +1864,10 @@ recording::comment::make_debug_string ()
 }
 
 void
-recording::conditional::replay_into (replayer *)
+recording::conditional::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_conditional (playback_location (),
+    ->add_conditional (playback_location (r),
                       m_boolval->playback_rvalue (),
                       playback_label (m_on_true),
                       playback_label (m_on_false));
@@ -1680,7 +1878,7 @@ recording::conditional::make_debug_string ()
 {
   if (m_on_false)
     return string::from_printf (m_ctxt,
-                               "if (%s) goto %s else goto %s;",
+                               "if (%s) goto %s; else goto %s;",
                                m_boolval->get_debug_string (),
                                m_on_true->get_debug_string (),
                                m_on_false->get_debug_string ());
@@ -1704,10 +1902,10 @@ recording::place_label::place_label (function *func,
 }
 
 void
-recording::place_label::replay_into (replayer *)
+recording::place_label::replay_into (replayer *r)
 {
   playback_function ()
-    ->place_forward_label (playback_location (),
+    ->place_forward_label (playback_location (r),
                           m_label->playback_label ());
 }
 
@@ -1720,10 +1918,16 @@ recording::place_label::make_debug_string ()
 }
 
 void
-recording::jump::replay_into (replayer *)
+recording::place_label::write_to_dump (dump &d)
+{
+  d.write ("\n%s\n", get_debug_string ());
+}
+
+void
+recording::jump::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_jump (playback_location (),
+    ->add_jump (playback_location (r),
                m_target->playback_label ());
 }
 
@@ -1736,10 +1940,10 @@ recording::jump::make_debug_string ()
 }
 
 void
-recording::return_::replay_into (replayer *)
+recording::return_::replay_into (replayer *r)
 {
   playback_function ()
-    ->add_return (playback_location (),
+    ->add_return (playback_location (r),
                  m_rvalue ? m_rvalue->playback_rvalue () : NULL);
 }
 
@@ -1756,11 +1960,11 @@ recording::return_::make_debug_string ()
 }
 
 void
-recording::loop::replay_into (replayer *)
+recording::loop::replay_into (replayer *r)
 {
   set_playback_obj (
     m_func->playback_function ()
-      ->new_loop (playback_location (m_loc),
+      ->new_loop (playback_location (r, m_loc),
                  m_boolval->playback_rvalue ()));
 }
 
@@ -1789,9 +1993,9 @@ recording::loop::end (location *loc)
 }
 
 void
-recording::loop_end::replay_into (replayer *)
+recording::loop_end::replay_into (replayer *r)
 {
-  m_loop->playback_loop ()->end (playback_location (m_loc));
+  m_loop->playback_loop ()->end (playback_location (r, m_loc));
 }
 
 recording::string *
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 1be192e..83bda17 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -74,6 +74,7 @@ namespace gcc {
 namespace jit {
 
 class result;
+class dump;
 
 namespace recording {
   class context;
@@ -90,6 +91,7 @@ namespace recording {
   class label;
   class rvalue;
   class lvalue;
+  class local;
   class param;
   class loop;
 }
@@ -112,6 +114,31 @@ namespace playback {
 
 typedef playback::context replayer;
 
+class dump
+{
+public:
+  dump (recording::context &ctxt,
+       const char *filename,
+       bool update_locations);
+  ~dump ();
+
+  void write (const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  bool update_locations () const { return m_update_locations; }
+
+  recording::location *
+  make_location () const;
+
+private:
+  recording::context &m_ctxt;
+  const char *m_filename;
+  bool m_update_locations;
+  int m_line;
+  int m_column;
+  FILE *m_file;
+};
+
 /**********************************************************************
  Recording.
  **********************************************************************/
@@ -119,7 +146,7 @@ typedef playback::context replayer;
 namespace recording {
 
 playback::location *
-playback_location (location *loc);
+playback_location (replayer *r, location *loc);
 
 const char *
 playback_string (string *str);
@@ -282,6 +309,8 @@ public:
 
   type *get_opaque_FILE_type ();
 
+  void dump_to_file (const char *path, bool update_locations);
+
 private:
   context *m_parent_ctxt;
 
@@ -295,6 +324,10 @@ private:
   /* Recorded API usage.  */
   vec<memento *> m_mementos;
 
+  /* Specific recordings, for use by dump_to_file.  */
+  vec<struct_ *> m_structs;
+  vec<function *> m_functions;
+
   type *m_basic_types[NUM_GCC_JIT_TYPES];
   type *m_FILE_type;
 
@@ -325,6 +358,8 @@ public:
   const char *
   get_debug_string ();
 
+  virtual void write_to_dump (dump &d);
+
 protected:
   memento (context *ctxt)
   : m_ctxt (ctxt),
@@ -384,8 +419,29 @@ public:
   void replay_into (replayer *r);
 
   playback::location *
-  playback_location () const
+  playback_location (replayer *r)
   {
+    /* Normally during playback, we can walk forwards through the list of
+       recording objects, playing them back.  The ordering of recording
+       ensures that everything that a recording object refers to has
+       already been played back, so we can simply look up the relevant
+       m_playback_obj.
+
+       Locations are an exception, due to the "write_to_dump" method of
+       recording::statement.  This method can set a new location on a
+       statement after the statement is created, and thus the location
+       appears in the context's memento list *after* the statement that
+       refers to it.
+
+       In such circumstances, the statement is replayed *before* the location,
+       when the latter doesn't yet have a playback object.
+
+       Hence we need to ensure that locations have playback objects.  */
+    if (!m_playback_obj)
+      {
+       replay_into (r);
+      }
+    gcc_assert (m_playback_obj);
     return static_cast <playback::location *> (m_playback_obj);
   }
 
@@ -597,6 +653,8 @@ public:
 
   void replay_into (replayer *);
 
+  void write_to_dump (dump &d);
+
   playback::field *
   playback_field () const
   {
@@ -659,6 +717,8 @@ public:
 
   void replay_into (replayer *r);
 
+  void write_to_dump (dump &d);
+
 private:
   string * make_debug_string ();
 
@@ -839,6 +899,8 @@ public:
   param *get_param (int i) const { return m_params[i]; }
   bool is_variadic () const { return m_is_variadic; }
 
+  void write_to_dump (dump &d);
+
 private:
   string * make_debug_string ();
 
@@ -850,6 +912,9 @@ private:
   vec<param *> m_params;
   int m_is_variadic;
   enum built_in_function m_builtin_id;
+  /* Additional vectors to help when dumping.  */
+  vec<local *> m_locals;
+  vec<memento *> m_activity; // statements and labels
 };
 
 class label : public memento
@@ -1206,6 +1271,8 @@ public:
 
   void replay_into (replayer *r);
 
+  void write_to_dump (dump &d);
+
 private:
   string * make_debug_string () { return m_name; }
 
@@ -1229,12 +1296,15 @@ protected:
   }
 
   playback::location *
-  playback_location () const
+  playback_location (replayer *r) const
   {
-    return ::gcc::jit::recording::playback_location (m_loc);
+    return ::gcc::jit::recording::playback_location (r, m_loc);
   }
 
 private:
+  void write_to_dump (dump &d);
+
+private:
   function *m_func;
   location *m_loc;
 };
@@ -1356,6 +1426,8 @@ public:
 private:
   string * make_debug_string ();
 
+  void write_to_dump (dump &d);
+
 private:
   label *m_label;
 };
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 63f8610..db01053 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -72,6 +72,9 @@ namespace gccjit
 
     gcc_jit_result *compile ();
 
+    void dump_to_file (const std::string &path,
+                      bool update_locations);
+
     void set_int_option (enum gcc_jit_int_option opt,
                         int value);
 
@@ -472,6 +475,15 @@ context::compile ()
 }
 
 inline void
+context::dump_to_file (const std::string &path,
+                      bool update_locations)
+{
+  gcc_jit_context_dump_to_file (m_inner_ctxt,
+                               path.c_str (),
+                               update_locations);
+}
+
+inline void
 context::set_int_option (enum gcc_jit_int_option opt,
                         int value)
 {
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 797785b..7226d81 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -1228,6 +1228,16 @@ gcc_jit_context_compile (gcc_jit_context *ctxt)
   return (gcc_jit_result *)ctxt->compile ();
 }
 
+void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+                             const char *path,
+                             int update_locations)
+{
+  RETURN_IF_FAIL (ctxt, NULL, "NULL context");
+  RETURN_IF_FAIL (path, ctxt, "NULL path");
+  ctxt->dump_to_file (path, update_locations);
+}
+
 const char *
 gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
 {
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 3ea6653..f6fbcdf 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -218,6 +218,19 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
 extern gcc_jit_result *
 gcc_jit_context_compile (gcc_jit_context *ctxt);
 
+/* To help with debugging: dump a C-like representation to the given path,
+   describing what's been set up on the context.
+
+   If "update_locations" is true, then also set up gcc_jit_location
+   information throughout the context, pointing at the dump file as if it
+   were a source file.  This may be of use in conjunction with
+   GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a
+   debugger.  */
+extern void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+                             const char *path,
+                             int update_locations);
+
 /* To be called after a compile, this gives the first error message
    that occurred on the context.
 
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index fbdca38..3a5bb10 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -4,6 +4,7 @@
     # Keep this list sorted alphabetically:
     gcc_jit_context_acquire;
     gcc_jit_context_compile;
+    gcc_jit_context_dump_to_file;
     gcc_jit_context_get_builtin_function;
     gcc_jit_context_get_first_error;
     gcc_jit_context_get_type;
-- 
1.7.11.7

Reply via email to