On Tue, Jul 10, 2018 at 1:00 PM David Malcolm <dmalc...@redhat.com> wrote: > > On Mon, 2018-07-09 at 15:00 +0200, Richard Biener wrote: > > On Mon, Jul 2, 2018 at 10:51 PM David Malcolm <dmalc...@redhat.com> > > wrote: > > > > > > This patch implements a way to consolidate dump_* calls into > > > optinfo objects, as enabling work towards being able to write out > > > optimization records to a file, or emit them as diagnostic > > > "remarks". > > > > > > The patch adds the support for building optinfo instances from > > > dump_* > > > calls, but leaves implementing any *users* of them to followup > > > patches. > > > > > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > > > > > > OK for trunk? > > > > Looks good overall, but ... > > > > To "fix" the GC issue you'd need to capture all possibly interesting > > information from tree/gimple while it is still in flight. This _may_ > > be > > necessary anyway since I remember writing code like > > > > fprintf (dump_file, "old: "); > > print_gimple_stmt (..., stmt); > > gimple_set_rhs1 (stmt, op); > > fprintf (dump_file, "new: "); > > print_gmple_stmt (..., stmt); > > fprintf (dump_file, "\n"); > > > > capturing interesting information means we know all targeted > > optinfo channels, right? And the optinfo consumers > > need to handle "streams" of input and may not look back. > > > I've yet have to look at the 2nd patch but can you comment on > > this? How difficult is it to re-wire how the data flows to make > > stmt re-use like the above possible? > > I *think* it's doable: rather than capture, say, a gimple *, the > optinfo_item would capture the result of pp_gimple_stmt_1, plus some > metadata. In fact, it would probably allow for removing the > optinfo_item subclasses, making optinfo_item concrete, containing > something like: > > /* Textual form. */ > char *m_text; > bool m_ownership_of_text; > > /* Metadata for optimization records. */ > enum optinfo_item_kind m_kind; > location_t m_location; > > or somesuch. > > I'll have a go at implementing this.
Thanks, that would be much cleaner (if also a bit more fugly when you need to debug things) Richard. > Thanks > Dave > > > Thanks, > > Richard. > > > > > gcc/ChangeLog: > > > * Makefile.in (OBJS): Add optinfo.o. > > > * coretypes.h (class symtab_node): New forward decl. > > > (struct cgraph_node): New forward decl. > > > (class varpool_node): New forward decl. > > > * dump-context.h: New file. > > > * dumpfile.c: Include "optinfo.h", "dump-context.h", > > > "cgraph.h", > > > "tree-pass.h", "optinfo-internal.h". > > > (refresh_dumps_are_enabled): Use optinfo_enabled_p. > > > (set_dump_file): Call > > > dumpfile_ensure_any_optinfo_are_flushed. > > > (set_alt_dump_file): Likewise. > > > (dump_context::~dump_context): New dtor. > > > (dump_gimple_stmt): Move implementation to... > > > (dump_context::dump_gimple_stmt): ...this new member > > > function. > > > 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 member > > > function. > > > 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 member > > > function. > > > Add the tree to any pending optinfo, creating one if need > > > be. > > > (dump_generic_expr_loc): Move implementation to... > > > (dump_context::dump_generic_expr_loc): ...this new member > > > function. Add the tree to any pending optinfo, creating > > > one if > > > need be. > > > (dump_printf): Move implementation to... > > > (dump_context::dump_printf_va): ...this new member > > > function. 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 member > > > function. > > > 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 member function. Add > > > the > > > value to any pending optinfo, creating one if need be. > > > (dump_context::dump_symtab_node): New member function. > > > (dump_context::get_scope_depth): New member function. > > > (dump_context::begin_scope): New member function. > > > (dump_context::end_scope): New member function. > > > (dump_context::ensure_pending_optinfo): New member > > > function. > > > (dump_context::begin_next_optinfo): New member function. > > > (dump_context::end_any_optinfo): New member function. > > > (dump_context::s_current): New global. > > > (dump_context::s_default): New global. > > > (dump_scope_depth): Delete global. > > > (dumpfile_ensure_any_optinfo_are_flushed): New function. > > > (dump_symtab_node): New function. > > > (get_dump_scope_depth): Reimplement in terms of > > > dump_context. > > > (dump_begin_scope): Likewise. > > > (dump_end_scope): Likewise. > > > (selftest::temp_dump_context::temp_dump_context): New ctor. > > > (selftest::temp_dump_context::~temp_dump_context): New > > > dtor. > > > (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): Call it. > > > * dumpfile.h (dump_printf, dump_printf_loc, > > > dump_basic_block, > > > dump_generic_expr_loc, dump_generic_expr, > > > dump_gimple_stmt_loc, > > > dump_gimple_stmt, dump_dec): Gather these related decls and > > > add a > > > descriptive comment. > > > (dump_function, print_combine_total_stats, > > > enable_rtl_dump_file, > > > dump_node, dump_bb): Move these unrelated decls. > > > (class dump_manager): Add leading comment. > > > * ggc-page.c (ggc_collect): Call > > > dumpfile_ensure_any_optinfo_are_flushed. > > > * optinfo-internal.h: New file. > > > * optinfo.cc: New file. > > > * optinfo.h: New file. > > > * selftest-run-tests.c (selftest::run_tests): Call > > > selftest::optinfo_cc_tests. > > > * selftest.h (selftest::optinfo_cc_tests): New decl. > > > --- > > > gcc/Makefile.in | 1 + > > > gcc/coretypes.h | 7 + > > > gcc/dump-context.h | 128 ++++++++++++ > > > gcc/dumpfile.c | 498 > > > +++++++++++++++++++++++++++++++++++++++++++---- > > > gcc/dumpfile.h | 82 +++++--- > > > gcc/ggc-page.c | 2 + > > > gcc/optinfo-internal.h | 148 ++++++++++++++ > > > gcc/optinfo.cc | 251 ++++++++++++++++++++++++ > > > gcc/optinfo.h | 175 +++++++++++++++++ > > > gcc/selftest-run-tests.c | 1 + > > > gcc/selftest.h | 1 + > > > 11 files changed, 1233 insertions(+), 61 deletions(-) > > > create mode 100644 gcc/dump-context.h > > > create mode 100644 gcc/optinfo-internal.h > > > create mode 100644 gcc/optinfo.cc > > > create mode 100644 gcc/optinfo.h > > > > > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > > > index 66c8b6e..7d36a77 100644 > > > --- a/gcc/Makefile.in > > > +++ b/gcc/Makefile.in > > > @@ -1426,6 +1426,7 @@ OBJS = \ > > > optabs-libfuncs.o \ > > > optabs-query.o \ > > > optabs-tree.o \ > > > + optinfo.o \ > > > options-save.o \ > > > opts-global.o \ > > > passes.o \ > > > diff --git a/gcc/coretypes.h b/gcc/coretypes.h > > > index 283b4eb..ed0e825 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, 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; > > > diff --git a/gcc/dump-context.h b/gcc/dump-context.h > > > new file mode 100644 > > > index 0000000..753f714 > > > --- /dev/null > > > +++ b/gcc/dump-context.h > > > @@ -0,0 +1,128 @@ > > > +/* Support code for handling the various dump_* calls in > > > dumpfile.h > > > + 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_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_generic_expr_loc (dump_flags_t dump_kind, > > > + const dump_location_t &loc, > > > + 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 (); > > > + > > > + /* For use in selftests; if true then optinfo_enabled_p is > > > true. */ > > > + bool forcibly_enable_optinfo_p () const > > > + { > > > + return m_forcibly_enable_optinfo; > > > + } > > > + > > > + void end_any_optinfo (); > > > + > > > + private: > > > + optinfo &ensure_pending_optinfo (); > > > + optinfo &begin_next_optinfo (const dump_location_t &loc); > > > + > > > + /* For use in selftests; if true then optinfo_enabled_p is > > > true. */ > > > + bool m_forcibly_enable_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-style class for use in selftests for temporarily using > > > a different > > > + dump_context. */ > > > + > > > +class temp_dump_context > > > +{ > > > + public: > > > + temp_dump_context (bool forcibly_enable_optinfo); > > > + ~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 5f69f9b..6e089ef 100644 > > > --- a/gcc/dumpfile.c > > > +++ b/gcc/dumpfile.c > > > @@ -33,6 +33,11 @@ along with GCC; see the file COPYING3. If not > > > see > > > #include "gimple.h" /* for dump_user_location_t ctor. */ > > > #include "rtl.h" /* for dump_user_location_t ctor. */ > > > #include "selftest.h" > > > +#include "optinfo.h" > > > +#include "dump-context.h" > > > +#include "cgraph.h" > > > +#include "tree-pass.h" /* for "current_pass". */ > > > +#include "optinfo-internal.h" /* for selftests. */ > > > > > > /* If non-NULL, return one past-the-end of the matching SUBPART of > > > the WHOLE string. */ > > > @@ -64,7 +69,7 @@ bool dumps_are_enabled = false; > > > static void > > > refresh_dumps_are_enabled () > > > { > > > - dumps_are_enabled = (dump_file || alt_dump_file); > > > + dumps_are_enabled = (dump_file || alt_dump_file || > > > optinfo_enabled_p ()); > > > } > > > > > > /* Set global "dump_file" to NEW_DUMP_FILE, refreshing the > > > "dumps_are_enabled" > > > @@ -73,6 +78,7 @@ refresh_dumps_are_enabled () > > > void > > > set_dump_file (FILE *new_dump_file) > > > { > > > + dumpfile_ensure_any_optinfo_are_flushed (); > > > dump_file = new_dump_file; > > > refresh_dumps_are_enabled (); > > > } > > > @@ -83,6 +89,7 @@ set_dump_file (FILE *new_dump_file) > > > static void > > > set_alt_dump_file (FILE *new_alt_dump_file) > > > { > > > + dumpfile_ensure_any_optinfo_are_flushed (); > > > alt_dump_file = new_alt_dump_file; > > > refresh_dumps_are_enabled (); > > > } > > > @@ -458,25 +465,44 @@ dump_loc (dump_flags_t dump_kind, FILE > > > *dfile, source_location loc) > > > } > > > } > > > > > > +/* Implementation of dump_context member functions. */ > > > + > > > +/* 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, const > > > dump_location_t &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)) > > > @@ -490,20 +516,35 @@ dump_gimple_stmt_loc (dump_flags_t dump_kind, > > > const dump_location_t &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); > > > + } > > > } > > > > > > > > > @@ -511,8 +552,10 @@ dump_generic_expr (dump_flags_t dump_kind, > > > dump_flags_t extra_dump_flags, > > > location. */ > > > > > > void > > > -dump_generic_expr_loc (dump_flags_t dump_kind, const > > > dump_location_t &loc, > > > - dump_flags_t extra_dump_flags, tree t) > > > +dump_context::dump_generic_expr_loc (dump_flags_t dump_kind, > > > + const dump_location_t &loc, > > > + dump_flags_t extra_dump_flags, > > > + tree t) > > > { > > > location_t srcloc = loc.get_location_t (); > > > if (dump_file && (dump_kind & pflags)) > > > @@ -526,53 +569,82 @@ dump_generic_expr_loc (dump_flags_t > > > dump_kind, const dump_location_t &loc, > > > dump_loc (dump_kind, alt_dump_file, srcloc); > > > print_generic_expr (alt_dump_file, t, dump_flags | > > > extra_dump_flags); > > > } > > > + > > > + if (optinfo_enabled_p ()) > > > + { > > > + optinfo &info = begin_next_optinfo (loc); > > > + info.handle_dump_file_kind (dump_kind); > > > + info.add_tree (t, extra_dump_flags); > > > + } > > > } > > > > > > /* Output a formatted message using FORMAT on appropriate dump > > > streams. */ > > > > > > void > > > -dump_printf (dump_flags_t dump_kind, const char *format, ...) > > > +dump_context::dump_printf_va (dump_flags_t dump_kind, const char > > > *format, > > > + va_list ap) > > > { > > > if (dump_file && (dump_kind & pflags)) > > > { > > > - va_list ap; > > > - va_start (ap, format); > > > - vfprintf (dump_file, format, ap); > > > - va_end (ap); > > > + 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); > > > + 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); > > > } > > > } > > > > > > -/* Similar to dump_printf, except source location is also > > > printed. */ > > > +/* 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, ...) > > > +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; > > > dump_loc (dump_kind, dump_file, srcloc); > > > - va_start (ap, format); > > > - vfprintf (dump_file, format, ap); > > > - va_end (ap); > > > + 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; > > > dump_loc (dump_kind, alt_dump_file, srcloc); > > > - va_start (ap, format); > > > - vfprintf (alt_dump_file, format, ap); > > > - va_end (ap); > > > + 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); > > > } > > > } > > > > > > @@ -580,7 +652,7 @@ dump_printf_loc (dump_flags_t dump_kind, const > > > dump_location_t &loc, > > > > > > template<unsigned int N, typename C> > > > void > > > -dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value) > > > +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; > > > @@ -589,6 +661,203 @@ dump_dec (dump_flags_t dump_kind, const > > > poly_int<N, C> &value) > > > > > > if (alt_dump_file && (dump_kind & alt_flags)) > > > print_dec (value, alt_dump_file, sgn); > > > + > > > + if (optinfo_enabled_p ()) > > > + { > > > + 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 ()) > > > + { > > > + 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 -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. > > > + Emit a "scope" optinfo 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--; > > > +} > > > + > > > +/* 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 to any destinations as appropriate - though none have > > > currently been > > > + implemented. */ > > > + > > > +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 > > > + member functions. */ > > > + > > > +/* 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); > > > +} > > > + > > > +/* Similar to dump_generic_expr, except additionally print the > > > source > > > + location. */ > > > + > > > +void > > > +dump_generic_expr_loc (dump_flags_t dump_kind, const > > > dump_location_t &loc, > > > + dump_flags_t extra_dump_flags, tree t) > > > +{ > > > + dump_context::get ().dump_generic_expr_loc (dump_kind, loc, > > > 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) > > > +{ > > > + dump_context::get ().dump_dec (dump_kind, value); > > > } > > > > > > template void dump_dec (dump_flags_t, const poly_uint16 &); > > > @@ -597,29 +866,42 @@ 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 &); > > > > > > -/* The current dump scope-nesting depth. */ > > > +/* Emit and delete the currently pending optinfo, if there is one, > > > + without the caller needing to know about class > > > dump_context. */ > > > + > > > +void > > > +dumpfile_ensure_any_optinfo_are_flushed () > > > +{ > > > + dump_context::get().end_any_optinfo (); > > > +} > > > + > > > +/* Output the name of NODE on appropriate dump streams. */ > > > > > > -static int dump_scope_depth; > > > +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 dump_*_loc (for showing nesting via > > > indentation). */ > > > + For use by -fopt-info (for showing nesting via > > > indentation). */ > > > > > > unsigned int > > > get_dump_scope_depth () > > > { > > > - return 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. > > > + Emit a "scope" opinfo if optinfos are enabled. > > > Increment the scope depth. */ > > > > > > void > > > dump_begin_scope (const char *name, const dump_location_t &loc) > > > { > > > - dump_printf_loc (MSG_NOTE, loc, "=== %s ===\n", name); > > > - dump_scope_depth++; > > > + dump_context::get ().begin_scope (name, loc); > > > } > > > > > > /* Pop a nested dump scope. */ > > > @@ -627,7 +909,7 @@ dump_begin_scope (const char *name, const > > > dump_location_t &loc) > > > void > > > dump_end_scope () > > > { > > > - dump_scope_depth--; > > > + dump_context::get ().end_scope (); > > > } > > > > > > /* Start a dump for PHASE. Store user-supplied dump flags in > > > @@ -1180,6 +1462,24 @@ enable_rtl_dump_file (void) > > > > > > #if CHECKING_P > > > > > > +/* temp_dump_context's ctor. Temporarily override the > > > dump_context > > > + (to forcibly enable optinfo-generation). */ > > > + > > > +temp_dump_context::temp_dump_context (bool > > > forcibly_enable_optinfo) > > > +: m_context (), > > > + m_saved (&dump_context ().get ()) > > > +{ > > > + dump_context::s_current = &m_context; > > > + m_context.m_forcibly_enable_optinfo = forcibly_enable_optinfo; > > > +} > > > + > > > +/* temp_dump_context's dtor. Restore the saved dump_context. */ > > > + > > > +temp_dump_context::~temp_dump_context () > > > +{ > > > + dump_context::s_current = m_saved; > > > +} > > > + > > > namespace selftest { > > > > > > /* Verify that the dump_location_t constructors capture the source > > > location > > > @@ -1216,12 +1516,136 @@ test_impl_location () > > > #endif > > > } > > > > > > +/* Verify that ITEM is a text item, with EXPECTED_TEXT. */ > > > + > > > +static void > > > +assert_is_text (const optinfo_item *item, const char > > > *expected_text) > > > +{ > > > + ASSERT_EQ (item->get_kind (), OPTINFO_ITEM_KIND_TEXT); > > > + const optinfo_item_text * text_item > > > + = static_cast <const optinfo_item_text *> (item); > > > + ASSERT_STREQ (text_item->get_text (), expected_text); > > > +} > > > + > > > +/* Verify that ITEM is a tree item, with the expected values. */ > > > + > > > +static void > > > +assert_is_tree (const optinfo_item *item, tree expected_tree, > > > + dump_flags_t expected_dump_flags) > > > +{ > > > + ASSERT_EQ (item->get_kind (), OPTINFO_ITEM_KIND_TREE); > > > + const optinfo_item_tree * tree_item > > > + = static_cast <const optinfo_item_tree *> (item); > > > + ASSERT_EQ (tree_item->get_node (), expected_tree); > > > + ASSERT_EQ (tree_item->get_flags (), expected_dump_flags); > > > +} > > > + > > > +/* Verify that ITEM is a gimple item, with the expected > > > values. */ > > > + > > > +static void > > > +assert_is_gimple (const optinfo_item *item, gimple *expected_stmt, > > > + dump_flags_t expected_dump_flags) > > > +{ > > > + ASSERT_EQ (item->get_kind (), OPTINFO_ITEM_KIND_GIMPLE); > > > + const optinfo_item_gimple * gimple_item > > > + = static_cast <const optinfo_item_gimple *> (item); > > > + ASSERT_EQ (gimple_item->get_stmt (), expected_stmt); > > > + ASSERT_EQ (gimple_item->get_flags (), expected_dump_flags); > > > +} > > > + > > > +/* Verify that calls to the dump_* API are captured and > > > consolidated into > > > + optimization records. */ > > > + > > > +static void > > > +test_capture_of_dump_calls () > > > +{ > > > + dump_location_t loc; > > > + > > > + /* Tree, via dump_generic_expr. */ > > > + { > > > + temp_dump_context tmp (true); > > > + 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); > > > + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); > > > + ASSERT_EQ (info->num_items (), 2); > > > + assert_is_text (info->get_item (0), "test of tree: "); > > > + assert_is_tree (info->get_item (1), integer_zero_node, > > > TDF_SLIM); > > > + } > > > + > > > + /* Tree, via dump_generic_expr_loc. */ > > > + { > > > + temp_dump_context tmp (true); > > > + dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, > > > integer_one_node); > > > + > > > + optinfo *info = tmp.get_pending_optinfo (); > > > + ASSERT_TRUE (info != NULL); > > > + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); > > > + ASSERT_EQ (info->num_items (), 1); > > > + assert_is_tree (info->get_item (0), integer_one_node, > > > TDF_SLIM); > > > + } > > > + > > > + /* Gimple. */ > > > + { > > > + greturn *stmt = gimple_build_return (NULL); > > > + > > > + temp_dump_context tmp (true); > > > + dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 0); > > > + > > > + optinfo *info = tmp.get_pending_optinfo (); > > > + ASSERT_TRUE (info != NULL); > > > + ASSERT_EQ (info->num_items (), 1); > > > + assert_is_gimple (info->get_item (0), stmt, TDF_SLIM); > > > + > > > + /* Verify that optinfo instances are flushed if a GC is about > > > to > > > + happen (and thus don't need to be GTY-marked). > > > + We don't want them in the PCH file, but we don't want the > > > + items to have their data collected from under them. */ > > > + selftest::forcibly_ggc_collect (); > > > + ASSERT_TRUE (tmp.get_pending_optinfo () == NULL); > > > + } > > > + > > > + /* poly_int. */ > > > + { > > > + temp_dump_context tmp (true); > > > + dump_dec (MSG_NOTE, poly_int64 (42)); > > > + > > > + optinfo *info = tmp.get_pending_optinfo (); > > > + ASSERT_TRUE (info != NULL); > > > + ASSERT_EQ (info->num_items (), 1); > > > + assert_is_text (info->get_item (0), "42"); > > > + } > > > + > > > + /* Verify that MSG_* affects optinfo->get_kind (); we tested > > > MSG_NOTE > > > + above. */ > > > + { > > > + /* MSG_OPTIMIZED_LOCATIONS. */ > > > + { > > > + temp_dump_context tmp (true); > > > + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test"); > > > + ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), > > > + OPTINFO_KIND_SUCCESS); > > > + } > > > + > > > + /* MSG_MISSED_OPTIMIZATION. */ > > > + { > > > + temp_dump_context tmp (true); > > > + dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test"); > > > + ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), > > > + OPTINFO_KIND_FAILURE); > > > + } > > > + } > > > +} > > > + > > > /* Run all of the selftests within this file. */ > > > > > > void > > > dumpfile_c_tests () > > > { > > > test_impl_location (); > > > + test_capture_of_dump_calls (); > > > } > > > > > > } // namespace selftest > > > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h > > > index 0e588a6..899bb89 100644 > > > --- a/gcc/dumpfile.h > > > +++ b/gcc/dumpfile.h > > > @@ -420,30 +420,6 @@ extern FILE *dump_begin (int, dump_flags_t *); > > > extern void dump_end (int, FILE *); > > > extern int opt_info_switch_p (const char *); > > > extern const char *dump_flag_name (int); > > > -extern void dump_printf (dump_flags_t, const char *, ...) > > > ATTRIBUTE_PRINTF_2; > > > -extern void dump_printf_loc (dump_flags_t, const dump_location_t > > > &, > > > - const char *, ...) ATTRIBUTE_PRINTF_3; > > > -extern void dump_function (int phase, tree fn); > > > -extern void dump_basic_block (dump_flags_t, basic_block, int); > > > -extern void dump_generic_expr_loc (dump_flags_t, const > > > dump_location_t &, > > > - dump_flags_t, tree); > > > -extern void dump_generic_expr (dump_flags_t, dump_flags_t, tree); > > > -extern void dump_gimple_stmt_loc (dump_flags_t, const > > > dump_location_t &, > > > - dump_flags_t, gimple *, int); > > > -extern void dump_gimple_stmt (dump_flags_t, dump_flags_t, gimple > > > *, int); > > > -extern void print_combine_total_stats (void); > > > -extern bool enable_rtl_dump_file (void); > > > - > > > -template<unsigned int N, typename C> > > > -void dump_dec (dump_flags_t, const poly_int<N, C> &); > > > - > > > -/* In tree-dump.c */ > > > -extern void dump_node (const_tree, dump_flags_t, FILE *); > > > - > > > -/* In combine.c */ > > > -extern void dump_combine_total_stats (FILE *); > > > -/* In cfghooks.c */ > > > -extern void dump_bb (FILE *, basic_block, int, dump_flags_t); > > > > > > /* Global variables used to communicate with passes. */ > > > extern FILE *dump_file; > > > @@ -461,6 +437,49 @@ dump_enabled_p (void) > > > return dumps_are_enabled; > > > } > > > > > > +/* The following API calls (which *don't* take a "FILE *") > > > + write the output to zero or more locations: > > > + (a) the active dump_file, if any > > > + (b) the -fopt-info destination, if any > > > + (c) to the "optinfo" destinations, if any: > > > + > > > + dump_* (MSG_*) --> dumpfile.c --+--> (a) dump_file > > > + | > > > + +--> (b) alt_dump_file > > > + | > > > + `--> (c) optinfo > > > + `---> optinfo > > > destinations > > > + > > > + For optinfos, the dump_*_loc mark the beginning of an optinfo > > > + instance: all subsequent dump_* calls are consolidated into > > > + that optinfo, until the next dump_*_loc call (or a change in > > > + dump scope, or a call to > > > dumpfile_ensure_any_optinfo_are_flushed). > > > + > > > + A group of dump_* calls should be guarded by: > > > + > > > + if (dump_enabled_p ()) > > > + > > > + to minimize the work done for the common case where dumps > > > + are disabled. */ > > > + > > > +extern void dump_printf (dump_flags_t, const char *, ...) > > > ATTRIBUTE_PRINTF_2; > > > +extern void dump_printf_loc (dump_flags_t, const dump_location_t > > > &, > > > + const char *, ...) ATTRIBUTE_PRINTF_3; > > > +extern void dump_function (int phase, tree fn); > > > +extern void dump_basic_block (dump_flags_t, basic_block, int); > > > +extern void dump_generic_expr (dump_flags_t, dump_flags_t, tree); > > > +extern void dump_generic_expr_loc (dump_flags_t, const > > > dump_location_t &, > > > + dump_flags_t, tree); > > > +extern void dump_gimple_stmt_loc (dump_flags_t, const > > > dump_location_t &, > > > + dump_flags_t, gimple *, int); > > > +extern void dump_gimple_stmt (dump_flags_t, dump_flags_t, gimple > > > *, int); > > > +extern void dump_symtab_node (dump_flags_t, symtab_node *); > > > + > > > +template<unsigned int N, typename C> > > > +void dump_dec (dump_flags_t, const poly_int<N, C> &); > > > + > > > +extern void dumpfile_ensure_any_optinfo_are_flushed (); > > > + > > > /* Managing nested scopes, so that dumps can express the call > > > chain > > > leading to a dump message. */ > > > > > > @@ -500,8 +519,23 @@ class auto_dump_scope > > > #define AUTO_DUMP_SCOPE(NAME, LOC) \ > > > auto_dump_scope scope (NAME, LOC) > > > > > > +extern void dump_function (int phase, tree fn); > > > +extern void print_combine_total_stats (void); > > > +extern bool enable_rtl_dump_file (void); > > > + > > > +/* In tree-dump.c */ > > > +extern void dump_node (const_tree, dump_flags_t, FILE *); > > > + > > > +/* In combine.c */ > > > +extern void dump_combine_total_stats (FILE *); > > > +/* In cfghooks.c */ > > > +extern void dump_bb (FILE *, basic_block, int, dump_flags_t); > > > + > > > namespace gcc { > > > > > > +/* A class for managing all of the various dump files used by the > > > + optimization passes. */ > > > + > > > class dump_manager > > > { > > > public: > > > diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c > > > index 51783e5..f3a2119 100644 > > > --- a/gcc/ggc-page.c > > > +++ b/gcc/ggc-page.c > > > @@ -2177,6 +2177,8 @@ ggc_collect (void) > > > if (G.allocated < allocated_last_gc + min_expand && > > > !ggc_force_collect) > > > return; > > > > > > + dumpfile_ensure_any_optinfo_are_flushed (); > > > + > > > timevar_push (TV_GC); > > > if (!quiet_flag) > > > fprintf (stderr, " {GC %luk -> ", (unsigned long) G.allocated > > > / 1024); > > > diff --git a/gcc/optinfo-internal.h b/gcc/optinfo-internal.h > > > new file mode 100644 > > > index 0000000..8144174 > > > --- /dev/null > > > +++ b/gcc/optinfo-internal.h > > > @@ -0,0 +1,148 @@ > > > +/* Implementation details of optinfo. > > > + 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_INTERNAL_H > > > +#define GCC_OPTINFO_INTERNAL_H > > > + > > > +/* Multiple dispatch: there are various kinds of items within an > > > optinfo, > > > + and various destinations to send optinfo to. > > > + > > > + Handling this for now by exposing all of the item subclasses, > > > + and having the destinations handle them with "switch" > > > statements. */ > > > + > > > +/* An enum for discriminating between optinfo_item subclasses. */ > > > + > > > +enum optinfo_item_kind > > > +{ > > > + OPTINFO_ITEM_KIND_TEXT, > > > + OPTINFO_ITEM_KIND_TREE, > > > + OPTINFO_ITEM_KIND_GIMPLE, > > > + OPTINFO_ITEM_KIND_SYMTAB_NODE > > > +}; > > > + > > > +/* Abstract base class for items within an optinfo. */ > > > + > > > +class optinfo_item > > > +{ > > > + public: > > > + virtual ~optinfo_item () {} > > > + > > > + virtual enum optinfo_item_kind get_kind () const = 0; > > > +}; > > > + > > > +/* optinfo_item subclasses. */ > > > + > > > +/* Item within an optinfo: text, either owned by the item > > > + (for optinfo_printf), or borrowed (for string literals). */ > > > + > > > +class optinfo_item_text : public optinfo_item > > > +{ > > > + public: > > > + optinfo_item_text (char *text, bool owned) > > > + : m_text (text), m_owned (owned) > > > + {} > > > + ~optinfo_item_text () > > > + { > > > + if (m_owned) > > > + free (m_text); > > > + } > > > + > > > + enum optinfo_item_kind get_kind () const FINAL OVERRIDE > > > + { > > > + return OPTINFO_ITEM_KIND_TEXT; > > > + } > > > + > > > + const char *get_text () const { return m_text; } > > > + > > > + void trim_trailing_whitespace (); > > > + > > > + private: > > > + char *m_text; > > > + bool m_owned; > > > +}; > > > + > > > +/* Item within an optinfo: a tree, with dump flags. > > > + Note that this is not GTY-marked; see the description of > > > + class optinfo for a discussion of the interaction with the > > > + garbage-collector. */ > > > + > > > +class optinfo_item_tree : public optinfo_item > > > +{ > > > + public: > > > + optinfo_item_tree (tree node, dump_flags_t dump_flags) > > > + : m_node (node), m_dump_flags (dump_flags) > > > + {} > > > + enum optinfo_item_kind get_kind () const FINAL OVERRIDE > > > + { > > > + return OPTINFO_ITEM_KIND_TREE; > > > + } > > > + > > > + tree get_node () const { return m_node; } > > > + dump_flags_t get_flags () const { return m_dump_flags; } > > > + > > > + private: > > > + tree m_node; > > > + dump_flags_t m_dump_flags; > > > +}; > > > + > > > +/* Item within an optinfo: a gimple statement. > > > + Note that this is not GTY-marked; see the description of > > > + class optinfo for a discussion of the interaction with the > > > + garbage-collector. */ > > > + > > > +class optinfo_item_gimple : public optinfo_item > > > +{ > > > + public: > > > + optinfo_item_gimple (gimple *stmt, dump_flags_t dump_flags) > > > + : m_stmt (stmt), m_dump_flags (dump_flags) {} > > > + enum optinfo_item_kind get_kind () const FINAL OVERRIDE > > > + { > > > + return OPTINFO_ITEM_KIND_GIMPLE; > > > + } > > > + > > > + gimple *get_stmt () const { return m_stmt; } > > > + dump_flags_t get_flags () const { return m_dump_flags; } > > > + > > > + private: > > > + gimple *m_stmt; > > > + dump_flags_t m_dump_flags; > > > +}; > > > + > > > +/* Item within an optinfo: a symbol table node. > > > + Note that this is not GTY-marked; see the description of > > > + class optinfo for a discussion of the interaction with the > > > + garbage-collector. */ > > > + > > > +class optinfo_item_symtab_node : public optinfo_item > > > +{ > > > + public: > > > + optinfo_item_symtab_node (symtab_node *node) : m_node (node) {} > > > + enum optinfo_item_kind get_kind () const FINAL OVERRIDE > > > + { > > > + return OPTINFO_ITEM_KIND_SYMTAB_NODE; > > > + } > > > + > > > + symtab_node *get_node () const { return m_node; } > > > + > > > + private: > > > + symtab_node *m_node; > > > +}; > > > + > > > +#endif /* #ifndef GCC_OPTINFO_INTERNAL_H */ > > > diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc > > > new file mode 100644 > > > index 0000000..1da7d37 > > > --- /dev/null > > > +++ b/gcc/optinfo.cc > > > @@ -0,0 +1,251 @@ > > > +/* Optimization information. > > > + 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 "gimple.h" > > > + > > > +#include "optinfo.h" > > > +#include "optinfo-internal.h" > > > +#include "dump-context.h" > > > +#include "selftest.h" > > > + > > > +/* Remove any trailing whitespace characters from this text item. > > > + Primarily for use in stripping trailing newline characters when > > > + emitting remarks (since the diagnostic subsystem doesn't expect > > > + trailing newlines in messages). */ > > > + > > > +void > > > +optinfo_item_text::trim_trailing_whitespace () > > > +{ > > > + size_t len = strlen (m_text); > > > + if (len == 0) > > > + return; > > > + > > > + size_t new_len = len; > > > + while (new_len > 0 && ISSPACE (m_text[new_len - 1])) > > > + new_len--; > > > + > > > + if (new_len == len) > > > + return; > > > + > > > + if (m_owned) > > > + m_text[new_len] = '\0'; > > > + else > > > + { > > > + m_text = xstrndup (m_text, new_len); > > > + m_owned = true; > > > + } > > > +} > > > + > > > +/* Get a string from KIND. */ > > > + > > > +const char * > > > +optinfo_kind_to_string (enum optinfo_kind kind) > > > +{ > > > + switch (kind) > > > + { > > > + default: > > > + gcc_unreachable (); > > > + case OPTINFO_KIND_SUCCESS: > > > + return "success"; > > > + case OPTINFO_KIND_FAILURE: > > > + return "failure"; > > > + case OPTINFO_KIND_NOTE: > > > + return "note"; > > > + case OPTINFO_KIND_SCOPE: > > > + return "scope"; > > > + } > > > +} > > > + > > > +/* optinfo's dtor. */ > > > + > > > +optinfo::~optinfo () > > > +{ > > > + /* Cleanup. */ > > > + unsigned i; > > > + optinfo_item *item; > > > + FOR_EACH_VEC_ELT (m_items, i, item) > > > + delete item; > > > +} > > > + > > > +/* Emit the optinfo to all of the active destinations. */ > > > + > > > +void > > > +optinfo::emit () > > > +{ > > > + /* Eliminate any trailing whitespace. */ > > > + while (m_items.length () > 0) > > > + { > > > + optinfo_item *last_item = m_items[m_items.length () - 1]; > > > + if (last_item->get_kind () != OPTINFO_ITEM_KIND_TEXT) > > > + break; > > > + > > > + optinfo_item_text *last_text = (optinfo_item_text > > > *)last_item; > > > + last_text->trim_trailing_whitespace (); > > > + > > > + if (strlen (last_text->get_text ()) > 0) > > > + break; > > > + > > > + m_items.pop (); > > > + delete last_item; > > > + } > > > + > > > + /* currently this is a no-op. */ > > > +} > > > + > > > +/* Update the optinfo's kind based on DUMP_KIND. */ > > > + > > > +void > > > +optinfo::handle_dump_file_kind (dump_flags_t dump_kind) > > > +{ > > > + if (dump_kind & MSG_OPTIMIZED_LOCATIONS) > > > + m_kind = OPTINFO_KIND_SUCCESS; > > > + else if (dump_kind & MSG_MISSED_OPTIMIZATION) > > > + m_kind = OPTINFO_KIND_FAILURE; > > > + else if (dump_kind & MSG_NOTE) > > > + m_kind = OPTINFO_KIND_NOTE; > > > +} > > > + > > > +/* Append a string literal to this optinfo. */ > > > + > > > +void > > > +optinfo::add_string (const char *str) > > > +{ > > > + optinfo_item *item > > > + = new optinfo_item_text (const_cast <char *> (str), false); > > > + m_items.safe_push (item); > > > +} > > > + > > > +/* Append printf-formatted text to this optinfo. */ > > > + > > > +void > > > +optinfo::add_printf (const char *format, ...) > > > +{ > > > + va_list ap; > > > + va_start (ap, format); > > > + add_printf_va (format, ap); > > > + va_end (ap); > > > +} > > > + > > > +/* Append printf-formatted text to this optinfo. */ > > > + > > > +void > > > +optinfo::add_printf_va (const char *format, va_list ap) > > > +{ > > > + char *formatted_text = xvasprintf (format, ap); > > > + optinfo_item *item > > > + = new optinfo_item_text (formatted_text, true); > > > + m_items.safe_push (item); > > > +} > > > + > > > +/* Append a gimple statement to this optinfo. */ > > > + > > > +void > > > +optinfo::add_stmt (gimple *stmt, dump_flags_t dump_flags) > > > +{ > > > + m_items.safe_push (new optinfo_item_gimple (stmt, dump_flags)); > > > +} > > > + > > > +/* Append a tree node to this optinfo. */ > > > + > > > +void > > > +optinfo::add_tree (tree node, dump_flags_t dump_flags) > > > +{ > > > + m_items.safe_push (new optinfo_item_tree (node, dump_flags)); > > > +} > > > + > > > +/* Append a symbol table node to this optinfo. */ > > > + > > > +void > > > +optinfo::add_symtab_node (symtab_node *node) > > > +{ > > > + m_items.safe_push (new optinfo_item_symtab_node (node)); > > > +} > > > + > > > +/* Append the decimal represenation of a wide_int_ref to this > > > + optinfo. */ > > > + > > > +void > > > +optinfo::add_dec (const wide_int_ref &wi, signop sgn) > > > +{ > > > + char buf[WIDE_INT_PRINT_BUFFER_SIZE]; > > > + print_dec (wi, buf, sgn); > > > + optinfo_item *item > > > + = new optinfo_item_text (xstrdup (buf), true); > > > + m_items.safe_push (item); > > > +} > > > + > > > +/* Should optinfo instances be created? > > > + All creation of optinfos should be guarded by this predicate. > > > + Return true if any optinfo destinations are active. */ > > > + > > > +bool optinfo_enabled_p () > > > +{ > > > + /* Currently no destinations are implemented, just a hook for > > > + selftests. */ > > > + return dump_context::get ().forcibly_enable_optinfo_p (); > > > +} > > > + > > > +/* Return true if any of the active optinfo destinations make use > > > + of inlining information. > > > + (if true, then the information is preserved). */ > > > + > > > +bool optinfo_wants_inlining_info_p () > > > +{ > > > + return false; > > > +} > > > + > > > +#if CHECKING_P > > > + > > > +namespace selftest { > > > + > > > +/* Verify that optinfo_item_text::trim_trailing_whitespace turns > > > + INPUT into EXPECTED. */ > > > + > > > +static void > > > +test_trim_trailing_whitespace (const char *input, const char > > > *expected) > > > +{ > > > + optinfo_item_text item (const_cast <char *> (input), false); > > > + item.trim_trailing_whitespace (); > > > + ASSERT_STREQ (item.get_text (), expected); > > > +} > > > + > > > +/* Run all of the selftests within this file. */ > > > + > > > +void > > > +optinfo_cc_tests () > > > +{ > > > + /* Verify that optinfo_item_text::trim_trailing_whitespace > > > works. */ > > > + test_trim_trailing_whitespace ("", ""); > > > + test_trim_trailing_whitespace ("\n", ""); > > > + test_trim_trailing_whitespace ("foo", "foo"); > > > + test_trim_trailing_whitespace ("foo\n", "foo"); > > > + test_trim_trailing_whitespace ("foo\n\n", "foo"); > > > + test_trim_trailing_whitespace ("foo bar \n\n", "foo bar"); > > > +} > > > + > > > +} // namespace selftest > > > + > > > +#endif /* CHECKING_P */ > > > diff --git a/gcc/optinfo.h b/gcc/optinfo.h > > > new file mode 100644 > > > index 0000000..0d49823 > > > --- /dev/null > > > +++ b/gcc/optinfo.h > > > @@ -0,0 +1,175 @@ > > > +/* Optimization information. > > > + 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_H > > > +#define GCC_OPTINFO_H > > > + > > > +/* An "optinfo" is a bundle of information describing part of an > > > + optimization, which can be emitted to zero or more of several > > > + destinations, such as: > > > + > > > + * as a "remark" through the diagnostics subsystem > > > + > > > + * saved to a file as an "optimization record" > > > + > > > + Currently no such destinations are implemented. > > > + > > > + They are generated in response to calls to the "dump_*" API in > > > + dumpfile.h; repeated calls to the "dump_*" API are consolidated > > > + into a pending optinfo instance, with a "dump_*_loc" starting a > > > new > > > + optinfo instance. > > > + > > > + The data sent to the dump calls are captured within the pending > > > optinfo > > > + instance as a sequence of optinfo_items. For example, given: > > > + > > > + if (dump_enabled_p ()) > > > + { > > > + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > > > + "not vectorized: live stmt not > > > supported: "); > > > + dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, > > > stmt, 0); > > > + } > > > + > > > + the "dump_printf_loc" call begins a new optinfo containing two > > > items: > > > + (1) a text item containing "not vectorized: live stmt not > > > supported: " > > > + (2) a gimple item for "stmt" > > > + > > > + Dump destinations are thus able to access rich metadata about > > > the > > > + items when the optinfo is emitted to them, rather than just > > > having plain > > > + text. For example, when saving the above optinfo to a file as > > > an > > > + "optimization record", the record could capture the source > > > location of > > > + "stmt" above, rather than just its textual form. > > > + > > > + The currently pending optinfo is emitted and deleted: > > > + * each time a "dump_*_loc" call occurs (which starts the next > > > optinfo), or > > > + * when the dump files are changed (at the end of a pass), or > > > + * when a garbage collection is about to happen. This safety > > > measure > > > + ensures that no GC happens during the lifetime of an optinfo > > > instance, > > > + and thus that any optinfo_items within the optinfo instances > > > can refer > > > + to GC-allocated objects without needing to be GTY-marked: > > > they will never > > > + refer to collected garbage. optinfo and optinfo_item are not > > > GTY-marked > > > + as it would make no sense for them to be in PCH files. > > > + > > > + Dumping to an optinfo instance is non-trivial (due to building > > > optinfo_item > > > + instances), so all usage should be guarded by > > > + > > > + if (optinfo_enabled_p ()) > > > + > > > + which is off by default. */ > > > + > > > + > > > +/* Forward decls. */ > > > +struct opt_pass; > > > +class optinfo_item; /* optinfo-internal.h. */ > > > + > > > +/* Should optinfo instances be created? > > > + All creation of optinfos should be guarded by this predicate. > > > + Return true if any optinfo destinations are active. */ > > > + > > > +extern bool optinfo_enabled_p (); > > > + > > > +/* Return true if any of the active optinfo destinations make use > > > + of inlining information. > > > + (if true, then the information is preserved). */ > > > + > > > +extern bool optinfo_wants_inlining_info_p (); > > > + > > > +/* The various kinds of optinfo. */ > > > + > > > +enum optinfo_kind > > > +{ > > > + OPTINFO_KIND_SUCCESS, > > > + OPTINFO_KIND_FAILURE, > > > + OPTINFO_KIND_NOTE, > > > + OPTINFO_KIND_SCOPE > > > +}; > > > + > > > +extern const char *optinfo_kind_to_string (enum optinfo_kind > > > kind); > > > + > > > +/* A bundle of information describing part of an optimization. */ > > > + > > > +class optinfo > > > +{ > > > + friend class dump_context; > > > + > > > + public: > > > + optinfo (const dump_location_t &loc, > > > + enum optinfo_kind kind, > > > + opt_pass *pass) > > > + : m_loc (loc), m_kind (kind), m_pass (pass), m_items () > > > + {} > > > + ~optinfo (); > > > + > > > + const dump_user_location_t & > > > + get_user_location () const { return m_loc.get_user_location (); > > > } > > > + > > > + const dump_impl_location_t & > > > + get_impl_location () const { return m_loc.get_impl_location (); > > > } > > > + > > > + enum optinfo_kind get_kind () const { return m_kind; } > > > + opt_pass *get_pass () const { return m_pass; } > > > + unsigned int num_items () const { return m_items.length (); } > > > + const optinfo_item *get_item (unsigned int i) const { return > > > m_items[i]; } > > > + > > > + location_t get_location_t () const { return m_loc.get_location_t > > > (); } > > > + profile_count get_count () const { return m_loc.get_count (); } > > > + > > > + private: > > > + void emit (); > > > + > > > + /* Pre-canned ways of manipulating the optinfo, for use by > > > friend class > > > + dump_context. */ > > > + void handle_dump_file_kind (dump_flags_t); > > > + void add_string (const char *str); > > > + void add_printf (const char *format, ...) ATTRIBUTE_PRINTF_2; > > > + void add_printf_va (const char *format, va_list ap) > > > ATTRIBUTE_PRINTF (2, 0); > > > + void add_stmt (gimple *stmt, dump_flags_t dump_flags); > > > + void add_tree (tree node, dump_flags_t dump_flags); > > > + void add_symtab_node (symtab_node *node); > > > + void add_dec (const wide_int_ref &wi, signop sgn); > > > + > > > + template<unsigned int N, typename C> > > > + void add_poly_int (const poly_int<N, C> &value) > > > + { > > > + /* Compare with dump_dec (MSG_NOTE, ). */ > > > + > > > + STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0); > > > + signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : > > > UNSIGNED; > > > + > > > + if (value.is_constant ()) > > > + add_dec (value.coeffs[0], sgn); > > > + else > > > + { > > > + add_string ("["); > > > + for (unsigned int i = 0; i < N; ++i) > > > + { > > > + add_dec (value.coeffs[i], sgn); > > > + add_string (i == N - 1 ? "]" : ","); > > > + } > > > + } > > > + } > > > + > > > + private: > > > + dump_location_t m_loc; > > > + enum optinfo_kind m_kind; > > > + opt_pass *m_pass; > > > + auto_vec <optinfo_item *> m_items; > > > +}; > > > + > > > +#endif /* #ifndef GCC_OPTINFO_H */ > > > diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c > > > index 7f4d6f3..989c50a 100644 > > > --- a/gcc/selftest-run-tests.c > > > +++ b/gcc/selftest-run-tests.c > > > @@ -72,6 +72,7 @@ selftest::run_tests () > > > typed_splay_tree_c_tests (); > > > unique_ptr_tests_cc_tests (); > > > opt_proposer_c_tests (); > > > + optinfo_cc_tests (); > > > > > > /* Mid-level data structures. */ > > > input_c_tests (); > > > diff --git a/gcc/selftest.h b/gcc/selftest.h > > > index 54fc488..48881c9 100644 > > > --- a/gcc/selftest.h > > > +++ b/gcc/selftest.h > > > @@ -228,6 +228,7 @@ extern void gimple_c_tests (); > > > 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 predict_c_tests (); > > > extern void pretty_print_c_tests (); > > > extern void read_rtl_function_c_tests (); > > > -- > > > 1.8.5.3 > > >