From patchwork Wed Mar 26 02:16:53 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 333760 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 9CEC514009F for ; Wed, 26 Mar 2014 13:17:11 +1100 (EST) 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=irCIu3dsJcBPg72F4cK8quwkH5mUw9J1zf/0v6nd6ts0epgfC4FEA NOFBDHx1ix8b1p5t7QF8UUlOWkucb4UYvhcQfXQM3c50XL6UPT3M6EsiVWfHGi/O 0EcYRcccgdoVbaNjhZ+DRLefL2hd+NYwYt8ZzCI22X9MIFFK/k4GGg= 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=e3XKcrhHFqSiP9iWo5eAtjmYnoc=; b=WyoHB0NAq7k3gkNecop6 KHFnql6mZKt7g8vFbMLYwDj0oi0b/4/Dyo9861xNlP9KZJkG0IFr72sYwONEuD+d s7dtcEZ/W58RU2rvVLfsaBI2zciq6uJKkKZyqOUkkLq1ujbvChb8Lyu16n1Bbe6X JfFF3uCxL2Un/xtWMRnyYdU= Received: (qmail 27021 invoked by alias); 26 Mar 2014 02:17:01 -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 27002 invoked by uid 89); 26 Mar 2014 02:16:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD autolearn=ham version=3.3.2 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 (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 26 Mar 2014 02:16:57 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 01C045418EC; Wed, 26 Mar 2014 03:16:53 +0100 (CET) Date: Wed, 26 Mar 2014 03:16:53 +0100 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Fix PR ipa/60315 (inliner explosion) Message-ID: <20140326021653.GA14614@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Hi, this patch fixes compile time issue in the testcase that is caused by fact that the inliner is repeatedly inlining into an call it earlier proved to be unreachable. The analysis part knows that such calls are not accounted into overall function summaries, but the transform part sees them merely as cold calls and thus it attempts to do inlining for size. This patch makes analysis part to practively redirect all known to be unreachable calls to BUILTIN_UNREAHABLE. Doing so uncovered the bug in ipa-pure-const I fixed earlier and also another but in set_cond_stmt_execution_predicate where invert_tree_comparison is called and the condition is used further. The function returns ERROR_MARK for FP comparsions in some cases (though I think it should not since there seems to be no toher way to invert comparsion without this and we have the unordered codes). This concide with ipa-inline-analysis.c internal use of ERROR_MARK and leads to inconsistent predicates. Bootstrapped/regtested x86_64-linux, comitted. PR ipa/60315 * cif-code.def (UNREACHABLE) New code. * ipa-inline.c (inline_small_functions): Skip edges to __builtlin_unreachable. (estimate_edge_growth): Allow edges to __builtlin_unreachable. * ipa-inline-analysis.c (edge_set_predicate): Redirect edges with false predicate to __bulitin_unreachable. (set_cond_stmt_execution_predicate): Fix issue when invert_tree_comparison returns ERROR_MARK. * ipa-pure-const.c (propagate_pure_const, propagate_nothrow): Do not propagate to inline clones. * cgraph.c (verify_edge_corresponds_to_fndecl): Allow redirection to unreachable. * ipa-cp.c (create_specialized_node): Be ready for new node to appear. * cgraphclones.c (cgraph_clone_node): If call destination is already ureachable, do not redirect it back. * tree-inline.c (fold_marked_statements): Hanlde calls becoming unreachable. * testsuite/g++.dg/torture/pr60315.C: New testcase. Index: cif-code.def =================================================================== --- cif-code.def (revision 208829) +++ cif-code.def (working copy) @@ -127,3 +127,7 @@ DEFCIFCODE(USES_COMDAT_LOCAL, CIF_FINAL_ /* We can't inline because of mismatched caller/callee attributes. */ DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_NORMAL, N_("function attribute mismatch")) + +/* We proved that the call is unreachable. */ +DEFCIFCODE(UNREACHABLE, CIF_FINAL_NORMAL, + N_("unreachable")) Index: cgraphclones.c =================================================================== --- cgraphclones.c (revision 208829) +++ cgraphclones.c (working copy) @@ -238,8 +238,12 @@ cgraph_clone_node (struct cgraph_node *n FOR_EACH_VEC_ELT (redirect_callers, i, e) { /* Redirect calls to the old version node to point to its new - version. */ - cgraph_redirect_edge_callee (e, new_node); + version. The only exception is when the edge was proved to + be unreachable during the clonning procedure. */ + if (!e->callee + || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL + || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE) + cgraph_redirect_edge_callee (e, new_node); } Index: ipa-inline.c =================================================================== --- ipa-inline.c (revision 208829) +++ ipa-inline.c (working copy) @@ -1685,7 +1685,7 @@ inline_small_functions (void) edge = (struct cgraph_edge *) fibheap_extract_min (edge_heap); gcc_assert (edge->aux); edge->aux = NULL; - if (!edge->inline_failed) + if (!edge->inline_failed || !edge->callee->analyzed) continue; /* Be sure that caches are maintained consistent. Index: ipa-inline.h =================================================================== --- ipa-inline.h (revision 208829) +++ ipa-inline.h (working copy) @@ -285,7 +285,8 @@ static inline int estimate_edge_growth (struct cgraph_edge *edge) { #ifdef ENABLE_CHECKING - gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size); + gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size + || !edge->callee->analyzed); #endif return (estimate_edge_size (edge) - inline_edge_summary (edge)->call_stmt_size); Index: testsuite/g++.dg/torture/pr60315.C =================================================================== --- testsuite/g++.dg/torture/pr60315.C (revision 0) +++ testsuite/g++.dg/torture/pr60315.C (revision 0) @@ -0,0 +1,32 @@ +// { dg-do compile } +struct Base { + virtual int f() = 0; +}; + +struct Derived : public Base { + virtual int f() final override { + return 42; + } +}; + +extern Base* b; + +int main() { + return (static_cast(b)->*(&Derived::f))(); +} +// { dg-do compile } +struct Base { + virtual int f() = 0; +}; + +struct Derived : public Base { + virtual int f() final override { + return 42; + } +}; + +extern Base* b; + +int main() { + return (static_cast(b)->*(&Derived::f))(); +} Index: cgraph.c =================================================================== --- cgraph.c (revision 208829) +++ cgraph.c (working copy) @@ -2612,6 +2612,12 @@ verify_edge_corresponds_to_fndecl (struc || node->in_other_partition || e->callee->in_other_partition) return false; + + /* Optimizers can redirect unreachable calls or calls triggering undefined + behaviour to builtin_unreachable. */ + if (DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (e->callee->decl) == BUILT_IN_UNREACHABLE) + return false; node = cgraph_function_or_thunk_node (node, NULL); if (e->callee->former_clone_of != node->decl Index: ipa-inline-analysis.c =================================================================== --- ipa-inline-analysis.c (revision 208829) +++ ipa-inline-analysis.c (working copy) @@ -746,6 +746,20 @@ static void edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate) { struct inline_edge_summary *es = inline_edge_summary (e); + + /* If the edge is determined to be never executed, redirect it + to BUILTIN_UNREACHABLE to save inliner from inlining into it. */ + if (predicate && false_predicate_p (predicate) && e->callee) + { + struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL; + + cgraph_redirect_edge_callee (e, + cgraph_get_create_node + (builtin_decl_implicit (BUILT_IN_UNREACHABLE))); + e->inline_failed = CIF_UNREACHABLE; + if (callee) + cgraph_remove_node_and_inline_clones (callee, NULL); + } if (predicate && !true_predicate_p (predicate)) { if (!es->predicate) @@ -1724,12 +1738,20 @@ set_cond_stmt_execution_predicate (struc FOR_EACH_EDGE (e, ei, bb->succs) { - struct predicate p = add_condition (summary, index, &aggpos, - e->flags & EDGE_TRUE_VALUE - ? code : inverted_code, - gimple_cond_rhs (last)); - e->aux = pool_alloc (edge_predicate_pool); - *(struct predicate *) e->aux = p; + enum tree_code this_code = (e->flags & EDGE_TRUE_VALUE + ? code : inverted_code); + /* invert_tree_comparison will return ERROR_MARK on FP + comparsions that are not EQ/NE instead of returning proper + unordered one. Be sure it is not confused with NON_CONSTANT. */ + if (this_code != ERROR_MARK) + { + struct predicate p = add_condition (summary, index, &aggpos, + e->flags & EDGE_TRUE_VALUE + ? code : inverted_code, + gimple_cond_rhs (last)); + e->aux = pool_alloc (edge_predicate_pool); + *(struct predicate *) e->aux = p; + } } } Index: ipa-cp.c =================================================================== --- ipa-cp.c (revision 208829) +++ ipa-cp.c (working copy) @@ -2811,9 +2811,7 @@ create_specialized_node (struct cgraph_n if (aggvals) ipa_dump_agg_replacement_values (dump_file, aggvals); } - gcc_checking_assert (ipa_node_params_vector.exists () - && (ipa_node_params_vector.length () - > (unsigned) cgraph_max_uid)); + ipa_check_create_node_params (); update_profiling_info (node, new_node); new_info = IPA_NODE_REF (new_node); new_info->ipcp_orig_node = node;