From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22031 invoked by alias); 13 Jun 2011 09:22:36 -0000 Received: (qmail 22023 invoked by uid 22791); 13 Jun 2011 09:22:34 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 13 Jun 2011 09:22:17 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 8FEC69AC7FE; Mon, 13 Jun 2011 11:22:15 +0200 (CEST) Date: Mon, 13 Jun 2011 10:51:00 -0000 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Cgraph alias reorg 19/14 (inline functions called once through alias) Message-ID: <20110613092215.GA30931@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) 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 X-SW-Source: 2011-06/txt/msg00965.txt.bz2 Hi, tramp3d and some other benchmarks regressed as a result of switch to new represnetaiton of same body aliases. The reason is that inliner doesn't handle functions with aliases so well as it used to. The problems are: 1) functions with aliases are not inlined when called once 2) we now have more same comdat groups and inliner never removed offline copy of such functions 3) early inlinining is weaker since topological sort ignore aliases. This patch fixes 1) Bootstrapped/regtested x86_64-linux, comitted. Honza * cgraph.c (cgraph_for_node_thunks_and_aliases, cgraph_for_node_and_aliases): Fix thinko in recursive walking. (nonremovable_p): New function. (cgraph_can_remove_if_no_direct_calls_p): New function. (used_from_object_file_p): New functoin. (cgraph_will_be_removed_from_program_if_no_direct_calls): Look for references from aliases. * cgraph.h (cgraph_can_remove_if_no_direct_calls_p): Bring offline. * ipa-inline.c (check_caller_edge): New function. (want_inline_function_called_once_p): Use it; accept aliases called once, too. * ipa-inline-analysis.c (do_estimate_growth): Remove FIXME. Index: cgraph.c =================================================================== *** cgraph.c (revision 174958) --- cgraph.c (working copy) *************** cgraph_for_node_thunks_and_aliases (stru *** 2567,2580 **** if (e->caller->thunk.thunk_p && (include_overwritable || cgraph_function_body_availability (e->caller))) ! cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable); for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { struct cgraph_node *alias = ipa_ref_refering_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) ! cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable); } return false; } --- 2567,2584 ---- if (e->caller->thunk.thunk_p && (include_overwritable || cgraph_function_body_availability (e->caller))) ! if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data, ! include_overwritable)) ! return true; for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { struct cgraph_node *alias = ipa_ref_refering_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) ! if (cgraph_for_node_thunks_and_aliases (alias, callback, data, ! include_overwritable)) ! return true; } return false; } *************** cgraph_for_node_and_aliases (struct cgra *** 2600,2606 **** struct cgraph_node *alias = ipa_ref_refering_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) ! cgraph_for_node_and_aliases (alias, callback, data, include_overwritable); } return false; } --- 2604,2612 ---- struct cgraph_node *alias = ipa_ref_refering_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) ! if (cgraph_for_node_and_aliases (alias, callback, data, ! include_overwritable)) ! return true; } return false; } *************** cgraph_can_remove_if_no_direct_calls_and *** 2900,2905 **** --- 2906,2941 ---- return true; } + /* Worker for cgraph_can_remove_if_no_direct_calls_p. */ + + static bool + nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) + { + return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node); + } + + /* Return true when function NODE and its aliases can be removed from callgraph + if all direct calls are eliminated. */ + + bool + cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) + { + /* Extern inlines can always go, we will use the external definition. */ + if (DECL_EXTERNAL (node->decl)) + return true; + if (node->address_taken) + return false; + return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true); + } + + /* Worker for cgraph_can_remove_if_no_direct_calls_p. */ + + static bool + used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) + { + return cgraph_used_from_object_file_p (node); + } + /* Return true when function NODE can be expected to be removed from program when direct calls in this compilation unit are removed. *************** bool *** 2918,2924 **** cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); ! if (cgraph_used_from_object_file_p (node)) return false; if (!in_lto_p && !flag_whole_program) return cgraph_only_called_directly_p (node); --- 2954,2960 ---- cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); ! if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true)) return false; if (!in_lto_p && !flag_whole_program) return cgraph_only_called_directly_p (node); Index: cgraph.h =================================================================== *** cgraph.h (revision 174958) --- cgraph.h (working copy) *************** bool cgraph_will_be_removed_from_program *** 535,540 **** --- 535,541 ---- (struct cgraph_node *node); bool cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node); + bool cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node); bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution); bool cgraph_used_from_object_file_p (struct cgraph_node *); bool varpool_used_from_object_file_p (struct varpool_node *); *************** cgraph_only_called_directly_or_aliased_p *** 926,945 **** if all direct calls are eliminated. */ static inline bool - cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) - { - /* Extern inlines can always go, we will use the external definition. */ - if (DECL_EXTERNAL (node->decl)) - return true; - return (!node->address_taken - && cgraph_can_remove_if_no_direct_calls_and_refs_p (node) - && !ipa_ref_has_aliases_p (&node->ref_list)); - } - - /* Return true when function NODE can be removed from callgraph - if all direct calls are eliminated. */ - - static inline bool varpool_can_remove_if_no_refs (struct varpool_node *node) { return (!node->force_output && !node->used_from_other_partition --- 927,932 ---- Index: ipa-inline.c =================================================================== *** ipa-inline.c (revision 174958) --- ipa-inline.c (working copy) *************** want_inline_self_recursive_call_p (struc *** 643,648 **** --- 643,658 ---- return want_inline; } + /* Return true when NODE has caller other than EDGE. + Worker for cgraph_for_node_and_aliases. */ + + static bool + check_caller_edge (struct cgraph_node *node, void *edge) + { + return (node->callers + && node->callers != edge); + } + /* Decide if NODE is called once inlining it would eliminate need for the offline copy of function. */ *************** want_inline_self_recursive_call_p (struc *** 650,673 **** static bool want_inline_function_called_once_p (struct cgraph_node *node) { ! if (node->alias) ! return false; /* Already inlined? */ ! if (node->global.inlined_to) return false; /* Zero or more then one callers? */ if (!node->callers || node->callers->next_caller) return false; /* Recursive call makes no sense to inline. */ ! if (node->callers->caller == node) return false; /* External functions are not really in the unit, so inlining them when called once would just increase the program size. */ ! if (DECL_EXTERNAL (node->decl)) return false; /* Offline body must be optimized out. */ ! if (!cgraph_will_be_removed_from_program_if_no_direct_calls (node)) return false; if (!can_inline_edge_p (node->callers, true)) return false; --- 660,685 ---- static bool want_inline_function_called_once_p (struct cgraph_node *node) { ! struct cgraph_node *function = cgraph_function_or_thunk_node (node, NULL); /* Already inlined? */ ! if (function->global.inlined_to) return false; /* Zero or more then one callers? */ if (!node->callers || node->callers->next_caller) return false; + /* Maybe other aliases has more direct calls. */ + if (cgraph_for_node_and_aliases (node, check_caller_edge, node->callers, true)) + return false; /* Recursive call makes no sense to inline. */ ! if (cgraph_edge_recursive_p (node->callers)) return false; /* External functions are not really in the unit, so inlining them when called once would just increase the program size. */ ! if (DECL_EXTERNAL (function->decl)) return false; /* Offline body must be optimized out. */ ! if (!cgraph_will_be_removed_from_program_if_no_direct_calls (function)) return false; if (!can_inline_edge_p (node->callers, true)) return false; Index: ipa-inline-analysis.c =================================================================== *** ipa-inline-analysis.c (revision 174958) --- ipa-inline-analysis.c (working copy) *************** do_estimate_growth (struct cgraph_node * *** 2229,2236 **** && !cgraph_will_be_removed_from_program_if_no_direct_calls (node)) d.growth -= info->size; /* COMDAT functions are very often not shared across multiple units since they ! come from various template instantiations. Take this into account. ! FIXME: allow also COMDATs with COMDAT aliases. */ else if (DECL_COMDAT (node->decl) && cgraph_can_remove_if_no_direct_calls_p (node)) d.growth -= (info->size --- 2229,2235 ---- && !cgraph_will_be_removed_from_program_if_no_direct_calls (node)) d.growth -= info->size; /* COMDAT functions are very often not shared across multiple units since they ! come from various template instantiations. Take this into account. */ else if (DECL_COMDAT (node->decl) && cgraph_can_remove_if_no_direct_calls_p (node)) d.growth -= (info->size