On Mon, Jul 2, 2018 at 10:51 PM David Malcolm <dmalc...@redhat.com> wrote: > > This patch adds the first destination for optinfo instances to be > emitted to: as "remarks" through the diagnostics subsystem. > > Examples can be seen at > https://dmalcolm.fedorapeople.org/gcc/2018-06-18/test.cc.remarks.html > > Remarks look a lot like the output of -fopt-info, with the following > differences: > > * announcing "In function 'blah':" etc when the function changes. > > * printing the corresponding source lines (unless > "-fno-diagnostics-show-caret"), as per other diagnostics, and > > * colorizing the various parts of the message if stderr is at a tty. > > * showing extra metadata: > * the pass that emitted the remark, > * the execution count of the code in question > * which file/line/function of GCC emitted the remark > > * possibly allowing for remarks to be used in DejaGnu tests to better > associate testing of an optimization with the source line in > question, rather than relying on a scan of the dumpfile (which is > per-source file and thus rather "coarse-grained").* > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > > (see the notes in the cover letter about the state of this patch; > posting for motivation of the optinfo stuff).
As an overall comment I do like this as it is an improvement over -fopt-info which is currently the user-facing way of showing remarks about what code is optimized and what not and why. But for this very reason I don't like introducing a separate set of options. This means the remark stuff should replace -fopt-info (and re-use that flag as far as possible). This eventually means some -fXYZ might reduce the verbosity level (source line / hotness, etc.) to the current state - but I don't think we have made any guarantees about the current format. Given there'll be the JSON stuff for machine-consumption I am also not worried about existing machines parsing the stuff. Anyway, I think the issue outlined in the comment to 1/n needs to be addressed first. Thanks for working on this! Richard. > gcc/ChangeLog: > * Makefile.in (OBJS): Add optinfo-emit-diagnostics.o. > * common.opt (fremarks): New option. > (fdiagnostics-show-remark-hotness): New option. > (fdiagnostics-show-remark-origin): New option. > (fdiagnostics-show-remark-pass): New option. > * 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. > (-fremarks): New option. > (-fno-diagnostics-show-remark-hotness): New option. > (-fno-diagnostics-show-remark-origin): New option. > (-fno-diagnostics-show-remark-pass): New option. > * dumpfile.c (dump_context::get_scope_depth): Update comment. > (dump_context::end_any_optinfo): Likewise. > * dumpfile.h: Update comment. > * opt-functions.awk (function): Handle "Remark" by adding > CL_REMARK. > * optinfo-emit-diagnostics.cc: New file. > * optinfo-emit-diagnostics.h: New file. > * optinfo.cc: Include "optinfo-emit-diagnostics.h". > (optinfo::emit): Call emit_optinfo_as_diagnostic_remark. > (optinfo_enabled_p): Use flag_remarks. > * optinfo.h: Update comment. > * 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. > * profile-count.c (profile_quality_as_string): New function. > * profile-count.h (profile_quality_as_string): New decl. > (profile_count::quality): New accessor. > * selftest-run-tests.c (selftest::run_tests): Call > selftest::optinfo_emit_diagnostics_cc_tests. > * selftest.h (selftest::optinfo_emit_diagnostics_cc_tests): New > decl. > > 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 | 1 + > gcc/common.opt | 17 ++ > gcc/diagnostic-color.c | 2 + > gcc/diagnostic-core.h | 2 + > gcc/diagnostic.c | 17 ++ > gcc/diagnostic.def | 1 + > gcc/doc/invoke.texi | 67 ++++++ > gcc/dumpfile.c | 5 +- > gcc/dumpfile.h | 2 + > gcc/fortran/gfc-diagnostic.def | 1 + > gcc/opt-functions.awk | 1 + > gcc/optinfo-emit-diagnostics.cc | 317 > +++++++++++++++++++++++++++ > gcc/optinfo-emit-diagnostics.h | 26 +++ > gcc/optinfo.cc | 9 +- > gcc/optinfo.h | 4 +- > gcc/opts.c | 4 + > gcc/opts.h | 13 +- > gcc/profile-count.c | 28 +++ > gcc/profile-count.h | 5 + > gcc/selftest-run-tests.c | 1 + > gcc/selftest.h | 1 + > 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 + > 25 files changed, 701 insertions(+), 16 deletions(-) > create mode 100644 gcc/optinfo-emit-diagnostics.cc > create mode 100644 gcc/optinfo-emit-diagnostics.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 7d36a77..232cae4 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1427,6 +1427,7 @@ OBJS = \ > optabs-query.o \ > optabs-tree.o \ > optinfo.o \ > + optinfo-emit-diagnostics.o \ > options-save.o \ > opts-global.o \ > passes.o \ > diff --git a/gcc/common.opt b/gcc/common.opt > index 5a50bc27..908432e 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -510,6 +510,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 > > @@ -1281,6 +1286,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. > 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 248e603..1a3c1a6 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. > @@ -471,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 > @@ -12040,6 +12046,67 @@ 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. > + > +@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/dumpfile.c b/gcc/dumpfile.c > index 6e089ef..955fd57 100644 > --- a/gcc/dumpfile.c > +++ b/gcc/dumpfile.c > @@ -690,7 +690,7 @@ dump_context::dump_symtab_node (dump_flags_t dump_kind, > symtab_node *node) > } > > /* Get the current dump scope-nesting depth. > - For use by -fopt-info (for showing nesting via indentation). */ > + For use by remarks and -fopt-info (for showing nesting via indentation). > */ > > unsigned int > dump_context::get_scope_depth () const > @@ -766,8 +766,7 @@ dump_context::begin_next_optinfo (const dump_location_t > &loc) > } > > /* End any optinfo that has been accumulated within this context; emitting > - it to any destinations as appropriate - though none have currently been > - implemented. */ > + it to any destinations as appropriate, such as a diagnostic "remark". */ > > void > dump_context::end_any_optinfo () > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h > index 899bb89..514efe3 100644 > --- a/gcc/dumpfile.h > +++ b/gcc/dumpfile.h > @@ -442,6 +442,7 @@ dump_enabled_p (void) > (a) the active dump_file, if any > (b) the -fopt-info destination, if any > (c) to the "optinfo" destinations, if any: > + (c.1) as diagnostic "remarks" > > dump_* (MSG_*) --> dumpfile.c --+--> (a) dump_file > | > @@ -449,6 +450,7 @@ dump_enabled_p (void) > | > `--> (c) optinfo > `---> optinfo destinations > + (c.1) diagnostic "remarks" > > For optinfos, the dump_*_loc mark the beginning of an optinfo > instance: all subsequent dump_* calls are consolidated into > diff --git a/gcc/fortran/gfc-diagnostic.def b/gcc/fortran/gfc-diagnostic.def > index 565fa83..a10b6aa 100644 > --- a/gcc/fortran/gfc-diagnostic.def > +++ b/gcc/fortran/gfc-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/opt-functions.awk b/gcc/opt-functions.awk > index 2c371e5..48ecac5 100644 > --- a/gcc/opt-functions.awk > +++ b/gcc/opt-functions.awk > @@ -105,6 +105,7 @@ function switch_flags (flags) > test_flag("Undocumented", flags, " | CL_UNDOCUMENTED") \ > test_flag("NoDWARFRecord", flags, " | CL_NO_DWARF_RECORD") \ > test_flag("Warning", flags, " | CL_WARNING") \ > + test_flag("Remark", flags, " | CL_REMARK") \ > test_flag("(Optimization|PerFunction)", flags, " | > CL_OPTIMIZATION") > sub( "^0 \\| ", "", result ) > return result > diff --git a/gcc/optinfo-emit-diagnostics.cc b/gcc/optinfo-emit-diagnostics.cc > new file mode 100644 > index 0000000..5320379 > --- /dev/null > +++ b/gcc/optinfo-emit-diagnostics.cc > @@ -0,0 +1,317 @@ > +/* Emit optimization information as "remark" diagnostics. > + Copyright (C) 2018 Free Software Foundation, Inc. > + Contributed by David Malcolm <dmalc...@redhat.com>. > + > +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/>. */ > + > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > + > +#include "backend.h" > +#include "tree.h" > +#include "tree-pass.h" > +#include "gimple.h" > +#include "pretty-print.h" > +#include "tree-pretty-print.h" > +#include "gimple-pretty-print.h" > +#include "diagnostic.h" > +#include "diagnostic-color.h" > +#include "options.h" > +#include "cgraph.h" > + > +#include "optinfo.h" > +#include "optinfo-emit-diagnostics.h" > +#include "optinfo-internal.h" > +#include "dump-context.h" > +#include "selftest.h" > +#include "context.h" > +#include "pass_manager.h" > + > +/* Print the items within OPTINFO to PP (as part of a remark). */ > + > +static void > +print_optinfo_items (pretty_printer *pp, const optinfo *optinfo) > +{ > + bool show_color = pp_show_color (pp); > + > + for (unsigned i = 0; i < optinfo->num_items (); i++) > + { > + const optinfo_item *item = optinfo->get_item (i); > + switch (item->get_kind ()) > + { > + default: > + gcc_unreachable (); > + case OPTINFO_ITEM_KIND_TEXT: > + { > + const optinfo_item_text *as_text > + = (const optinfo_item_text *)item; > + pp_string (pp, as_text->get_text ()); > + } > + break; > + case OPTINFO_ITEM_KIND_TREE: > + { > + const optinfo_item_tree *as_tree > + = (const optinfo_item_tree *)item; > + pp_begin_quote (pp, show_color); > + dump_generic_node (pp, as_tree->get_node (), 0, TDF_DETAILS, > + false); > + pp_end_quote (pp, show_color); > + } > + break; > + case OPTINFO_ITEM_KIND_GIMPLE: > + { > + const optinfo_item_gimple *as_gimple > + = (const optinfo_item_gimple *)item; > + gimple *stmt = as_gimple->get_stmt (); > + pp_begin_quote (pp, show_color); > + pp_gimple_stmt_1 (pp, stmt, 0, TDF_SLIM); > + pp_end_quote (pp, show_color); > + } > + break; > + case OPTINFO_ITEM_KIND_SYMTAB_NODE: > + { > + const optinfo_item_symtab_node *as_symtab_node > + = (const optinfo_item_symtab_node *)item; > + symtab_node *node = as_symtab_node->get_node (); > + pp_begin_quote (pp, show_color); > + pp_string (pp, node->dump_name ()); > + pp_end_quote (pp, show_color); > + } > + break; > + } > + } > +} > + > +/* Print PASS to PP (as part of a remark). */ > + > +static void > +print_pass (pretty_printer *pp, opt_pass *pass) > +{ > + if (pass == NULL) > + return; > + > + bool show_color = pp_show_color (pp); > + > + pp_string (pp, " ["); > + pp_string (pp, colorize_start (show_color, > + diagnostic_get_color_for_kind (DK_REMARK))); > + pp_string (pp, "pass="); > + pp_string (pp, pass->name); > + pp_string (pp, colorize_stop (show_color)); > + pp_string (pp, "]"); > +} > + > +/* Print COUNT to PP (as part of a remark). */ > + > +static void > +print_count (pretty_printer *pp, profile_count count) > +{ > + if (!count.initialized_p ()) > + return; > + > + bool show_color = pp_show_color (pp); > + > + pp_string (pp, " ["); > + pp_string (pp, > + colorize_start (show_color, > + diagnostic_get_color_for_kind (DK_NOTE))); > + pp_string (pp, "count("); > + pp_string (pp, profile_quality_as_string (count.quality ())); > + pp_string (pp, ")="); > + pp_scalar (pp, "%li", count.to_gcov_type ()); > + pp_string (pp, colorize_stop (show_color)); > + pp_string (pp, "]"); > +} > + > +/* Print IMPL_LOC to PP (as part of a remark). */ > + > +static void > +print_impl_location (pretty_printer *pp, const dump_impl_location_t > &impl_loc) > +{ > + bool show_color = pp_show_color (pp); > + > + pp_string (pp, " ["); > + pp_string (pp, > + colorize_start (show_color, > + diagnostic_get_color_for_kind (DK_REMARK))); > + pp_printf (pp, "%s:%i", impl_loc.m_file, impl_loc.m_line); > + if (impl_loc.m_function) > + pp_printf (pp, ":%s", impl_loc.m_function); > + pp_string (pp, colorize_stop (show_color)); > + pp_string (pp, "]"); > +} > + > +/* Print OPTINFO to PP. */ > + > +static void > +print_optinfo_as_remark (pretty_printer *pp, const optinfo *optinfo) > +{ > + /* Start with scope-based indentation. */ > + for (unsigned i = get_dump_scope_depth (); i > 0; i--) > + pp_space (pp); > + > + /* Print the items into PP. */ > + print_optinfo_items (pp, optinfo); > + > + /* Add metadata: which pass? */ > + if (flag_diagnostics_show_remark_pass) > + print_pass (pp, optinfo->get_pass ()); > + > + /* Add metadata: hotness. */ > + if (flag_diagnostics_show_remark_hotness) > + print_count (pp, optinfo->get_count ()); > + > + /* Add metadata: where was this emitted from. */ > + if (flag_diagnostics_show_remark_origin) > + print_impl_location (pp, optinfo->get_impl_location ()); > +} > + > +/* Subclass of pretty_printer for building up the text of a remark. */ > + > +class remark_printer : public pretty_printer > +{ > +public: > + remark_printer (bool show_color_); > +}; > + > +/* remark_printer's ctor. */ > + > +remark_printer::remark_printer (bool show_color_) > +{ > + pp_needs_newline (this) = true; > + pp_translate_identifiers (this) = false; > + pp_show_color (this) = show_color_; > +} > + > +/* If diagnostic "remarks" are enabled, then emit OPTINFO as a remark. */ > + > +void > +emit_optinfo_as_diagnostic_remark (const optinfo *optinfo) > +{ > + if (!flag_remarks) > + return; > + > + remark_printer pp (pp_show_color (global_dc->printer)); > + > + print_optinfo_as_remark (&pp, optinfo); > + > + const char *msg = pp_formatted_text (&pp); > + location_t loc = optinfo->get_location_t (); > + > + remark (loc, 0, "%s", msg); > +} > + > +#if CHECKING_P > + > +namespace selftest { > + > +/* Verify that print_optinfo_items works. */ > + > +static void > +test_print_optinfo_items () > +{ > + temp_dump_context tmp (true); > + dump_location_t loc; > + dump_printf_loc (MSG_NOTE, loc, "test of tree: "); > + dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); > + optinfo *info = tmp.get_pending_optinfo (); > + ASSERT_TRUE (info != NULL); > + > + /* Avoid introducing locale-specific differences in the results > + by hardcoding open_quote and close_quote. */ > + auto_fix_quotes fix_quotes; > + > + remark_printer pp (false); > + print_optinfo_items (&pp, info); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, "test of tree: `0'"); > +} > + > +/* Verify that print_pass works. */ > + > +static void > +test_print_pass () > +{ > + /* NULL pass. */ > + { > + remark_printer pp (false); > + print_pass (&pp, NULL); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, ""); > + } > + > + /* Non-NULL pass. */ > + { > + remark_printer pp (false); > + opt_pass *pass = make_pass_ipa_increase_alignment (NULL); > + print_pass (&pp, pass); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, " [pass=increase_alignment]"); > + delete pass; > + } > +} > + > +/* Verify that print_count works. */ > + > +static void > +test_print_count () > +{ > + remark_printer pp (false); > + print_count (&pp, profile_count ()); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, " [count(uninitialized)=0]"); > +} > + > +/* Verify that print_impl_location works. */ > + > +static void > +test_print_impl_location () > +{ > + /* Non-NULL function. */ > + { > + remark_printer pp (false); > + dump_impl_location_t loc ("foo.c", 42, "funcname"); > + print_impl_location (&pp, loc); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, " [foo.c:42:funcname]"); > + } > + > + /* NULL function. */ > + { > + remark_printer pp (false); > + dump_impl_location_t loc ("foo.c", 42, NULL); > + print_impl_location (&pp, loc); > + const char *msg = pp_formatted_text (&pp); > + ASSERT_STREQ (msg, " [foo.c:42]"); > + } > +} > + > +/* Run all of the selftests within this file. */ > + > +void > +optinfo_emit_diagnostics_cc_tests () > +{ > + test_print_optinfo_items (); > + test_print_pass (); > + test_print_count (); > + test_print_impl_location (); > +} > + > +} // namespace selftest > + > +#endif /* CHECKING_P */ > diff --git a/gcc/optinfo-emit-diagnostics.h b/gcc/optinfo-emit-diagnostics.h > new file mode 100644 > index 0000000..820cefd > --- /dev/null > +++ b/gcc/optinfo-emit-diagnostics.h > @@ -0,0 +1,26 @@ > +/* Emit optimization information as "remark" diagnostics. > + Copyright (C) 2018 Free Software Foundation, Inc. > + Contributed by David Malcolm <dmalc...@redhat.com>. > + > +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_OPTINFO_EMIT_DIAGNOSTICS_H > +#define GCC_OPTINFO_EMIT_DIAGNOSTICS_H > + > +extern void emit_optinfo_as_diagnostic_remark (const optinfo *); > + > +#endif /* #ifndef GCC_OPTINFO_EMIT_DIAGNOSTICS_H */ > diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc > index 1da7d37..bc86696 100644 > --- a/gcc/optinfo.cc > +++ b/gcc/optinfo.cc > @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see > > #include "optinfo.h" > #include "optinfo-internal.h" > +#include "optinfo-emit-diagnostics.h" > #include "dump-context.h" > #include "selftest.h" > > @@ -112,7 +113,8 @@ optinfo::emit () > delete last_item; > } > > - /* currently this is a no-op. */ > + /* -fremarks. */ > + emit_optinfo_as_diagnostic_remark (this); > } > > /* Update the optinfo's kind based on DUMP_KIND. */ > @@ -203,9 +205,8 @@ optinfo::add_dec (const wide_int_ref &wi, signop sgn) > > bool optinfo_enabled_p () > { > - /* Currently no destinations are implemented, just a hook for > - selftests. */ > - return dump_context::get ().forcibly_enable_optinfo_p (); > + return (dump_context::get ().forcibly_enable_optinfo_p () > + || flag_remarks); > } > > /* Return true if any of the active optinfo destinations make use > diff --git a/gcc/optinfo.h b/gcc/optinfo.h > index 0d49823..8a8f812 100644 > --- a/gcc/optinfo.h > +++ b/gcc/optinfo.h > @@ -27,9 +27,7 @@ along with GCC; see the file COPYING3. If not see > > * as a "remark" through the diagnostics subsystem > > - * saved to a file as an "optimization record" > - > - Currently no such destinations are implemented. > + * saved to a file as an "optimization record" (not yet implemented) > > They are generated in response to calls to the "dump_*" API in > dumpfile.h; repeated calls to the "dump_*" API are consolidated > diff --git a/gcc/opts.c b/gcc/opts.c > index ed102c0..5cc8801 100644 > --- a/gcc/opts.c > +++ b/gcc/opts.c > @@ -1435,6 +1435,9 @@ print_specific_help (unsigned int include_flags, > case CL_WARNING: > description = _("The following options control compiler warning > messages"); > break; > + case CL_REMARK: > + description = _("The following options control compiler remarks"); > + break; > case CL_OPTIMIZATION: > description = _("The following options control optimizations"); > break; > @@ -1875,6 +1878,7 @@ common_handle_option (struct gcc_options *opts, > { "optimizers", CL_OPTIMIZATION }, > { "target", CL_TARGET }, > { "warnings", CL_WARNING }, > + { "remarks", CL_REMARK }, > { "undocumented", CL_UNDOCUMENTED }, > { "params", CL_PARAMS }, > { "joined", CL_JOINED }, > diff --git a/gcc/opts.h b/gcc/opts.h > index 3c4065ea..d9df788 100644 > --- a/gcc/opts.h > +++ b/gcc/opts.h > @@ -137,20 +137,21 @@ extern const unsigned int cl_lang_count; > #define CL_DRIVER (1U << 19) /* Driver option. */ > #define CL_TARGET (1U << 20) /* Target-specific option. */ > #define CL_COMMON (1U << 21) /* Language-independent. */ > +#define CL_REMARK (1U << 22) /* Enables an (optional) remark. > */ > > #define CL_MIN_OPTION_CLASS CL_PARAMS > -#define CL_MAX_OPTION_CLASS CL_COMMON > +#define CL_MAX_OPTION_CLASS CL_REMARK > > /* From here on the bits describe attributes of the options. > Before this point the bits have described the class of the option. > This distinction is important because --help will not list options > which only have these higher bits set. */ > > -#define CL_JOINED (1U << 22) /* If takes joined argument. */ > -#define CL_SEPARATE (1U << 23) /* If takes a separate argument. > */ > -#define CL_UNDOCUMENTED (1U << 24) /* Do not output with > --help. */ > -#define CL_NO_DWARF_RECORD (1U << 25) /* Do not add to producer string. > */ > -#define CL_PCH_IGNORE (1U << 26) /* Do compare state for pch. */ > +#define CL_JOINED (1U << 23) /* If takes joined argument. */ > +#define CL_SEPARATE (1U << 24) /* If takes a separate argument. > */ > +#define CL_UNDOCUMENTED (1U << 25) /* Do not output with > --help. */ > +#define CL_NO_DWARF_RECORD (1U << 26) /* Do not add to producer string. > */ > +#define CL_PCH_IGNORE (1U << 27) /* Do compare state for pch. */ > > /* Flags for an enumerated option argument. */ > #define CL_ENUM_CANONICAL (1 << 0) /* Canonical for this value. */ > diff --git a/gcc/profile-count.c b/gcc/profile-count.c > index 3d411cf..6a17f5e 100644 > --- a/gcc/profile-count.c > +++ b/gcc/profile-count.c > @@ -33,6 +33,34 @@ along with GCC; see the file COPYING3. If not see > #include "wide-int.h" > #include "sreal.h" > > +/* Get a string describing QUALITY. */ > + > +const char * > +profile_quality_as_string (enum profile_quality quality) > +{ > + switch (quality) > + { > + default: > + gcc_unreachable (); > + case profile_uninitialized: > + return "uninitialized"; > + case profile_guessed_local: > + return "guessed_local"; > + case profile_guessed_global0: > + return "guessed_global0"; > + case profile_guessed_global0adjusted: > + return "guessed_global0adjusted"; > + case profile_guessed: > + return "guessed"; > + case profile_afdo: > + return "afdo"; > + case profile_adjusted: > + return "adjusted"; > + case profile_precise: > + return "precise"; > + } > +} > + > /* Dump THIS to F. */ > > void > diff --git a/gcc/profile-count.h b/gcc/profile-count.h > index c83fa3b..f4d0c340 100644 > --- a/gcc/profile-count.h > +++ b/gcc/profile-count.h > @@ -59,6 +59,8 @@ enum profile_quality { > profile_precise > }; > > +extern const char *profile_quality_as_string (enum profile_quality); > + > /* The base value for branch probability notes and edge probabilities. */ > #define REG_BR_PROB_BASE 10000 > > @@ -721,6 +723,9 @@ public: > return m_quality == profile_precise; > } > > + /* Get the quality of the count. */ > + enum profile_quality quality () const { return m_quality; } > + > /* When merging basic blocks, the two different profile counts are unified. > Return true if this can be done without losing info about profile. > The only case we care about here is when first BB contains something > diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c > index 989c50a..c0acf19 100644 > --- a/gcc/selftest-run-tests.c > +++ b/gcc/selftest-run-tests.c > @@ -73,6 +73,7 @@ selftest::run_tests () > unique_ptr_tests_cc_tests (); > opt_proposer_c_tests (); > optinfo_cc_tests (); > + optinfo_emit_diagnostics_cc_tests (); > > /* Mid-level data structures. */ > input_c_tests (); > diff --git a/gcc/selftest.h b/gcc/selftest.h > index 48881c9..1594d1d 100644 > --- a/gcc/selftest.h > +++ b/gcc/selftest.h > @@ -229,6 +229,7 @@ extern void hash_map_tests_c_tests (); > extern void hash_set_tests_c_tests (); > extern void input_c_tests (); > extern void optinfo_cc_tests (); > +extern void optinfo_emit_diagnostics_cc_tests (); > extern void predict_c_tests (); > extern void pretty_print_c_tests (); > extern void read_rtl_function_c_tests (); > diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp > b/gcc/testsuite/gcc.dg/plugin/plugin.exp > index 5a19fc9..1f0a079 100644 > --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp > +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp > @@ -96,6 +96,8 @@ set plugin_test_list [list \ > must-tail-call-2.c } \ > { expensive_selftests_plugin.c \ > expensive-selftests-1.c } \ > + { remarks_plugin.c \ > + remarks-1.c } \ > ] > > foreach plugin_test $plugin_test_list { > diff --git a/gcc/testsuite/gcc.dg/plugin/remarks-1.c > b/gcc/testsuite/gcc.dg/plugin/remarks-1.c > new file mode 100644 > index 0000000..9139b9d > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/plugin/remarks-1.c > @@ -0,0 +1,30 @@ > +/* { dg-do compile } */ > +/* { dg-options "-fremarks" } */ > + > +extern void test_string_literal (void); > +extern void test_tree (void); > +extern void test_gimple (int); > +extern void test_cgraph_node (void); > +extern void test_printf (void); > +extern void test_wide_int (void); > +extern void test_poly_int (void); > +extern void test_scopes (void); > + > +void test_remarks (void) > +{ > + test_string_literal (); /* { dg-remark "test of remark for > test_string_literal" } */ > + test_tree (); /* { dg-remark "test of tree: '0'" } */ > + test_gimple (42); /* { dg-remark "test of gimple: 'test_gimple \\(42\\);'" > } */ > + test_cgraph_node (); /* { dg-remark "test of callgraph node: > 'test_cgraph_node/.*'" } */ > + test_printf (); /* { dg-remark "test of optinfo printf: 42" } */ > + test_wide_int (); /* { dg-remark "test of wide int: 0" } */ > + test_poly_int (); /* { dg-remark "test of poly int: 42" } */ > + > + test_scopes (); /* { dg-line test_scopes_line } */ > + /* { dg-remark "=== outer scope ===" "" { target *-*-* } test_scopes_line > } */ > + /* { dg-remark " at outer scope" "" { target *-*-* } test_scopes_line } */ > + /* { dg-remark " === middle scope ===" "" { target *-*-* } > test_scopes_line } */ > + /* { dg-remark " at middle scope" "" { target *-*-* } test_scopes_line } > */ > + /* { dg-remark " === innermost scope ===" "" { target *-*-* } > test_scopes_line } */ > + /* { dg-remark " at innermost scope" "" { target *-*-* } > test_scopes_line } */ > +} > diff --git a/gcc/testsuite/gcc.dg/plugin/remarks_plugin.c > b/gcc/testsuite/gcc.dg/plugin/remarks_plugin.c > new file mode 100644 > index 0000000..332bba6 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/plugin/remarks_plugin.c > @@ -0,0 +1,152 @@ > +/* Test of remark-emission by optinfo. */ > + > +#include "gcc-plugin.h" > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > +#include "tree.h" > +#include "tree-pass.h" > +#include "intl.h" > +#include "plugin-version.h" > +#include "diagnostic.h" > +#include "context.h" > +#include "optinfo.h" > +#include "gimple.h" > +#include "gimple-iterator.h" > +#include "cgraph.h" > + > +int plugin_is_GPL_compatible; > + > +const pass_data pass_data_test_remarks = > +{ > + GIMPLE_PASS, /* type */ > + "test_remarks", /* name */ > + OPTGROUP_NONE, /* optinfo_flags */ > + TV_NONE, /* tv_id */ > + PROP_ssa, /* properties_required */ > + 0, /* properties_provided */ > + 0, /* properties_destroyed */ > + 0, /* todo_flags_start */ > + 0, /* todo_flags_finish */ > +}; > + > +class pass_test_remarks : public gimple_opt_pass > +{ > +public: > + pass_test_remarks(gcc::context *ctxt) > + : gimple_opt_pass(pass_data_test_remarks, ctxt) > + {} > + > + /* opt_pass methods: */ > + bool gate (function *) { return true; } > + virtual unsigned int execute (function *); > + > +}; // class pass_test_remarks > + > +unsigned int > +pass_test_remarks::execute (function *fun) > +{ > + basic_block bb; > + > + if (!dump_enabled_p ()) > + return 0; > + > + FOR_ALL_BB_FN (bb, fun) > + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); > + !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gimple *stmt = gsi_stmt (gsi); > + gcall *call = dyn_cast <gcall *> (stmt); > + if (!call) > + continue; > + tree callee_decl = gimple_call_fndecl (call); > + if (!callee_decl) > + continue; > + tree callee_name = DECL_NAME (callee_decl); > + if (!callee_name) > + continue; > + const char *callee = IDENTIFIER_POINTER (callee_name); > + > + /* Various optinfo tests, done at callsites, > + controlled by the callee name. */ > + if (strcmp (callee, "test_string_literal") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of remark for "); > + dump_printf (MSG_NOTE, callee); > + } > + else if (strcmp (callee, "test_tree") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of tree: "); > + dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); > + } > + else if (strcmp (callee, "test_gimple") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of gimple: "); > + dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0); > + } > + else if (strcmp (callee, "test_cgraph_node") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of callgraph node: "); > + dump_symtab_node (MSG_NOTE, cgraph_node::get (callee_decl)); > + } > + else if (strcmp (callee, "test_printf") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of optinfo printf: %d", > 42); > + } > + else if (strcmp (callee, "test_wide_int") == 0) > + { > + HOST_WIDE_INT val = 0; > + dump_printf_loc (MSG_NOTE, stmt, > + "test of wide int: " HOST_WIDE_INT_PRINT_DEC, > + val); > + } > + else if (strcmp (callee, "test_poly_int") == 0) > + { > + dump_printf_loc (MSG_NOTE, stmt, "test of poly int: "); > + dump_dec (MSG_NOTE, poly_int64 (42)); > + } > + else if (strcmp (callee, "test_scopes") == 0) > + { > + AUTO_DUMP_SCOPE ("outer scope", stmt); > + { > + dump_printf_loc (MSG_NOTE, stmt, "at outer scope"); > + AUTO_DUMP_SCOPE ("middle scope", stmt); > + { > + dump_printf_loc (MSG_NOTE, stmt, "at middle scope"); > + AUTO_DUMP_SCOPE ("innermost scope", stmt); > + dump_printf_loc (MSG_NOTE, stmt, "at innermost scope"); > + } > + } > + } > + } > + > + return 0; > +} > + > +static gimple_opt_pass * > +make_pass_test_remarks (gcc::context *ctxt) > +{ > + return new pass_test_remarks (ctxt); > +} > + > +int > +plugin_init (struct plugin_name_args *plugin_info, > + struct plugin_gcc_version *version) > +{ > + struct register_pass_info pass_info; > + const char *plugin_name = plugin_info->base_name; > + int argc = plugin_info->argc; > + struct plugin_argument *argv = plugin_info->argv; > + > + if (!plugin_default_version_check (version, &gcc_version)) > + return 1; > + > + pass_info.pass = make_pass_test_remarks (g); > + pass_info.reference_pass_name = "ssa"; > + pass_info.ref_pass_instance_number = 1; > + pass_info.pos_op = PASS_POS_INSERT_AFTER; > + register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, > + &pass_info); > + > + return 0; > +} > diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp > index a15c5d5..906ee3b 100644 > --- a/gcc/testsuite/lib/gcc-dg.exp > +++ b/gcc/testsuite/lib/gcc-dg.exp > @@ -1154,6 +1154,15 @@ proc dg-locus { args } { > verbose "process-message:\n${dg-messages}" 2 > } > > +# Handle remarks. > + > +proc dg-remark { args } { > + # Make this variable available here and to the saved proc. > + upvar dg-messages dg-messages > + > + process-message saved-dg-error "remark: " "$args" > +} > + > # Check the existence of a gdb in the path, and return true if there > # is one. > # > -- > 1.8.5.3 >