00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include "config.h"
00067 #include "system.h"
00068 #include "coretypes.h"
00069 #include "tm.h"
00070 #include "tree.h"
00071 #include "tree-inline.h"
00072 #include "langhooks.h"
00073 #include "flags.h"
00074 #include "cgraph.h"
00075 #include "diagnostic.h"
00076 #include "timevar.h"
00077 #include "params.h"
00078 #include "fibheap.h"
00079 #include "intl.h"
00080 #include "tree-pass.h"
00081 #include "hashtab.h"
00082 #include "coverage.h"
00083 #include "ggc.h"
00084
00085
00086 static int ncalls_inlined;
00087 static int nfunctions_inlined;
00088 static int initial_insns;
00089 static int overall_insns;
00090 static int max_insns;
00091 static gcov_type max_count;
00092
00093
00094
00095 static int
00096 cgraph_estimate_size_after_inlining (int times, struct cgraph_node *to,
00097 struct cgraph_node *what)
00098 {
00099 int size;
00100 tree fndecl = what->decl, arg;
00101 int call_insns = PARAM_VALUE (PARAM_INLINE_CALL_COST);
00102
00103 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
00104 call_insns += estimate_move_cost (TREE_TYPE (arg));
00105 size = (what->global.insns - call_insns) * times + to->global.insns;
00106 gcc_assert (size >= 0);
00107 return size;
00108 }
00109
00110
00111
00112
00113
00114
00115 void
00116 cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, bool update_original)
00117 {
00118 if (duplicate)
00119 {
00120
00121
00122 if (!e->callee->callers->next_caller
00123 && !e->callee->needed
00124 && flag_unit_at_a_time)
00125 {
00126 gcc_assert (!e->callee->global.inlined_to);
00127 if (DECL_SAVED_TREE (e->callee->decl))
00128 overall_insns -= e->callee->global.insns, nfunctions_inlined++;
00129 duplicate = false;
00130 }
00131 else
00132 {
00133 struct cgraph_node *n;
00134 n = cgraph_clone_node (e->callee, e->count, e->loop_nest,
00135 update_original);
00136 cgraph_redirect_edge_callee (e, n);
00137 }
00138 }
00139
00140 if (e->caller->global.inlined_to)
00141 e->callee->global.inlined_to = e->caller->global.inlined_to;
00142 else
00143 e->callee->global.inlined_to = e->caller;
00144
00145
00146 for (e = e->callee->callees; e; e = e->next_callee)
00147 if (!e->inline_failed)
00148 cgraph_clone_inlined_nodes (e, duplicate, update_original);
00149 }
00150
00151
00152
00153
00154
00155 void
00156 cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original)
00157 {
00158 int old_insns = 0, new_insns = 0;
00159 struct cgraph_node *to = NULL, *what;
00160
00161 if (e->callee->inline_decl)
00162 cgraph_redirect_edge_callee (e, cgraph_node (e->callee->inline_decl));
00163
00164 gcc_assert (e->inline_failed);
00165 e->inline_failed = NULL;
00166
00167 if (!e->callee->global.inlined && flag_unit_at_a_time)
00168 DECL_POSSIBLY_INLINED (e->callee->decl) = true;
00169 e->callee->global.inlined = true;
00170
00171 cgraph_clone_inlined_nodes (e, true, update_original);
00172
00173 what = e->callee;
00174
00175
00176 for (;e && !e->inline_failed; e = e->caller->callers)
00177 {
00178 old_insns = e->caller->global.insns;
00179 new_insns = cgraph_estimate_size_after_inlining (1, e->caller,
00180 what);
00181 gcc_assert (new_insns >= 0);
00182 to = e->caller;
00183 to->global.insns = new_insns;
00184 }
00185 gcc_assert (what->global.inlined_to == to);
00186 if (new_insns > old_insns)
00187 overall_insns += new_insns - old_insns;
00188 ncalls_inlined++;
00189 }
00190
00191
00192
00193
00194
00195 static struct cgraph_edge *
00196 cgraph_mark_inline (struct cgraph_edge *edge)
00197 {
00198 struct cgraph_node *to = edge->caller;
00199 struct cgraph_node *what = edge->callee;
00200 struct cgraph_edge *e, *next;
00201 int times = 0;
00202
00203
00204
00205 for (e = what->callers; e; e = next)
00206 {
00207 next = e->next_caller;
00208 if (e->caller == to && e->inline_failed)
00209 {
00210 cgraph_mark_inline_edge (e, true);
00211 if (e == edge)
00212 edge = next;
00213 times++;
00214 }
00215 }
00216 gcc_assert (times);
00217 return edge;
00218 }
00219
00220
00221
00222 static int
00223 cgraph_estimate_growth (struct cgraph_node *node)
00224 {
00225 int growth = 0;
00226 struct cgraph_edge *e;
00227 if (node->global.estimated_growth != INT_MIN)
00228 return node->global.estimated_growth;
00229
00230 for (e = node->callers; e; e = e->next_caller)
00231 if (e->inline_failed)
00232 growth += (cgraph_estimate_size_after_inlining (1, e->caller, node)
00233 - e->caller->global.insns);
00234
00235
00236
00237
00238 if (!node->needed && !DECL_EXTERNAL (node->decl))
00239 growth -= node->global.insns;
00240
00241 node->global.estimated_growth = growth;
00242 return growth;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252 static bool
00253 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
00254 const char **reason, bool one_only)
00255 {
00256 int times = 0;
00257 struct cgraph_edge *e;
00258 int newsize;
00259 int limit;
00260
00261 if (one_only)
00262 times = 1;
00263 else
00264 for (e = to->callees; e; e = e->next_callee)
00265 if (e->callee == what)
00266 times++;
00267
00268 if (to->global.inlined_to)
00269 to = to->global.inlined_to;
00270
00271
00272
00273 if (to->local.self_insns > what->local.self_insns)
00274 limit = to->local.self_insns;
00275 else
00276 limit = what->local.self_insns;
00277
00278 limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100;
00279
00280
00281
00282 newsize = cgraph_estimate_size_after_inlining (times, to, what);
00283 if (newsize >= to->global.insns
00284 && newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
00285 && newsize > limit)
00286 {
00287 if (reason)
00288 *reason = N_("--param large-function-growth limit reached");
00289 return false;
00290 }
00291 return true;
00292 }
00293
00294
00295
00296 bool
00297 cgraph_default_inline_p (struct cgraph_node *n, const char **reason)
00298 {
00299 tree decl = n->decl;
00300
00301 if (n->inline_decl)
00302 decl = n->inline_decl;
00303 if (!DECL_INLINE (decl))
00304 {
00305 if (reason)
00306 *reason = N_("function not inlinable");
00307 return false;
00308 }
00309
00310 if (!DECL_STRUCT_FUNCTION (decl)->cfg)
00311 {
00312 if (reason)
00313 *reason = N_("function body not available");
00314 return false;
00315 }
00316
00317 if (DECL_DECLARED_INLINE_P (decl))
00318 {
00319 if (n->global.insns >= MAX_INLINE_INSNS_SINGLE)
00320 {
00321 if (reason)
00322 *reason = N_("--param max-inline-insns-single limit reached");
00323 return false;
00324 }
00325 }
00326 else
00327 {
00328 if (n->global.insns >= MAX_INLINE_INSNS_AUTO)
00329 {
00330 if (reason)
00331 *reason = N_("--param max-inline-insns-auto limit reached");
00332 return false;
00333 }
00334 }
00335
00336 return true;
00337 }
00338
00339
00340
00341
00342
00343 static bool
00344 cgraph_recursive_inlining_p (struct cgraph_node *to,
00345 struct cgraph_node *what,
00346 const char **reason)
00347 {
00348 bool recursive;
00349 if (to->global.inlined_to)
00350 recursive = what->decl == to->global.inlined_to->decl;
00351 else
00352 recursive = what->decl == to->decl;
00353
00354
00355 if (recursive && reason)
00356 *reason = (what->local.disregard_inline_limits
00357 ? N_("recursive inlining") : "");
00358 return recursive;
00359 }
00360
00361
00362 static bool
00363 cgraph_maybe_hot_edge_p (struct cgraph_edge *edge)
00364 {
00365 if (profile_info && flag_branch_probabilities
00366 && (edge->count
00367 <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
00368 return false;
00369 return true;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 static int
00384 cgraph_edge_badness (struct cgraph_edge *edge)
00385 {
00386 if (max_count)
00387 {
00388 int growth =
00389 cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
00390 growth -= edge->caller->global.insns;
00391
00392
00393 if (growth <= 0)
00394 return INT_MIN - growth;
00395 return ((int)((double)edge->count * INT_MIN / max_count)) / growth;
00396 }
00397 else
00398 {
00399 int nest = MIN (edge->loop_nest, 8);
00400 int badness = cgraph_estimate_growth (edge->callee) * 256;
00401
00402
00403 if (badness > 0)
00404 badness >>= nest;
00405 else
00406 badness <<= nest;
00407
00408
00409 if (cgraph_recursive_inlining_p (edge->caller, edge->callee, NULL))
00410 return badness + 1;
00411 else
00412 return badness;
00413 }
00414 }
00415
00416
00417
00418 static void
00419 update_caller_keys (fibheap_t heap, struct cgraph_node *node,
00420 bitmap updated_nodes)
00421 {
00422 struct cgraph_edge *edge;
00423 const char *failed_reason;
00424
00425 if (!node->local.inlinable || node->local.disregard_inline_limits
00426 || node->global.inlined_to)
00427 return;
00428 if (bitmap_bit_p (updated_nodes, node->uid))
00429 return;
00430 bitmap_set_bit (updated_nodes, node->uid);
00431 node->global.estimated_growth = INT_MIN;
00432
00433 if (!node->local.inlinable)
00434 return;
00435
00436 if (!cgraph_default_inline_p (node, &failed_reason))
00437 {
00438 for (edge = node->callers; edge; edge = edge->next_caller)
00439 if (edge->aux)
00440 {
00441 fibheap_delete_node (heap, edge->aux);
00442 edge->aux = NULL;
00443 if (edge->inline_failed)
00444 edge->inline_failed = failed_reason;
00445 }
00446 return;
00447 }
00448
00449 for (edge = node->callers; edge; edge = edge->next_caller)
00450 if (edge->inline_failed)
00451 {
00452 int badness = cgraph_edge_badness (edge);
00453 if (edge->aux)
00454 {
00455 fibnode_t n = edge->aux;
00456 gcc_assert (n->data == edge);
00457 if (n->key == badness)
00458 continue;
00459
00460
00461 if (fibheap_replace_key (heap, n, badness))
00462 continue;
00463 fibheap_delete_node (heap, edge->aux);
00464 }
00465 edge->aux = fibheap_insert (heap, badness, edge);
00466 }
00467 }
00468
00469
00470
00471 static void
00472 update_callee_keys (fibheap_t heap, struct cgraph_node *node,
00473 bitmap updated_nodes)
00474 {
00475 struct cgraph_edge *e;
00476 node->global.estimated_growth = INT_MIN;
00477
00478 for (e = node->callees; e; e = e->next_callee)
00479 if (e->inline_failed)
00480 update_caller_keys (heap, e->callee, updated_nodes);
00481 else if (!e->inline_failed)
00482 update_callee_keys (heap, e->callee, updated_nodes);
00483 }
00484
00485
00486
00487
00488 static void
00489 lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
00490 fibheap_t heap)
00491 {
00492 static int priority;
00493 struct cgraph_edge *e;
00494 for (e = where->callees; e; e = e->next_callee)
00495 if (e->callee == node)
00496 {
00497
00498
00499
00500 fibheap_insert (heap,
00501 !max_count ? priority++
00502 : -(e->count / ((max_count + (1<<24) - 1) / (1<<24))),
00503 e);
00504 }
00505 for (e = where->callees; e; e = e->next_callee)
00506 if (!e->inline_failed)
00507 lookup_recursive_calls (node, e->callee, heap);
00508 }
00509
00510
00511
00512
00513
00514
00515 static void
00516 cgraph_find_cycles (struct cgraph_node *node, htab_t cycles)
00517 {
00518 struct cgraph_edge *e;
00519
00520 if (node->aux)
00521 {
00522 void **slot;
00523 slot = htab_find_slot (cycles, node, INSERT);
00524 if (!*slot)
00525 {
00526 if (dump_file)
00527 fprintf (dump_file, "Cycle contains %s\n", cgraph_node_name (node));
00528 *slot = node;
00529 }
00530 return;
00531 }
00532
00533 node->aux = node;
00534 for (e = node->callees; e; e = e->next_callee)
00535 cgraph_find_cycles (e->callee, cycles);
00536 node->aux = 0;
00537 }
00538
00539
00540
00541
00542
00543
00544 static void
00545 cgraph_flatten_node (struct cgraph_node *node, htab_t cycles)
00546 {
00547 struct cgraph_edge *e;
00548
00549 for (e = node->callees; e; e = e->next_callee)
00550 {
00551
00552
00553 if (e->inline_failed
00554 && e->callee->local.inlinable
00555 && !cgraph_recursive_inlining_p (node, e->callee,
00556 &e->inline_failed)
00557 && !htab_find (cycles, e->callee))
00558 {
00559 if (dump_file)
00560 fprintf (dump_file, " inlining %s", cgraph_node_name (e->callee));
00561 cgraph_mark_inline_edge (e, true);
00562 cgraph_flatten_node (e->callee, cycles);
00563 }
00564 else if (dump_file)
00565 fprintf (dump_file, " !inlining %s", cgraph_node_name (e->callee));
00566 }
00567 }
00568
00569
00570
00571
00572 static bool
00573 cgraph_decide_recursive_inlining (struct cgraph_node *node)
00574 {
00575 int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
00576 int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO);
00577 int probability = PARAM_VALUE (PARAM_MIN_INLINE_RECURSIVE_PROBABILITY);
00578 fibheap_t heap;
00579 struct cgraph_edge *e;
00580 struct cgraph_node *master_clone, *next;
00581 int depth = 0;
00582 int n = 0;
00583
00584 if (DECL_DECLARED_INLINE_P (node->decl))
00585 {
00586 limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE);
00587 max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH);
00588 }
00589
00590
00591 if (!max_depth
00592 || cgraph_estimate_size_after_inlining (1, node, node) >= limit)
00593 return false;
00594 heap = fibheap_new ();
00595 lookup_recursive_calls (node, node, heap);
00596 if (fibheap_empty (heap))
00597 {
00598 fibheap_delete (heap);
00599 return false;
00600 }
00601
00602 if (dump_file)
00603 fprintf (dump_file,
00604 " Performing recursive inlining on %s\n",
00605 cgraph_node_name (node));
00606
00607
00608 master_clone = cgraph_clone_node (node, node->count, 1, false);
00609 master_clone->needed = true;
00610 for (e = master_clone->callees; e; e = e->next_callee)
00611 if (!e->inline_failed)
00612 cgraph_clone_inlined_nodes (e, true, false);
00613
00614
00615 while (!fibheap_empty (heap)
00616 && (cgraph_estimate_size_after_inlining (1, node, master_clone)
00617 <= limit))
00618 {
00619 struct cgraph_edge *curr = fibheap_extract_min (heap);
00620 struct cgraph_node *cnode;
00621
00622 depth = 1;
00623 for (cnode = curr->caller;
00624 cnode->global.inlined_to; cnode = cnode->callers->caller)
00625 if (node->decl == curr->callee->decl)
00626 depth++;
00627 if (depth > max_depth)
00628 {
00629 if (dump_file)
00630 fprintf (dump_file,
00631 " maxmal depth reached\n");
00632 continue;
00633 }
00634
00635 if (max_count)
00636 {
00637 if (!cgraph_maybe_hot_edge_p (curr))
00638 {
00639 if (dump_file)
00640 fprintf (dump_file, " Not inlining cold call\n");
00641 continue;
00642 }
00643 if (curr->count * 100 / node->count < probability)
00644 {
00645 if (dump_file)
00646 fprintf (dump_file,
00647 " Probability of edge is too small\n");
00648 continue;
00649 }
00650 }
00651
00652 if (dump_file)
00653 {
00654 fprintf (dump_file,
00655 " Inlining call of depth %i", depth);
00656 if (node->count)
00657 {
00658 fprintf (dump_file, " called approx. %.2f times per call",
00659 (double)curr->count / node->count);
00660 }
00661 fprintf (dump_file, "\n");
00662 }
00663 cgraph_redirect_edge_callee (curr, master_clone);
00664 cgraph_mark_inline_edge (curr, false);
00665 lookup_recursive_calls (node, curr->callee, heap);
00666 n++;
00667 }
00668 if (!fibheap_empty (heap) && dump_file)
00669 fprintf (dump_file, " Recursive inlining growth limit met.\n");
00670
00671 fibheap_delete (heap);
00672 if (dump_file)
00673 fprintf (dump_file,
00674 "\n Inlined %i times, body grown from %i to %i insns\n", n,
00675 master_clone->global.insns, node->global.insns);
00676
00677
00678
00679
00680 for (node = cgraph_nodes; node != master_clone;
00681 node = next)
00682 {
00683 next = node->next;
00684 if (node->global.inlined_to == master_clone)
00685 cgraph_remove_node (node);
00686 }
00687 cgraph_remove_node (master_clone);
00688
00689
00690
00691
00692 return n > 0;
00693 }
00694
00695
00696
00697 static void
00698 cgraph_set_inline_failed (struct cgraph_node *node, const char *reason)
00699 {
00700 struct cgraph_edge *e;
00701
00702 if (dump_file)
00703 fprintf (dump_file, "Inlining failed: %s\n", reason);
00704 for (e = node->callers; e; e = e->next_caller)
00705 if (e->inline_failed)
00706 e->inline_failed = reason;
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716 static void
00717 cgraph_decide_inlining_of_small_functions (void)
00718 {
00719 struct cgraph_node *node;
00720 struct cgraph_edge *edge;
00721 const char *failed_reason;
00722 fibheap_t heap = fibheap_new ();
00723 bitmap updated_nodes = BITMAP_ALLOC (NULL);
00724
00725 if (dump_file)
00726 fprintf (dump_file, "\nDeciding on smaller functions:\n");
00727
00728
00729
00730 for (node = cgraph_nodes; node; node = node->next)
00731 {
00732 if (!node->local.inlinable || !node->callers
00733 || node->local.disregard_inline_limits)
00734 continue;
00735 if (dump_file)
00736 fprintf (dump_file, "Considering inline candidate %s.\n", cgraph_node_name (node));
00737
00738 node->global.estimated_growth = INT_MIN;
00739 if (!cgraph_default_inline_p (node, &failed_reason))
00740 {
00741 cgraph_set_inline_failed (node, failed_reason);
00742 continue;
00743 }
00744
00745 for (edge = node->callers; edge; edge = edge->next_caller)
00746 if (edge->inline_failed)
00747 {
00748 gcc_assert (!edge->aux);
00749 edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge);
00750 }
00751 }
00752 while (overall_insns <= max_insns && (edge = fibheap_extract_min (heap)))
00753 {
00754 int old_insns = overall_insns;
00755 struct cgraph_node *where;
00756 int growth =
00757 cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
00758
00759 growth -= edge->caller->global.insns;
00760
00761 if (dump_file)
00762 {
00763 fprintf (dump_file,
00764 "\nConsidering %s with %i insns\n",
00765 cgraph_node_name (edge->callee),
00766 edge->callee->global.insns);
00767 fprintf (dump_file,
00768 " to be inlined into %s\n"
00769 " Estimated growth after inlined into all callees is %+i insns.\n"
00770 " Estimated badness is %i.\n",
00771 cgraph_node_name (edge->caller),
00772 cgraph_estimate_growth (edge->callee),
00773 cgraph_edge_badness (edge));
00774 if (edge->count)
00775 fprintf (dump_file," Called "HOST_WIDEST_INT_PRINT_DEC"x\n", edge->count);
00776 }
00777 gcc_assert (edge->aux);
00778 edge->aux = NULL;
00779 if (!edge->inline_failed)
00780 continue;
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 if (!max_count)
00792 {
00793 where = edge->caller;
00794 while (where->global.inlined_to)
00795 {
00796 if (where->decl == edge->callee->decl)
00797 break;
00798 where = where->callers->caller;
00799 }
00800 if (where->global.inlined_to)
00801 {
00802 edge->inline_failed
00803 = (edge->callee->local.disregard_inline_limits ? N_("recursive inlining") : "");
00804 if (dump_file)
00805 fprintf (dump_file, " inline_failed:Recursive inlining performed only for function itself.\n");
00806 continue;
00807 }
00808 }
00809
00810 if (!cgraph_maybe_hot_edge_p (edge) && growth > 0)
00811 {
00812 if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
00813 &edge->inline_failed))
00814 {
00815 edge->inline_failed =
00816 N_("call is unlikely");
00817 if (dump_file)
00818 fprintf (dump_file, " inline_failed:%s.\n", edge->inline_failed);
00819 }
00820 continue;
00821 }
00822 if (!cgraph_default_inline_p (edge->callee, &edge->inline_failed))
00823 {
00824 if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
00825 &edge->inline_failed))
00826 {
00827 if (dump_file)
00828 fprintf (dump_file, " inline_failed:%s.\n", edge->inline_failed);
00829 }
00830 continue;
00831 }
00832 if (cgraph_recursive_inlining_p (edge->caller, edge->callee,
00833 &edge->inline_failed))
00834 {
00835 where = edge->caller;
00836 if (where->global.inlined_to)
00837 where = where->global.inlined_to;
00838 if (!cgraph_decide_recursive_inlining (where))
00839 continue;
00840 update_callee_keys (heap, where, updated_nodes);
00841 }
00842 else
00843 {
00844 struct cgraph_node *callee;
00845 if (!cgraph_check_inline_limits (edge->caller, edge->callee,
00846 &edge->inline_failed, true))
00847 {
00848 if (dump_file)
00849 fprintf (dump_file, " Not inlining into %s:%s.\n",
00850 cgraph_node_name (edge->caller), edge->inline_failed);
00851 continue;
00852 }
00853 callee = edge->callee;
00854 cgraph_mark_inline_edge (edge, true);
00855 update_callee_keys (heap, callee, updated_nodes);
00856 }
00857 where = edge->caller;
00858 if (where->global.inlined_to)
00859 where = where->global.inlined_to;
00860
00861
00862
00863
00864
00865
00866
00867 update_caller_keys (heap, where, updated_nodes);
00868 bitmap_clear (updated_nodes);
00869
00870 if (dump_file)
00871 {
00872 fprintf (dump_file,
00873 " Inlined into %s which now has %i insns,"
00874 "net change of %+i insns.\n",
00875 cgraph_node_name (edge->caller),
00876 edge->caller->global.insns,
00877 overall_insns - old_insns);
00878 }
00879 }
00880 while ((edge = fibheap_extract_min (heap)) != NULL)
00881 {
00882 gcc_assert (edge->aux);
00883 edge->aux = NULL;
00884 if (!edge->callee->local.disregard_inline_limits && edge->inline_failed
00885 && !cgraph_recursive_inlining_p (edge->caller, edge->callee,
00886 &edge->inline_failed))
00887 edge->inline_failed = N_("--param inline-unit-growth limit reached");
00888 }
00889 fibheap_delete (heap);
00890 BITMAP_FREE (updated_nodes);
00891 }
00892
00893
00894
00895
00896 static unsigned int
00897 cgraph_decide_inlining (void)
00898 {
00899 struct cgraph_node *node;
00900 int nnodes;
00901 struct cgraph_node **order =
00902 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
00903 int old_insns = 0;
00904 int i;
00905
00906 timevar_push (TV_INLINE_HEURISTICS);
00907 max_count = 0;
00908 for (node = cgraph_nodes; node; node = node->next)
00909 if (node->analyzed && (node->needed || node->reachable))
00910 {
00911 struct cgraph_edge *e;
00912
00913
00914
00915
00916 if (!flag_early_inlining)
00917 node->local.self_insns = node->global.insns
00918 = estimate_num_insns (node->decl);
00919
00920 initial_insns += node->local.self_insns;
00921 gcc_assert (node->local.self_insns == node->global.insns);
00922 for (e = node->callees; e; e = e->next_callee)
00923 if (max_count < e->count)
00924 max_count = e->count;
00925 }
00926 overall_insns = initial_insns;
00927 gcc_assert (!max_count || (profile_info && flag_branch_probabilities));
00928
00929 max_insns = overall_insns;
00930 if (max_insns < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
00931 max_insns = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
00932
00933 max_insns = ((HOST_WIDEST_INT) max_insns
00934 * (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH)) / 100);
00935
00936 nnodes = cgraph_postorder (order);
00937
00938 if (dump_file)
00939 fprintf (dump_file,
00940 "\nDeciding on inlining. Starting with %i insns.\n",
00941 initial_insns);
00942
00943 for (node = cgraph_nodes; node; node = node->next)
00944 node->aux = 0;
00945
00946 if (dump_file)
00947 fprintf (dump_file, "\nInlining always_inline functions:\n");
00948
00949
00950
00951 for (i = nnodes - 1; i >= 0; i--)
00952 {
00953 struct cgraph_edge *e, *next;
00954
00955 node = order[i];
00956
00957
00958 if (lookup_attribute ("flatten", DECL_ATTRIBUTES (node->decl)) != NULL)
00959 {
00960 int old_overall_insns = overall_insns;
00961 htab_t cycles;
00962 if (dump_file)
00963 fprintf (dump_file,
00964 "Flattening %s\n", cgraph_node_name (node));
00965 cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
00966 cgraph_find_cycles (node, cycles);
00967 cgraph_flatten_node (node, cycles);
00968 htab_delete (cycles);
00969 overall_insns = old_overall_insns;
00970
00971
00972 continue;
00973 }
00974
00975 if (!node->local.disregard_inline_limits)
00976 continue;
00977 if (dump_file)
00978 fprintf (dump_file,
00979 "\nConsidering %s %i insns (always inline)\n",
00980 cgraph_node_name (node), node->global.insns);
00981 old_insns = overall_insns;
00982 for (e = node->callers; e; e = next)
00983 {
00984 next = e->next_caller;
00985 if (!e->inline_failed)
00986 continue;
00987 if (cgraph_recursive_inlining_p (e->caller, e->callee,
00988 &e->inline_failed))
00989 continue;
00990 cgraph_mark_inline_edge (e, true);
00991 if (dump_file)
00992 fprintf (dump_file,
00993 " Inlined into %s which now has %i insns.\n",
00994 cgraph_node_name (e->caller),
00995 e->caller->global.insns);
00996 }
00997 if (dump_file)
00998 fprintf (dump_file,
00999 " Inlined for a net change of %+i insns.\n",
01000 overall_insns - old_insns);
01001 }
01002
01003 if (!flag_really_no_inline)
01004 cgraph_decide_inlining_of_small_functions ();
01005
01006 if (!flag_really_no_inline
01007 && flag_inline_functions_called_once)
01008 {
01009 if (dump_file)
01010 fprintf (dump_file, "\nDeciding on functions called once:\n");
01011
01012
01013
01014 for (i = nnodes - 1; i >= 0; i--)
01015 {
01016 node = order[i];
01017
01018 if (node->callers && !node->callers->next_caller && !node->needed
01019 && node->local.inlinable && node->callers->inline_failed
01020 && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
01021 {
01022 bool ok = true;
01023 struct cgraph_node *node1;
01024
01025
01026 for (node1 = node->callers->caller;
01027 node1->callers && !node1->callers->inline_failed
01028 && ok; node1 = node1->callers->caller)
01029 if (node1->callers->next_caller || node1->needed)
01030 ok = false;
01031 if (ok)
01032 {
01033 if (dump_file)
01034 {
01035 fprintf (dump_file,
01036 "\nConsidering %s %i insns.\n",
01037 cgraph_node_name (node), node->global.insns);
01038 fprintf (dump_file,
01039 " Called once from %s %i insns.\n",
01040 cgraph_node_name (node->callers->caller),
01041 node->callers->caller->global.insns);
01042 }
01043
01044 old_insns = overall_insns;
01045
01046 if (cgraph_check_inline_limits (node->callers->caller, node,
01047 NULL, false))
01048 {
01049 cgraph_mark_inline (node->callers);
01050 if (dump_file)
01051 fprintf (dump_file,
01052 " Inlined into %s which now has %i insns"
01053 " for a net change of %+i insns.\n",
01054 cgraph_node_name (node->callers->caller),
01055 node->callers->caller->global.insns,
01056 overall_insns - old_insns);
01057 }
01058 else
01059 {
01060 if (dump_file)
01061 fprintf (dump_file,
01062 " Inline limit reached, not inlined.\n");
01063 }
01064 }
01065 }
01066 }
01067 }
01068
01069 if (dump_file)
01070 fprintf (dump_file,
01071 "\nInlined %i calls, eliminated %i functions, "
01072 "%i insns turned to %i insns.\n\n",
01073 ncalls_inlined, nfunctions_inlined, initial_insns,
01074 overall_insns);
01075 free (order);
01076 timevar_pop (TV_INLINE_HEURISTICS);
01077 return 0;
01078 }
01079
01080
01081
01082
01083 bool
01084 cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
01085 {
01086 struct cgraph_edge *e;
01087 bool inlined = false;
01088 const char *failed_reason;
01089
01090
01091 for (e = node->callees; e; e = e->next_callee)
01092 if (e->callee->local.disregard_inline_limits
01093 && e->inline_failed
01094 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
01095
01096
01097 && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
01098 {
01099 if (dump_file && early)
01100 {
01101 fprintf (dump_file, " Early inlining %s",
01102 cgraph_node_name (e->callee));
01103 fprintf (dump_file, " into %s\n", cgraph_node_name (node));
01104 }
01105 cgraph_mark_inline (e);
01106 inlined = true;
01107 }
01108
01109
01110 if (!flag_really_no_inline)
01111 for (e = node->callees; e; e = e->next_callee)
01112 if (e->callee->local.inlinable
01113 && e->inline_failed
01114 && !e->callee->local.disregard_inline_limits
01115 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
01116 && (!early
01117 || (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
01118 <= e->caller->global.insns))
01119 && cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
01120 false)
01121 && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
01122 {
01123 if (cgraph_default_inline_p (e->callee, &failed_reason))
01124 {
01125 if (dump_file && early)
01126 {
01127 fprintf (dump_file, " Early inlining %s",
01128 cgraph_node_name (e->callee));
01129 fprintf (dump_file, " into %s\n", cgraph_node_name (node));
01130 }
01131 cgraph_mark_inline (e);
01132 inlined = true;
01133 }
01134 else if (!early)
01135 e->inline_failed = failed_reason;
01136 }
01137 if (early && inlined)
01138 {
01139 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
01140 tree_register_cfg_hooks ();
01141 current_function_decl = node->decl;
01142 optimize_inline_calls (current_function_decl);
01143 node->local.self_insns = node->global.insns;
01144 current_function_decl = NULL;
01145 pop_cfun ();
01146 }
01147 return inlined;
01148 }
01149
01150
01151 static bool
01152 cgraph_gate_inlining (void)
01153 {
01154 return flag_inline_trees;
01155 }
01156
01157 struct tree_opt_pass pass_ipa_inline =
01158 {
01159 "inline",
01160 cgraph_gate_inlining,
01161 cgraph_decide_inlining,
01162 NULL,
01163 NULL,
01164 0,
01165 TV_INTEGRATION,
01166 0,
01167 PROP_cfg,
01168 0,
01169 0,
01170 TODO_dump_cgraph | TODO_dump_func,
01171 0
01172 };
01173
01174
01175
01176
01177 static int nnodes;
01178 static GTY ((length ("nnodes"))) struct cgraph_node **order;
01179
01180
01181
01182
01183 static unsigned int
01184 cgraph_early_inlining (void)
01185 {
01186 struct cgraph_node *node;
01187 int i;
01188
01189 if (sorrycount || errorcount)
01190 return 0;
01191 #ifdef ENABLE_CHECKING
01192 for (node = cgraph_nodes; node; node = node->next)
01193 gcc_assert (!node->aux);
01194 #endif
01195
01196 order = ggc_alloc (sizeof (*order) * cgraph_n_nodes);
01197 nnodes = cgraph_postorder (order);
01198 for (i = nnodes - 1; i >= 0; i--)
01199 {
01200 node = order[i];
01201 if (node->analyzed && (node->needed || node->reachable))
01202 node->local.self_insns = node->global.insns
01203 = estimate_num_insns (node->decl);
01204 }
01205 for (i = nnodes - 1; i >= 0; i--)
01206 {
01207 node = order[i];
01208 if (node->analyzed && node->local.inlinable
01209 && (node->needed || node->reachable)
01210 && node->callers)
01211 {
01212 if (cgraph_decide_inlining_incrementally (node, true))
01213 ggc_collect ();
01214 }
01215 }
01216 cgraph_remove_unreachable_nodes (true, dump_file);
01217 #ifdef ENABLE_CHECKING
01218 for (node = cgraph_nodes; node; node = node->next)
01219 gcc_assert (!node->global.inlined_to);
01220 #endif
01221 ggc_free (order);
01222 order = NULL;
01223 nnodes = 0;
01224 return 0;
01225 }
01226
01227
01228 static bool
01229 cgraph_gate_early_inlining (void)
01230 {
01231 return flag_inline_trees && flag_early_inlining;
01232 }
01233
01234 struct tree_opt_pass pass_early_ipa_inline =
01235 {
01236 "einline",
01237 cgraph_gate_early_inlining,
01238 cgraph_early_inlining,
01239 NULL,
01240 NULL,
01241 0,
01242 TV_INTEGRATION,
01243 0,
01244 PROP_cfg,
01245 0,
01246 0,
01247 TODO_dump_cgraph | TODO_dump_func,
01248 0
01249 };
01250
01251 #include "gt-ipa-inline.h"