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