From patchwork Tue Jan 30 13:13:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 867488 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-472281-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="lIhGEvj8"; 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 3zW6KJ37Kzz9ryT for ; Wed, 31 Jan 2018 00:14:11 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=XkuLsDVJeb8P+M4RI2nv2SpOssy65yoqypCHnH0T8PmCuop2LpEeG wJCw8bznVL3Gt2AbbBWvkFJoKI0+wNEA6eP/9LSkzLwpReCo1gwH9HCbxzyG1iiX q31mcp4tL9IS949qbroRcrkSMLVWzuRoEu2Tes+1vZieRvLX4WjmQE= 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:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=mRjZytd1hPYUO6doOQ3AuCg32g4=; b=lIhGEvj8b1Z4TPRTCExf rbhsQIrIXchDioymTXT8am0dcg9poED7CO7AtJ6jkADKu2tAj9QU4HNRXqrgQ4E0 txiQCam0gNKbBXU+TSWAmdLZBObj3cDqp5v1tlsQ9Jtgjcc+dtBhILs9VLkfWjZk //7MqXI8OCCaxSampI5rOVU= Received: (qmail 53687 invoked by alias); 30 Jan 2018 13:14:02 -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 53635 invoked by uid 89); 30 Jan 2018 13:14:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-9.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=tend, sk:lookup, REPORT X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 30 Jan 2018 13:13:57 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id CB4B95488B2; Tue, 30 Jan 2018 14:13:54 +0100 (CET) Date: Tue, 30 Jan 2018 14:13:54 +0100 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Fix ipa-inline ICE Message-ID: <20180130131354.GB5559@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) Hi, this patch fixed ICE that was introduced by Richard Standiford's change to reorder can and want_inline predicates to reduce amount of work done to verify inlining limits. This bypasses check that the function is optimized that makes inliner to ICE because function summary is missing. This patch breaks out the expensive limits checking from can predicate to new one which makes code bit more convoluted but I hope to clean things up next stage1. Bootstrapped/regtested x86_64-linux, will commit it later today. Honza PR ipa/81360 * ipa-inline.c (can_inline_edge_p): Break out late tests to... (can_inline_edge_by_limits_p): ... here. (can_early_inline_edge_p, check_callers, update_caller_keys, update_callee_keys, recursive_inlining, add_new_edges_to_heap, speculation_useful_p, inline_small_functions, inline_small_functions, flatten_function, inline_to_all_callers_1): Update. * g++.dg/torture/pr81360.C: New testcase Index: ipa-inline.c =================================================================== --- ipa-inline.c (revision 257174) +++ ipa-inline.c (working copy) @@ -289,18 +289,16 @@ sanitize_attrs_match_for_inline_p (const (opts_for_fn (caller->decl)->x_##flag \ != opts_for_fn (callee->decl)->x_##flag) - /* Decide if we can inline the edge and possibly update +/* 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. - - if DISREGARD_LIMITS is true, ignore size limits.*/ + if REPORT is true, output reason to the dump file. */ static bool can_inline_edge_p (struct cgraph_edge *e, bool report, - bool disregard_limits = false, bool early = false) + bool early = false) { gcc_checking_assert (e->inline_failed); @@ -316,9 +314,6 @@ can_inline_edge_p (struct cgraph_edge *e 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); - tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl); - tree callee_tree - = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL; if (!callee->definition) { @@ -379,12 +374,47 @@ can_inline_edge_p (struct cgraph_edge *e e->inline_failed = CIF_ATTRIBUTE_MISMATCH; inlinable = false; } + if (!inlinable && report) + report_inline_failed_reason (e); + return inlinable; +} + +/* 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. + + if DISREGARD_LIMITS is true, ignore size limits. */ + +static bool +can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report, + bool disregard_limits = false, bool early = false) +{ + 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); + tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl); + tree callee_tree + = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL; /* Check if caller growth allows the inlining. */ - else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl) - && !disregard_limits - && !lookup_attribute ("flatten", - DECL_ATTRIBUTES (caller->decl)) - && !caller_growth_limits (e)) + if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl) + && !disregard_limits + && !lookup_attribute ("flatten", + DECL_ATTRIBUTES (caller->decl)) + && !caller_growth_limits (e)) inlinable = false; /* Don't inline a function with a higher optimization level than the caller. FIXME: this is really just tip of iceberg of handling @@ -541,7 +571,8 @@ can_early_inline_edge_p (struct cgraph_e fprintf (dump_file, " edge not inlinable: not in SSA form\n"); return false; } - if (!can_inline_edge_p (e, true, false, true)) + if (!can_inline_edge_p (e, true, true) + || !can_inline_edge_by_limits_p (e, true, false, true)) return false; return true; } @@ -925,6 +956,8 @@ check_callers (struct cgraph_node *node, return true; if (e->recursive_p ()) return true; + if (!can_inline_edge_by_limits_p (e, true)) + return true; if (!(*(bool *)has_hot_call) && e->maybe_hot_p ()) *(bool *)has_hot_call = true; } @@ -1317,8 +1350,9 @@ update_caller_keys (edge_heap_t *heap, s if (!check_inlinablity_for || check_inlinablity_for == edge) { - if (want_inline_small_function_p (edge, false) - && can_inline_edge_p (edge, false)) + if (can_inline_edge_p (edge, false) + && want_inline_small_function_p (edge, false) + && can_inline_edge_by_limits_p (edge, false)) update_edge_key (heap, edge); else if (edge->aux) { @@ -1361,8 +1395,9 @@ update_callee_keys (edge_heap_t *heap, s && avail >= AVAIL_AVAILABLE && !bitmap_bit_p (updated_nodes, callee->uid)) { - if (want_inline_small_function_p (e, false) - && can_inline_edge_p (e, false)) + if (can_inline_edge_p (e, false) + && want_inline_small_function_p (e, false) + && can_inline_edge_by_limits_p (e, false)) update_edge_key (heap, e); else if (e->aux) { @@ -1449,7 +1484,8 @@ recursive_inlining (struct cgraph_edge * struct cgraph_edge *curr = heap.extract_min (); struct cgraph_node *cnode, *dest = curr->callee; - if (!can_inline_edge_p (curr, true)) + if (!can_inline_edge_p (curr, true) + || can_inline_edge_by_limits_p (curr, true)) continue; /* MASTER_CLONE is produced in the case we already started modified @@ -1569,7 +1605,8 @@ add_new_edges_to_heap (edge_heap_t *heap gcc_assert (!edge->aux); if (edge->inline_failed && can_inline_edge_p (edge, true) - && want_inline_small_function_p (edge, true)) + && want_inline_small_function_p (edge, true) + && can_inline_edge_by_limits_p (edge, true)) edge->aux = heap->insert (edge_badness (edge, false), edge); } } @@ -1630,7 +1667,9 @@ speculation_useful_p (struct cgraph_edge if (!anticipate_inlining && e->inline_failed && !target->local.local) return false; /* For overwritable targets there is not much to do. */ - if (e->inline_failed && !can_inline_edge_p (e, false, true)) + if (e->inline_failed + && (!can_inline_edge_p (e, false) + || !can_inline_edge_by_limits_p (e, false, true))) return false; /* OK, speculation seems interesting. */ return true; @@ -1790,6 +1829,7 @@ inline_small_functions (void) && !edge->aux && can_inline_edge_p (edge, true) && want_inline_small_function_p (edge, true) + && can_inline_edge_by_limits_p (edge, true) && edge->inline_failed) { gcc_assert (!edge->aux); @@ -1890,7 +1930,8 @@ inline_small_functions (void) badness = current_badness; } - if (!can_inline_edge_p (edge, true)) + if (!can_inline_edge_p (edge, true) + || !can_inline_edge_by_limits_p (edge, true)) { resolve_noninline_speculation (&edge_heap, edge); continue; @@ -2101,6 +2142,7 @@ flatten_function (struct cgraph_node *no too. */ if (!early ? !can_inline_edge_p (e, true) + && !can_inline_edge_by_limits_p (e, true) : !can_early_inline_edge_p (e)) continue; @@ -2155,6 +2197,7 @@ inline_to_all_callers_1 (struct cgraph_n struct cgraph_node *caller = node->callers->caller; if (!can_inline_edge_p (node->callers, true) + || !can_inline_edge_by_limits_p (node->callers, true) || node->callers->recursive_p ()) { if (dump_file) Index: testsuite/g++.dg/torture/pr81360.C =================================================================== --- testsuite/g++.dg/torture/pr81360.C (revision 0) +++ testsuite/g++.dg/torture/pr81360.C (working copy) @@ -0,0 +1,79 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-early-inlining" } */ + +template class B; +template class TriaObjectAccessor; +template class A; +template class TriaDimensionInfo { +public: + typedef A<3, TriaObjectAccessor<2, 3> > raw_quad_iterator; + typedef A<3, B<3> > raw_hex_iterator; + typedef raw_hex_iterator raw_cell_iterator; +}; +template class Triangulation : public TriaDimensionInfo<1> { + public: + typedef typename TriaDimensionInfo::raw_quad_iterator raw_quad_iterator; + TriaDimensionInfo::raw_cell_iterator end() const; + raw_quad_iterator end_quad() const { + return raw_quad_iterator(const_cast(this), 0, 0); + } +}; +template class TriaAccessor { +public: + typedef void AccessorData; + TriaAccessor(const Triangulation * = 0); + Triangulation<1> *tria; + + int a, b, c; +}; +template class TriaObjectAccessor<2, dim> : public TriaAccessor { +public: + typedef typename TriaAccessor::AccessorData AccessorData; + TriaObjectAccessor(const Triangulation * = 0); +}; +template class TriaObjectAccessor<3, dim> : public TriaAccessor { +public: + typedef typename TriaAccessor::AccessorData AccessorData; + TriaObjectAccessor(const Triangulation * = 0); +}; +template class B : public TriaObjectAccessor { +public: + typedef typename TriaObjectAccessor::AccessorData AccessorData; + B(const Triangulation * = 0); +}; +template class A { +public: + A(const A &); + A(const Triangulation *, int, int); + Accessor accessor; +}; +template class Triangulation<3>; +template +A::A(const Triangulation *, int, int) {} +template +TriaAccessor::TriaAccessor(const Triangulation *) + : tria(), a(-1), b(-2), c(-3) {} +template +TriaObjectAccessor<2, dim>::TriaObjectAccessor(const Triangulation *) {} +template +TriaObjectAccessor<3, dim>::TriaObjectAccessor(const Triangulation *) {} +template B::B(const Triangulation *) {} +template <> +TriaDimensionInfo<3>::raw_cell_iterator Triangulation<3>::end() const { + return raw_hex_iterator(const_cast(this), 0, 0); +} + +#pragma GCC optimize ("-O0") +int main() +{ + Triangulation <3> t; + Triangulation<3>::raw_quad_iterator i1 = t.end_quad(); + TriaDimensionInfo<3>::raw_cell_iterator i2 = t.end(); + + if(i2.accessor.c != -3) + return 1; + + return 0; +} + +/* { dg-final { scan-ipa-dump "Equal symbols: 0" "icf" } } */