From patchwork Fri Feb 21 15:56:59 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 322933 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 9D87B2C0331 for ; Sat, 22 Feb 2014 02:58:42 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=tJo/9jdBH/GU W8pegtEtUcE5h2pJXgwKzAo9t6IjiswYXdCSe5HjxicY8RrSZ4R9XN73zg29GrVO GAM02dwX4wQE5t28Cr3FIUN8NFDNysUVwrAehgbXug8MjockrMECmyqotr+otIda GxbCbJt6vJXU9IEOUtnbFZHB8241iaM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; s=default; bh=Ii3M05lhGOldhjiit0 3t4QreKDI=; b=HqrPFIFnvlHBvPOqwd81Wu1wsE16Lvpc8CT5aZf/he1kAa6/Dg leO/MsJLhZrjkYfmJV0hDF6OEV2hjpe0ADQnFwCMHLg0JYNDKdAjpjxOi2w1LE4/ aCg+2zwKB3+GeTZfBXLN2vYThsmXCjGOohpozpDN4nzBLcxKyO4914tbg= Received: (qmail 1440 invoked by alias); 21 Feb 2014 15:58:34 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 1420 invoked by uid 89); 21 Feb 2014 15:58:33 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_40, FILL_THIS_FORM, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 21 Feb 2014 15:58:30 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s1LFwTvY008009 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 21 Feb 2014 10:58:29 -0500 Received: from surprise.redhat.com (vpn-236-245.phx2.redhat.com [10.3.236.245]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s1LFwSHF030876; Fri, 21 Feb 2014 10:58:28 -0500 From: David Malcolm To: jit@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [jit] New API entrypoint: gcc_jit_context_dump_to_file Date: Fri, 21 Feb 2014 10:56:59 -0500 Message-Id: <1392998219-1843-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes 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 + + * 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 * 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 m_mementos; + /* Specific recordings, for use by dump_to_file. */ + vec m_structs; + vec 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 (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 m_params; int m_is_variadic; enum built_in_function m_builtin_id; + /* Additional vectors to help when dumping. */ + vec m_locals; + vec 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;