On Wed, Jun 20, 2018 at 6:34 PM David Malcolm <dmalc...@redhat.com> wrote: > > Here's v3 of the patch (one big patch this time, rather than a kit). > > Like the v2 patch kit, this patch reuses the existing dump API, > rather than inventing its own. > > Specifically, it uses the dump_* functions in dumpfile.h that don't > take a FILE *, the ones that implicitly write to dump_file and/or > alt_dump_file. I needed a name for them, so I've taken to calling > them the "structured dump API" (better name ideas welcome). > > v3 eliminates v2's optinfo_guard class, instead using "dump_*_loc" > calls as delimiters when consolidating "dump_*" calls. There's a > new dump_context class which has responsibility for consolidating > them into optimization records. > > The dump_*_loc calls now capture more than just a location_t: they > capture the profile_count and the location in GCC's own sources where > the dump is being emitted from. > > This works by introducing a new "dump_location_t" class as the > argument of those dump_*_loc calls. The dump_location_t can > be constructed from a gimple * or from an rtx_insn *, so that > rather than writing: > > dump_printf_loc (MSG_NOTE, gimple_location (stmt), > "some message: %i", 42); > > you can write: > > dump_printf_loc (MSG_NOTE, stmt, > "some message: %i", 42); > > and the dump_location_t constructor will grab the location_t and > profile_count of stmt, and the location of the "dump_printf_loc" > callsite (and gracefully handle "stmt" being NULL). > > Earlier versions of the patch captured the location of the > dump_*_loc call via preprocessor hacks, or didn't work properly; > this version of the patch works more cleanly: internally, > dump_location_t is split into two new classes: > * dump_user_location_t: the location_t and profile_count within > the *user's code*, and > * dump_impl_location_t: the __builtin_FILE/LINE/FUNCTION within > the *implementation* code (i.e. GCC or a plugin), captured > "automagically" via default params > > These classes are sometimes used elsewhere in the code. For > example, "vect_location" becomes a dump_user_location_t > (location_t and profile_count), so that in e.g: > > vect_location = find_loop_location (loop); > > it's capturing the location_t and profile_count, and then when > it's used here: > > dump_printf_loc (MSG_NOTE, vect_location, "foo"); > > the dump_location_t is constructed from the vect_location > plus the dump_impl_location_t at that callsite. > > In contrast, loop-unroll.c's report_unroll's "locus" param > becomes a dump_location_t: we're interested in where it was > called from, not in the locations of the various dump_*_loc calls > within it. > > Previous versions of the patch captured a gimple *, and needed > GTY markers; in this patch, the dump_user_location_t is now just a > location_t and a profile_count. > > The v2 patch added an overload for dump_printf_loc so that you > could pass in either a location_t, or the new type; this version > of the patch eliminates that: they all now take dump_location_t. > > Doing so required adding support for rtx_insn *, so that one can > write this kind of thing in RTL passes: > > dump_printf_loc (MSG_NOTE, insn, "foo"); > > One knock-on effect is that get_loop_location now returns a > dump_user_location_t rather than a location_t, so that it has > hotness information. > > Richi: would you like me to split out this location-handling > code into a separate patch? (It's kind of redundant without > adding the remarks and optimization records work, but if that's > easier I can do it)
I think that would be easier because it doesn't require the JSON stuff and so I'll happily approve it. Thus - trying to review that bits (and sorry for the delay). + location_t srcloc = loc.get_location_t (); + if (dump_file && (dump_kind & pflags)) { - dump_loc (dump_kind, dump_file, loc); + dump_loc (dump_kind, dump_file, srcloc); print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); } if (alt_dump_file && (dump_kind & alt_flags)) { - dump_loc (dump_kind, alt_dump_file, loc); + dump_loc (dump_kind, alt_dump_file, srcloc); print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); } + + if (optinfo_enabled_p ()) + { + optinfo &info = begin_next_optinfo (loc); + info.handle_dump_file_kind (dump_kind); + info.add_stmt (gs, extra_dump_flags); + } seeing this in multiple places. I seem to remember that dump_file / alt_dump_file was suposed to handle dumping into two locations - a dump file and optinfo (or stdout). This looks like the optinfo "stream" is even more separate. Could that obsolete the alt_dump_file stream? I'd need to review existing stuff in more detail to answer but maybe you already know from recently digging into this. Oh, and all the if (optinfo_enable_p ()) stuff is for the followup then, right? I like the boiler-plate changes to dump_* using stuff a lot, so the infrastructure to do that (the location wrapping) and these boiler-plate changes are pre-approved if split out. I think the *_REMARK stuff should get attention of the respective maintainers - not sure what the difference between NOTE and REMARK is ;) Thanks and sorry again for the repeated delays... Richard. > > The v3 patch adds more detail to remarks: they now show the gcc > source location that emitted them e.g.: > > test.c:8:3: remark: Symbolic number of iterations is '(unsigned int) > n_9(D)' [pass=vect] [count(precise)=76800000] > [../../src/gcc/tree-vect-loop.c:1387:vect_analyze_loop_form] > > and I added new command-line options for controlling the above: > * -fno-diagnostics-show-remark-hotness > * -fno-diagnostics-show-remark-origin > * -fno-diagnostics-show-remark-pass > > An example of remark output (showing colors) can be seen here: > > https://dmalcolm.fedorapeople.org/gcc/2018-06-18/test.cc.remarks.html > > I haven't yet implemented options for filtering remarks (I'm thinking > of using the optgroups from -fopt-info, a hotness threshold, and pragmas > for narrowing them to a specific region of the user's code); though > the HTML visualization from the JSON output is likely to provide more > flexibility. > > I got rid of GCC_UNLIKELY in favor of a __builtin_expect in > dump_enabled_p, but I haven't measured the impact yet. > > Other changes relative to v2: > * added class dump_context; eliminate class pending_optinfo; moved optinfo > emission from optinfo dtor and into dump_context > * added selftests for dump_* consolidation, for JSON emission, and for > remarks > * minimized global state in JSON emission > * renamed OPTINFO_SCOPE to AUTO_DUMP_SCOPE and moved from optinfo.h to > dumpfile.h (and similar changes to the support class) > * added "m_pass" field to optinfo, reading current_pass at time of > creation, rather than as needed later on > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu > (relative to r261555). > > How is this looking? > > As before, this patch requires the JSON support patch from v1 of the kit: > "[PATCH 02/10] Add JSON implementation" > https://gcc.gnu.org/ml/gcc-patches/2018-05/msg01676.html > > This approach means we can use all of the existing dump_* calls without > having to rewrite anything, gaining the ability to prioritize dump messages > by code hotness and to track where in GCC any dump message came from > without needing to resort to "grep". > > But in terms of actually helping users figure out "how do I get gcc to > vectorize this loop?", it's only a start. Maybe followup activity would be > to go through the existing dump messages and to make them more user-friendly. > Or to add new dump API entrypoints? > I find the MSG_* a bit verbose, so maybe instead of e.g.: > > dump_printf_loc (MSG_MISSED_OPTIMIZATION, call_stmt, > "can't inline function call: "); > dump_symtab_node (callee); > dump_printf (" into "); > dump_symtab_node (caller); > dump_printf (" as body is not available\n"); > > there could be, say: > > missed_opt_at (call_stmt, > ("can't inline function call: %N into %N" > " as body is not available\n"), > callee, caller); > > (plus, say "optimized_at", "opt_note_at"), introducing a new family > of format codes (so that the optimization records "know" how to > embed them). > > This would also allow for i18n; such API calls would be more explicitly > aimed at tech-savvy end-users. > > Anyway, that last bit is more me just thinking aloud about possible future > work here, so here's the v3 patch as it is: > > gcc/ChangeLog: > * Makefile.in (OBJS): Add optinfo.o, optinfo-emit-diagnostics.o, > optinfo-emit-json.o. > (CFLAGS-optinfo-emit-json.o): Add -DTARGET_NAME as per toplev.o. > * cfgloop.c (get_loop_location): Convert return type from > location_t to dump_user_location_t, replacing INSN_LOCATION lookups > by implicit construction from rtx_insn *, and using > dump_user_location_t::from_function_decl for the fallback case. > * cfgloop.h (get_loop_location): Convert return type from > location_t to dump_user_location_t. > * cgraph.c (cgraph_node::get_body): Replace assignment to > "dump_file" with call to set_dump_file. > * cgraphunit.c (walk_polymorphic_call_targets): Update call to > dump_printf_loc to pass in a dump_location_t rather than a > location_t, via the gimple stmt. > * common.opt (fremarks): New option. > (fdiagnostics-show-remark-hotness): New option. > (fdiagnostics-show-remark-origin): New option. > (fdiagnostics-show-remark-pass): New option. > (fsave-optimization-record): New option. > * coretypes.h (class symtab_node): New forward declaration. > (struct cgraph_node): Likewise. > (class varpool_node): Likewise. > (struct kv_pair): Move here from dumpfile.c. > * coverage.c (get_coverage_counts): Update calls to > dump_printf_loc to pass in dump_location_t rather than a > location_t. > * diagnostic-color.c (color_dict): Add "remark", as bold green. > * diagnostic-core.h (remark): New decl. > * diagnostic.c (diagnostic_action_after_output): Handle DK_REMARK. > (remark): New function. > * diagnostic.def (DK_REMARK): New diagnostic kind. > * doc/invoke.texi (Remarks): New section. > (-fsave-optimization-record): New option. > (-fremarks): New option. > (-fno-diagnostics-show-remark-hotness): New option. > (-fno-diagnostics-show-remark-origin): New option. > (-fno-diagnostics-show-remark-pass): New option. > * dump-context.h: New file. > * dumpfile.c: Include "optinfo.h", "cgraph.h", > "optinfo-emit-json.h", "optinfo-internal.h", "backend.h", > "gimple.h", "rtl.h", "dump-context.h", "tree-pass.h", "selftest.h" > (alt_dump_file): Make static, and group with... > (alt_flags): ...this definition. > (dumps_are_enabled): New variable. > (refresh_dumps_are_enabled): New function. > (set_dump_file): New function. > (set_alt_dump_file): New function. > (struct kv_pair): Move from here to coretypes.h. > (optgroup_options): Make non-static. > (dump_user_location_t::dump_user_location_t): New ctors > (dump_user_location_t::from_function_decl): New function. > (dump_loc): Make static. Add indentation based on scope depth. > (dump_context::~dump_context): New dtor. > (dump_gimple_stmt): Move implementation to... > (dump_context::dump_gimple_stmt): ...this new method. Add the stmt > to any pending optinfo, creating one if need be. > (dump_gimple_stmt_loc): Move implementation to... > (dump_context::dump_gimple_stmt_loc): ...this new method. Convert > param "loc" from location_t to const dump_location_t &. Start a > new optinfo and add the stmt to it. > (dump_generic_expr): Move implementation to... > (dump_context::dump_generic_expr): ...this new method. Add the > tree to any pending optinfo, creating one if need be. > (dump_generic_expr_loc): Delete. > (dump_printf): Move implementation to... > (dump_context::dump_printf_va): ...this new method. Add the > text to any pending optinfo, creating one if need be. > (dump_printf_loc): Move implementation to... > (dump_context::dump_printf_loc_va): ...this new method. Convert > param "loc" from location_t to const dump_location_t &. Start a > new optinfo and add the stmt to it. > (dump_dec): Move implementation to... > (dump_context::dump_dec): ...this new method. Add the value to > any pending optinfo, creating one if need be. > (dump_context::dump_symtab_node): New method. > (dump_context::get_scope_depth): New method. > (dump_context::begin_scope): New method. > (dump_context::end_scope): New method. > (dump_context::ensure_pending_optinfo): New method. > (dump_context::begin_next_optinfo): New method. > (dump_context::end_any_optinfo): New method. > (dump_context::s_current): New global. > (dump_context::s_default): New global. > (dump_symtab_node): New function. > (get_dump_scope_depth): New function. > (dump_begin_scope): New function. > (dump_end_scope): New function. > (gcc::dump_manager::dump_start): Replace assignments to > "dump_file" and "alt_dump_file" with call to set_dump_file and > set_alt_dump_file. > (gcc::dump_manager::dump_finish): Likewise. > (selftest::temp_dump_context::temp_dump_context): New ctor. > (selftest::temp_dump_context::~temp_dump_context): New dtor. > (selftest::test_impl_location): New test. > (selftest::assert_is_text): New support function. > (selftest::assert_is_tree): New support function. > (selftest::assert_is_gimple): New support function. > (selftest::test_capture_of_dump_calls): New test. > (selftest::dumpfile_c_tests): New function. > * dumpfile.h: Include "profile-count.h". > (dump_file, dump_flags, dump_file_name): Move decls to top of > file, to split them out from the "Structured dumping" API. > (set_dump_file): New function decl. > (dumps_are_enabled): New variable decl. > (dump_enabled_p): Rewrite in terms of new "dumps_are_enabled" > global. > (class dump_user_location_t): New class. > (struct dump_impl_location_t): New struct. > (class dump_location_t): New class. > (dump_printf_loc): Convert 2nd param from source_location to > const dump_location_t &. > (dump_generic_expr_loc): Delete. > (dump_gimple_stmt_loc): Convert 2nd param from source_location to > const dump_location_t &. > (dump_symtab_node): New decl. > (get_dump_scope_depth): New decl. > (dump_begin_scope): New decl. > (dump_end_scope): New decl. > (class auto_dump_scope): New class. > (AUTO_DUMP_SCOPE): New macro. > (dump_function, print_combine_total_stats, enable_rtl_dump_file): > Move these decls, to split them out from the "Structured dumping" > API. > (alt_dump_file): Delete decl. > (optgroup_options): New decl. > (class dump_manager): Add leading comment. > * gimple-fold.c (fold_gimple_assign): Update call to > dump_printf_loc to pass in a dump_location_t rather than a > location_t, via the gimple stmt. > (gimple_fold_call): Likewise. > * gimple-loop-interchange.cc > (loop_cand::analyze_iloop_reduction_var): Update for change to > check_reduction_path. > (tree_loop_interchange::interchange): Update for change to > find_loop_location. Add a usage of AUTO_DUMP_SCOPE. > * gimple-pretty-print.c (gimple_dump_bb_buff): Make non-static. > * gimple-pretty-print.h (gimple_dump_bb_buff): New decl. > * graphite-isl-ast-to-gimple.c (scop_to_isl_ast): Update for > change in return-type of find_loop_location. > (graphite_regenerate_ast_isl): Likewise. > * graphite-optimize-isl.c (optimize_isl): Likewise. > * graphite.c (graphite_transform_loops): Update for change in > return-type of find_loop_location. > * ipa-devirt.c (ipa_devirt): Update call to dump_printf_loc to > pass in a dump_location_t rather than a location_t, via the > gimple stmt. > * ipa-prop.c (ipa_make_edge_direct_to_target): Likewise. > (ipa_make_edge_direct_to_target): Likewise. > * ipa.c (walk_polymorphic_call_targets): Likewise. > * loop-unroll.c (report_unroll): Convert "locus" param from > location_t to dump_location_t. > (decide_unrolling): Update for change to get_loop_location's > return type. > * omp-grid.c (struct grid_prop): Convert field "target_loc" from > location_t to dump_user_location_t. > (grid_find_single_omp_among_assignments_1): Updates calls to > dump_printf_loc to pass in a dump_location_t rather than a > location_t, via the gimple stmt. > (grid_parallel_clauses_gridifiable): Convert "tloc" from > location_t to dump_location_t. Updates calls to dump_printf_loc > to pass in a dump_location_t rather than a location_t, via the > gimple stmt. > (grid_inner_loop_gridifiable_p): Likewise. > (grid_dist_follows_simple_pattern): Likewise. > (grid_gfor_follows_tiling_pattern): Likewise. > (grid_target_follows_gridifiable_pattern): Likewise. > (grid_attempt_target_gridification): Convert initialization > of local "grid" from memset to zero-initialization; FIXME: does > this require C++11? Update call to dump_printf_loc to pass in a > optinfo_location rather than a location_t, via the gimple stmt. > * opt-functions.awk (function): Handle "Remark" by adding > CL_REMARK. > * optinfo-emit-diagnostics.cc: New file. > * optinfo-emit-diagnostics.h: New file. > * optinfo-emit-json.cc: New file. > * optinfo-emit-json.h: New file. > * optinfo-internal.h: New file. > * optinfo.cc: New file. > * optinfo.h: New file. > * opts.c (print_specific_help): Handle CL_REMARK. > (common_handle_option): Likewise. > * opts.h (CL_REMARK): New macro. > (CL_MAX_OPTION_CLASS): Update for CL_REMARK. > (CL_JOINED, CL_SEPARATE, CL_UNDOCUMENTED, CL_NO_DWARF_RECORD) > (CL_PCH_IGNORE): Likewise. > * passes.c: Include "optinfo.h" and "optinfo-emit-json.h". > (execute_optinfo_function_dump): New function. > (execute_one_ipa_transform_pass): Add per-function call to > execute_optinfo_function_dump. > (execute_one_pass): Likewise. > * pretty-print.c (test_pp_format): Move save and restore of quotes > to class auto_fix_quotes, and add an instance. > * profile-count.c (profile_quality_as_string): New function. > * profile-count.h (profile_quality_as_string): New decl. > (profile_count::quality): New accessor. > * profile.c (read_profile_edge_counts): Updates call to > dump_printf_loc to pass in a dump_location_t rather than a > location_t > (compute_branch_probabilities): Likewise. > * selftest-run-tests.c (selftest::run_tests): Call > dumpfile_c_tests, optinfo_cc_tests, > optinfo_emit_diagnostics_cc_tests, and optinfo_emit_json_cc_tests. > * selftest.c: Include "intl.h". > (selftest::auto_fix_quotes::auto_fix_quotes): New ctor. > (selftest::auto_fix_quotes::~auto_fix_quotes): New dtor. > * selftest.h (selftest::auto_fix_quotes): New class. > (dumpfile_c_tests): New decl. > (optinfo_cc_tests): New decl. > (optinfo_emit_diagnostics_cc_tests): New decl. > (optinfo_emit_json_cc_tests): New decl. > * toplev.c: Include "optinfo-emit-json.h". > (compile_file): Call optimization_records_start and > optimization_records_finish. > * tree-loop-distribution.c (pass_loop_distribution::execute): > Update for change in return type of find_loop_location. > * tree-nested.c (lower_nested_functions): Replace assignments to > "dump_file" with calls to set_dump_file. > * tree-parloops.c (parallelize_loops): Update for change in return > type of find_loop_location. > * tree-ssa-live.c: Include "optinfo.h". > (remove_unused_scope_block_p): Retain inlining information if > optinfo_wants_inlining_info_p returns true. > * tree-ssa-loop-ivcanon.c (try_unroll_loop_completely): Convert > "locus" from location_t to dump_user_location_t. > (canonicalize_loop_induction_variables): Likewise. > * tree-ssa-loop-ivopts.c (tree_ssa_iv_optimize_loop): Update > for change in return type of find_loop_location. > * tree-ssa-loop-niter.c (number_of_iterations_exit): Update call > to dump_printf_loc to pass in a dump_location_t rather than a > location_t, via the stmt. > * tree-vect-loop-manip.c (find_loop_location): Convert return > type from source_location to dump_user_location_t. > (vect_do_peeling): Update for above change. > (vect_loop_versioning): Update for change in type of > vect_location. > * tree-vect-loop.c (check_reduction_path): Convert "loc" param > from location_t to dump_user_location_t. > (vect_estimate_min_profitable_iters): Update for change in type > of vect_location. > * tree-vect-slp.c (vect_print_slp_tree): Convert param "loc" from > location_t to dump_location_t. > (vect_slp_bb): Update for change in type of vect_location. > * tree-vectorizer.c (vect_location): Convert from source_location > to dump_user_location_t. > (vectorize_loops): Update for change in vect_location's type. Add > top-level DUMP_VECT_SCOPE. > (increase_alignment): Update for change in vect_location's type. > * tree-vectorizer.h: Include "optinfo.h". > (vect_location): Convert from source_location to > dump_user_location_t. > (DUMP_VECT_SCOPE): Convert to usage of AUTO_DUMP_SCOPE. > (find_loop_location): Convert return type from source_location to > dump_user_location_t. > (check_reduction_path): Convert 1st param from location_t to > dump_user_location_t. > * value-prof.c (check_counter): Update call to dump_printf_loc to > pass in a dump_user_location_t rather than a location_t; update > call to error_at for change in type of "locus". > (check_ic_target): Update call to dump_printf_loc to > pass in a dump_user_location_t rather than a location_t, via the > call_stmt. > > gcc/fortran/ChangeLog: > * gfc-diagnostic.def (DK_REMARK): New diagnostic kind. > > gcc/testsuite/ChangeLog: > * gcc.dg/plugin/plugin.exp (plugin_test_list): Add > remarks_plugin.c. > * gcc.dg/plugin/remarks-1.c: New test. > * gcc.dg/plugin/remarks_plugin.c: New test plugin. > * lib/gcc-dg.exp (dg-remark): New function. > --- > gcc/Makefile.in | 4 + > gcc/cfgloop.c | 12 +- > gcc/cfgloop.h | 2 +- > gcc/cgraph.c | 4 +- > gcc/cgraphunit.c | 3 +- > gcc/common.opt | 21 + > gcc/coretypes.h | 15 + > gcc/coverage.c | 22 +- > gcc/diagnostic-color.c | 2 + > gcc/diagnostic-core.h | 2 + > gcc/diagnostic.c | 17 + > gcc/diagnostic.def | 1 + > gcc/doc/invoke.texi | 83 ++- > gcc/dump-context.h | 112 ++++ > gcc/dumpfile.c | 648 +++++++++++++++++++--- > gcc/dumpfile.h | 258 ++++++++- > gcc/fortran/gfc-diagnostic.def | 1 + > gcc/gimple-fold.c | 6 +- > gcc/gimple-loop-interchange.cc | 7 +- > gcc/gimple-pretty-print.c | 2 +- > gcc/gimple-pretty-print.h | 2 + > gcc/graphite-isl-ast-to-gimple.c | 4 +- > gcc/graphite-optimize-isl.c | 4 +- > gcc/graphite.c | 2 +- > gcc/ipa-devirt.c | 3 +- > gcc/ipa-prop.c | 10 +- > gcc/ipa.c | 9 +- > gcc/loop-unroll.c | 4 +- > gcc/omp-grid.c | 47 +- > gcc/opt-functions.awk | 1 + > gcc/optinfo-emit-diagnostics.cc | 317 +++++++++++ > gcc/optinfo-emit-diagnostics.h | 26 + > gcc/optinfo-emit-json.cc | 773 > +++++++++++++++++++++++++++ > gcc/optinfo-emit-json.h | 39 ++ > gcc/optinfo-internal.h | 145 +++++ > gcc/optinfo.cc | 254 +++++++++ > gcc/optinfo.h | 147 +++++ > gcc/opts.c | 4 + > gcc/opts.h | 13 +- > gcc/passes.c | 17 + > gcc/pretty-print.c | 9 +- > gcc/profile-count.c | 28 + > gcc/profile-count.h | 5 + > gcc/profile.c | 14 +- > gcc/selftest-run-tests.c | 4 + > gcc/selftest.c | 20 + > gcc/selftest.h | 24 + > gcc/testsuite/gcc.dg/plugin/plugin.exp | 2 + > gcc/testsuite/gcc.dg/plugin/remarks-1.c | 30 ++ > gcc/testsuite/gcc.dg/plugin/remarks_plugin.c | 152 ++++++ > gcc/testsuite/lib/gcc-dg.exp | 9 + > gcc/toplev.c | 5 + > gcc/tree-loop-distribution.c | 2 +- > gcc/tree-nested.c | 4 +- > gcc/tree-parloops.c | 3 +- > gcc/tree-ssa-live.c | 4 +- > gcc/tree-ssa-loop-ivcanon.c | 8 +- > gcc/tree-ssa-loop-ivopts.c | 2 +- > gcc/tree-ssa-loop-niter.c | 2 +- > gcc/tree-ssa-sccvn.c | 3 +- > gcc/tree-vect-loop-manip.c | 16 +- > gcc/tree-vect-loop.c | 8 +- > gcc/tree-vect-slp.c | 5 +- > gcc/tree-vectorizer.c | 17 +- > gcc/tree-vectorizer.h | 25 +- > gcc/value-prof.c | 15 +- > 66 files changed, 3229 insertions(+), 230 deletions(-) > create mode 100644 gcc/dump-context.h > create mode 100644 gcc/optinfo-emit-diagnostics.cc > create mode 100644 gcc/optinfo-emit-diagnostics.h > create mode 100644 gcc/optinfo-emit-json.cc > create mode 100644 gcc/optinfo-emit-json.h > create mode 100644 gcc/optinfo-internal.h > create mode 100644 gcc/optinfo.cc > create mode 100644 gcc/optinfo.h > create mode 100644 gcc/testsuite/gcc.dg/plugin/remarks-1.c > create mode 100644 gcc/testsuite/gcc.dg/plugin/remarks_plugin.c > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 9b85787..23060a3 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1421,6 +1421,9 @@ OBJS = \ > omp-grid.o \ > omp-low.o \ > omp-simd-clone.o \ > + optinfo.o \ > + optinfo-emit-diagnostics.o \ > + optinfo-emit-json.o \ > optabs.o \ > optabs-libfuncs.o \ > optabs-query.o \ > @@ -2248,6 +2251,7 @@ s-bversion: BASE-VER > $(STAMP) s-bversion > > CFLAGS-toplev.o += -DTARGET_NAME=\"$(target_noncanonical)\" > +CFLAGS-optinfo-emit-json.o += -DTARGET_NAME=\"$(target_noncanonical)\" > > pass-instances.def: $(srcdir)/passes.def $(PASSES_EXTRA) \ > $(srcdir)/gen-pass-instances.awk > diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c > index 8af793c..e27cd39 100644 > --- a/gcc/cfgloop.c > +++ b/gcc/cfgloop.c > @@ -1800,7 +1800,7 @@ loop_exits_from_bb_p (struct loop *loop, basic_block bb) > > /* Return location corresponding to the loop control condition if possible. > */ > > -location_t > +dump_user_location_t > get_loop_location (struct loop *loop) > { > rtx_insn *insn = NULL; > @@ -1819,7 +1819,7 @@ get_loop_location (struct loop *loop) > FOR_BB_INSNS_REVERSE (desc->in_edge->src, insn) > { > if (INSN_P (insn) && INSN_HAS_LOCATION (insn)) > - return INSN_LOCATION (insn); > + return insn; > } > } > /* If loop has a single exit, then the loop control branch > @@ -1829,24 +1829,24 @@ get_loop_location (struct loop *loop) > FOR_BB_INSNS_REVERSE (exit->src, insn) > { > if (INSN_P (insn) && INSN_HAS_LOCATION (insn)) > - return INSN_LOCATION (insn); > + return insn; > } > } > /* Next check the latch, to see if it is non-empty. */ > FOR_BB_INSNS_REVERSE (loop->latch, insn) > { > if (INSN_P (insn) && INSN_HAS_LOCATION (insn)) > - return INSN_LOCATION (insn); > + return insn; > } > /* Finally, if none of the above identifies the loop control branch, > return the first location in the loop header. */ > FOR_BB_INSNS (loop->header, insn) > { > if (INSN_P (insn) && INSN_HAS_LOCATION (insn)) > - return INSN_LOCATION (insn); > + return insn; > } > /* If all else fails, simply return the current function location. */ > - return DECL_SOURCE_LOCATION (current_function_decl); > + return dump_user_location_t::from_function_decl (current_function_decl); > } > > /* Records that every statement in LOOP is executed I_BOUND times. > diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h > index af9bfab..80a31c4 100644 > --- a/gcc/cfgloop.h > +++ b/gcc/cfgloop.h > @@ -357,7 +357,7 @@ extern bool loop_exit_edge_p (const struct loop *, > const_edge); > extern bool loop_exits_to_bb_p (struct loop *, basic_block); > extern bool loop_exits_from_bb_p (struct loop *, basic_block); > extern void mark_loop_exit_edges (void); > -extern location_t get_loop_location (struct loop *loop); > +extern dump_user_location_t get_loop_location (struct loop *loop); > > /* Loops & cfg manipulation. */ > extern basic_block *get_loop_body (const struct loop *); > diff --git a/gcc/cgraph.c b/gcc/cgraph.c > index 3899467..d19f1aa 100644 > --- a/gcc/cgraph.c > +++ b/gcc/cgraph.c > @@ -3582,7 +3582,7 @@ cgraph_node::get_body (void) > const char *saved_dump_file_name = dump_file_name; > dump_flags_t saved_dump_flags = dump_flags; > dump_file_name = NULL; > - dump_file = NULL; > + set_dump_file (NULL); > > push_cfun (DECL_STRUCT_FUNCTION (decl)); > execute_all_ipa_transforms (); > @@ -3593,7 +3593,7 @@ cgraph_node::get_body (void) > updated = true; > > current_pass = saved_current_pass; > - dump_file = saved_dump_file; > + set_dump_file (saved_dump_file); > dump_file_name = saved_dump_file_name; > dump_flags = saved_dump_flags; > } > diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c > index 04b6919..7cfb8a0 100644 > --- a/gcc/cgraphunit.c > +++ b/gcc/cgraphunit.c > @@ -928,8 +928,7 @@ walk_polymorphic_call_targets (hash_set<void *> > *reachable_call_targets, > } > if (dump_enabled_p ()) > { > - location_t locus = gimple_location_safe (edge->call_stmt); > - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, locus, > + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, edge->call_stmt, > "devirtualizing call in %s to %s\n", > edge->caller->name (), target->name ()); > } > diff --git a/gcc/common.opt b/gcc/common.opt > index 4aebcaf..141f5dd 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -506,6 +506,11 @@ Driver Negative(Qn) > R > Driver Joined Separate > > +fremarks > +Common Remark Var(flag_remarks) > +Emit diagnostic remarks about optimizations > +FIXME: should this be -fdiagnostics-foo or somesuch? > + > S > Driver > > @@ -1273,6 +1278,18 @@ fdiagnostics-show-option > Common Var(flag_diagnostics_show_option) Init(1) > Amend appropriate diagnostic messages with the command line option that > controls them. > > +fdiagnostics-show-remark-hotness > +Common Var(flag_diagnostics_show_remark_hotness) Init(1) > +When emitting optimization remarks, show the execution count of the code > being optimized. > + > +fdiagnostics-show-remark-origin > +Common Var(flag_diagnostics_show_remark_origin) Init(1) > +When emitting optimization remarks, show which line of GCC code produced the > remark. > + > +fdiagnostics-show-remark-pass > +Common Var(flag_diagnostics_show_remark_pass) Init(1) > +When emitting optimization remarks, show which optimization pass produced > the remark. > + > fdisable- > Common Joined RejectNegative Var(common_deferred_options) Defer > -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass. > @@ -1942,6 +1959,10 @@ fopt-info- > Common Joined RejectNegative Var(common_deferred_options) Defer > -fopt-info[-<type>=filename] Dump compiler optimization details. > > +fsave-optimization-record > +Common Report Var(flag_save_optimization_record) Optimization > +Write a SRCFILE.opt-record.json file detailing what optimizations were > performed. > + > foptimize-register-move > Common Ignore > Does nothing. Preserved for backward compatibility. > diff --git a/gcc/coretypes.h b/gcc/coretypes.h > index 283b4eb..33f3d21 100644 > --- a/gcc/coretypes.h > +++ b/gcc/coretypes.h > @@ -134,6 +134,13 @@ struct gomp_single; > struct gomp_target; > struct gomp_teams; > > +/* Subclasses of symtab_node_def, using indentation to show the class > + hierarchy. */ > + > +class symtab_node; > + struct cgraph_node; > + class varpool_node; > + > union section; > typedef union section section; > struct gcc_options; > @@ -325,6 +332,14 @@ namespace gcc { > > typedef std::pair <tree, tree> tree_pair; > > +/* Define a name->value mapping. */ > +template <typename ValueType> > +struct kv_pair > +{ > + const char *const name; /* the name of the value */ > + const ValueType value; /* the value of the name */ > +}; > + > #else > > struct _dont_use_rtx_here_; > diff --git a/gcc/coverage.c b/gcc/coverage.c > index 84fff13..350cc45 100644 > --- a/gcc/coverage.c > +++ b/gcc/coverage.c > @@ -342,12 +342,16 @@ get_coverage_counts (unsigned counter, unsigned > expected, > static int warned = 0; > > if (!warned++ && dump_enabled_p ()) > - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location, > - (flag_guess_branch_prob > - ? "file %s not found, execution counts estimated\n" > - : "file %s not found, execution counts assumed to " > - "be zero\n"), > - da_file_name); > + { > + dump_user_location_t loc > + = dump_user_location_t::from_location_t (input_location); > + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, > + (flag_guess_branch_prob > + ? "file %s not found, execution counts > estimated\n" > + : "file %s not found, execution counts assumed to > " > + "be zero\n"), > + da_file_name); > + } > return NULL; > } > if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID)) > @@ -378,7 +382,9 @@ get_coverage_counts (unsigned counter, unsigned expected, > "its profile data (counter %qs)", id, ctr_names[counter]); > if (warning_printed && dump_enabled_p ()) > { > - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location, > + dump_user_location_t loc > + = dump_user_location_t::from_location_t (input_location); > + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, > "use -Wno-error=coverage-mismatch to tolerate " > "the mismatch but performance may drop if the " > "function is hot\n"); > @@ -386,7 +392,7 @@ get_coverage_counts (unsigned counter, unsigned expected, > if (!seen_error () > && !warned++) > { > - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location, > + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, > "coverage mismatch ignored\n"); > dump_printf (MSG_OPTIMIZED_LOCATIONS, > flag_guess_branch_prob > diff --git a/gcc/diagnostic-color.c b/gcc/diagnostic-color.c > index 3ee21bc..bcc3767 100644 > --- a/gcc/diagnostic-color.c > +++ b/gcc/diagnostic-color.c > @@ -84,6 +84,8 @@ static struct color_cap color_dict[] = > { "error", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED), 5, false }, > { "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA), > 7, false }, > + { "remark", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), > + 6, false }, > { "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false }, > { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false }, > { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false }, > diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h > index aa5807e..63166b8 100644 > --- a/gcc/diagnostic-core.h > +++ b/gcc/diagnostic-core.h > @@ -69,6 +69,8 @@ extern bool warning_at (location_t, int, const char *, ...) > ATTRIBUTE_GCC_DIAG(3,4); > extern bool warning_at (rich_location *, int, const char *, ...) > ATTRIBUTE_GCC_DIAG(3,4); > +extern bool remark (location_t, int, const char *, ...) > + ATTRIBUTE_GCC_DIAG(3,4); > extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); > extern void error_n (location_t, unsigned HOST_WIDE_INT, const char *, > const char *, ...) > diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c > index e22c17b..97ed88b 100644 > --- a/gcc/diagnostic.c > +++ b/gcc/diagnostic.c > @@ -492,6 +492,7 @@ diagnostic_action_after_output (diagnostic_context > *context, > { > case DK_DEBUG: > case DK_NOTE: > + case DK_REMARK: > case DK_ANACHRONISM: > case DK_WARNING: > break; > @@ -1274,6 +1275,22 @@ warning_n (location_t location, int opt, unsigned > HOST_WIDE_INT n, > return ret; > } > > +/* Emit an optimization remark at LOCATION. This is used by the optinfo > + framework. > + Return true if the remark was printed, false if it was inhibited. */ > +// FIXME: we don't yet have a more fine-grained way of inhibiting remarks > + > +bool > +remark (location_t location, int opt, const char *gmsgid, ...) > +{ > + va_list ap; > + va_start (ap, gmsgid); > + rich_location richloc (line_table, location); > + bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_REMARK); > + va_end (ap); > + return ret; > +} > + > /* A "pedantic" warning at LOCATION: issues a warning unless > -pedantic-errors was given on the command line, in which case it > issues an error. Use this for diagnostics required by the relevant > diff --git a/gcc/diagnostic.def b/gcc/diagnostic.def > index ce3dc56..b58095d 100644 > --- a/gcc/diagnostic.def > +++ b/gcc/diagnostic.def > @@ -37,6 +37,7 @@ DEFINE_DIAGNOSTIC_KIND (DK_SORRY, "sorry, unimplemented: ", > "error") > DEFINE_DIAGNOSTIC_KIND (DK_WARNING, "warning: ", "warning") > DEFINE_DIAGNOSTIC_KIND (DK_ANACHRONISM, "anachronism: ", "warning") > DEFINE_DIAGNOSTIC_KIND (DK_NOTE, "note: ", "note") > +DEFINE_DIAGNOSTIC_KIND (DK_REMARK, "remark: ", "remark") > DEFINE_DIAGNOSTIC_KIND (DK_DEBUG, "debug: ", "note") > /* These two would be re-classified as DK_WARNING or DK_ERROR, so the > prefix does not matter. */ > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index b06ea6e..7454ae5 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -141,6 +141,7 @@ only one of these two forms, whichever one is not the > default. > * Debugging Options:: Producing debuggable code. > * Optimize Options:: How much optimization? > * Instrumentation Options:: Enabling profiling and extra run-time error > checking. > +* Remarks:: Details on how your code is being optimized. > * Preprocessor Options:: Controlling header files and macro definitions. > Also, getting dependency information for Make. > * Assembler Options:: Passing options to the assembler. > @@ -416,7 +417,8 @@ Objective-C and Objective-C++ Dialects}. > -freorder-blocks-algorithm=@var{algorithm} @gol > -freorder-blocks-and-partition -freorder-functions @gol > -frerun-cse-after-loop -freschedule-modulo-scheduled-loops @gol > --frounding-math -fsched2-use-superblocks -fsched-pressure @gol > +-frounding-math -fsave-optimization-record @gol > +-fsched2-use-superblocks -fsched-pressure @gol > -fsched-spec-load -fsched-spec-load-dangerous @gol > -fsched-stalled-insns-dep[=@var{n}] -fsched-stalled-insns[=@var{n}] @gol > -fsched-group-heuristic -fsched-critical-path-heuristic @gol > @@ -470,6 +472,11 @@ Objective-C and Objective-C++ Dialects}. > -finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol > -finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{}} > > +@item Remarks > +@xref{Remarks,,Options to Control Remarks from the Compiler}. > +@gccoptlist{-fremarks -fno-diagnostics-show-remark-hotness @gol > +-fno-diagnostics-show-remark-origin -fno-diagnostics-show-remark-pass} > + > @item Preprocessor Options > @xref{Preprocessor Options,,Options Controlling the Preprocessor}. > @gccoptlist{-A@var{question}=@var{answer} @gol > @@ -9904,6 +9911,15 @@ Future versions of GCC may provide finer control of > this setting > using C99's @code{FENV_ACCESS} pragma. This command-line option > will be used to specify the default state for @code{FENV_ACCESS}. > > +@item -fsave-optimization-record > +@opindex fsave-optimization-record > +Write a SRCFILE.opt-record.json file detailing what optimizations > +were performed. > +FIXME: The precise format is not yet set in stone, but it ought > +to be stabilized and then documented somewhere. > +FIXME: should this be described here within the optimization options, > +or within the developer options? > + > @item -fsignaling-nans > @opindex fsignaling-nans > Compile code assuming that IEEE signaling NaNs may generate user-visible > @@ -12037,6 +12053,71 @@ The NOP instructions are inserted at---and maybe > before, depending on > @end table > > > +@node Remarks > +@section Options to Control Remarks from the Compiler > +@cindex remarks > +@cindex options, remarks > + > +These options are aimed at advanced users who may be interested > +in seeing additional diagnostics from the compiler, giving information > +on the decisions it is making on the code. > + > +The precise messages and their format are subject to change. > + > +Rather than attempting to parse the textual remark format, consider > +using @option{-fsave-optimization-record}, which works from the same > +data internally. > + > +@table @gcctabopt > +@item -fremarks > +@opindex fremarks > +Emit diagnostic remarks about optimizations. > + > +Enabling this option leads to GCC emitting diagnostics detailing the > +optimization decisions it is making. > + > +For example, this message: > + > +@smallexample > +test.c:13:3: remark: Symbolic number of iterations is '(unsigned int) > n_8(D)' [pass=vect] [count(precise)=76800000] > [../../src/gcc/tree-vect-loop.c:1387:vect_analyze_loop_form] > +@end smallexample > + > +describes an internal detail of the ``vect'' optimization pass, acting at > +the given source location within ``test.c'', where the remark was emitted > +by the function ``vect_analyze_loop_form'' at line 1387 of GCC's source > +file ``tree-vect-loop.c''. > + > +@item -fno-diagnostics-show-remark-hotness > +@opindex fno-diagnostics-show-remark-hotness > +@opindex fdiagnostics-show-remark-hotness > +By default, if diagnostic remarks are enabled, they include information > +on the execution count, or ``hotness'', of the code being optimized: > +the ``[count(precise)=76800000]'' in the example above. > + > +This option suppresses this part of the remark. > + > +@item -fno-diagnostics-show-remark-origin > +@opindex fno-diagnostics-show-remark-origin > +@opindex fdiagnostics-show-remark-origin > +By default, if diagnostic remarks are enabled, they include information > +on where in GCC's own source code (or a plugin's source code) the remark > +is being emitted from; the > +``[../../src/gcc/tree-vect-loop.c:1387:vect_analyze_loop_form]'' > +in the example above. > + > +This option suppresses this part of the remark. > + > +@item -fno-diagnostics-show-remark-pass > +@opindex fno-diagnostics-show-remark-pass > +@opindex fdiagnostics-show-remark-pass > +By default, if diagnostic remarks are enabled, they include information > +on which optimization pass emitted the remark: the ``[pass=vect]'' > +in the example above. > + > +This option suppresses this part of the remark. > + > +@end table > + > @node Preprocessor Options > @section Options Controlling the Preprocessor > @cindex preprocessor options > diff --git a/gcc/dump-context.h b/gcc/dump-context.h > new file mode 100644 > index 0000000..2986317 > --- /dev/null > +++ b/gcc/dump-context.h > @@ -0,0 +1,112 @@ > +/* Support code for handling the various dump_* calls in dumpfile.h > + Copyright (C) 2018 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify > +it under the terms of the GNU General Public License as published by > +the Free Software Foundation; either version 3, or (at your option) > +any later version. > + > +GCC is distributed in the hope that it will be useful, > +but WITHOUT ANY WARRANTY; without even the implied warranty of > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +GNU General Public License for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > + > +#ifndef GCC_DUMP_CONTEXT_H > +#define GCC_DUMP_CONTEXT_H 1 > + > +/* A class for handling the various dump_* calls. > + > + In particular, this class has responsibility for consolidating > + the "dump_*" calls into optinfo instances (delimited by "dump_*_loc" > + calls), and emitting them. > + > + Putting this in a class (rather than as global state) allows > + for selftesting of this code. */ > + > +class dump_context > +{ > + friend class temp_dump_context; > + public: > + static dump_context &get () { return *s_current; } > + > + ~dump_context (); > + > + void dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t > extra_dump_flags, > + gimple *gs, int spc); > + > + void dump_gimple_stmt_loc (dump_flags_t dump_kind, > + const dump_location_t &loc, > + dump_flags_t extra_dump_flags, > + gimple *gs, int spc); > + > + void dump_generic_expr (dump_flags_t dump_kind, > + dump_flags_t extra_dump_flags, > + tree t); > + > + void dump_printf_va (dump_flags_t dump_kind, const char *format, > + va_list ap) ATTRIBUTE_PRINTF (3, 0); > + > + void dump_printf_loc_va (dump_flags_t dump_kind, const dump_location_t > &loc, > + const char *format, va_list ap) > + ATTRIBUTE_PRINTF (4, 0); > + > + template<unsigned int N, typename C> > + void dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value); > + > + void dump_symtab_node (dump_flags_t dump_kind, symtab_node *node); > + > + /* Managing nested scopes. */ > + unsigned int get_scope_depth () const; > + void begin_scope (const char *name, const dump_location_t &loc); > + void end_scope (); > + > + private: > + optinfo &ensure_pending_optinfo (); > + optinfo &begin_next_optinfo (const dump_location_t &loc); > + void end_any_optinfo (); > + > + /* The current nesting depth of dump scopes, for showing nesting > + via indentation). */ > + unsigned int m_scope_depth; > + > + /* The optinfo currently being accumulated since the last dump_*_loc call, > + if any. */ > + optinfo *m_pending; > + > + /* The currently active dump_context, for use by the dump_* API calls. */ > + static dump_context *s_current; > + > + /* The default active context. */ > + static dump_context s_default; > +}; > + > +#if CHECKING_P > + > +/* An RAII class for use in selftests for temporarily using a different > + dump_context. */ > + > +class temp_dump_context > +{ > + public: > + temp_dump_context (bool new_flag_remarks); > + ~temp_dump_context (); > + > + /* Support for selftests. */ > + optinfo *get_pending_optinfo () const { return m_context.m_pending; } > + > + private: > + dump_context m_context; > + dump_context *m_saved; > + bool m_saved_flag_remarks; > +}; > + > +#endif /* CHECKING_P */ > + > +#endif /* GCC_DUMP_CONTEXT_H */ > diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c > index 2f11284..3be4af5 100644 > --- a/gcc/dumpfile.c > +++ b/gcc/dumpfile.c > @@ -29,6 +29,16 @@ along with GCC; see the file COPYING3. If not see > #include "profile-count.h" > #include "tree-cfg.h" > #include "langhooks.h" > +#include "optinfo.h" > +#include "cgraph.h" /* for selftests. */ > +#include "optinfo-emit-json.h" > +#include "optinfo-internal.h" /* for selftests. */ > +#include "backend.h" > +#include "gimple.h" /* for dump_user_location_t ctor. */ > +#include "rtl.h" /* for dump_user_location_t ctor. */ > +#include "dump-context.h" > +#include "tree-pass.h" /* for "current_pass". */ > +#include "selftest.h" > > /* If non-NULL, return one past-the-end of the matching SUBPART of > the WHOLE string. */ > @@ -36,18 +46,52 @@ along with GCC; see the file COPYING3. If not see > (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part)) > > static dump_flags_t pflags; /* current dump_flags */ > -static dump_flags_t alt_flags; /* current opt_info flags */ > > static void dump_loc (dump_flags_t, FILE *, source_location); > + > +/* Current -fopt-info output stream, if any, and flags. */ > +static FILE *alt_dump_file = NULL; > +static dump_flags_t alt_flags; > + > static FILE *dump_open_alternate_stream (struct dump_file_info *); > > /* These are currently used for communicating between passes. > However, instead of accessing them directly, the passes can use > dump_printf () for dumps. */ > FILE *dump_file = NULL; > -FILE *alt_dump_file = NULL; > const char *dump_file_name; > dump_flags_t dump_flags; > +bool dumps_are_enabled = false; > + > + > +/* Update the "dumps_are_enabled" global; to be called whenever dump_file > + or alt_dump_file change. */ > + > +static void > +refresh_dumps_are_enabled () > +{ > + dumps_are_enabled = (dump_file || alt_dump_file || optinfo_enabled_p ()); > +} > + > +/* Set global "dump_file" to NEW_DUMP_FILE, refreshing the > "dumps_are_enabled" > + global. */ > + > +void > +set_dump_file (FILE *new_dump_file) > +{ > + dump_file = new_dump_file; > + refresh_dumps_are_enabled (); > +} > + > +/* Set "alt_dump_file" to NEW_ALT_DUMP_FILE, refreshing the > "dumps_are_enabled" > + global. */ > + > +static void > +set_alt_dump_file (FILE *new_alt_dump_file) > +{ > + alt_dump_file = new_alt_dump_file; > + refresh_dumps_are_enabled (); > +} > > #define DUMP_FILE_INFO(suffix, swtch, dkind, num) \ > {suffix, swtch, NULL, NULL, NULL, NULL, NULL, dkind, TDF_NONE, TDF_NONE, \ > @@ -74,14 +118,6 @@ static struct dump_file_info dump_files[TDI_end] = > DUMP_FILE_INFO (NULL, "ipa-all", DK_ipa, 0), > }; > > -/* Define a name->number mapping for a dump flag value. */ > -template <typename ValueType> > -struct kv_pair > -{ > - const char *const name; /* the name of the value */ > - const ValueType value; /* the value of the name */ > -}; > - > /* Table of dump options. This must be consistent with the TDF_* flags > in dumpfile.h and opt_info_options below. */ > static const kv_pair<dump_flags_t> dump_options[] = > @@ -132,7 +168,7 @@ static const kv_pair<dump_flags_t> > optinfo_verbosity_options[] = > }; > > /* Flags used for -fopt-info groups. */ > -static const kv_pair<optgroup_flags_t> optgroup_options[] = > +const kv_pair<optgroup_flags_t> optgroup_options[] = > { > {"ipa", OPTGROUP_IPA}, > {"loop", OPTGROUP_LOOP}, > @@ -358,9 +394,53 @@ dump_open_alternate_stream (struct dump_file_info *dfi) > return stream; > } > > +/* Implementation of "structured dumping API". */ > + > +/* Construct a dump_user_location_t from STMT (using its location and > + hotness). */ > + > +dump_user_location_t::dump_user_location_t (gimple *stmt) > +: m_count (), m_loc (UNKNOWN_LOCATION) > +{ > + if (stmt) > + { > + if (stmt->bb) > + m_count = stmt->bb->count; > + m_loc = gimple_location (stmt); > + } > +} > + > +/* Construct a dump_user_location_t from an RTL instruction (using its > + location and hotness). */ > +dump_user_location_t::dump_user_location_t (rtx_insn *insn) > +: m_count (), m_loc (UNKNOWN_LOCATION) > +{ > + if (insn) > + { > + basic_block bb = BLOCK_FOR_INSN (insn); > + if (bb) > + m_count = bb->count; > + m_loc = INSN_LOCATION (insn); > + } > +} > + > +/* Construct from a function declaration. This one requires spelling out > + to avoid accidentally constructing from other kinds of tree. */ > + > +dump_user_location_t > +dump_user_location_t::from_function_decl (tree fndecl) > +{ > + gcc_assert (fndecl); > + > + // FIXME: profile count for function? > + return dump_user_location_t (profile_count (), > + DECL_SOURCE_LOCATION (fndecl)); > +} > + > + > /* Print source location on DFILE if enabled. */ > > -void > +static void > dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc) > { > if (dump_kind) > @@ -373,137 +453,363 @@ dump_loc (dump_flags_t dump_kind, FILE *dfile, > source_location loc) > DECL_SOURCE_FILE (current_function_decl), > DECL_SOURCE_LINE (current_function_decl), > DECL_SOURCE_COLUMN (current_function_decl)); > + /* Indentation based on scope depth. */ > + fprintf (dfile, "%*s", get_dump_scope_depth (), ""); > } > } > > +/* Implementation of dump_context methods. */ > + > +/* dump_context's dtor. */ > + > +dump_context::~dump_context () > +{ > + delete m_pending; > +} > + > /* Dump gimple statement GS with SPC indentation spaces and > EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */ > > void > -dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > - gimple *gs, int spc) > +dump_context::dump_gimple_stmt (dump_flags_t dump_kind, > + dump_flags_t extra_dump_flags, > + gimple *gs, int spc) > { > if (dump_file && (dump_kind & pflags)) > print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); > > if (alt_dump_file && (dump_kind & alt_flags)) > print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | > extra_dump_flags); > + > + if (optinfo_enabled_p ()) > + { > + optinfo &info = ensure_pending_optinfo (); > + info.handle_dump_file_kind (dump_kind); > + info.add_stmt (gs, extra_dump_flags); > + } > } > > /* Similar to dump_gimple_stmt, except additionally print source location. > */ > > void > -dump_gimple_stmt_loc (dump_flags_t dump_kind, source_location loc, > - dump_flags_t extra_dump_flags, gimple *gs, int spc) > +dump_context::dump_gimple_stmt_loc (dump_flags_t dump_kind, > + const dump_location_t &loc, > + dump_flags_t extra_dump_flags, > + gimple *gs, int spc) > { > + location_t srcloc = loc.get_location_t (); > + > if (dump_file && (dump_kind & pflags)) > { > - dump_loc (dump_kind, dump_file, loc); > + dump_loc (dump_kind, dump_file, srcloc); > print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); > } > > if (alt_dump_file && (dump_kind & alt_flags)) > { > - dump_loc (dump_kind, alt_dump_file, loc); > + dump_loc (dump_kind, alt_dump_file, srcloc); > print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | > extra_dump_flags); > } > + > + if (optinfo_enabled_p ()) > + { > + optinfo &info = begin_next_optinfo (loc); > + info.handle_dump_file_kind (dump_kind); > + info.add_stmt (gs, extra_dump_flags); > + } > } > > /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if > DUMP_KIND is enabled. */ > > void > -dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > - tree t) > +dump_context::dump_generic_expr (dump_flags_t dump_kind, > + dump_flags_t extra_dump_flags, > + tree t) > { > if (dump_file && (dump_kind & pflags)) > print_generic_expr (dump_file, t, dump_flags | extra_dump_flags); > > if (alt_dump_file && (dump_kind & alt_flags)) > print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); > -} > > + if (optinfo_enabled_p ()) > + { > + optinfo &info = ensure_pending_optinfo (); > + info.handle_dump_file_kind (dump_kind); > + info.add_tree (t, extra_dump_flags); > + } > +} > > -/* Similar to dump_generic_expr, except additionally print the source > - location. */ > +/* Output a formatted message using FORMAT on appropriate dump streams. */ > > void > -dump_generic_expr_loc (dump_flags_t dump_kind, source_location loc, > - dump_flags_t extra_dump_flags, tree t) > +dump_context::dump_printf_va (dump_flags_t dump_kind, const char *format, > + va_list ap) > { > if (dump_file && (dump_kind & pflags)) > { > - dump_loc (dump_kind, dump_file, loc); > - print_generic_expr (dump_file, t, dump_flags | extra_dump_flags); > + va_list aq; > + va_copy (aq, ap); > + vfprintf (dump_file, format, aq); > + va_end (aq); > } > > if (alt_dump_file && (dump_kind & alt_flags)) > { > - dump_loc (dump_kind, alt_dump_file, loc); > - print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); > + va_list aq; > + va_copy (aq, ap); > + vfprintf (alt_dump_file, format, aq); > + va_end (aq); > + } > + > + if (optinfo_enabled_p ()) > + { > + optinfo &info = ensure_pending_optinfo (); > + va_list aq; > + va_copy (aq, ap); > + info.add_printf_va (format, aq); > + va_end (aq); > } > } > > -/* Output a formatted message using FORMAT on appropriate dump streams. */ > +/* Similar to dump_printf, except source location is also printed, and > + dump location captured. */ > > void > -dump_printf (dump_flags_t dump_kind, const char *format, ...) > +dump_context::dump_printf_loc_va (dump_flags_t dump_kind, const > dump_location_t &loc, > + const char *format, va_list ap) > { > + location_t srcloc = loc.get_location_t (); > + > if (dump_file && (dump_kind & pflags)) > { > - va_list ap; > - va_start (ap, format); > - vfprintf (dump_file, format, ap); > - va_end (ap); > + dump_loc (dump_kind, dump_file, srcloc); > + va_list aq; > + va_copy (aq, ap); > + vfprintf (dump_file, format, aq); > + va_end (aq); > } > > if (alt_dump_file && (dump_kind & alt_flags)) > { > - va_list ap; > - va_start (ap, format); > - vfprintf (alt_dump_file, format, ap); > - va_end (ap); > + dump_loc (dump_kind, alt_dump_file, srcloc); > + va_list aq; > + va_copy (aq, ap); > + vfprintf (alt_dump_file, format, aq); > + va_end (aq); > + } > + > + if (optinfo_enabled_p ()) > + { > + optinfo &info = begin_next_optinfo (loc); > + info.handle_dump_file_kind (dump_kind); > + va_list aq; > + va_copy (aq, ap); > + info.add_printf_va (format, aq); > + va_end (aq); > } > } > > -/* Similar to dump_printf, except source location is also printed. */ > +/* Output VALUE in decimal to appropriate dump streams. */ > > +template<unsigned int N, typename C> > void > -dump_printf_loc (dump_flags_t dump_kind, source_location loc, > - const char *format, ...) > +dump_context::dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value) > { > + STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0); > + signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED; > if (dump_file && (dump_kind & pflags)) > + print_dec (value, dump_file, sgn); > + > + if (alt_dump_file && (dump_kind & alt_flags)) > + print_dec (value, alt_dump_file, sgn); > + > + if (optinfo_enabled_p ()) > { > - va_list ap; > - dump_loc (dump_kind, dump_file, loc); > - va_start (ap, format); > - vfprintf (dump_file, format, ap); > - va_end (ap); > + optinfo &info = ensure_pending_optinfo (); > + info.handle_dump_file_kind (dump_kind); > + info.add_poly_int<N,C> (value); > } > +} > + > +/* Output the name of NODE on appropriate dump streams. */ > + > +void > +dump_context::dump_symtab_node (dump_flags_t dump_kind, symtab_node *node) > +{ > + if (dump_file && (dump_kind & pflags)) > + fprintf (dump_file, "%s", node->dump_name ()); > > if (alt_dump_file && (dump_kind & alt_flags)) > + fprintf (alt_dump_file, "%s", node->dump_name ()); > + > + if (optinfo_enabled_p ()) > { > - va_list ap; > - dump_loc (dump_kind, alt_dump_file, loc); > - va_start (ap, format); > - vfprintf (alt_dump_file, format, ap); > - va_end (ap); > + optinfo &info = ensure_pending_optinfo (); > + info.handle_dump_file_kind (dump_kind); > + info.add_symtab_node (node); > } > } > > +/* Get the current dump scope-nesting depth. > + For use by remarks and -fopt-info (for showing nesting via indentation). > */ > + > +unsigned int > +dump_context::get_scope_depth () const > +{ > + return m_scope_depth; > +} > + > +/* Push a nested dump scope. > + Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info > + destination, if any. > + Push a "scope" opinfo if optinfos are enabled. > + Increment the scope depth. */ > + > +void > +dump_context::begin_scope (const char *name, const dump_location_t &loc) > +{ > + /* Specialcase, to avoid going through dump_printf_loc, > + so that we can create a optinfo of kind OPTINFO_KIND_SCOPE. */ > + > + if (dump_file) > + { > + dump_loc (MSG_NOTE, dump_file, loc.get_location_t ()); > + fprintf (dump_file, "=== %s ===\n", name); > + } > + > + if (alt_dump_file) > + { > + dump_loc (MSG_NOTE, alt_dump_file, loc.get_location_t ()); > + fprintf (alt_dump_file, "=== %s ===\n", name); > + } > + > + if (optinfo_enabled_p ()) > + { > + end_any_optinfo (); > + optinfo info (loc, OPTINFO_KIND_SCOPE, current_pass); > + info.add_printf ("=== %s ===", name); > + info.emit (); > + } > + > + m_scope_depth++; > +} > + > +/* Pop a nested dump scope. */ > + > +void > +dump_context::end_scope () > +{ > + end_any_optinfo (); > + m_scope_depth--; > + optimization_records_maybe_pop_dump_scope (); > +} > + > +/* Return the optinfo currently being accumulated, creating one if > + necessary. */ > + > +optinfo & > +dump_context::ensure_pending_optinfo () > +{ > + if (!m_pending) > + return begin_next_optinfo (dump_location_t (dump_user_location_t ())); > + return *m_pending; > +} > + > +/* Start a new optinfo and return it, ending any optinfo that was already > + accumulated. */ > + > +optinfo & > +dump_context::begin_next_optinfo (const dump_location_t &loc) > +{ > + end_any_optinfo (); > + gcc_assert (m_pending == NULL); > + m_pending = new optinfo (loc, OPTINFO_KIND_NOTE, current_pass); > + return *m_pending; > +} > + > +/* End any optinfo that has been accumulated within this context, emitting > + it as a diagnostic remark or to optimization records as appropriate. */ > + > +void > +dump_context::end_any_optinfo () > +{ > + if (m_pending) > + m_pending->emit (); > + delete m_pending; > + m_pending = NULL; > +} > + > +/* The current singleton dump_context, and its default. */ > + > +dump_context *dump_context::s_current = &dump_context::s_default; > +dump_context dump_context::s_default; > + > +/* Implementation of dump_* API calls, calling into dump_context > + methods. */ > + > +/* Dump gimple statement GS with SPC indentation spaces and > + EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */ > + > +void > +dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > + gimple *gs, int spc) > +{ > + dump_context::get ().dump_gimple_stmt (dump_kind, extra_dump_flags, gs, > spc); > +} > + > +/* Similar to dump_gimple_stmt, except additionally print source location. > */ > + > +void > +dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc, > + dump_flags_t extra_dump_flags, gimple *gs, int spc) > +{ > + dump_context::get ().dump_gimple_stmt_loc (dump_kind, loc, > extra_dump_flags, > + gs, spc); > +} > + > +/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if > + DUMP_KIND is enabled. */ > + > +void > +dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > + tree t) > +{ > + dump_context::get ().dump_generic_expr (dump_kind, extra_dump_flags, t); > +} > + > +/* Output a formatted message using FORMAT on appropriate dump streams. */ > + > +void > +dump_printf (dump_flags_t dump_kind, const char *format, ...) > +{ > + va_list ap; > + va_start (ap, format); > + dump_context::get ().dump_printf_va (dump_kind, format, ap); > + va_end (ap); > +} > + > +/* Similar to dump_printf, except source location is also printed, and > + dump location captured. */ > + > +void > +dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc, > + const char *format, ...) > +{ > + va_list ap; > + va_start (ap, format); > + dump_context::get ().dump_printf_loc_va (dump_kind, loc, format, ap); > + va_end (ap); > +} > + > /* Output VALUE in decimal to appropriate dump streams. */ > > template<unsigned int N, typename C> > void > dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value) > { > - STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0); > - signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED; > - if (dump_file && (dump_kind & pflags)) > - print_dec (value, dump_file, sgn); > - > - if (alt_dump_file && (dump_kind & alt_flags)) > - print_dec (value, alt_dump_file, sgn); > + dump_context::get ().dump_dec (dump_kind, value); > } > > template void dump_dec (dump_flags_t, const poly_uint16 &); > @@ -512,6 +818,45 @@ template void dump_dec (dump_flags_t, const poly_uint64 > &); > template void dump_dec (dump_flags_t, const poly_offset_int &); > template void dump_dec (dump_flags_t, const poly_widest_int &); > > +/* Output the name of NODE on appropriate dump streams. */ > + > +void > +dump_symtab_node (dump_flags_t dump_kind, symtab_node *node) > +{ > + dump_context::get ().dump_symtab_node (dump_kind, node); > +} > + > +/* Get the current dump scope-nesting depth. > + For use by remarks and -fopt-info (for showing nesting via indentation). > */ > + > +unsigned int > +get_dump_scope_depth () > +{ > + return dump_context::get ().get_scope_depth (); > +} > + > +/* Push a nested dump scope. > + Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info > + destination, if any. > + Push a "scope" opinfo if optinfos are enabled. > + Increment the scope depth. */ > + > +void > +dump_begin_scope (const char *name, const dump_location_t &loc) > +{ > + dump_context::get ().begin_scope (name, loc); > +} > + > +/* Pop a nested dump scope. */ > + > +void > +dump_end_scope () > +{ > + dump_context::get ().end_scope (); > +} > + > +/* End of implementation of "structured dumping API". */ > + > /* Start a dump for PHASE. Store user-supplied dump flags in > *FLAG_PTR. Return the number of streams opened. Set globals > DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and > @@ -541,7 +886,7 @@ dump_start (int phase, dump_flags_t *flag_ptr) > } > free (name); > dfi->pstream = stream; > - dump_file = dfi->pstream; > + set_dump_file (dfi->pstream); > /* Initialize current dump flags. */ > pflags = dfi->pflags; > } > @@ -551,7 +896,7 @@ dump_start (int phase, dump_flags_t *flag_ptr) > { > dfi->alt_stream = stream; > count++; > - alt_dump_file = dfi->alt_stream; > + set_alt_dump_file (dfi->alt_stream); > /* Initialize current -fopt-info flags. */ > alt_flags = dfi->alt_flags; > } > @@ -582,8 +927,8 @@ dump_finish (int phase) > > dfi->alt_stream = NULL; > dfi->pstream = NULL; > - dump_file = NULL; > - alt_dump_file = NULL; > + set_dump_file (NULL); > + set_alt_dump_file (NULL); > dump_flags = TDF_NONE; > alt_flags = TDF_NONE; > pflags = TDF_NONE; > @@ -1021,6 +1366,7 @@ dump_basic_block (dump_flags_t dump_kind, basic_block > bb, int indent) > dump_bb (dump_file, bb, indent, TDF_DETAILS); > if (alt_dump_file && (dump_kind & alt_flags)) > dump_bb (alt_dump_file, bb, indent, TDF_DETAILS); > + // TODO: should this also write to optinfo? > } > > /* Dump FUNCTION_DECL FN as tree dump PHASE. */ > @@ -1059,3 +1405,179 @@ enable_rtl_dump_file (void) > NULL); > return num_enabled > 0; > } > + > +#if CHECKING_P > + > +/* temp_dump_context's ctor. Temporarily override the dump_context, > + and the value of "flag_remarks" (to forcibly enable optinfo-generation). > */ > + > +temp_dump_context::temp_dump_context (bool new_flag_remarks) > +: m_context (), > + m_saved (&dump_context ().get ()), > + m_saved_flag_remarks (flag_remarks) > +{ > + dump_context::s_current = &m_context; > + flag_remarks = new_flag_remarks; > +} > + > +/* temp_dump_context's dtor. Restore the saved values of dump_context and > + "flag_remarks". */ > + > +temp_dump_context::~temp_dump_context () > +{ > + dump_context::s_current = m_saved; > + flag_remarks = m_saved_flag_remarks; > +} > + > +namespace selftest { > + > +/* Verify that the dump_location_t constructor ca