From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 81809 invoked by alias); 6 Jun 2019 08:46:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 81796 invoked by uid 89); 6 Jun 2019 08:46:21 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.3 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Jun 2019 08:46:19 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 51EF1AF48 for ; Thu, 6 Jun 2019 08:46:17 +0000 (UTC) Subject: Re: [PR 89330] Avoid adding dead speculative edges to inlinig heap To: Martin Jambor , GCC Patches Cc: Jan Hubicka References: From: =?UTF-8?Q?Martin_Li=c5=a1ka?= Message-ID: <604653d9-cf5f-8a41-8f8c-1426f33a9e2a@suse.cz> Date: Thu, 06 Jun 2019 08:46:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/mixed; boundary="------------2D080541B976D87DCF7A6FEB" X-IsSubscribed: yes X-SW-Source: 2019-06/txt/msg00316.txt.bz2 This is a multi-part message in MIME format. --------------2D080541B976D87DCF7A6FEB Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Content-length: 153 Hi. This is rebased version of the patch that Martin J. wrote. Patch can bootstrap on x86_64-linux-gnu and survives regression tests. Thanks, Martin --------------2D080541B976D87DCF7A6FEB Content-Type: text/x-patch; name="0001-Avoid-adding-dead-speculative-edges-to-inlining-heap.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Avoid-adding-dead-speculative-edges-to-inlining-heap.pa"; filename*1="tch" Content-length: 10780 >From 17290dd6dc4412aee6c6484844f9edb149129d36 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Wed, 5 Jun 2019 16:11:44 +0200 Subject: [PATCH] Avoid adding dead speculative edges to inlining heap 2019-02-15 Martin Jambor PR ipa/89330 * ipa-inline.c (can_inline_edge_p): Move most of the checks... (call_not_inlinable_p): ...this new function. * ipa-inline.h (call_not_inlinable_p): Declare. * ipa-prop.c: Include ipa-inline.h (try_make_edge_direct_virtual_call): Create speculative edges only if there is any chance of inlining them. testsuite/ * g++.dg/lto/pr89330_[01].C: New test. --- gcc/ipa-inline.c | 119 +++++++++++++-------------- gcc/ipa-inline.h | 4 +- gcc/ipa-prop.c | 8 +- gcc/testsuite/g++.dg/lto/pr89330_0.C | 50 +++++++++++ gcc/testsuite/g++.dg/lto/pr89330_1.C | 36 ++++++++ 5 files changed, 151 insertions(+), 66 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lto/pr89330_0.C create mode 100644 gcc/testsuite/g++.dg/lto/pr89330_1.C diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 745bdf3002a..ba8155f006e 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -299,95 +299,87 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee) (opts_for_fn (caller->decl)->x_##flag \ != opts_for_fn (callee->decl)->x_##flag) -/* Decide if we can inline the edge and possibly update - inline_failed reason. - We check whether inlining is possible at all and whether - caller growth limits allow doing so. - - if REPORT is true, output reason to the dump file. */ +/* Return CIF_OK if a call from CALLER to CALLEE is or would be inlineable. + Otherwise, return the reason why it cannot. EARLY should be set when + deciding about early inlining. */ -static bool -can_inline_edge_p (struct cgraph_edge *e, bool report, - bool early = false) +enum cgraph_inline_failed_t +call_not_inlinable_p (cgraph_node *caller, cgraph_node *callee, + bool early) { - gcc_checking_assert (e->inline_failed); - - if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) - { - if (report) - report_inline_failed_reason (e); - return false; - } - - bool inlinable = true; enum availability avail; - cgraph_node *caller = e->caller->global.inlined_to - ? e->caller->global.inlined_to : e->caller; - cgraph_node *callee = e->callee->ultimate_alias_target (&avail, caller); + caller = caller->global.inlined_to ? caller->global.inlined_to : caller; + callee = callee->ultimate_alias_target (&avail, caller); if (!callee->definition) - { - e->inline_failed = CIF_BODY_NOT_AVAILABLE; - inlinable = false; - } + return CIF_BODY_NOT_AVAILABLE; if (!early && (!opt_for_fn (callee->decl, optimize) || !opt_for_fn (caller->decl, optimize))) - { - e->inline_failed = CIF_FUNCTION_NOT_OPTIMIZED; - inlinable = false; - } + return CIF_FUNCTION_NOT_OPTIMIZED; else if (callee->calls_comdat_local) - { - e->inline_failed = CIF_USES_COMDAT_LOCAL; - inlinable = false; - } + return CIF_USES_COMDAT_LOCAL; else if (avail <= AVAIL_INTERPOSABLE) - { - e->inline_failed = CIF_OVERWRITABLE; - inlinable = false; - } - /* All edges with call_stmt_cannot_inline_p should have inline_failed - initialized to one of FINAL_ERROR reasons. */ - else if (e->call_stmt_cannot_inline_p) - gcc_unreachable (); + return CIF_OVERWRITABLE; /* Don't inline if the functions have different EH personalities. */ else if (DECL_FUNCTION_PERSONALITY (caller->decl) && DECL_FUNCTION_PERSONALITY (callee->decl) && (DECL_FUNCTION_PERSONALITY (caller->decl) != DECL_FUNCTION_PERSONALITY (callee->decl))) - { - e->inline_failed = CIF_EH_PERSONALITY; - inlinable = false; - } + return CIF_EH_PERSONALITY; /* TM pure functions should not be inlined into non-TM_pure functions. */ else if (is_tm_pure (callee->decl) && !is_tm_pure (caller->decl)) - { - e->inline_failed = CIF_UNSPECIFIED; - inlinable = false; - } + return CIF_UNSPECIFIED; /* Check compatibility of target optimization options. */ else if (!targetm.target_option.can_inline_p (caller->decl, callee->decl)) - { - e->inline_failed = CIF_TARGET_OPTION_MISMATCH; - inlinable = false; - } + return CIF_TARGET_OPTION_MISMATCH; else if (ipa_fn_summaries->get (callee) == NULL || !ipa_fn_summaries->get (callee)->inlinable) - { - e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; - inlinable = false; - } + return CIF_FUNCTION_NOT_INLINABLE; /* Don't inline a function with mismatched sanitization attributes. */ else if (!sanitize_attrs_match_for_inline_p (caller->decl, callee->decl)) + return CIF_ATTRIBUTE_MISMATCH; + return CIF_OK; +} + +/* Decide if we can inline the edge and possibly update + inline_failed reason. + We check whether inlining is possible at all and whether + caller growth limits allow doing so. + + If REPORT is true, output reason to the dump file. EARLY should be set when + deciding about early inlining. */ + +static bool +can_inline_edge_p (struct cgraph_edge *e, bool report, + bool early = false) +{ + gcc_checking_assert (e->inline_failed); + + if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) { - e->inline_failed = CIF_ATTRIBUTE_MISMATCH; - inlinable = false; + if (report) + report_inline_failed_reason (e); + return false; } - if (!inlinable && report) - report_inline_failed_reason (e); - return inlinable; + + enum cgraph_inline_failed_t fail_reason + = call_not_inlinable_p (e->caller, e->callee, early); + + + if (fail_reason != CIF_OK) + { + e->inline_failed = fail_reason; + if (report) + report_inline_failed_reason (e); + } + /* All edges with call_stmt_cannot_inline_p should have inline_failed + initialized to one of FINAL_ERROR reasons. */ + else if (e->call_stmt_cannot_inline_p) + gcc_unreachable (); + + return fail_reason == CIF_OK; } /* Decide if we can inline the edge and possibly update @@ -1628,6 +1620,7 @@ add_new_edges_to_heap (edge_heap_t *heap, vec new_edges) { struct cgraph_edge *edge = new_edges.pop (); + gcc_assert (edge->callee); gcc_assert (!edge->aux); if (edge->inline_failed && can_inline_edge_p (edge, true) diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index f6eb677d618..911df58d646 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -52,7 +52,9 @@ void free_growth_caches (void); /* In ipa-inline.c */ unsigned int early_inliner (function *fun); bool inline_account_function_p (struct cgraph_node *node); - +enum cgraph_inline_failed_t call_not_inlinable_p (cgraph_node *caller, + cgraph_node *callee, + bool early); /* In ipa-inline-transform.c */ bool inline_call (struct cgraph_edge *, bool, vec *, int *, bool, diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index d86c2f3db55..36ba91c3800 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "domwalk.h" #include "builtins.h" #include "tree-cfgcleanup.h" +#include "ipa-inline.h" /* Function summary where the parameter infos are actually stored. */ ipa_node_params_t *ipa_node_params_sum = NULL; @@ -3346,13 +3347,16 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, if (target) { - if (!possible_polymorphic_call_target_p - (ie, cgraph_node::get_create (target))) + cgraph_node *target_node = cgraph_node::get_create (target); + if (!possible_polymorphic_call_target_p (ie, target_node)) { if (speculative) return NULL; target = ipa_impossible_devirt_target (ie, target); } + if (speculative + && call_not_inlinable_p (ie->caller, target_node, false)) + return NULL; return ipa_make_edge_direct_to_target (ie, target, speculative); } else diff --git a/gcc/testsuite/g++.dg/lto/pr89330_0.C b/gcc/testsuite/g++.dg/lto/pr89330_0.C new file mode 100644 index 00000000000..10082f83412 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr89330_0.C @@ -0,0 +1,50 @@ +// { dg-lto-do link } +// { dg-lto-options { { -O3 -g -flto -shared -Wno-odr } } } + +namespace Inkscape { +class Anchored {}; +namespace XML { +enum NodeType {}; +class Node :Anchored { +public: + virtual NodeType type() ; + virtual char name() ; + virtual int code() ; + virtual unsigned position() ; + virtual unsigned childCount() ; + virtual char content() ; + virtual char *attribute() const ; + virtual int attributeList() ; + virtual bool matchAttributeName() ; + virtual void setPosition() ; + virtual void setContent() ; + virtual void setAttribute() ; + virtual int document() ; + virtual int document() const ; + virtual Node *root() ; + virtual Node *root() const ; + virtual Node *parent() ; + virtual Node *next() const ; + virtual Node *firstChild() const ; + +}; +} } struct rdf_license_t { + }; +; +class RDFImpl { +; + rdf_license_t *getLicense(); +}; +static bool rdf_match_license(Inkscape::XML::Node const *repr) { + for (Inkscape::XML::Node *current = repr->firstChild(); current; + current->next()->attribute()); + return 0; +} +rdf_license_t *RDFImpl::getLicense() { + Inkscape::XML::Node *repr ; + for (rdf_license_t *license ; license; + license) { + rdf_match_license(repr); + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/lto/pr89330_1.C b/gcc/testsuite/g++.dg/lto/pr89330_1.C new file mode 100644 index 00000000000..5b999eee8d7 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr89330_1.C @@ -0,0 +1,36 @@ +typedef char gchar; +namespace Inkscape { +class Anchored { +int _anchor; +}; +namespace XML { +enum NodeType {}; +class Node :Anchored { +virtual NodeType type() ; + virtual char const *name() const ; + virtual int code() ; + virtual unsigned position() ; + virtual unsigned childCount() ; + virtual char content() ; + virtual char attribute() ; + virtual int attributeList() ; + virtual bool matchAttributeName() ; + virtual void setPosition() ; + virtual void setContent() ; + virtual int document() ; + virtual int document() const ; + virtual Node *root() ; + virtual Node *root() const ; + virtual Node *parent() ; + virtual Node *parent() const ; + virtual Node *next() ; + virtual Node const *next() const ; + +}; +class SimpleNode : virtual Node { +char const *name() const; + Node *next() const { return _next; } + SimpleNode *_next; +}; +gchar const *SimpleNode::name() const { return 0; } +} } -- 2.21.0 --------------2D080541B976D87DCF7A6FEB--