On Mon, Jul 2, 2018 at 10:51 PM David Malcolm <[email protected]> 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 <[email protected]>.
> +
> +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 <[email protected]>.
> +
> +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
>