This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PING] Re: [PATCH 1/2] v5: Add "optinfo" framework
Ping, re these patches:
"[PATCH 1/2] v5: Add "optinfo" framework"
https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00535.html
"[PATCH 2/2] Add "-fsave-optimization-record""
https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00536.html
Thanks
Dave
On Wed, 2018-07-11 at 07:37 -0400, David Malcolm 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?
>
> 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 <dmalcolm@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 <dmalcolm@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 <dmalcolm@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 */