xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/ipa-inline-transform.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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