From: David Malcolm Date: Thu, 19 Jul 2018 20:49:25 +0000 (+0000) Subject: Add "optinfo" framework X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4df3629eb775ef9a4578c0bed3194565ca30e690;p=gcc.git Add "optinfo" framework 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. The patch adds the support for building optinfo instances from dump_* calls, but leaves implementing any *users* of them to followup patches. 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. From-SVN: r262891 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bb4ed8e3e91..a498df47aba 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,77 @@ +2018-07-19 David Malcolm + + * 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. + 2018-07-19 Michael Collison Richard Henderson diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2a05a66ea9b..dd1dfc1e87c 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 09d2270e188..917fdc9aba1 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 00000000000..a191e3a7133 --- /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 . + +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 +. */ + + +#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 + void dump_dec (dump_flags_t dump_kind, const poly_int &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 4de7d28895d..74b585594df 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 (); } @@ -465,25 +471,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)) @@ -497,6 +522,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 @@ -504,21 +536,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)) @@ -532,6 +575,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); + } } @@ -539,14 +589,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); + } } @@ -554,8 +612,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)) @@ -569,53 +629,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); } } @@ -623,7 +713,7 @@ dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc, template void -dump_dec (dump_flags_t dump_kind, const poly_int &value) +dump_context::dump_dec (dump_flags_t dump_kind, const poly_int &value) { STATIC_ASSERT (poly_coeff_traits::signedness >= 0); signop sgn = poly_coeff_traits::signedness ? SIGNED : UNSIGNED; @@ -632,6 +722,224 @@ dump_dec (dump_flags_t dump_kind, const poly_int &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 (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 +void +dump_dec (dump_flags_t dump_kind, const poly_int &value) +{ + dump_context::get ().dump_dec (dump_kind, value); } template void dump_dec (dump_flags_t, const poly_uint16 &); @@ -662,29 +970,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. */ @@ -692,7 +1013,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 @@ -1249,6 +1570,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 @@ -1285,12 +1624,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 40e3332217e..558351d5122 100644 --- a/gcc/dumpfile.h +++ b/gcc/dumpfile.h @@ -420,6 +420,48 @@ extern FILE *dump_begin (int, dump_flags_t *, int part=-1); 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 void dump_dec (dump_flags_t, const poly_int &); 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 00000000000..6f224bc84ad --- /dev/null +++ b/gcc/optinfo.cc @@ -0,0 +1,236 @@ +/* Optimization information. + Copyright (C) 2018 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#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 (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 00000000000..8fd5202b94d --- /dev/null +++ b/gcc/optinfo.h @@ -0,0 +1,203 @@ +/* Optimization information. + Copyright (C) 2018 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#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; + +/* 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 + void add_poly_int (const poly_int &value) + { + /* Compare with dump_dec (MSG_NOTE, ). */ + + STATIC_ASSERT (poly_coeff_traits::signedness >= 0); + signop sgn = poly_coeff_traits::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 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 */