From d32ac4d666f008e1e4b6ee3f5acb6093f4b93d69 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 2 Jul 2018 15:36:02 -0400 Subject: [PATCH 11/46] FIXME: record per-pass function state in optimization records --- gcc/gimple-pretty-print.c | 2 +- gcc/gimple-pretty-print.h | 2 + gcc/optinfo-emit-json.cc | 166 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/optinfo-emit-json.h | 2 + gcc/passes.c | 17 +++++ 5 files changed, 188 insertions(+), 1 deletion(-) diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 19cdb40..2554950 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -2793,7 +2793,7 @@ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent, /* Dumps basic block BB to buffer BUFFER with details described by FLAGS and indented by INDENT spaces. */ -static void +void gimple_dump_bb_buff (pretty_printer *buffer, basic_block bb, int indent, dump_flags_t flags) { diff --git a/gcc/gimple-pretty-print.h b/gcc/gimple-pretty-print.h index 6ae6a3b..e7a5607 100644 --- a/gcc/gimple-pretty-print.h +++ b/gcc/gimple-pretty-print.h @@ -34,6 +34,8 @@ extern void print_gimple_expr (FILE *, gimple *, int, dump_flags_t = TDF_NONE); extern void pp_gimple_stmt_1 (pretty_printer *, gimple *, int, dump_flags_t); extern void gimple_dump_bb (FILE *, basic_block, int, dump_flags_t); extern void gimple_dump_bb_for_graph (pretty_printer *, basic_block); +extern void gimple_dump_bb_buff (pretty_printer *buffer, basic_block bb, int indent, + dump_flags_t flags); extern void dump_ssaname_info_to_file (FILE *, tree, int); extern void percent_G_format (text_info *); diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc index 82eb336..93de887 100644 --- a/gcc/optinfo-emit-json.cc +++ b/gcc/optinfo-emit-json.cc @@ -57,6 +57,7 @@ public: void write () const; void add_record (const optinfo *optinfo); void pop_scope (); + void record_function_state (function *fn, opt_pass *pass); void add_record (json::object *obj); json::object *impl_location_to_json (dump_impl_location_t loc); @@ -67,6 +68,9 @@ public: json::value *inlining_chain_to_json (location_t loc); json::object *optinfo_to_json (const optinfo *optinfo); void add_pass_list (json::array *arr, opt_pass *pass); + void add_bb_to_json (basic_block bb, json::array *cfg_obj); + void add_function_state_to_json (function *fun, json::object *fn_obj); + json::object *function_state_to_json (function *fn, opt_pass *pass); private: /* The root value for the JSON file. @@ -492,6 +496,154 @@ optrecord_json_writer::add_pass_list (json::array *arr, opt_pass *pass) while (pass); } +/* Generate a JSON object describing BB, adding it to CFG_OBJ. + Compare with dump_bb, dump_bb_info etc. */ + +void +optrecord_json_writer::add_bb_to_json (basic_block bb, json::array *cfg_obj) +{ + json::object *bb_obj = new json::object (); + cfg_obj->append (bb_obj); + + /* Basic metadata. Compare with dump_bb_info. */ + + bb_obj->set ("index", new json::number (bb->index)); + if (bb->count.initialized_p ()) + bb_obj->set ("count", profile_count_to_json (bb->count)); + + /* Flags. */ + static const char * const bb_bitnames[] = + { +#define DEF_BASIC_BLOCK_FLAG(NAME,IDX) #NAME , +#include "cfg-flags.def" + NULL +#undef DEF_BASIC_BLOCK_FLAG + }; + const unsigned n_bitnames = sizeof (bb_bitnames) / sizeof (char *); + json::array *bb_flags = new json::array (); + bb_obj->set ("flags", bb_flags); + for (unsigned i = 0; i < n_bitnames; i++) + if (bb->flags & (1 << i)) + bb_flags->append (new json::string (bb_bitnames[i])); + + bb_obj->set ("discriminator", new json::number (bb->discriminator)); + + if (bb->index >= NUM_FIXED_BLOCKS) + { + /* For now, just capture all of the statements as one string. */ + pretty_printer pp; + pp.buffer->stream = NULL; + pp.buffer->flush_p = false; + pp_needs_newline (&pp) = true; + gimple_dump_bb_buff (&pp, bb, 0, TDF_NONE); + bb_obj->set ("stmts", new json::string (pp_formatted_text (&pp))); + } + + json::array *succs = new json::array (); + bb_obj->set ("succs", succs); + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->succs) + { + /* compare with dump_edge_info. */ + json::object *edge_obj = new json::object (); + succs->append (edge_obj); + edge_obj->set ("dest", new json::number (e->dest->index)); + + /* Edge flags. */ + static const char * const bitnames[] = + { +#define DEF_EDGE_FLAG(NAME,IDX) #NAME , +#include "cfg-flags.def" + NULL +#undef DEF_EDGE_FLAG + }; + + json::array *edge_flags = new json::array (); + edge_obj->set ("flags", edge_flags); + + gcc_assert (e->flags <= EDGE_ALL_FLAGS); + int flags = e->flags; + for (int i = 0; flags; i++) + if (flags & (1 << i)) + { + flags &= ~(1 << i); + edge_flags->append (new json::string (bitnames[i])); + } + } +} + +/* Populate FN_OBJ based on FUN. + Compare with dump_function_to_file. */ + +void +optrecord_json_writer::add_function_state_to_json (function *fun, + json::object *fn_obj) +{ + tree old_current_fndecl = current_function_decl; + basic_block bb; + tree fndecl = fun->decl; + + current_function_decl = fndecl; + + if (fun && fun->decl == fndecl + && fun->cfg + && basic_block_info_for_fn (fun)) + { + json::array *cfg_obj = new json::array (); + fn_obj->set ("cfg", cfg_obj); + + FOR_ALL_BB_FN (bb, fun) + add_bb_to_json (bb, cfg_obj); + } + + current_function_decl = old_current_fndecl; +} + +/* Add a record describing the state of FN after PASS to the queue of + records to be written. */ + + +void +optrecord_json_writer::record_function_state (function *fn, + opt_pass *pass) +{ + gcc_assert (fn); + gcc_assert (pass); + + json::object *obj = function_state_to_json (fn, pass); + add_record (obj); +} + +/* Create a JSON object representing the state of FN after PASS. */ + +json::object * +optrecord_json_writer::function_state_to_json (function *fn, + opt_pass *pass) +{ + gcc_assert (fn); + gcc_assert (pass); + + tree fndecl = fn->decl; + + json::object *obj = new json::object (); + obj->set ("kind", new json::string ("state")); + obj->set ("pass", get_id_value_for_pass (pass)); + const char *fnname = get_fnname_from_decl (fndecl); + obj->set ("function", new json::string (fnname)); + + if (fn->curr_properties & PROP_trees) + { + add_function_state_to_json (fn, obj); + } + else + { + // TODO? RTL equivalent when dumping is: + //print_rtl_with_bb (dump_file, get_insns (), dump_flags); + } + return obj; +} + /* File-level interface to rest of compiler (to avoid exposing class optrecord_json_writer outside of this file). */ @@ -561,6 +713,20 @@ optimization_records_maybe_pop_dump_scope () the_json_writer->pop_scope (); } +/* If optimization records were requested, then add a record describing the + state of FN after PASS to the queue of records to be written. */ + +void +optimization_records_maybe_record_function (function *fn, + opt_pass *pass) +{ + /* Bail if recording not enabled. */ + if (!the_json_writer) + return; + + the_json_writer->record_function_state (fn, pass); +} + #if CHECKING_P namespace selftest { diff --git a/gcc/optinfo-emit-json.h b/gcc/optinfo-emit-json.h index 4892992..9f2ceaa 100644 --- a/gcc/optinfo-emit-json.h +++ b/gcc/optinfo-emit-json.h @@ -32,6 +32,8 @@ extern bool optimization_records_enabled_p (); extern void optimization_records_maybe_record_optinfo (const optinfo *); extern void optimization_records_maybe_pop_dump_scope (); +extern void optimization_records_maybe_record_function (function *fun, + opt_pass *pass); #endif /* #ifndef GCC_OPTINFO_EMIT_JSON_H */ diff --git a/gcc/passes.c b/gcc/passes.c index 832f0b3..6cbc5f8 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -63,6 +63,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" /* for fnotice */ #include "stringpool.h" #include "attribs.h" +#include "optinfo.h" +#include "optinfo-emit-json.h" using namespace gcc; @@ -1734,6 +1736,16 @@ execute_function_dump (function *fn, void *data) } } +/* Helper function to perform function body dump. */ + +static void +execute_optinfo_function_dump (function *fn, void *data) +{ + opt_pass *pass = (opt_pass *)data; + + optimization_records_maybe_record_function (fn, pass); +} + /* This function is called when an internal compiler error is encountered. Ensure that function dump is made available before compiler is aborted. */ @@ -2202,6 +2214,8 @@ execute_one_ipa_transform_pass (struct cgraph_node *node, if (dump_file) do_per_function (execute_function_dump, pass); + if (optinfo_enabled_p ()) + do_per_function (execute_optinfo_function_dump, pass); pass_fini_dump_file (pass); current_pass = NULL; @@ -2503,6 +2517,9 @@ execute_one_pass (opt_pass *pass) else if (dump_file) do_per_function (execute_function_dump, pass); + if (optimization_records_enabled_p ()) + do_per_function (execute_optinfo_function_dump, pass); + if (!current_function_decl) symtab->process_new_functions (); -- 1.8.5.3