2005-04-29 Jim Tison <jtison@us.ibm.com>
[official-gcc.git] / gcc / ipa-inline.c
blobf1236eac5f47a9199ecfa40ad8ff83d24fd2eef5
1 /* Inlining decision heuristics.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
22 /* Inlining decision heuristics
24 We separate inlining decisions from the inliner itself and store it
25 inside callgraph as so called inline plan. Refer to cgraph.c
26 documentation about particular representation of inline plans in the
27 callgraph.
29 There are three major parts of this file:
31 cgraph_mark_inline implementation
33 This function allows to mark given call inline and performs necessary
34 modifications of cgraph (production of the clones and updating overall
35 statistics)
37 inlining heuristics limits
39 These functions allow to check that particular inlining is allowed
40 by the limits specified by user (allowed function growth, overall unit
41 growth and so on).
43 inlining heuristics
45 This is implementation of IPA pass aiming to get as much of benefit
46 from inlining obeying the limits checked above.
48 The implementation of particular heuristics is separated from
49 the rest of code to make it easier to replace it with more complicated
50 implementation in the future. The rest of inlining code acts as a
51 library aimed to modify the callgraph and verify that the parameters
52 on code size growth fits.
54 To mark given call inline, use cgraph_mark_inline function, the
55 verification is performed by cgraph_default_inline_p and
56 cgraph_check_inline_limits.
58 The heuristics implements simple knapsack style algorithm ordering
59 all functions by their "profitability" (estimated by code size growth)
60 and inlining them in priority order.
62 cgraph_decide_inlining implements heuristics taking whole callgraph
63 into account, while cgraph_decide_inlining_incrementally considers
64 only one function at a time and is used in non-unit-at-a-time mode. */
66 #include "config.h"
67 #include "system.h"
68 #include "coretypes.h"
69 #include "tm.h"
70 #include "tree.h"
71 #include "tree-inline.h"
72 #include "langhooks.h"
73 #include "flags.h"
74 #include "cgraph.h"
75 #include "diagnostic.h"
76 #include "timevar.h"
77 #include "params.h"
78 #include "fibheap.h"
79 #include "intl.h"
80 #include "tree-pass.h"
82 /* Statistics we collect about inlining algorithm. */
83 static int ncalls_inlined;
84 static int nfunctions_inlined;
85 static int initial_insns;
86 static int overall_insns;
88 /* Estimate size of the function after inlining WHAT into TO. */
90 static int
91 cgraph_estimate_size_after_inlining (int times, struct cgraph_node *to,
92 struct cgraph_node *what)
94 tree fndecl = what->decl;
95 tree arg;
96 int call_insns = PARAM_VALUE (PARAM_INLINE_CALL_COST);
97 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
98 call_insns += estimate_move_cost (TREE_TYPE (arg));
99 return (what->global.insns - call_insns) * times + to->global.insns;
102 /* E is expected to be an edge being inlined. Clone destination node of
103 the edge and redirect it to the new clone.
104 DUPLICATE is used for bookkeeping on whether we are actually creating new
105 clones or re-using node originally representing out-of-line function call.
107 void
108 cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate)
110 struct cgraph_node *n;
112 /* We may eliminate the need for out-of-line copy to be output. In that
113 case just go ahead and re-use it. */
114 if (!e->callee->callers->next_caller
115 && (!e->callee->needed || DECL_EXTERNAL (e->callee->decl))
116 && duplicate
117 && flag_unit_at_a_time)
119 gcc_assert (!e->callee->global.inlined_to);
120 if (!DECL_EXTERNAL (e->callee->decl))
121 overall_insns -= e->callee->global.insns, nfunctions_inlined++;
122 duplicate = 0;
124 else if (duplicate)
126 n = cgraph_clone_node (e->callee);
127 cgraph_redirect_edge_callee (e, n);
130 if (e->caller->global.inlined_to)
131 e->callee->global.inlined_to = e->caller->global.inlined_to;
132 else
133 e->callee->global.inlined_to = e->caller;
135 /* Recursively clone all bodies. */
136 for (e = e->callee->callees; e; e = e->next_callee)
137 if (!e->inline_failed)
138 cgraph_clone_inlined_nodes (e, duplicate);
141 /* Mark edge E as inlined and update callgraph accordingly. */
143 void
144 cgraph_mark_inline_edge (struct cgraph_edge *e)
146 int old_insns = 0, new_insns = 0;
147 struct cgraph_node *to = NULL, *what;
149 gcc_assert (e->inline_failed);
150 e->inline_failed = NULL;
152 if (!e->callee->global.inlined && flag_unit_at_a_time)
153 DECL_POSSIBLY_INLINED (e->callee->decl) = true;
154 e->callee->global.inlined = true;
156 cgraph_clone_inlined_nodes (e, true);
158 what = e->callee;
160 /* Now update size of caller and all functions caller is inlined into. */
161 for (;e && !e->inline_failed; e = e->caller->callers)
163 old_insns = e->caller->global.insns;
164 new_insns = cgraph_estimate_size_after_inlining (1, e->caller,
165 what);
166 gcc_assert (new_insns >= 0);
167 to = e->caller;
168 to->global.insns = new_insns;
170 gcc_assert (what->global.inlined_to == to);
171 if (new_insns > old_insns)
172 overall_insns += new_insns - old_insns;
173 ncalls_inlined++;
176 /* Mark all calls of EDGE->CALLEE inlined into EDGE->CALLER.
177 Return following unredirected edge in the list of callers
178 of EDGE->CALLEE */
180 static struct cgraph_edge *
181 cgraph_mark_inline (struct cgraph_edge *edge)
183 struct cgraph_node *to = edge->caller;
184 struct cgraph_node *what = edge->callee;
185 struct cgraph_edge *e, *next;
186 int times = 0;
188 /* Look for all calls, mark them inline and clone recursively
189 all inlined functions. */
190 for (e = what->callers; e; e = next)
192 next = e->next_caller;
193 if (e->caller == to && e->inline_failed)
195 cgraph_mark_inline_edge (e);
196 if (e == edge)
197 edge = next;
198 times++;
201 gcc_assert (times);
202 return edge;
205 /* Estimate the growth caused by inlining NODE into all callees. */
207 static int
208 cgraph_estimate_growth (struct cgraph_node *node)
210 int growth = 0;
211 struct cgraph_edge *e;
213 for (e = node->callers; e; e = e->next_caller)
214 if (e->inline_failed)
215 growth += (cgraph_estimate_size_after_inlining (1, e->caller, node)
216 - e->caller->global.insns);
218 /* ??? Wrong for self recursive functions or cases where we decide to not
219 inline for different reasons, but it is not big deal as in that case
220 we will keep the body around, but we will also avoid some inlining. */
221 if (!node->needed && !DECL_EXTERNAL (node->decl))
222 growth -= node->global.insns;
224 return growth;
227 /* Return false when inlining WHAT into TO is not good idea
228 as it would cause too large growth of function bodies. */
230 static bool
231 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
232 const char **reason)
234 int times = 0;
235 struct cgraph_edge *e;
236 int newsize;
237 int limit;
239 if (to->global.inlined_to)
240 to = to->global.inlined_to;
242 for (e = to->callees; e; e = e->next_callee)
243 if (e->callee == what)
244 times++;
246 /* When inlining large function body called once into small function,
247 take the inlined function as base for limiting the growth. */
248 if (to->local.self_insns > what->local.self_insns)
249 limit = to->local.self_insns;
250 else
251 limit = what->local.self_insns;
253 limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100;
255 newsize = cgraph_estimate_size_after_inlining (times, to, what);
256 if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
257 && newsize > limit)
259 if (reason)
260 *reason = N_("--param large-function-growth limit reached");
261 return false;
263 return true;
266 /* Return true when function N is small enough to be inlined. */
268 bool
269 cgraph_default_inline_p (struct cgraph_node *n)
271 if (!DECL_INLINE (n->decl) || !DECL_SAVED_TREE (n->decl))
272 return false;
273 if (DECL_DECLARED_INLINE_P (n->decl))
274 return n->global.insns < MAX_INLINE_INSNS_SINGLE;
275 else
276 return n->global.insns < MAX_INLINE_INSNS_AUTO;
279 /* Return true when inlining WHAT would create recursive inlining.
280 We call recursive inlining all cases where same function appears more than
281 once in the single recursion nest path in the inline graph. */
283 static bool
284 cgraph_recursive_inlining_p (struct cgraph_node *to,
285 struct cgraph_node *what,
286 const char **reason)
288 bool recursive;
289 if (to->global.inlined_to)
290 recursive = what->decl == to->global.inlined_to->decl;
291 else
292 recursive = what->decl == to->decl;
293 /* Marking recursive function inline has sane semantic and thus we should
294 not warn on it. */
295 if (recursive && reason)
296 *reason = (what->local.disregard_inline_limits
297 ? N_("recursive inlining") : "");
298 return recursive;
301 /* Recompute heap nodes for each of callees. */
302 static void
303 update_callee_keys (fibheap_t heap, struct fibnode **heap_node,
304 struct cgraph_node *node)
306 struct cgraph_edge *e;
308 for (e = node->callees; e; e = e->next_callee)
309 if (e->inline_failed && heap_node[e->callee->uid])
310 fibheap_replace_key (heap, heap_node[e->callee->uid],
311 cgraph_estimate_growth (e->callee));
312 else if (!e->inline_failed)
313 update_callee_keys (heap, heap_node, e->callee);
316 /* Enqueue all recursive calls from NODE into queue linked via aux pointers
317 in between FIRST and LAST. WHERE is used for bookkeeping while looking
318 int calls inlined within NODE. */
319 static void
320 lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
321 struct cgraph_edge **first, struct cgraph_edge **last)
323 struct cgraph_edge *e;
324 for (e = where->callees; e; e = e->next_callee)
325 if (e->callee == node)
327 if (!*first)
328 *first = e;
329 else
330 (*last)->aux = e;
331 *last = e;
333 for (e = where->callees; e; e = e->next_callee)
334 if (!e->inline_failed)
335 lookup_recursive_calls (node, e->callee, first, last);
338 /* Decide on recursive inlining: in the case function has recursive calls,
339 inline until body size reaches given argument. */
340 static void
341 cgraph_decide_recursive_inlining (struct cgraph_node *node)
343 int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
344 int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO);
345 struct cgraph_edge *first_call = NULL, *last_call = NULL;
346 struct cgraph_edge *last_in_current_depth;
347 struct cgraph_edge *e;
348 struct cgraph_node *master_clone;
349 int depth = 0;
350 int n = 0;
352 if (DECL_DECLARED_INLINE_P (node->decl))
354 limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE);
355 max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH);
358 /* Make sure that function is small enough to be considered for inlining. */
359 if (!max_depth
360 || cgraph_estimate_size_after_inlining (1, node, node) >= limit)
361 return;
362 lookup_recursive_calls (node, node, &first_call, &last_call);
363 if (!first_call)
364 return;
366 if (dump_file)
367 fprintf (dump_file,
368 "\nPerforming recursive inlining on %s\n",
369 cgraph_node_name (node));
371 /* We need original clone to copy around. */
372 master_clone = cgraph_clone_node (node);
373 master_clone->needed = true;
374 for (e = master_clone->callees; e; e = e->next_callee)
375 if (!e->inline_failed)
376 cgraph_clone_inlined_nodes (e, true);
378 /* Do the inlining and update list of recursive call during process. */
379 last_in_current_depth = last_call;
380 while (first_call
381 && cgraph_estimate_size_after_inlining (1, node, master_clone) <= limit)
383 struct cgraph_edge *curr = first_call;
385 first_call = first_call->aux;
386 curr->aux = NULL;
388 cgraph_redirect_edge_callee (curr, master_clone);
389 cgraph_mark_inline_edge (curr);
390 lookup_recursive_calls (node, curr->callee, &first_call, &last_call);
392 if (last_in_current_depth
393 && ++depth >= max_depth)
394 break;
395 n++;
398 /* Cleanup queue pointers. */
399 while (first_call)
401 struct cgraph_edge *next = first_call->aux;
402 first_call->aux = NULL;
403 first_call = next;
405 if (dump_file)
406 fprintf (dump_file,
407 "\n Inlined %i times, body grown from %i to %i insns\n", n,
408 master_clone->global.insns, node->global.insns);
410 /* Remove master clone we used for inlining. We rely that clones inlined
411 into master clone gets queued just before master clone so we don't
412 need recursion. */
413 for (node = cgraph_nodes; node != master_clone;
414 node = node->next)
415 if (node->global.inlined_to == master_clone)
416 cgraph_remove_node (node);
417 cgraph_remove_node (master_clone);
420 /* Set inline_failed for all callers of given function to REASON. */
422 static void
423 cgraph_set_inline_failed (struct cgraph_node *node, const char *reason)
425 struct cgraph_edge *e;
427 if (dump_file)
428 fprintf (dump_file, "Inlining failed: %s\n", reason);
429 for (e = node->callers; e; e = e->next_caller)
430 if (e->inline_failed)
431 e->inline_failed = reason;
434 /* We use greedy algorithm for inlining of small functions:
435 All inline candidates are put into prioritized heap based on estimated
436 growth of the overall number of instructions and then update the estimates.
438 INLINED and INLINED_CALEES are just pointers to arrays large enough
439 to be passed to cgraph_inlined_into and cgraph_inlined_callees. */
441 static void
442 cgraph_decide_inlining_of_small_functions (void)
444 struct cgraph_node *node;
445 fibheap_t heap = fibheap_new ();
446 struct fibnode **heap_node =
447 xcalloc (cgraph_max_uid, sizeof (struct fibnode *));
448 int max_insns = ((HOST_WIDEST_INT) initial_insns
449 * (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH)) / 100);
451 /* Put all inline candidates into the heap. */
453 for (node = cgraph_nodes; node; node = node->next)
455 if (!node->local.inlinable || !node->callers
456 || node->local.disregard_inline_limits)
457 continue;
459 if (!cgraph_default_inline_p (node))
461 cgraph_set_inline_failed (node,
462 N_("--param max-inline-insns-single limit reached"));
463 continue;
465 heap_node[node->uid] =
466 fibheap_insert (heap, cgraph_estimate_growth (node), node);
469 if (dump_file)
470 fprintf (dump_file, "\nDeciding on smaller functions:\n");
471 while (overall_insns <= max_insns && (node = fibheap_extract_min (heap)))
473 struct cgraph_edge *e, *next;
474 int old_insns = overall_insns;
476 heap_node[node->uid] = NULL;
477 if (dump_file)
478 fprintf (dump_file,
479 "\nConsidering %s with %i insns\n"
480 " Estimated growth is %+i insns.\n",
481 cgraph_node_name (node), node->global.insns,
482 cgraph_estimate_growth (node));
483 if (!cgraph_default_inline_p (node))
485 cgraph_set_inline_failed (node,
486 N_("--param max-inline-insns-single limit reached after inlining into the callee"));
487 continue;
489 for (e = node->callers; e; e = next)
491 next = e->next_caller;
492 if (e->inline_failed)
494 struct cgraph_node *where;
496 if (cgraph_recursive_inlining_p (e->caller, e->callee,
497 &e->inline_failed)
498 || !cgraph_check_inline_limits (e->caller, e->callee,
499 &e->inline_failed))
501 if (dump_file)
502 fprintf (dump_file, " Not inlining into %s:%s.\n",
503 cgraph_node_name (e->caller), e->inline_failed);
504 continue;
506 next = cgraph_mark_inline (e);
507 where = e->caller;
508 if (where->global.inlined_to)
509 where = where->global.inlined_to;
511 if (heap_node[where->uid])
512 fibheap_replace_key (heap, heap_node[where->uid],
513 cgraph_estimate_growth (where));
515 if (dump_file)
516 fprintf (dump_file,
517 " Inlined into %s which now has %i insns.\n",
518 cgraph_node_name (e->caller),
519 e->caller->global.insns);
523 cgraph_decide_recursive_inlining (node);
525 /* Similarly all functions called by the function we just inlined
526 are now called more times; update keys. */
527 update_callee_keys (heap, heap_node, node);
529 if (dump_file)
530 fprintf (dump_file,
531 " Inlined for a net change of %+i insns.\n",
532 overall_insns - old_insns);
534 while ((node = fibheap_extract_min (heap)) != NULL)
535 if (!node->local.disregard_inline_limits)
536 cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached"));
537 fibheap_delete (heap);
538 free (heap_node);
541 /* Decide on the inlining. We do so in the topological order to avoid
542 expenses on updating data structures. */
544 static void
545 cgraph_decide_inlining (void)
547 struct cgraph_node *node;
548 int nnodes;
549 struct cgraph_node **order =
550 xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
551 int old_insns = 0;
552 int i;
554 for (node = cgraph_nodes; node; node = node->next)
555 initial_insns += node->local.self_insns;
556 overall_insns = initial_insns;
558 nnodes = cgraph_postorder (order);
560 if (dump_file)
561 fprintf (dump_file,
562 "\nDeciding on inlining. Starting with %i insns.\n",
563 initial_insns);
565 for (node = cgraph_nodes; node; node = node->next)
566 node->aux = 0;
568 if (dump_file)
569 fprintf (dump_file, "\nInlining always_inline functions:\n");
571 /* In the first pass mark all always_inline edges. Do this with a priority
572 so none of our later choices will make this impossible. */
573 for (i = nnodes - 1; i >= 0; i--)
575 struct cgraph_edge *e, *next;
577 node = order[i];
579 if (!node->local.disregard_inline_limits)
580 continue;
581 if (dump_file)
582 fprintf (dump_file,
583 "\nConsidering %s %i insns (always inline)\n",
584 cgraph_node_name (node), node->global.insns);
585 old_insns = overall_insns;
586 for (e = node->callers; e; e = next)
588 next = e->next_caller;
589 if (!e->inline_failed)
590 continue;
591 if (cgraph_recursive_inlining_p (e->caller, e->callee,
592 &e->inline_failed))
593 continue;
594 cgraph_mark_inline_edge (e);
595 if (dump_file)
596 fprintf (dump_file,
597 " Inlined into %s which now has %i insns.\n",
598 cgraph_node_name (e->caller),
599 e->caller->global.insns);
601 if (dump_file)
602 fprintf (dump_file,
603 " Inlined for a net change of %+i insns.\n",
604 overall_insns - old_insns);
607 if (!flag_really_no_inline)
609 cgraph_decide_inlining_of_small_functions ();
611 if (dump_file)
612 fprintf (dump_file, "\nDeciding on functions called once:\n");
614 /* And finally decide what functions are called once. */
616 for (i = nnodes - 1; i >= 0; i--)
618 node = order[i];
620 if (node->callers && !node->callers->next_caller && !node->needed
621 && node->local.inlinable && node->callers->inline_failed
622 && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
624 bool ok = true;
625 struct cgraph_node *node1;
627 /* Verify that we won't duplicate the caller. */
628 for (node1 = node->callers->caller;
629 node1->callers && !node1->callers->inline_failed
630 && ok; node1 = node1->callers->caller)
631 if (node1->callers->next_caller || node1->needed)
632 ok = false;
633 if (ok)
635 if (dump_file)
636 fprintf (dump_file,
637 "\nConsidering %s %i insns.\n"
638 " Called once from %s %i insns.\n",
639 cgraph_node_name (node), node->global.insns,
640 cgraph_node_name (node->callers->caller),
641 node->callers->caller->global.insns);
643 old_insns = overall_insns;
645 if (cgraph_check_inline_limits (node->callers->caller, node,
646 NULL))
648 cgraph_mark_inline (node->callers);
649 if (dump_file)
650 fprintf (dump_file,
651 " Inlined into %s which now has %i insns"
652 " for a net change of %+i insns.\n",
653 cgraph_node_name (node->callers->caller),
654 node->callers->caller->global.insns,
655 overall_insns - old_insns);
657 else
659 if (dump_file)
660 fprintf (dump_file,
661 " Inline limit reached, not inlined.\n");
668 /* We will never output extern functions we didn't inline.
669 ??? Perhaps we can prevent accounting of growth of external
670 inline functions. */
671 cgraph_remove_unreachable_nodes (false, dump_file);
673 if (dump_file)
674 fprintf (dump_file,
675 "\nInlined %i calls, eliminated %i functions, "
676 "%i insns turned to %i insns.\n\n",
677 ncalls_inlined, nfunctions_inlined, initial_insns,
678 overall_insns);
679 free (order);
682 /* Decide on the inlining. We do so in the topological order to avoid
683 expenses on updating data structures. */
685 void
686 cgraph_decide_inlining_incrementally (struct cgraph_node *node)
688 struct cgraph_edge *e;
690 /* First of all look for always inline functions. */
691 for (e = node->callees; e; e = e->next_callee)
692 if (e->callee->local.disregard_inline_limits
693 && e->inline_failed
694 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
695 /* ??? It is possible that renaming variable removed the function body
696 in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */
697 && DECL_SAVED_TREE (e->callee->decl))
698 cgraph_mark_inline (e);
700 /* Now do the automatic inlining. */
701 if (!flag_really_no_inline)
702 for (e = node->callees; e; e = e->next_callee)
703 if (e->callee->local.inlinable
704 && e->inline_failed
705 && !e->callee->local.disregard_inline_limits
706 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
707 && cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
708 && DECL_SAVED_TREE (e->callee->decl))
710 if (cgraph_default_inline_p (e->callee))
711 cgraph_mark_inline (e);
712 else
713 e->inline_failed
714 = N_("--param max-inline-insns-single limit reached");
718 /* When inlining shall be performed. */
719 static bool
720 cgraph_gate_inlining (void)
722 return flag_inline_trees;
725 struct tree_opt_pass pass_ipa_inline =
727 "inline", /* name */
728 cgraph_gate_inlining, /* gate */
729 cgraph_decide_inlining, /* execute */
730 NULL, /* sub */
731 NULL, /* next */
732 0, /* static_pass_number */
733 TV_INTEGRATION, /* tv_id */
734 0, /* properties_required */
735 PROP_trees, /* properties_provided */
736 0, /* properties_destroyed */
737 0, /* todo_flags_start */
738 TODO_dump_cgraph | TODO_dump_func, /* todo_flags_finish */
739 0 /* letter */