11debfc3dSmrg /* Callgraph transformations to handle inlining
2*8feb0f0bSmrg Copyright (C) 2003-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Jan Hubicka
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg /* The inline decisions are stored in callgraph in "inline plan" and
221debfc3dSmrg applied later.
231debfc3dSmrg
241debfc3dSmrg To mark given call inline, use inline_call function.
251debfc3dSmrg The function marks the edge inlinable and, if necessary, produces
261debfc3dSmrg virtual clone in the callgraph representing the new copy of callee's
271debfc3dSmrg function body.
281debfc3dSmrg
291debfc3dSmrg The inline plan is applied on given function body by inline_transform. */
301debfc3dSmrg
311debfc3dSmrg #include "config.h"
321debfc3dSmrg #include "system.h"
331debfc3dSmrg #include "coretypes.h"
341debfc3dSmrg #include "tm.h"
351debfc3dSmrg #include "function.h"
361debfc3dSmrg #include "tree.h"
371debfc3dSmrg #include "alloc-pool.h"
381debfc3dSmrg #include "tree-pass.h"
391debfc3dSmrg #include "cgraph.h"
401debfc3dSmrg #include "tree-cfg.h"
411debfc3dSmrg #include "symbol-summary.h"
421debfc3dSmrg #include "tree-vrp.h"
431debfc3dSmrg #include "ipa-prop.h"
44a2dc1f3fSmrg #include "ipa-fnsummary.h"
451debfc3dSmrg #include "ipa-inline.h"
461debfc3dSmrg #include "tree-inline.h"
47a2dc1f3fSmrg #include "function.h"
48a2dc1f3fSmrg #include "cfg.h"
49a2dc1f3fSmrg #include "basic-block.h"
50*8feb0f0bSmrg #include "ipa-utils.h"
511debfc3dSmrg
521debfc3dSmrg int ncalls_inlined;
531debfc3dSmrg int nfunctions_inlined;
541debfc3dSmrg
55a2dc1f3fSmrg /* Scale counts of NODE edges by NUM/DEN. */
561debfc3dSmrg
571debfc3dSmrg static void
update_noncloned_counts(struct cgraph_node * node,profile_count num,profile_count den)58a2dc1f3fSmrg update_noncloned_counts (struct cgraph_node *node,
59a2dc1f3fSmrg profile_count num, profile_count den)
601debfc3dSmrg {
611debfc3dSmrg struct cgraph_edge *e;
621debfc3dSmrg
63a2dc1f3fSmrg profile_count::adjust_for_ipa_scaling (&num, &den);
64a2dc1f3fSmrg
651debfc3dSmrg for (e = node->callees; e; e = e->next_callee)
661debfc3dSmrg {
671debfc3dSmrg if (!e->inline_failed)
68a2dc1f3fSmrg update_noncloned_counts (e->callee, num, den);
69a2dc1f3fSmrg e->count = e->count.apply_scale (num, den);
701debfc3dSmrg }
711debfc3dSmrg for (e = node->indirect_calls; e; e = e->next_callee)
72a2dc1f3fSmrg e->count = e->count.apply_scale (num, den);
73a2dc1f3fSmrg node->count = node->count.apply_scale (num, den);
741debfc3dSmrg }
751debfc3dSmrg
761debfc3dSmrg /* We removed or are going to remove the last call to NODE.
771debfc3dSmrg Return true if we can and want proactively remove the NODE now.
781debfc3dSmrg This is important to do, since we want inliner to know when offline
791debfc3dSmrg copy of function was removed. */
801debfc3dSmrg
811debfc3dSmrg static bool
can_remove_node_now_p_1(struct cgraph_node * node,struct cgraph_edge * e)821debfc3dSmrg can_remove_node_now_p_1 (struct cgraph_node *node, struct cgraph_edge *e)
831debfc3dSmrg {
841debfc3dSmrg ipa_ref *ref;
851debfc3dSmrg
861debfc3dSmrg FOR_EACH_ALIAS (node, ref)
871debfc3dSmrg {
881debfc3dSmrg cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
891debfc3dSmrg if ((alias->callers && alias->callers != e)
901debfc3dSmrg || !can_remove_node_now_p_1 (alias, e))
911debfc3dSmrg return false;
921debfc3dSmrg }
931debfc3dSmrg /* FIXME: When address is taken of DECL_EXTERNAL function we still
941debfc3dSmrg can remove its offline copy, but we would need to keep unanalyzed node in
951debfc3dSmrg the callgraph so references can point to it.
961debfc3dSmrg
971debfc3dSmrg Also for comdat group we can ignore references inside a group as we
981debfc3dSmrg want to prove the group as a whole to be dead. */
991debfc3dSmrg return (!node->address_taken
1001debfc3dSmrg && node->can_remove_if_no_direct_calls_and_refs_p ()
1011debfc3dSmrg /* Inlining might enable more devirtualizing, so we want to remove
1021debfc3dSmrg those only after all devirtualizable virtual calls are processed.
1031debfc3dSmrg Lacking may edges in callgraph we just preserve them post
1041debfc3dSmrg inlining. */
1051debfc3dSmrg && (!DECL_VIRTUAL_P (node->decl)
1061debfc3dSmrg || !opt_for_fn (node->decl, flag_devirtualize))
1071debfc3dSmrg /* During early inlining some unanalyzed cgraph nodes might be in the
108*8feb0f0bSmrg callgraph and they might refer the function in question. */
1091debfc3dSmrg && !cgraph_new_nodes.exists ());
1101debfc3dSmrg }
1111debfc3dSmrg
1121debfc3dSmrg /* We are going to eliminate last direct call to NODE (or alias of it) via edge E.
1131debfc3dSmrg Verify that the NODE can be removed from unit and if it is contained in comdat
1141debfc3dSmrg group that the whole comdat group is removable. */
1151debfc3dSmrg
1161debfc3dSmrg static bool
can_remove_node_now_p(struct cgraph_node * node,struct cgraph_edge * e)1171debfc3dSmrg can_remove_node_now_p (struct cgraph_node *node, struct cgraph_edge *e)
1181debfc3dSmrg {
1191debfc3dSmrg struct cgraph_node *next;
1201debfc3dSmrg if (!can_remove_node_now_p_1 (node, e))
1211debfc3dSmrg return false;
1221debfc3dSmrg
1231debfc3dSmrg /* When we see same comdat group, we need to be sure that all
1241debfc3dSmrg items can be removed. */
1251debfc3dSmrg if (!node->same_comdat_group || !node->externally_visible)
1261debfc3dSmrg return true;
1271debfc3dSmrg for (next = dyn_cast<cgraph_node *> (node->same_comdat_group);
1281debfc3dSmrg next != node; next = dyn_cast<cgraph_node *> (next->same_comdat_group))
1291debfc3dSmrg {
1301debfc3dSmrg if (next->alias)
1311debfc3dSmrg continue;
1321debfc3dSmrg if ((next->callers && next->callers != e)
1331debfc3dSmrg || !can_remove_node_now_p_1 (next, e))
1341debfc3dSmrg return false;
1351debfc3dSmrg }
1361debfc3dSmrg return true;
1371debfc3dSmrg }
1381debfc3dSmrg
1391debfc3dSmrg /* Return true if NODE is a master clone with non-inline clones. */
1401debfc3dSmrg
1411debfc3dSmrg static bool
master_clone_with_noninline_clones_p(struct cgraph_node * node)1421debfc3dSmrg master_clone_with_noninline_clones_p (struct cgraph_node *node)
1431debfc3dSmrg {
1441debfc3dSmrg if (node->clone_of)
1451debfc3dSmrg return false;
1461debfc3dSmrg
1471debfc3dSmrg for (struct cgraph_node *n = node->clones; n; n = n->next_sibling_clone)
1481debfc3dSmrg if (n->decl != node->decl)
1491debfc3dSmrg return true;
1501debfc3dSmrg
1511debfc3dSmrg return false;
1521debfc3dSmrg }
1531debfc3dSmrg
1541debfc3dSmrg /* E is expected to be an edge being inlined. Clone destination node of
1551debfc3dSmrg the edge and redirect it to the new clone.
1561debfc3dSmrg DUPLICATE is used for bookkeeping on whether we are actually creating new
1571debfc3dSmrg clones or re-using node originally representing out-of-line function call.
1581debfc3dSmrg By default the offline copy is removed, when it appears dead after inlining.
1591debfc3dSmrg UPDATE_ORIGINAL prevents this transformation.
1601debfc3dSmrg If OVERALL_SIZE is non-NULL, the size is updated to reflect the
161a2dc1f3fSmrg transformation. */
1621debfc3dSmrg
1631debfc3dSmrg void
clone_inlined_nodes(struct cgraph_edge * e,bool duplicate,bool update_original,int * overall_size)1641debfc3dSmrg clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
165a2dc1f3fSmrg bool update_original, int *overall_size)
1661debfc3dSmrg {
1671debfc3dSmrg struct cgraph_node *inlining_into;
1681debfc3dSmrg struct cgraph_edge *next;
1691debfc3dSmrg
170*8feb0f0bSmrg if (e->caller->inlined_to)
171*8feb0f0bSmrg inlining_into = e->caller->inlined_to;
1721debfc3dSmrg else
1731debfc3dSmrg inlining_into = e->caller;
1741debfc3dSmrg
1751debfc3dSmrg if (duplicate)
1761debfc3dSmrg {
1771debfc3dSmrg /* We may eliminate the need for out-of-line copy to be output.
1781debfc3dSmrg In that case just go ahead and re-use it. This is not just an
179*8feb0f0bSmrg memory optimization. Making offline copy of function disappear
1801debfc3dSmrg from the program will improve future decisions on inlining. */
1811debfc3dSmrg if (!e->callee->callers->next_caller
1821debfc3dSmrg /* Recursive inlining never wants the master clone to
1831debfc3dSmrg be overwritten. */
1841debfc3dSmrg && update_original
1851debfc3dSmrg && can_remove_node_now_p (e->callee, e)
1861debfc3dSmrg /* We cannot overwrite a master clone with non-inline clones
1871debfc3dSmrg until after these clones are materialized. */
1881debfc3dSmrg && !master_clone_with_noninline_clones_p (e->callee))
1891debfc3dSmrg {
1901debfc3dSmrg /* TODO: When callee is in a comdat group, we could remove all of it,
1911debfc3dSmrg including all inline clones inlined into it. That would however
1921debfc3dSmrg need small function inlining to register edge removal hook to
1931debfc3dSmrg maintain the priority queue.
1941debfc3dSmrg
195*8feb0f0bSmrg For now we keep the other functions in the group in program until
1961debfc3dSmrg cgraph_remove_unreachable_functions gets rid of them. */
197*8feb0f0bSmrg gcc_assert (!e->callee->inlined_to);
1981debfc3dSmrg e->callee->remove_from_same_comdat_group ();
1991debfc3dSmrg if (e->callee->definition
2001debfc3dSmrg && inline_account_function_p (e->callee))
2011debfc3dSmrg {
2021debfc3dSmrg gcc_assert (!e->callee->alias);
2031debfc3dSmrg if (overall_size)
204*8feb0f0bSmrg *overall_size -= ipa_size_summaries->get (e->callee)->size;
2051debfc3dSmrg nfunctions_inlined++;
2061debfc3dSmrg }
2071debfc3dSmrg duplicate = false;
2081debfc3dSmrg e->callee->externally_visible = false;
209a2dc1f3fSmrg update_noncloned_counts (e->callee, e->count, e->callee->count);
2101debfc3dSmrg
2111debfc3dSmrg dump_callgraph_transformation (e->callee, inlining_into,
2121debfc3dSmrg "inlining to");
2131debfc3dSmrg }
2141debfc3dSmrg else
2151debfc3dSmrg {
2161debfc3dSmrg struct cgraph_node *n;
2171debfc3dSmrg
2181debfc3dSmrg n = e->callee->create_clone (e->callee->decl,
219a2dc1f3fSmrg e->count,
2201debfc3dSmrg update_original, vNULL, true,
2211debfc3dSmrg inlining_into,
2221debfc3dSmrg NULL);
2231debfc3dSmrg n->used_as_abstract_origin = e->callee->used_as_abstract_origin;
2241debfc3dSmrg e->redirect_callee (n);
2251debfc3dSmrg }
2261debfc3dSmrg }
2271debfc3dSmrg else
2281debfc3dSmrg e->callee->remove_from_same_comdat_group ();
2291debfc3dSmrg
230*8feb0f0bSmrg e->callee->inlined_to = inlining_into;
2311debfc3dSmrg
2321debfc3dSmrg /* Recursively clone all bodies. */
2331debfc3dSmrg for (e = e->callee->callees; e; e = next)
2341debfc3dSmrg {
2351debfc3dSmrg next = e->next_callee;
2361debfc3dSmrg if (!e->inline_failed)
237a2dc1f3fSmrg clone_inlined_nodes (e, duplicate, update_original, overall_size);
2381debfc3dSmrg }
2391debfc3dSmrg }
2401debfc3dSmrg
241*8feb0f0bSmrg /* Check all speculations in N and if any seem useless, resolve them. When a
242*8feb0f0bSmrg first edge is resolved, pop all edges from NEW_EDGES and insert them to
243*8feb0f0bSmrg EDGE_SET. Then remove each resolved edge from EDGE_SET, if it is there. */
2441debfc3dSmrg
2451debfc3dSmrg static bool
check_speculations_1(cgraph_node * n,vec<cgraph_edge * > * new_edges,hash_set<cgraph_edge * > * edge_set)246*8feb0f0bSmrg check_speculations_1 (cgraph_node *n, vec<cgraph_edge *> *new_edges,
247*8feb0f0bSmrg hash_set <cgraph_edge *> *edge_set)
2481debfc3dSmrg {
2491debfc3dSmrg bool speculation_removed = false;
2501debfc3dSmrg cgraph_edge *next;
2511debfc3dSmrg
2521debfc3dSmrg for (cgraph_edge *e = n->callees; e; e = next)
2531debfc3dSmrg {
2541debfc3dSmrg next = e->next_callee;
2551debfc3dSmrg if (e->speculative && !speculation_useful_p (e, true))
2561debfc3dSmrg {
257*8feb0f0bSmrg while (new_edges && !new_edges->is_empty ())
258*8feb0f0bSmrg edge_set->add (new_edges->pop ());
259*8feb0f0bSmrg edge_set->remove (e);
260*8feb0f0bSmrg
261*8feb0f0bSmrg cgraph_edge::resolve_speculation (e, NULL);
2621debfc3dSmrg speculation_removed = true;
2631debfc3dSmrg }
2641debfc3dSmrg else if (!e->inline_failed)
265*8feb0f0bSmrg speculation_removed |= check_speculations_1 (e->callee, new_edges,
266*8feb0f0bSmrg edge_set);
2671debfc3dSmrg }
2681debfc3dSmrg return speculation_removed;
2691debfc3dSmrg }
2701debfc3dSmrg
271*8feb0f0bSmrg /* Push E to NEW_EDGES. Called from hash_set traverse method, which
272*8feb0f0bSmrg unfortunately means this function has to have external linkage, otherwise
273*8feb0f0bSmrg the code will not compile with gcc 4.8. */
274*8feb0f0bSmrg
275*8feb0f0bSmrg bool
push_all_edges_in_set_to_vec(cgraph_edge * const & e,vec<cgraph_edge * > * new_edges)276*8feb0f0bSmrg push_all_edges_in_set_to_vec (cgraph_edge * const &e,
277*8feb0f0bSmrg vec<cgraph_edge *> *new_edges)
278*8feb0f0bSmrg {
279*8feb0f0bSmrg new_edges->safe_push (e);
280*8feb0f0bSmrg return true;
281*8feb0f0bSmrg }
282*8feb0f0bSmrg
283*8feb0f0bSmrg /* Check all speculations in N and if any seem useless, resolve them and remove
284*8feb0f0bSmrg them from NEW_EDGES. */
285*8feb0f0bSmrg
286*8feb0f0bSmrg static bool
check_speculations(cgraph_node * n,vec<cgraph_edge * > * new_edges)287*8feb0f0bSmrg check_speculations (cgraph_node *n, vec<cgraph_edge *> *new_edges)
288*8feb0f0bSmrg {
289*8feb0f0bSmrg hash_set <cgraph_edge *> edge_set;
290*8feb0f0bSmrg bool res = check_speculations_1 (n, new_edges, &edge_set);
291*8feb0f0bSmrg if (!edge_set.is_empty ())
292*8feb0f0bSmrg edge_set.traverse <vec<cgraph_edge *> *,
293*8feb0f0bSmrg push_all_edges_in_set_to_vec> (new_edges);
294*8feb0f0bSmrg return res;
295*8feb0f0bSmrg }
296*8feb0f0bSmrg
2971debfc3dSmrg /* Mark all call graph edges coming out of NODE and all nodes that have been
2981debfc3dSmrg inlined to it as in_polymorphic_cdtor. */
2991debfc3dSmrg
3001debfc3dSmrg static void
mark_all_inlined_calls_cdtor(cgraph_node * node)3011debfc3dSmrg mark_all_inlined_calls_cdtor (cgraph_node *node)
3021debfc3dSmrg {
3031debfc3dSmrg for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
3041debfc3dSmrg {
3051debfc3dSmrg cs->in_polymorphic_cdtor = true;
3061debfc3dSmrg if (!cs->inline_failed)
3071debfc3dSmrg mark_all_inlined_calls_cdtor (cs->callee);
3081debfc3dSmrg }
3091debfc3dSmrg for (cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee)
3101debfc3dSmrg cs->in_polymorphic_cdtor = true;
3111debfc3dSmrg }
3121debfc3dSmrg
3131debfc3dSmrg
3141debfc3dSmrg /* Mark edge E as inlined and update callgraph accordingly. UPDATE_ORIGINAL
3151debfc3dSmrg specify whether profile of original function should be updated. If any new
3161debfc3dSmrg indirect edges are discovered in the process, add them to NEW_EDGES, unless
3171debfc3dSmrg it is NULL. If UPDATE_OVERALL_SUMMARY is false, do not bother to recompute overall
3181debfc3dSmrg size of caller after inlining. Caller is required to eventually do it via
319a2dc1f3fSmrg ipa_update_overall_fn_summary.
3201debfc3dSmrg If callee_removed is non-NULL, set it to true if we removed callee node.
3211debfc3dSmrg
3221debfc3dSmrg Return true iff any new callgraph edges were discovered as a
3231debfc3dSmrg result of inlining. */
3241debfc3dSmrg
3251debfc3dSmrg bool
inline_call(struct cgraph_edge * e,bool update_original,vec<cgraph_edge * > * new_edges,int * overall_size,bool update_overall_summary,bool * callee_removed)3261debfc3dSmrg inline_call (struct cgraph_edge *e, bool update_original,
3271debfc3dSmrg vec<cgraph_edge *> *new_edges,
3281debfc3dSmrg int *overall_size, bool update_overall_summary,
3291debfc3dSmrg bool *callee_removed)
3301debfc3dSmrg {
3311debfc3dSmrg int old_size = 0, new_size = 0;
3321debfc3dSmrg struct cgraph_node *to = NULL;
3331debfc3dSmrg struct cgraph_edge *curr = e;
334*8feb0f0bSmrg bool comdat_local = e->callee->comdat_local_p ();
3351debfc3dSmrg struct cgraph_node *callee = e->callee->ultimate_alias_target ();
3361debfc3dSmrg bool new_edges_found = false;
3371debfc3dSmrg
3381debfc3dSmrg int estimated_growth = 0;
3391debfc3dSmrg if (! update_overall_summary)
3401debfc3dSmrg estimated_growth = estimate_edge_growth (e);
3411debfc3dSmrg /* This is used only for assert bellow. */
3421debfc3dSmrg #if 0
3431debfc3dSmrg bool predicated = inline_edge_summary (e)->predicate != NULL;
3441debfc3dSmrg #endif
3451debfc3dSmrg
3461debfc3dSmrg /* Don't inline inlined edges. */
3471debfc3dSmrg gcc_assert (e->inline_failed);
3481debfc3dSmrg /* Don't even think of inlining inline clone. */
349*8feb0f0bSmrg gcc_assert (!callee->inlined_to);
3501debfc3dSmrg
3511debfc3dSmrg to = e->caller;
352*8feb0f0bSmrg if (to->inlined_to)
353*8feb0f0bSmrg to = to->inlined_to;
3541debfc3dSmrg if (to->thunk.thunk_p)
3551debfc3dSmrg {
3561debfc3dSmrg struct cgraph_node *target = to->callees->callee;
357*8feb0f0bSmrg thunk_expansion = true;
358*8feb0f0bSmrg symtab->call_cgraph_removal_hooks (to);
3591debfc3dSmrg if (in_lto_p)
3601debfc3dSmrg to->get_untransformed_body ();
3611debfc3dSmrg to->expand_thunk (false, true);
3621debfc3dSmrg /* When thunk is instrumented we may have multiple callees. */
3631debfc3dSmrg for (e = to->callees; e && e->callee != target; e = e->next_callee)
3641debfc3dSmrg ;
365*8feb0f0bSmrg symtab->call_cgraph_insertion_hooks (to);
366*8feb0f0bSmrg thunk_expansion = false;
3671debfc3dSmrg gcc_assert (e);
3681debfc3dSmrg }
3691debfc3dSmrg
3701debfc3dSmrg
3711debfc3dSmrg e->inline_failed = CIF_OK;
3721debfc3dSmrg DECL_POSSIBLY_INLINED (callee->decl) = true;
3731debfc3dSmrg
3741debfc3dSmrg if (DECL_FUNCTION_PERSONALITY (callee->decl))
3751debfc3dSmrg DECL_FUNCTION_PERSONALITY (to->decl)
3761debfc3dSmrg = DECL_FUNCTION_PERSONALITY (callee->decl);
3771debfc3dSmrg
3781debfc3dSmrg bool reload_optimization_node = false;
3791debfc3dSmrg if (!opt_for_fn (callee->decl, flag_strict_aliasing)
3801debfc3dSmrg && opt_for_fn (to->decl, flag_strict_aliasing))
3811debfc3dSmrg {
3821debfc3dSmrg struct gcc_options opts = global_options;
3831debfc3dSmrg
3841debfc3dSmrg cl_optimization_restore (&opts, opts_for_fn (to->decl));
3851debfc3dSmrg opts.x_flag_strict_aliasing = false;
3861debfc3dSmrg if (dump_file)
387a2dc1f3fSmrg fprintf (dump_file, "Dropping flag_strict_aliasing on %s\n",
388a2dc1f3fSmrg to->dump_name ());
3891debfc3dSmrg DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
3901debfc3dSmrg = build_optimization_node (&opts);
3911debfc3dSmrg reload_optimization_node = true;
3921debfc3dSmrg }
3931debfc3dSmrg
394a2dc1f3fSmrg ipa_fn_summary *caller_info = ipa_fn_summaries->get (to);
395a2dc1f3fSmrg ipa_fn_summary *callee_info = ipa_fn_summaries->get (callee);
3961debfc3dSmrg if (!caller_info->fp_expressions && callee_info->fp_expressions)
3971debfc3dSmrg {
3981debfc3dSmrg caller_info->fp_expressions = true;
3991debfc3dSmrg if (opt_for_fn (callee->decl, flag_rounding_math)
4001debfc3dSmrg != opt_for_fn (to->decl, flag_rounding_math)
4011debfc3dSmrg || opt_for_fn (callee->decl, flag_trapping_math)
4021debfc3dSmrg != opt_for_fn (to->decl, flag_trapping_math)
4031debfc3dSmrg || opt_for_fn (callee->decl, flag_unsafe_math_optimizations)
4041debfc3dSmrg != opt_for_fn (to->decl, flag_unsafe_math_optimizations)
4051debfc3dSmrg || opt_for_fn (callee->decl, flag_finite_math_only)
4061debfc3dSmrg != opt_for_fn (to->decl, flag_finite_math_only)
4071debfc3dSmrg || opt_for_fn (callee->decl, flag_signaling_nans)
4081debfc3dSmrg != opt_for_fn (to->decl, flag_signaling_nans)
4091debfc3dSmrg || opt_for_fn (callee->decl, flag_cx_limited_range)
4101debfc3dSmrg != opt_for_fn (to->decl, flag_cx_limited_range)
4111debfc3dSmrg || opt_for_fn (callee->decl, flag_signed_zeros)
4121debfc3dSmrg != opt_for_fn (to->decl, flag_signed_zeros)
4131debfc3dSmrg || opt_for_fn (callee->decl, flag_associative_math)
4141debfc3dSmrg != opt_for_fn (to->decl, flag_associative_math)
4151debfc3dSmrg || opt_for_fn (callee->decl, flag_reciprocal_math)
4161debfc3dSmrg != opt_for_fn (to->decl, flag_reciprocal_math)
4171debfc3dSmrg || opt_for_fn (callee->decl, flag_fp_int_builtin_inexact)
4181debfc3dSmrg != opt_for_fn (to->decl, flag_fp_int_builtin_inexact)
4191debfc3dSmrg || opt_for_fn (callee->decl, flag_errno_math)
4201debfc3dSmrg != opt_for_fn (to->decl, flag_errno_math))
4211debfc3dSmrg {
4221debfc3dSmrg struct gcc_options opts = global_options;
4231debfc3dSmrg
4241debfc3dSmrg cl_optimization_restore (&opts, opts_for_fn (to->decl));
4251debfc3dSmrg opts.x_flag_rounding_math
4261debfc3dSmrg = opt_for_fn (callee->decl, flag_rounding_math);
4271debfc3dSmrg opts.x_flag_trapping_math
4281debfc3dSmrg = opt_for_fn (callee->decl, flag_trapping_math);
4291debfc3dSmrg opts.x_flag_unsafe_math_optimizations
4301debfc3dSmrg = opt_for_fn (callee->decl, flag_unsafe_math_optimizations);
4311debfc3dSmrg opts.x_flag_finite_math_only
4321debfc3dSmrg = opt_for_fn (callee->decl, flag_finite_math_only);
4331debfc3dSmrg opts.x_flag_signaling_nans
4341debfc3dSmrg = opt_for_fn (callee->decl, flag_signaling_nans);
4351debfc3dSmrg opts.x_flag_cx_limited_range
4361debfc3dSmrg = opt_for_fn (callee->decl, flag_cx_limited_range);
4371debfc3dSmrg opts.x_flag_signed_zeros
4381debfc3dSmrg = opt_for_fn (callee->decl, flag_signed_zeros);
4391debfc3dSmrg opts.x_flag_associative_math
4401debfc3dSmrg = opt_for_fn (callee->decl, flag_associative_math);
4411debfc3dSmrg opts.x_flag_reciprocal_math
4421debfc3dSmrg = opt_for_fn (callee->decl, flag_reciprocal_math);
4431debfc3dSmrg opts.x_flag_fp_int_builtin_inexact
4441debfc3dSmrg = opt_for_fn (callee->decl, flag_fp_int_builtin_inexact);
4451debfc3dSmrg opts.x_flag_errno_math
4461debfc3dSmrg = opt_for_fn (callee->decl, flag_errno_math);
4471debfc3dSmrg if (dump_file)
448a2dc1f3fSmrg fprintf (dump_file, "Copying FP flags from %s to %s\n",
449a2dc1f3fSmrg callee->dump_name (), to->dump_name ());
4501debfc3dSmrg DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
4511debfc3dSmrg = build_optimization_node (&opts);
4521debfc3dSmrg reload_optimization_node = true;
4531debfc3dSmrg }
4541debfc3dSmrg }
4551debfc3dSmrg
4561debfc3dSmrg /* Reload global optimization flags. */
4571debfc3dSmrg if (reload_optimization_node && DECL_STRUCT_FUNCTION (to->decl) == cfun)
4581debfc3dSmrg set_cfun (cfun, true);
4591debfc3dSmrg
4601debfc3dSmrg /* If aliases are involved, redirect edge to the actual destination and
4611debfc3dSmrg possibly remove the aliases. */
4621debfc3dSmrg if (e->callee != callee)
4631debfc3dSmrg {
4641debfc3dSmrg struct cgraph_node *alias = e->callee, *next_alias;
4651debfc3dSmrg e->redirect_callee (callee);
4661debfc3dSmrg while (alias && alias != callee)
4671debfc3dSmrg {
4681debfc3dSmrg if (!alias->callers
4691debfc3dSmrg && can_remove_node_now_p (alias,
4701debfc3dSmrg !e->next_caller && !e->prev_caller ? e : NULL))
4711debfc3dSmrg {
4721debfc3dSmrg next_alias = alias->get_alias_target ();
4731debfc3dSmrg alias->remove ();
4741debfc3dSmrg if (callee_removed)
4751debfc3dSmrg *callee_removed = true;
4761debfc3dSmrg alias = next_alias;
4771debfc3dSmrg }
4781debfc3dSmrg else
4791debfc3dSmrg break;
4801debfc3dSmrg }
4811debfc3dSmrg }
4821debfc3dSmrg
483a2dc1f3fSmrg clone_inlined_nodes (e, true, update_original, overall_size);
4841debfc3dSmrg
485*8feb0f0bSmrg gcc_assert (curr->callee->inlined_to == to);
4861debfc3dSmrg
487*8feb0f0bSmrg old_size = ipa_size_summaries->get (to)->size;
488a2dc1f3fSmrg ipa_merge_fn_summary_after_inlining (e);
4891debfc3dSmrg if (e->in_polymorphic_cdtor)
4901debfc3dSmrg mark_all_inlined_calls_cdtor (e->callee);
4911debfc3dSmrg if (opt_for_fn (e->caller->decl, optimize))
4921debfc3dSmrg new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges);
493*8feb0f0bSmrg bool removed_p = check_speculations (e->callee, new_edges);
4941debfc3dSmrg if (update_overall_summary)
495*8feb0f0bSmrg ipa_update_overall_fn_summary (to, new_edges_found || removed_p);
4961debfc3dSmrg else
4971debfc3dSmrg /* Update self size by the estimate so overall function growth limits
4981debfc3dSmrg work for further inlining into this function. Before inlining
4991debfc3dSmrg the function we inlined to again we expect the caller to update
5001debfc3dSmrg the overall summary. */
501*8feb0f0bSmrg ipa_size_summaries->get (to)->size += estimated_growth;
502*8feb0f0bSmrg new_size = ipa_size_summaries->get (to)->size;
5031debfc3dSmrg
5041debfc3dSmrg if (callee->calls_comdat_local)
5051debfc3dSmrg to->calls_comdat_local = true;
506*8feb0f0bSmrg else if (to->calls_comdat_local && comdat_local)
507*8feb0f0bSmrg to->calls_comdat_local = to->check_calls_comdat_local_p ();
5081debfc3dSmrg
5091debfc3dSmrg /* FIXME: This assert suffers from roundoff errors, disable it for GCC 5
5101debfc3dSmrg and revisit it after conversion to sreals in GCC 6.
5111debfc3dSmrg See PR 65654. */
5121debfc3dSmrg #if 0
5131debfc3dSmrg /* Verify that estimated growth match real growth. Allow off-by-one
514a2dc1f3fSmrg error due to ipa_fn_summary::size_scale roudoff errors. */
5151debfc3dSmrg gcc_assert (!update_overall_summary || !overall_size || new_edges_found
5161debfc3dSmrg || abs (estimated_growth - (new_size - old_size)) <= 1
5171debfc3dSmrg || speculation_removed
5181debfc3dSmrg /* FIXME: a hack. Edges with false predicate are accounted
5191debfc3dSmrg wrong, we should remove them from callgraph. */
5201debfc3dSmrg || predicated);
5211debfc3dSmrg #endif
5221debfc3dSmrg
5231debfc3dSmrg /* Account the change of overall unit size; external functions will be
5241debfc3dSmrg removed and are thus not accounted. */
5251debfc3dSmrg if (overall_size && inline_account_function_p (to))
5261debfc3dSmrg *overall_size += new_size - old_size;
5271debfc3dSmrg ncalls_inlined++;
5281debfc3dSmrg
529a2dc1f3fSmrg /* This must happen after ipa_merge_fn_summary_after_inlining that rely on jump
5301debfc3dSmrg functions of callee to not be updated. */
5311debfc3dSmrg return new_edges_found;
5321debfc3dSmrg }
5331debfc3dSmrg
534*8feb0f0bSmrg /* For each node that was made the holder of function body by
535*8feb0f0bSmrg save_inline_function_body, this summary contains pointer to the previous
536*8feb0f0bSmrg holder of the body. */
537*8feb0f0bSmrg
538*8feb0f0bSmrg function_summary <tree *> *ipa_saved_clone_sources;
5391debfc3dSmrg
5401debfc3dSmrg /* Copy function body of NODE and redirect all inline clones to it.
5411debfc3dSmrg This is done before inline plan is applied to NODE when there are
5421debfc3dSmrg still some inline clones if it.
5431debfc3dSmrg
5441debfc3dSmrg This is necessary because inline decisions are not really transitive
5451debfc3dSmrg and the other inline clones may have different bodies. */
5461debfc3dSmrg
5471debfc3dSmrg static struct cgraph_node *
save_inline_function_body(struct cgraph_node * node)5481debfc3dSmrg save_inline_function_body (struct cgraph_node *node)
5491debfc3dSmrg {
5501debfc3dSmrg struct cgraph_node *first_clone, *n;
5511debfc3dSmrg
5521debfc3dSmrg if (dump_file)
5531debfc3dSmrg fprintf (dump_file, "\nSaving body of %s for later reuse\n",
554*8feb0f0bSmrg node->dump_name ());
5551debfc3dSmrg
5561debfc3dSmrg gcc_assert (node == cgraph_node::get (node->decl));
5571debfc3dSmrg
5581debfc3dSmrg /* first_clone will be turned into real function. */
5591debfc3dSmrg first_clone = node->clones;
5601debfc3dSmrg
5611debfc3dSmrg /* Arrange first clone to not be thunk as those do not have bodies. */
5621debfc3dSmrg if (first_clone->thunk.thunk_p)
5631debfc3dSmrg {
5641debfc3dSmrg while (first_clone->thunk.thunk_p)
5651debfc3dSmrg first_clone = first_clone->next_sibling_clone;
5661debfc3dSmrg first_clone->prev_sibling_clone->next_sibling_clone
5671debfc3dSmrg = first_clone->next_sibling_clone;
5681debfc3dSmrg if (first_clone->next_sibling_clone)
5691debfc3dSmrg first_clone->next_sibling_clone->prev_sibling_clone
5701debfc3dSmrg = first_clone->prev_sibling_clone;
5711debfc3dSmrg first_clone->next_sibling_clone = node->clones;
5721debfc3dSmrg first_clone->prev_sibling_clone = NULL;
5731debfc3dSmrg node->clones->prev_sibling_clone = first_clone;
5741debfc3dSmrg node->clones = first_clone;
5751debfc3dSmrg }
5761debfc3dSmrg first_clone->decl = copy_node (node->decl);
5771debfc3dSmrg first_clone->decl->decl_with_vis.symtab_node = first_clone;
5781debfc3dSmrg gcc_assert (first_clone == cgraph_node::get (first_clone->decl));
5791debfc3dSmrg
5801debfc3dSmrg /* Now reshape the clone tree, so all other clones descends from
5811debfc3dSmrg first_clone. */
5821debfc3dSmrg if (first_clone->next_sibling_clone)
5831debfc3dSmrg {
5841debfc3dSmrg for (n = first_clone->next_sibling_clone; n->next_sibling_clone;
5851debfc3dSmrg n = n->next_sibling_clone)
5861debfc3dSmrg n->clone_of = first_clone;
5871debfc3dSmrg n->clone_of = first_clone;
5881debfc3dSmrg n->next_sibling_clone = first_clone->clones;
5891debfc3dSmrg if (first_clone->clones)
5901debfc3dSmrg first_clone->clones->prev_sibling_clone = n;
5911debfc3dSmrg first_clone->clones = first_clone->next_sibling_clone;
5921debfc3dSmrg first_clone->next_sibling_clone->prev_sibling_clone = NULL;
5931debfc3dSmrg first_clone->next_sibling_clone = NULL;
5941debfc3dSmrg gcc_assert (!first_clone->prev_sibling_clone);
5951debfc3dSmrg }
596*8feb0f0bSmrg
597*8feb0f0bSmrg tree prev_body_holder = node->decl;
598*8feb0f0bSmrg if (!ipa_saved_clone_sources)
599*8feb0f0bSmrg ipa_saved_clone_sources = new function_summary <tree *> (symtab);
600*8feb0f0bSmrg else
601*8feb0f0bSmrg {
602*8feb0f0bSmrg tree *p = ipa_saved_clone_sources->get (node);
603*8feb0f0bSmrg if (p)
604*8feb0f0bSmrg {
605*8feb0f0bSmrg prev_body_holder = *p;
606*8feb0f0bSmrg gcc_assert (prev_body_holder);
607*8feb0f0bSmrg }
608*8feb0f0bSmrg }
609*8feb0f0bSmrg *ipa_saved_clone_sources->get_create (first_clone) = prev_body_holder;
610*8feb0f0bSmrg first_clone->former_clone_of
611*8feb0f0bSmrg = node->former_clone_of ? node->former_clone_of : node->decl;
6121debfc3dSmrg first_clone->clone_of = NULL;
6131debfc3dSmrg
6141debfc3dSmrg /* Now node in question has no clones. */
6151debfc3dSmrg node->clones = NULL;
6161debfc3dSmrg
6171debfc3dSmrg /* Inline clones share decl with the function they are cloned
6181debfc3dSmrg from. Walk the whole clone tree and redirect them all to the
6191debfc3dSmrg new decl. */
6201debfc3dSmrg if (first_clone->clones)
6211debfc3dSmrg for (n = first_clone->clones; n != first_clone;)
6221debfc3dSmrg {
6231debfc3dSmrg gcc_assert (n->decl == node->decl);
6241debfc3dSmrg n->decl = first_clone->decl;
6251debfc3dSmrg if (n->clones)
6261debfc3dSmrg n = n->clones;
6271debfc3dSmrg else if (n->next_sibling_clone)
6281debfc3dSmrg n = n->next_sibling_clone;
6291debfc3dSmrg else
6301debfc3dSmrg {
6311debfc3dSmrg while (n != first_clone && !n->next_sibling_clone)
6321debfc3dSmrg n = n->clone_of;
6331debfc3dSmrg if (n != first_clone)
6341debfc3dSmrg n = n->next_sibling_clone;
6351debfc3dSmrg }
6361debfc3dSmrg }
6371debfc3dSmrg
6381debfc3dSmrg /* Copy the OLD_VERSION_NODE function tree to the new version. */
6391debfc3dSmrg tree_function_versioning (node->decl, first_clone->decl,
640*8feb0f0bSmrg NULL, NULL, true, NULL, NULL);
6411debfc3dSmrg
6421debfc3dSmrg /* The function will be short lived and removed after we inline all the clones,
6431debfc3dSmrg but make it internal so we won't confuse ourself. */
6441debfc3dSmrg DECL_EXTERNAL (first_clone->decl) = 0;
6451debfc3dSmrg TREE_PUBLIC (first_clone->decl) = 0;
6461debfc3dSmrg DECL_COMDAT (first_clone->decl) = 0;
6471debfc3dSmrg first_clone->ipa_transforms_to_apply.release ();
6481debfc3dSmrg
6491debfc3dSmrg /* When doing recursive inlining, the clone may become unnecessary.
6501debfc3dSmrg This is possible i.e. in the case when the recursive function is proved to be
6511debfc3dSmrg non-throwing and the recursion happens only in the EH landing pad.
6521debfc3dSmrg We cannot remove the clone until we are done with saving the body.
6531debfc3dSmrg Remove it now. */
6541debfc3dSmrg if (!first_clone->callers)
6551debfc3dSmrg {
6561debfc3dSmrg first_clone->remove_symbol_and_inline_clones ();
6571debfc3dSmrg first_clone = NULL;
6581debfc3dSmrg }
6591debfc3dSmrg else if (flag_checking)
6601debfc3dSmrg first_clone->verify ();
6611debfc3dSmrg
6621debfc3dSmrg return first_clone;
6631debfc3dSmrg }
6641debfc3dSmrg
6651debfc3dSmrg /* Return true when function body of DECL still needs to be kept around
6661debfc3dSmrg for later re-use. */
6671debfc3dSmrg static bool
preserve_function_body_p(struct cgraph_node * node)6681debfc3dSmrg preserve_function_body_p (struct cgraph_node *node)
6691debfc3dSmrg {
6701debfc3dSmrg gcc_assert (symtab->global_info_ready);
6711debfc3dSmrg gcc_assert (!node->alias && !node->thunk.thunk_p);
6721debfc3dSmrg
6731debfc3dSmrg /* Look if there is any non-thunk clone around. */
6741debfc3dSmrg for (node = node->clones; node; node = node->next_sibling_clone)
6751debfc3dSmrg if (!node->thunk.thunk_p)
6761debfc3dSmrg return true;
6771debfc3dSmrg return false;
6781debfc3dSmrg }
6791debfc3dSmrg
6801debfc3dSmrg /* Apply inline plan to function. */
6811debfc3dSmrg
6821debfc3dSmrg unsigned int
inline_transform(struct cgraph_node * node)6831debfc3dSmrg inline_transform (struct cgraph_node *node)
6841debfc3dSmrg {
6851debfc3dSmrg unsigned int todo = 0;
6861debfc3dSmrg struct cgraph_edge *e, *next;
6871debfc3dSmrg bool has_inline = false;
6881debfc3dSmrg
6891debfc3dSmrg /* FIXME: Currently the pass manager is adding inline transform more than
6901debfc3dSmrg once to some clones. This needs revisiting after WPA cleanups. */
6911debfc3dSmrg if (cfun->after_inlining)
6921debfc3dSmrg return 0;
6931debfc3dSmrg
6941debfc3dSmrg /* We might need the body of this function so that we can expand
6951debfc3dSmrg it inline somewhere else. */
6961debfc3dSmrg if (preserve_function_body_p (node))
6971debfc3dSmrg save_inline_function_body (node);
6981debfc3dSmrg
699a2dc1f3fSmrg profile_count num = node->count;
700a2dc1f3fSmrg profile_count den = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
701a2dc1f3fSmrg bool scale = num.initialized_p () && !(num == den);
702a2dc1f3fSmrg if (scale)
703a2dc1f3fSmrg {
704a2dc1f3fSmrg profile_count::adjust_for_ipa_scaling (&num, &den);
705a2dc1f3fSmrg if (dump_file)
706a2dc1f3fSmrg {
707a2dc1f3fSmrg fprintf (dump_file, "Applying count scale ");
708a2dc1f3fSmrg num.dump (dump_file);
709a2dc1f3fSmrg fprintf (dump_file, "/");
710a2dc1f3fSmrg den.dump (dump_file);
711a2dc1f3fSmrg fprintf (dump_file, "\n");
712a2dc1f3fSmrg }
713a2dc1f3fSmrg
714a2dc1f3fSmrg basic_block bb;
715a2dc1f3fSmrg cfun->cfg->count_max = profile_count::uninitialized ();
716a2dc1f3fSmrg FOR_ALL_BB_FN (bb, cfun)
717a2dc1f3fSmrg {
718a2dc1f3fSmrg bb->count = bb->count.apply_scale (num, den);
719a2dc1f3fSmrg cfun->cfg->count_max = cfun->cfg->count_max.max (bb->count);
720a2dc1f3fSmrg }
721a2dc1f3fSmrg ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = node->count;
722a2dc1f3fSmrg }
723*8feb0f0bSmrg
724*8feb0f0bSmrg for (e = node->callees; e; e = next)
725*8feb0f0bSmrg {
726*8feb0f0bSmrg if (!e->inline_failed)
727*8feb0f0bSmrg has_inline = true;
728*8feb0f0bSmrg next = e->next_callee;
729*8feb0f0bSmrg cgraph_edge::redirect_call_stmt_to_callee (e);
730*8feb0f0bSmrg }
731*8feb0f0bSmrg node->remove_all_references ();
732*8feb0f0bSmrg
733*8feb0f0bSmrg timevar_push (TV_INTEGRATION);
734*8feb0f0bSmrg if (node->callees && (opt_for_fn (node->decl, optimize) || has_inline))
735*8feb0f0bSmrg {
7361debfc3dSmrg todo = optimize_inline_calls (current_function_decl);
737a2dc1f3fSmrg }
7381debfc3dSmrg timevar_pop (TV_INTEGRATION);
7391debfc3dSmrg
7401debfc3dSmrg cfun->always_inline_functions_inlined = true;
7411debfc3dSmrg cfun->after_inlining = true;
7421debfc3dSmrg todo |= execute_fixup_cfg ();
7431debfc3dSmrg
7441debfc3dSmrg if (!(todo & TODO_update_ssa_any))
7451debfc3dSmrg /* Redirecting edges might lead to a need for vops to be recomputed. */
7461debfc3dSmrg todo |= TODO_update_ssa_only_virtuals;
7471debfc3dSmrg
7481debfc3dSmrg return todo;
7491debfc3dSmrg }
750