On Wed, Jul 11, 2018 at 12:53 PM David Malcolm <dmalc...@redhat.com> wrote: > > Changes relative to v4: > * eliminated optinfo subclasses as discussed > * eliminated optinfo-internal.h, moving what remained into optinfo.h > * added support for dump_gimple_expr_loc and dump_gimple_expr > * more selftests > > 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 (I'm focussing on that destination > in this patch kit, rather than 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?
dump_context::get ().dump_symtab_node and friends is a bit visually disturbing. They are well-hidden so I guess I simply look away for a second ;) Otherwise looks very good now, thus... ... OK. Thanks and sorry for the delay in reviewing. 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". > (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. > Start a new optinfo and add the stmt to it. > (dump_gimple_expr): Move implementation to... > (dump_context::dump_gimple_expr): ...this new member function. > Add the stmt to any pending optinfo, creating one if need be. > (dump_gimple_expr_loc): Move implementation to... > (dump_context::dump_gimple_expr_loc): ...this new member function. > 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. > 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::verify_item): New function. > (ASSERT_IS_TEXT): New macro. > (ASSERT_IS_TREE): New macro. > (ASSERT_IS_GIMPLE): New macro. > (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. > * optinfo.cc: New file. > * optinfo.h: New file. > --- > gcc/Makefile.in | 1 + > gcc/coretypes.h | 7 + > gcc/dump-context.h | 138 +++++++++++++ > gcc/dumpfile.c | 597 > +++++++++++++++++++++++++++++++++++++++++++++++++---- > gcc/dumpfile.h | 84 +++++--- > gcc/optinfo.cc | 236 +++++++++++++++++++++ > gcc/optinfo.h | 203 ++++++++++++++++++ > 7 files changed, 1200 insertions(+), 66 deletions(-) > create mode 100644 gcc/dump-context.h > create mode 100644 gcc/optinfo.cc > create mode 100644 gcc/optinfo.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 2a05a66..dd1dfc1 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1427,6 +1427,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..a191e3a > --- /dev/null > +++ b/gcc/dump-context.h > @@ -0,0 +1,138 @@ > +/* 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_gimple_expr (dump_flags_t dump_kind, > + dump_flags_t extra_dump_flags, > + gimple *gs, int spc); > + > + void dump_gimple_expr_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 7ed1796..38f9539 100644 > --- a/gcc/dumpfile.c > +++ b/gcc/dumpfile.c > @@ -33,6 +33,10 @@ 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". */ > > /* If non-NULL, return one past-the-end of the matching SUBPART of > the WHOLE string. */ > @@ -64,7 +68,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 +77,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 +88,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 +464,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_gimple_stmt (gs, spc, dump_flags | 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,6 +515,13 @@ 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_gimple_stmt (gs, spc, dump_flags | extra_dump_flags); > + } > } > > /* Dump gimple statement GS with SPC indentation spaces and > @@ -497,21 +529,32 @@ dump_gimple_stmt_loc (dump_flags_t dump_kind, const > dump_location_t &loc, > Do not terminate with a newline or semicolon. */ > > void > -dump_gimple_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > - gimple *gs, int spc) > +dump_context::dump_gimple_expr (dump_flags_t dump_kind, > + dump_flags_t extra_dump_flags, > + gimple *gs, int spc) > { > if (dump_file && (dump_kind & pflags)) > print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags); > > if (alt_dump_file && (dump_kind & alt_flags)) > print_gimple_expr (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_gimple_expr (gs, spc, dump_flags | extra_dump_flags); > + } > } > > /* Similar to dump_gimple_expr, except additionally print source location. > */ > > void > -dump_gimple_expr_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_expr_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)) > @@ -525,6 +568,13 @@ dump_gimple_expr_loc (dump_flags_t dump_kind, const > dump_location_t &loc, > dump_loc (dump_kind, alt_dump_file, srcloc); > print_gimple_expr (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_gimple_expr (gs, spc, dump_flags | extra_dump_flags); > + } > } > > > @@ -532,14 +582,22 @@ dump_gimple_expr_loc (dump_flags_t dump_kind, const > dump_location_t &loc, > 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, dump_flags | extra_dump_flags); > + } > } > > > @@ -547,8 +605,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)) > @@ -562,53 +622,83 @@ 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, dump_flags | 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); > } > } > > @@ -616,7 +706,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; > @@ -625,6 +715,224 @@ 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 gimple statement GS with SPC indentation spaces and > + EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. > + Do not terminate with a newline or semicolon. */ > + > +void > +dump_gimple_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, > + gimple *gs, int spc) > +{ > + dump_context::get ().dump_gimple_expr (dump_kind, extra_dump_flags, gs, > spc); > +} > + > +/* Similar to dump_gimple_expr, except additionally print source location. > */ > + > +void > +dump_gimple_expr_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_expr_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 &); > @@ -655,29 +963,42 @@ dump_hex (dump_flags_t dump_kind, const poly_wide_int > &value) > print_hex (value, alt_dump_file); > } > > -/* 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. */ > @@ -685,7 +1006,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 > @@ -1238,6 +1559,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 > @@ -1274,12 +1613,188 @@ test_impl_location () > #endif > } > > +/* Verify that ITEM has the expected values. */ > + > +static void > +verify_item (const location &loc, > + const optinfo_item *item, > + enum optinfo_item_kind expected_kind, > + location_t expected_location, > + const char *expected_text) > +{ > + ASSERT_EQ_AT (loc, item->get_kind (), expected_kind); > + ASSERT_EQ_AT (loc, item->get_location (), expected_location); > + ASSERT_STREQ_AT (loc, item->get_text (), expected_text); > +} > + > +/* Verify that ITEM is a text item, with EXPECTED_TEXT. */ > + > +#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \ > + SELFTEST_BEGIN_STMT \ > + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \ > + UNKNOWN_LOCATION, (EXPECTED_TEXT)); \ > + SELFTEST_END_STMT > + > +/* Verify that ITEM is a tree item, with the expected values. */ > + > +#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ > + SELFTEST_BEGIN_STMT \ > + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \ > + (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ > + SELFTEST_END_STMT > + > +/* Verify that ITEM is a gimple item, with the expected values. */ > + > +#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ > + SELFTEST_BEGIN_STMT \ > + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \ > + (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ > + SELFTEST_END_STMT > + > +/* Verify that calls to the dump_* API are captured and consolidated into > + optimization records. */ > + > +static void > +test_capture_of_dump_calls (const line_table_case &case_) > +{ > + /* Generate a location_t for testing. */ > + line_table_test ltt (case_); > + linemap_add (line_table, LC_ENTER, false, "test.txt", 0); > + linemap_line_start (line_table, 5, 100); > + linemap_add (line_table, LC_LEAVE, false, NULL, 0); > + location_t where = linemap_position_for_column (line_table, 10); > + > + dump_location_t loc = dump_location_t::from_location_t (where); > + > + /* Test of dump_printf. */ > + { > + temp_dump_context tmp (true); > + dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo"); > + > + 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_TEXT (info->get_item (0), "int: 42 str: foo"); > + } > + > + /* 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_location_t (), where); > + 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), UNKNOWN_LOCATION, "0"); > + } > + > + /* 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_location_t (), where); > + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); > + ASSERT_EQ (info->num_items (), 1); > + ASSERT_IS_TREE (info->get_item (0), UNKNOWN_LOCATION, "1"); > + } > + > + /* Gimple. */ > + { > + greturn *stmt = gimple_build_return (NULL); > + gimple_set_location (stmt, where); > + > + /* dump_gimple_stmt_loc. */ > + { > + temp_dump_context tmp (true); > + dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2); > + > + optinfo *info = tmp.get_pending_optinfo (); > + ASSERT_TRUE (info != NULL); > + ASSERT_EQ (info->num_items (), 1); > + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;\n"); > + } > + > + /* dump_gimple_stmt. */ > + { > + temp_dump_context tmp (true); > + dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2); > + > + optinfo *info = tmp.get_pending_optinfo (); > + ASSERT_TRUE (info != NULL); > + ASSERT_EQ (info->num_items (), 1); > + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;\n"); > + } > + > + /* dump_gimple_expr_loc. */ > + { > + temp_dump_context tmp (true); > + dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2); > + > + optinfo *info = tmp.get_pending_optinfo (); > + ASSERT_TRUE (info != NULL); > + ASSERT_EQ (info->num_items (), 1); > + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;"); > + } > + > + /* dump_gimple_expr. */ > + { > + temp_dump_context tmp (true); > + dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2); > + > + optinfo *info = tmp.get_pending_optinfo (); > + ASSERT_TRUE (info != NULL); > + ASSERT_EQ (info->num_items (), 1); > + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;"); > + } > + } > + > + /* 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 (); > + for_each_line_table_case (test_capture_of_dump_calls); > } > > } // namespace selftest > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h > index 4a71ef7..3096a89 100644 > --- a/gcc/dumpfile.h > +++ b/gcc/dumpfile.h > @@ -420,6 +420,48 @@ 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); > + > +/* Global variables used to communicate with passes. */ > +extern FILE *dump_file; > +extern dump_flags_t dump_flags; > +extern const char *dump_file_name; > + > +extern bool dumps_are_enabled; > + > +extern void set_dump_file (FILE *new_dump_file); > + > +/* Return true if any of the dumps is enabled, false otherwise. */ > +static inline bool > +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; > @@ -434,37 +476,14 @@ extern void dump_gimple_stmt (dump_flags_t, > dump_flags_t, gimple *, int); > extern void dump_gimple_expr_loc (dump_flags_t, const dump_location_t &, > dump_flags_t, gimple *, int); > extern void dump_gimple_expr (dump_flags_t, dump_flags_t, gimple *, int); > -extern void print_combine_total_stats (void); > -extern bool enable_rtl_dump_file (void); > +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 dump_dec (dump_flags_t, const poly_wide_int &, signop); > extern void dump_hex (dump_flags_t, const poly_wide_int &); > > -/* 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; > -extern dump_flags_t dump_flags; > -extern const char *dump_file_name; > - > -extern bool dumps_are_enabled; > - > -extern void set_dump_file (FILE *new_dump_file); > - > -/* Return true if any of the dumps is enabled, false otherwise. */ > -static inline bool > -dump_enabled_p (void) > -{ > - return dumps_are_enabled; > -} > +extern void dumpfile_ensure_any_optinfo_are_flushed (); > > /* Managing nested scopes, so that dumps can express the call chain > leading to a dump message. */ > @@ -505,8 +524,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/optinfo.cc b/gcc/optinfo.cc > new file mode 100644 > index 0000000..6f224bc > --- /dev/null > +++ b/gcc/optinfo.cc > @@ -0,0 +1,236 @@ > +/* 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 "dump-context.h" > +#include "pretty-print.h" > +#include "gimple-pretty-print.h" > +#include "cgraph.h" > +#include "selftest.h" > + > +/* optinfo_item's ctor. */ > + > +optinfo_item::optinfo_item (enum optinfo_item_kind kind, location_t location, > + char *text, bool owned) > +: m_kind (kind), m_location (location), m_text (text), m_owned (owned) > +{ > +} > + > +/* optinfo_item's dtor. */ > + > +optinfo_item::~optinfo_item () > +{ > + if (m_owned) > + free (m_text); > +} > + > +/* 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 () > +{ > + /* 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 (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, > + 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 (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, > + formatted_text, true); > + m_items.safe_push (item); > +} > + > +/* Append a gimple statement to this optinfo, equivalent to > + print_gimple_stmt. */ > + > +void > +optinfo::add_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags) > +{ > + pretty_printer pp; > + pp_needs_newline (&pp) = true; > + pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags); > + pp_newline (&pp); > + > + optinfo_item *item > + = new optinfo_item (OPTINFO_ITEM_KIND_GIMPLE, gimple_location (stmt), > + xstrdup (pp_formatted_text (&pp)), true); > + m_items.safe_push (item); > +} > + > +/* Append a gimple statement to this optinfo, equivalent to > + print_gimple_expr. */ > + > +void > +optinfo::add_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags) > +{ > + dump_flags |= TDF_RHS_ONLY; > + pretty_printer pp; > + pp_needs_newline (&pp) = true; > + pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags); > + > + optinfo_item *item > + = new optinfo_item (OPTINFO_ITEM_KIND_GIMPLE, gimple_location (stmt), > + xstrdup (pp_formatted_text (&pp)), true); > + m_items.safe_push (item); > +} > + > +/* Append a tree node to this optinfo, equivalent to print_generic_expr. */ > + > +void > +optinfo::add_tree (tree node, dump_flags_t dump_flags) > +{ > + pretty_printer pp; > + pp_needs_newline (&pp) = true; > + pp_translate_identifiers (&pp) = false; > + dump_generic_node (&pp, node, 0, dump_flags, false); > + > + location_t loc = UNKNOWN_LOCATION; > + if (EXPR_HAS_LOCATION (node)) > + loc = EXPR_LOCATION (node); > + > + optinfo_item *item > + = new optinfo_item (OPTINFO_ITEM_KIND_TREE, loc, > + xstrdup (pp_formatted_text (&pp)), true); > + m_items.safe_push (item); > +} > + > +/* Append a symbol table node to this optinfo. */ > + > +void > +optinfo::add_symtab_node (symtab_node *node) > +{ > + location_t loc = DECL_SOURCE_LOCATION (node->decl); > + optinfo_item *item > + = new optinfo_item (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc, > + xstrdup (node->dump_name ()), true); > + m_items.safe_push (item); > +} > + > +/* 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 (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, > + 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; > +} > diff --git a/gcc/optinfo.h b/gcc/optinfo.h > new file mode 100644 > index 0000000..5bdb9eb > --- /dev/null > +++ b/gcc/optinfo.h > @@ -0,0 +1,203 @@ > +/* 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) > + > + 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_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags); > + void add_gimple_expr (gimple *stmt, int spc, 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; > +}; > + > +/* An enum for discriminating between different kinds of optinfo_item. */ > + > +enum optinfo_item_kind > +{ > + OPTINFO_ITEM_KIND_TEXT, > + OPTINFO_ITEM_KIND_TREE, > + OPTINFO_ITEM_KIND_GIMPLE, > + OPTINFO_ITEM_KIND_SYMTAB_NODE > +}; > + > +/* An item within an optinfo. */ > + > +class optinfo_item > +{ > + public: > + optinfo_item (enum optinfo_item_kind kind, location_t location, > + char *text, bool owned); > + ~optinfo_item (); > + > + enum optinfo_item_kind get_kind () const { return m_kind; } > + location_t get_location () const { return m_location; } > + const char *get_text () const { return m_text; } > + > + private: > + /* Metadata (e.g. for optimization records). */ > + enum optinfo_item_kind m_kind; > + location_t m_location; > + > + /* The textual form of the item. */ > + char *m_text; > + bool m_owned; > +}; > + > +#endif /* #ifndef GCC_OPTINFO_H */ > -- > 1.8.5.3 >