This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] v3 of optinfo, remarks and optimization records
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: David Malcolm <dmalcolm at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 25 Jun 2018 15:34:38 +0200
- Subject: Re: [PATCH] v3 of optinfo, remarks and optimization records
- References: <CAFiYyc0BVW1m-YTem7kbkw5T3+gXcZvKS-HHv-PCj7+=r9Lm7w@mail.gmail.com> <1529515085-22879-1-git-send-email-dmalcolm@redhat.com>
On Wed, Jun 20, 2018 at 6:34 PM David Malcolm <dmalcolm@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