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 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 > >