From patchwork Wed Jul 11 11:37:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 942425 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-481338-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="EbfOArE5"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41QbXS0Wrcz9s01 for ; Wed, 11 Jul 2018 20:53:43 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=h2zCPN0onaDP+804HGn+YyLtsNrXg8JxWhZz7O+hCG7k//lWIXt0+ iSSs3FMtUBu41RudlPSCUIF8T6VnQnprfu+EdF92Id3Hx+F6VPmUONIsRnQyC8zU qtpswNNsHWB6TrMmMOBYhgXegRHaULGi5SfNU1rcAuWxzXWNcC0tQE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=f6hzMzRA5jfgC76JAzZgxI87GUs=; b=EbfOArE5SVMK9f35kDfd kweIWbBqAMyeD5oUX2zWiZu5vjA5dipN98sxE1Xn/vxkz49Ut6f3hyzaSSLeXCBI 9bAe5DHTLi0VwgkB0EUxqtDrc4zKTp6e4B2eK/plTR5BMHAvtYn/+m/aAGS4GEUN ELdhFMu/KcG+IM/b9Y/GBec= Received: (qmail 105113 invoked by alias); 11 Jul 2018 10:53:34 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 105058 invoked by uid 89); 11 Jul 2018 10:53:32 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=remained, consolidate, terminate X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 11 Jul 2018 10:53:26 +0000 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 861B75D5F9; Wed, 11 Jul 2018 10:53:25 +0000 (UTC) Received: from c64.redhat.com (ovpn-112-31.phx2.redhat.com [10.3.112.31]) by smtp.corp.redhat.com (Postfix) with ESMTP id DD4A93001A49; Wed, 11 Jul 2018 10:53:23 +0000 (UTC) From: David Malcolm To: Richard Biener Cc: GCC Patches , David Malcolm Subject: [PATCH 1/2] v5: Add "optinfo" framework Date: Wed, 11 Jul 2018 07:37:26 -0400 Message-Id: <1531309047-48505-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: References: X-IsSubscribed: yes Changes relative to v4: * eliminated optinfo subclasses as discussed * eliminated optinfo-internal.h, moving what remained into optinfo.h * added support for dump_gimple_expr_loc and dump_gimple_expr * more selftests This patch implements a way to consolidate dump_* calls into optinfo objects, as enabling work towards being able to write out optimization records to a file (I'm focussing on that destination in this patch kit, rather than diagnostic remarks). The patch adds the support for building optinfo instances from dump_* calls, but leaves implementing any *users* of them to followup patches. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. OK for trunk? gcc/ChangeLog: * Makefile.in (OBJS): Add optinfo.o. * coretypes.h (class symtab_node): New forward decl. (struct cgraph_node): New forward decl. (class varpool_node): New forward decl. * dump-context.h: New file. * dumpfile.c: Include "optinfo.h", "dump-context.h", "cgraph.h", "tree-pass.h". (refresh_dumps_are_enabled): Use optinfo_enabled_p. (set_dump_file): Call dumpfile_ensure_any_optinfo_are_flushed. (set_alt_dump_file): Likewise. (dump_context::~dump_context): New dtor. (dump_gimple_stmt): Move implementation to... (dump_context::dump_gimple_stmt): ...this new member function. Add the stmt to any pending optinfo, creating one if need be. (dump_gimple_stmt_loc): Move implementation to... (dump_context::dump_gimple_stmt_loc): ...this new member function. Start a new optinfo and add the stmt to it. (dump_gimple_expr): Move implementation to... (dump_context::dump_gimple_expr): ...this new member function. Add the stmt to any pending optinfo, creating one if need be. (dump_gimple_expr_loc): Move implementation to... (dump_context::dump_gimple_expr_loc): ...this new member function. Start a new optinfo and add the stmt to it. (dump_generic_expr): Move implementation to... (dump_context::dump_generic_expr): ...this new member function. Add the tree to any pending optinfo, creating one if need be. (dump_generic_expr_loc): Move implementation to... (dump_context::dump_generic_expr_loc): ...this new member function. Add the tree to any pending optinfo, creating one if need be. (dump_printf): Move implementation to... (dump_context::dump_printf_va): ...this new member function. Add the text to any pending optinfo, creating one if need be. (dump_printf_loc): Move implementation to... (dump_context::dump_printf_loc_va): ...this new member function. Start a new optinfo and add the stmt to it. (dump_dec): Move implementation to... (dump_context::dump_dec): ...this new member function. Add the value to any pending optinfo, creating one if need be. (dump_context::dump_symtab_node): New member function. (dump_context::get_scope_depth): New member function. (dump_context::begin_scope): New member function. (dump_context::end_scope): New member function. (dump_context::ensure_pending_optinfo): New member function. (dump_context::begin_next_optinfo): New member function. (dump_context::end_any_optinfo): New member function. (dump_context::s_current): New global. (dump_context::s_default): New global. (dump_scope_depth): Delete global. (dumpfile_ensure_any_optinfo_are_flushed): New function. (dump_symtab_node): New function. (get_dump_scope_depth): Reimplement in terms of dump_context. (dump_begin_scope): Likewise. (dump_end_scope): Likewise. (selftest::temp_dump_context::temp_dump_context): New ctor. (selftest::temp_dump_context::~temp_dump_context): New dtor. (selftest::verify_item): New function. (ASSERT_IS_TEXT): New macro. (ASSERT_IS_TREE): New macro. (ASSERT_IS_GIMPLE): New macro. (selftest::test_capture_of_dump_calls): New test. (selftest::dumpfile_c_tests): Call it. * dumpfile.h (dump_printf, dump_printf_loc, dump_basic_block) (dump_generic_expr_loc, dump_generic_expr, dump_gimple_stmt_loc) (dump_gimple_stmt, dump_dec): Gather these related decls and add a descriptive comment. (dump_function, print_combine_total_stats, enable_rtl_dump_file) (dump_node, dump_bb): Move these unrelated decls. (class dump_manager): Add leading comment. * optinfo.cc: New file. * optinfo.h: New file. --- gcc/Makefile.in | 1 + gcc/coretypes.h | 7 + gcc/dump-context.h | 138 +++++++++++++ gcc/dumpfile.c | 597 +++++++++++++++++++++++++++++++++++++++++++++++++---- gcc/dumpfile.h | 84 +++++--- gcc/optinfo.cc | 236 +++++++++++++++++++++ gcc/optinfo.h | 203 ++++++++++++++++++ 7 files changed, 1200 insertions(+), 66 deletions(-) create mode 100644 gcc/dump-context.h create mode 100644 gcc/optinfo.cc create mode 100644 gcc/optinfo.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2a05a66..dd1dfc1 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1427,6 +1427,7 @@ OBJS = \ optabs-libfuncs.o \ optabs-query.o \ optabs-tree.o \ + optinfo.o \ options-save.o \ opts-global.o \ passes.o \ diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 283b4eb..ed0e825 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -134,6 +134,13 @@ struct gomp_single; struct gomp_target; struct gomp_teams; +/* Subclasses of symtab_node, using indentation to show the class + hierarchy. */ + +class symtab_node; + struct cgraph_node; + class varpool_node; + union section; typedef union section section; struct gcc_options; diff --git a/gcc/dump-context.h b/gcc/dump-context.h new file mode 100644 index 0000000..a191e3a --- /dev/null +++ b/gcc/dump-context.h @@ -0,0 +1,138 @@ +/* Support code for handling the various dump_* calls in dumpfile.h + Copyright (C) 2018 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 7ed1796..38f9539 100644 --- a/gcc/dumpfile.c +++ b/gcc/dumpfile.c @@ -33,6 +33,10 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" /* for dump_user_location_t ctor. */ #include "rtl.h" /* for dump_user_location_t ctor. */ #include "selftest.h" +#include "optinfo.h" +#include "dump-context.h" +#include "cgraph.h" +#include "tree-pass.h" /* for "current_pass". */ /* If non-NULL, return one past-the-end of the matching SUBPART of the WHOLE string. */ @@ -64,7 +68,7 @@ bool dumps_are_enabled = false; static void refresh_dumps_are_enabled () { - dumps_are_enabled = (dump_file || alt_dump_file); + dumps_are_enabled = (dump_file || alt_dump_file || optinfo_enabled_p ()); } /* Set global "dump_file" to NEW_DUMP_FILE, refreshing the "dumps_are_enabled" @@ -73,6 +77,7 @@ refresh_dumps_are_enabled () void set_dump_file (FILE *new_dump_file) { + dumpfile_ensure_any_optinfo_are_flushed (); dump_file = new_dump_file; refresh_dumps_are_enabled (); } @@ -83,6 +88,7 @@ set_dump_file (FILE *new_dump_file) static void set_alt_dump_file (FILE *new_alt_dump_file) { + dumpfile_ensure_any_optinfo_are_flushed (); alt_dump_file = new_alt_dump_file; refresh_dumps_are_enabled (); } @@ -458,25 +464,44 @@ dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc) } } +/* Implementation of dump_context member functions. */ + +/* dump_context's dtor. */ + +dump_context::~dump_context () +{ + delete m_pending; +} + /* Dump gimple statement GS with SPC indentation spaces and EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */ void -dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, - gimple *gs, int spc) +dump_context::dump_gimple_stmt (dump_flags_t dump_kind, + dump_flags_t extra_dump_flags, + gimple *gs, int spc) { if (dump_file && (dump_kind & pflags)) print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); if (alt_dump_file && (dump_kind & alt_flags)) print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); + + if (optinfo_enabled_p ()) + { + optinfo &info = ensure_pending_optinfo (); + info.handle_dump_file_kind (dump_kind); + info.add_gimple_stmt (gs, spc, dump_flags | extra_dump_flags); + } } /* Similar to dump_gimple_stmt, except additionally print source location. */ void -dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc, - dump_flags_t extra_dump_flags, gimple *gs, int spc) +dump_context::dump_gimple_stmt_loc (dump_flags_t dump_kind, + const dump_location_t &loc, + dump_flags_t extra_dump_flags, + gimple *gs, int spc) { location_t srcloc = loc.get_location_t (); if (dump_file && (dump_kind & pflags)) @@ -490,6 +515,13 @@ dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc, dump_loc (dump_kind, alt_dump_file, srcloc); print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); } + + if (optinfo_enabled_p ()) + { + optinfo &info = begin_next_optinfo (loc); + info.handle_dump_file_kind (dump_kind); + info.add_gimple_stmt (gs, spc, dump_flags | extra_dump_flags); + } } /* Dump gimple statement GS with SPC indentation spaces and @@ -497,21 +529,32 @@ dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc, Do not terminate with a newline or semicolon. */ void -dump_gimple_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, - gimple *gs, int spc) +dump_context::dump_gimple_expr (dump_flags_t dump_kind, + dump_flags_t extra_dump_flags, + gimple *gs, int spc) { if (dump_file && (dump_kind & pflags)) print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags); if (alt_dump_file && (dump_kind & alt_flags)) print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); + + if (optinfo_enabled_p ()) + { + optinfo &info = ensure_pending_optinfo (); + info.handle_dump_file_kind (dump_kind); + info.add_gimple_expr (gs, spc, dump_flags | extra_dump_flags); + } } /* Similar to dump_gimple_expr, except additionally print source location. */ void -dump_gimple_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc, - dump_flags_t extra_dump_flags, gimple *gs, int spc) +dump_context::dump_gimple_expr_loc (dump_flags_t dump_kind, + const dump_location_t &loc, + dump_flags_t extra_dump_flags, + gimple *gs, + int spc) { location_t srcloc = loc.get_location_t (); if (dump_file && (dump_kind & pflags)) @@ -525,6 +568,13 @@ dump_gimple_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc, dump_loc (dump_kind, alt_dump_file, srcloc); print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); } + + if (optinfo_enabled_p ()) + { + optinfo &info = begin_next_optinfo (loc); + info.handle_dump_file_kind (dump_kind); + info.add_gimple_expr (gs, spc, dump_flags | extra_dump_flags); + } } @@ -532,14 +582,22 @@ dump_gimple_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc, DUMP_KIND is enabled. */ void -dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, - tree t) +dump_context::dump_generic_expr (dump_flags_t dump_kind, + dump_flags_t extra_dump_flags, + tree t) { if (dump_file && (dump_kind & pflags)) print_generic_expr (dump_file, t, dump_flags | extra_dump_flags); if (alt_dump_file && (dump_kind & alt_flags)) print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); + + if (optinfo_enabled_p ()) + { + optinfo &info = ensure_pending_optinfo (); + info.handle_dump_file_kind (dump_kind); + info.add_tree (t, dump_flags | extra_dump_flags); + } } @@ -547,8 +605,10 @@ dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags, location. */ void -dump_generic_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc, - dump_flags_t extra_dump_flags, tree t) +dump_context::dump_generic_expr_loc (dump_flags_t dump_kind, + const dump_location_t &loc, + dump_flags_t extra_dump_flags, + tree t) { location_t srcloc = loc.get_location_t (); if (dump_file && (dump_kind & pflags)) @@ -562,53 +622,83 @@ dump_generic_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc, dump_loc (dump_kind, alt_dump_file, srcloc); print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); } + + if (optinfo_enabled_p ()) + { + optinfo &info = begin_next_optinfo (loc); + info.handle_dump_file_kind (dump_kind); + info.add_tree (t, dump_flags | extra_dump_flags); + } } /* Output a formatted message using FORMAT on appropriate dump streams. */ void -dump_printf (dump_flags_t dump_kind, const char *format, ...) +dump_context::dump_printf_va (dump_flags_t dump_kind, const char *format, + va_list ap) { if (dump_file && (dump_kind & pflags)) { - va_list ap; - va_start (ap, format); - vfprintf (dump_file, format, ap); - va_end (ap); + va_list aq; + va_copy (aq, ap); + vfprintf (dump_file, format, aq); + va_end (aq); } if (alt_dump_file && (dump_kind & alt_flags)) { - va_list ap; - va_start (ap, format); - vfprintf (alt_dump_file, format, ap); - va_end (ap); + va_list aq; + va_copy (aq, ap); + vfprintf (alt_dump_file, format, aq); + va_end (aq); + } + + if (optinfo_enabled_p ()) + { + optinfo &info = ensure_pending_optinfo (); + va_list aq; + va_copy (aq, ap); + info.add_printf_va (format, aq); + va_end (aq); } } -/* Similar to dump_printf, except source location is also printed. */ +/* Similar to dump_printf, except source location is also printed, and + dump location captured. */ void -dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc, - const char *format, ...) +dump_context::dump_printf_loc_va (dump_flags_t dump_kind, + const dump_location_t &loc, + const char *format, va_list ap) { location_t srcloc = loc.get_location_t (); + if (dump_file && (dump_kind & pflags)) { - va_list ap; dump_loc (dump_kind, dump_file, srcloc); - va_start (ap, format); - vfprintf (dump_file, format, ap); - va_end (ap); + va_list aq; + va_copy (aq, ap); + vfprintf (dump_file, format, aq); + va_end (aq); } if (alt_dump_file && (dump_kind & alt_flags)) { - va_list ap; dump_loc (dump_kind, alt_dump_file, srcloc); - va_start (ap, format); - vfprintf (alt_dump_file, format, ap); - va_end (ap); + va_list aq; + va_copy (aq, ap); + vfprintf (alt_dump_file, format, aq); + va_end (aq); + } + + if (optinfo_enabled_p ()) + { + optinfo &info = begin_next_optinfo (loc); + info.handle_dump_file_kind (dump_kind); + va_list aq; + va_copy (aq, ap); + info.add_printf_va (format, aq); + va_end (aq); } } @@ -616,7 +706,7 @@ dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc, template 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; @@ -625,6 +715,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 &); @@ -655,29 +963,42 @@ dump_hex (dump_flags_t dump_kind, const poly_wide_int &value) print_hex (value, alt_dump_file); } -/* The current dump scope-nesting depth. */ +/* Emit and delete the currently pending optinfo, if there is one, + without the caller needing to know about class dump_context. */ + +void +dumpfile_ensure_any_optinfo_are_flushed () +{ + dump_context::get().end_any_optinfo (); +} + +/* Output the name of NODE on appropriate dump streams. */ -static int dump_scope_depth; +void +dump_symtab_node (dump_flags_t dump_kind, symtab_node *node) +{ + dump_context::get ().dump_symtab_node (dump_kind, node); +} /* Get the current dump scope-nesting depth. - For use by dump_*_loc (for showing nesting via indentation). */ + For use by -fopt-info (for showing nesting via indentation). */ unsigned int get_dump_scope_depth () { - return dump_scope_depth; + return dump_context::get ().get_scope_depth (); } /* Push a nested dump scope. Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info destination, if any. + Emit a "scope" opinfo if optinfos are enabled. Increment the scope depth. */ void dump_begin_scope (const char *name, const dump_location_t &loc) { - dump_printf_loc (MSG_NOTE, loc, "=== %s ===\n", name); - dump_scope_depth++; + dump_context::get ().begin_scope (name, loc); } /* Pop a nested dump scope. */ @@ -685,7 +1006,7 @@ dump_begin_scope (const char *name, const dump_location_t &loc) void dump_end_scope () { - dump_scope_depth--; + dump_context::get ().end_scope (); } /* Start a dump for PHASE. Store user-supplied dump flags in @@ -1238,6 +1559,24 @@ enable_rtl_dump_file (void) #if CHECKING_P +/* temp_dump_context's ctor. Temporarily override the dump_context + (to forcibly enable optinfo-generation). */ + +temp_dump_context::temp_dump_context (bool forcibly_enable_optinfo) +: m_context (), + m_saved (&dump_context ().get ()) +{ + dump_context::s_current = &m_context; + m_context.m_forcibly_enable_optinfo = forcibly_enable_optinfo; +} + +/* temp_dump_context's dtor. Restore the saved dump_context. */ + +temp_dump_context::~temp_dump_context () +{ + dump_context::s_current = m_saved; +} + namespace selftest { /* Verify that the dump_location_t constructors capture the source location @@ -1274,12 +1613,188 @@ test_impl_location () #endif } +/* Verify that ITEM has the expected values. */ + +static void +verify_item (const location &loc, + const optinfo_item *item, + enum optinfo_item_kind expected_kind, + location_t expected_location, + const char *expected_text) +{ + ASSERT_EQ_AT (loc, item->get_kind (), expected_kind); + ASSERT_EQ_AT (loc, item->get_location (), expected_location); + ASSERT_STREQ_AT (loc, item->get_text (), expected_text); +} + +/* Verify that ITEM is a text item, with EXPECTED_TEXT. */ + +#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \ + SELFTEST_BEGIN_STMT \ + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \ + UNKNOWN_LOCATION, (EXPECTED_TEXT)); \ + SELFTEST_END_STMT + +/* Verify that ITEM is a tree item, with the expected values. */ + +#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ + SELFTEST_BEGIN_STMT \ + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \ + (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ + SELFTEST_END_STMT + +/* Verify that ITEM is a gimple item, with the expected values. */ + +#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ + SELFTEST_BEGIN_STMT \ + verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \ + (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ + SELFTEST_END_STMT + +/* Verify that calls to the dump_* API are captured and consolidated into + optimization records. */ + +static void +test_capture_of_dump_calls (const line_table_case &case_) +{ + /* Generate a location_t for testing. */ + line_table_test ltt (case_); + linemap_add (line_table, LC_ENTER, false, "test.txt", 0); + linemap_line_start (line_table, 5, 100); + linemap_add (line_table, LC_LEAVE, false, NULL, 0); + location_t where = linemap_position_for_column (line_table, 10); + + dump_location_t loc = dump_location_t::from_location_t (where); + + /* Test of dump_printf. */ + { + temp_dump_context tmp (true); + dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo"); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_TEXT (info->get_item (0), "int: 42 str: foo"); + } + + /* Tree, via dump_generic_expr. */ + { + temp_dump_context tmp (true); + dump_printf_loc (MSG_NOTE, loc, "test of tree: "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->get_location_t (), where); + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->num_items (), 2); + ASSERT_IS_TEXT (info->get_item (0), "test of tree: "); + ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0"); + } + + /* Tree, via dump_generic_expr_loc. */ + { + temp_dump_context tmp (true); + dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->get_location_t (), where); + ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_TREE (info->get_item (0), UNKNOWN_LOCATION, "1"); + } + + /* Gimple. */ + { + greturn *stmt = gimple_build_return (NULL); + gimple_set_location (stmt, where); + + /* dump_gimple_stmt_loc. */ + { + temp_dump_context tmp (true); + dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;\n"); + } + + /* dump_gimple_stmt. */ + { + temp_dump_context tmp (true); + dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;\n"); + } + + /* dump_gimple_expr_loc. */ + { + temp_dump_context tmp (true); + dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;"); + } + + /* dump_gimple_expr. */ + { + temp_dump_context tmp (true); + dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_GIMPLE (info->get_item (0), where, "return;"); + } + } + + /* poly_int. */ + { + temp_dump_context tmp (true); + dump_dec (MSG_NOTE, poly_int64 (42)); + + optinfo *info = tmp.get_pending_optinfo (); + ASSERT_TRUE (info != NULL); + ASSERT_EQ (info->num_items (), 1); + ASSERT_IS_TEXT (info->get_item (0), "42"); + } + + /* Verify that MSG_* affects optinfo->get_kind (); we tested MSG_NOTE + above. */ + { + /* MSG_OPTIMIZED_LOCATIONS. */ + { + temp_dump_context tmp (true); + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test"); + ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), + OPTINFO_KIND_SUCCESS); + } + + /* MSG_MISSED_OPTIMIZATION. */ + { + temp_dump_context tmp (true); + dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test"); + ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), + OPTINFO_KIND_FAILURE); + } + } +} + /* Run all of the selftests within this file. */ void dumpfile_c_tests () { test_impl_location (); + for_each_line_table_case (test_capture_of_dump_calls); } } // namespace selftest diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h index 4a71ef7..3096a89 100644 --- a/gcc/dumpfile.h +++ b/gcc/dumpfile.h @@ -420,6 +420,48 @@ extern FILE *dump_begin (int, dump_flags_t *); extern void dump_end (int, FILE *); extern int opt_info_switch_p (const char *); extern const char *dump_flag_name (int); + +/* Global variables used to communicate with passes. */ +extern FILE *dump_file; +extern dump_flags_t dump_flags; +extern const char *dump_file_name; + +extern bool dumps_are_enabled; + +extern void set_dump_file (FILE *new_dump_file); + +/* Return true if any of the dumps is enabled, false otherwise. */ +static inline bool +dump_enabled_p (void) +{ + return dumps_are_enabled; +} + +/* The following API calls (which *don't* take a "FILE *") + write the output to zero or more locations: + (a) the active dump_file, if any + (b) the -fopt-info destination, if any + (c) to the "optinfo" destinations, if any: + + dump_* (MSG_*) --> dumpfile.c --+--> (a) dump_file + | + +--> (b) alt_dump_file + | + `--> (c) optinfo + `---> optinfo destinations + + For optinfos, the dump_*_loc mark the beginning of an optinfo + instance: all subsequent dump_* calls are consolidated into + that optinfo, until the next dump_*_loc call (or a change in + dump scope, or a call to dumpfile_ensure_any_optinfo_are_flushed). + + A group of dump_* calls should be guarded by: + + if (dump_enabled_p ()) + + to minimize the work done for the common case where dumps + are disabled. */ + extern void dump_printf (dump_flags_t, const char *, ...) ATTRIBUTE_PRINTF_2; extern void dump_printf_loc (dump_flags_t, const dump_location_t &, const char *, ...) ATTRIBUTE_PRINTF_3; @@ -434,37 +476,14 @@ extern void dump_gimple_stmt (dump_flags_t, dump_flags_t, gimple *, int); extern void dump_gimple_expr_loc (dump_flags_t, const dump_location_t &, dump_flags_t, gimple *, int); extern void dump_gimple_expr (dump_flags_t, dump_flags_t, gimple *, int); -extern void print_combine_total_stats (void); -extern bool enable_rtl_dump_file (void); +extern void dump_symtab_node (dump_flags_t, symtab_node *); template 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 0000000..6f224bc --- /dev/null +++ b/gcc/optinfo.cc @@ -0,0 +1,236 @@ +/* Optimization information. + Copyright (C) 2018 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 0000000..5bdb9eb --- /dev/null +++ b/gcc/optinfo.h @@ -0,0 +1,203 @@ +/* Optimization information. + Copyright (C) 2018 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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; /* optinfo-internal.h. */ + +/* Should optinfo instances be created? + All creation of optinfos should be guarded by this predicate. + Return true if any optinfo destinations are active. */ + +extern bool optinfo_enabled_p (); + +/* Return true if any of the active optinfo destinations make use + of inlining information. + (if true, then the information is preserved). */ + +extern bool optinfo_wants_inlining_info_p (); + +/* The various kinds of optinfo. */ + +enum optinfo_kind +{ + OPTINFO_KIND_SUCCESS, + OPTINFO_KIND_FAILURE, + OPTINFO_KIND_NOTE, + OPTINFO_KIND_SCOPE +}; + +extern const char *optinfo_kind_to_string (enum optinfo_kind kind); + +/* A bundle of information describing part of an optimization. */ + +class optinfo +{ + friend class dump_context; + + public: + optinfo (const dump_location_t &loc, + enum optinfo_kind kind, + opt_pass *pass) + : m_loc (loc), m_kind (kind), m_pass (pass), m_items () + {} + ~optinfo (); + + const dump_user_location_t & + get_user_location () const { return m_loc.get_user_location (); } + + const dump_impl_location_t & + get_impl_location () const { return m_loc.get_impl_location (); } + + enum optinfo_kind get_kind () const { return m_kind; } + opt_pass *get_pass () const { return m_pass; } + unsigned int num_items () const { return m_items.length (); } + const optinfo_item *get_item (unsigned int i) const { return m_items[i]; } + + location_t get_location_t () const { return m_loc.get_location_t (); } + profile_count get_count () const { return m_loc.get_count (); } + + private: + void emit (); + + /* Pre-canned ways of manipulating the optinfo, for use by friend class + dump_context. */ + void handle_dump_file_kind (dump_flags_t); + void add_string (const char *str); + void add_printf (const char *format, ...) ATTRIBUTE_PRINTF_2; + void add_printf_va (const char *format, va_list ap) ATTRIBUTE_PRINTF (2, 0); + void add_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags); + void add_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags); + void add_tree (tree node, dump_flags_t dump_flags); + void add_symtab_node (symtab_node *node); + void add_dec (const wide_int_ref &wi, signop sgn); + + template + 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 */