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
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 #include "config.h"
00173 #include "system.h"
00174 #include "coretypes.h"
00175 #include "tm.h"
00176 #include "tree.h"
00177 #include "rtl.h"
00178 #include "tree-flow.h"
00179 #include "tree-inline.h"
00180 #include "langhooks.h"
00181 #include "pointer-set.h"
00182 #include "toplev.h"
00183 #include "flags.h"
00184 #include "ggc.h"
00185 #include "debug.h"
00186 #include "target.h"
00187 #include "cgraph.h"
00188 #include "diagnostic.h"
00189 #include "timevar.h"
00190 #include "params.h"
00191 #include "fibheap.h"
00192 #include "c-common.h"
00193 #include "intl.h"
00194 #include "function.h"
00195 #include "tree-gimple.h"
00196
00197 #define INSNS_PER_CALL 10
00198
00199 static void cgraph_expand_all_functions (void);
00200 static void cgraph_mark_functions_to_output (void);
00201 static void cgraph_expand_function (struct cgraph_node *);
00202 static tree record_call_1 (tree *, int *, void *);
00203 static void cgraph_mark_local_functions (void);
00204 static bool cgraph_default_inline_p (struct cgraph_node *n);
00205 static void cgraph_analyze_function (struct cgraph_node *node);
00206 static void cgraph_decide_inlining_incrementally (struct cgraph_node *);
00207
00208
00209 static int ncalls_inlined;
00210 static int nfunctions_inlined;
00211 static int initial_insns;
00212 static int overall_insns;
00213
00214
00215
00216
00217
00218 static struct pointer_set_t *visited_nodes;
00219
00220 static FILE *cgraph_dump_file;
00221
00222
00223
00224
00225
00226
00227 static bool
00228 decide_is_function_needed (struct cgraph_node *node, tree decl)
00229 {
00230 tree origin;
00231
00232
00233
00234
00235 if (node->needed)
00236 return true;
00237
00238
00239
00240 if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
00241 return true;
00242
00243
00244
00245 if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))
00246 return true;
00247
00248
00249 if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
00250 return true;
00251
00252
00253
00254
00255 if (DECL_ASSEMBLER_NAME_SET_P (decl)
00256 && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
00257 return true;
00258
00259 if (flag_unit_at_a_time)
00260 return false;
00261
00262
00263
00264
00265
00266 if (DECL_EXTERNAL (decl))
00267 return false;
00268
00269
00270 for (origin = decl_function_context (decl); origin;
00271 origin = decl_function_context (origin))
00272 if (DECL_EXTERNAL (origin))
00273 return false;
00274
00275 if (DECL_COMDAT (decl))
00276 return false;
00277 if (!DECL_INLINE (decl)
00278 || (!node->local.disregard_inline_limits
00279
00280
00281 && !DECL_DECLARED_INLINE_P (decl)
00282 && (!node->local.inlinable || !cgraph_default_inline_p (node))))
00283 return true;
00284
00285 return false;
00286 }
00287
00288
00289
00290
00291
00292
00293 bool
00294 cgraph_assemble_pending_functions (void)
00295 {
00296 bool output = false;
00297
00298 if (flag_unit_at_a_time)
00299 return false;
00300
00301 while (cgraph_nodes_queue)
00302 {
00303 struct cgraph_node *n = cgraph_nodes_queue;
00304
00305 cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
00306 n->next_needed = NULL;
00307 if (!n->global.inlined_to
00308 && !n->alias
00309 && !DECL_EXTERNAL (n->decl))
00310 {
00311 cgraph_expand_function (n);
00312 output = true;
00313 }
00314 }
00315
00316 return output;
00317 }
00318
00319
00320
00321
00322
00323
00324 void
00325 cgraph_finalize_function (tree decl, bool nested)
00326 {
00327 struct cgraph_node *node = cgraph_node (decl);
00328
00329 if (node->local.finalized)
00330 {
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 gcc_assert (!node->output);
00348
00349
00350 memset (&node->local, 0, sizeof (node->local));
00351 memset (&node->global, 0, sizeof (node->global));
00352 memset (&node->rtl, 0, sizeof (node->rtl));
00353 node->analyzed = false;
00354 node->local.redefined_extern_inline = true;
00355
00356 if (!flag_unit_at_a_time)
00357 {
00358 struct cgraph_node *n;
00359
00360 for (n = cgraph_nodes; n; n = n->next)
00361 if (n->global.inlined_to == node)
00362 cgraph_remove_node (n);
00363 }
00364
00365 cgraph_node_remove_callees (node);
00366
00367
00368
00369 if (node->reachable && !flag_unit_at_a_time)
00370 {
00371 struct cgraph_node *n;
00372
00373 for (n = cgraph_nodes_queue; n; n = n->next_needed)
00374 if (n == node)
00375 break;
00376 if (!n)
00377 node->reachable = 0;
00378 }
00379 }
00380
00381 notice_global_symbol (decl);
00382 node->decl = decl;
00383 node->local.finalized = true;
00384 if (node->nested)
00385 lower_nested_functions (decl);
00386 gcc_assert (!node->nested);
00387
00388
00389
00390 if (!flag_unit_at_a_time)
00391 {
00392 cgraph_analyze_function (node);
00393 cgraph_decide_inlining_incrementally (node);
00394 }
00395
00396 if (decide_is_function_needed (node, decl))
00397 cgraph_mark_needed_node (node);
00398
00399
00400
00401 if (!nested)
00402 {
00403 if (!cgraph_assemble_pending_functions ())
00404 ggc_collect ();
00405 }
00406
00407
00408 if (!TREE_ASM_WRITTEN (decl))
00409 (*debug_hooks->deferred_inline_function) (decl);
00410
00411
00412 if (warn_unused_parameter)
00413 do_warn_unused_parameter (decl);
00414 }
00415
00416
00417 static tree
00418 record_call_1 (tree *tp, int *walk_subtrees, void *data)
00419 {
00420 tree t = *tp;
00421
00422 switch (TREE_CODE (t))
00423 {
00424 case VAR_DECL:
00425
00426
00427
00428 if (TREE_STATIC (t))
00429 {
00430 cgraph_varpool_mark_needed_node (cgraph_varpool_node (t));
00431 if (lang_hooks.callgraph.analyze_expr)
00432 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees,
00433 data);
00434 }
00435 break;
00436
00437 case ADDR_EXPR:
00438 if (flag_unit_at_a_time)
00439 {
00440
00441
00442 tree decl = TREE_OPERAND (*tp, 0);
00443 if (TREE_CODE (decl) == FUNCTION_DECL)
00444 cgraph_mark_needed_node (cgraph_node (decl));
00445 }
00446 break;
00447
00448 case CALL_EXPR:
00449 {
00450 tree decl = get_callee_fndecl (*tp);
00451 if (decl && TREE_CODE (decl) == FUNCTION_DECL)
00452 {
00453 cgraph_create_edge (data, cgraph_node (decl), *tp);
00454
00455
00456
00457
00458
00459
00460
00461
00462 walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data,
00463 visited_nodes);
00464 *walk_subtrees = 0;
00465 }
00466 break;
00467 }
00468
00469 default:
00470
00471
00472 if (IS_TYPE_OR_DECL_P (*tp))
00473 {
00474 *walk_subtrees = 0;
00475 break;
00476 }
00477
00478 if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
00479 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data);
00480 break;
00481 }
00482
00483 return NULL;
00484 }
00485
00486
00487
00488 void
00489 cgraph_create_edges (struct cgraph_node *node, tree body)
00490 {
00491
00492
00493 visited_nodes = pointer_set_create ();
00494 walk_tree (&body, record_call_1, node, visited_nodes);
00495 pointer_set_destroy (visited_nodes);
00496 visited_nodes = NULL;
00497 }
00498
00499 static bool error_found;
00500
00501
00502
00503
00504 static tree
00505 verify_cgraph_node_1 (tree *tp, int *walk_subtrees, void *data)
00506 {
00507 tree t = *tp;
00508 tree decl;
00509
00510 if (TREE_CODE (t) == CALL_EXPR && (decl = get_callee_fndecl (t)))
00511 {
00512 struct cgraph_edge *e = cgraph_edge (data, t);
00513 if (e)
00514 {
00515 if (e->aux)
00516 {
00517 error ("Shared call_expr:");
00518 debug_tree (t);
00519 error_found = true;
00520 }
00521 if (e->callee->decl != cgraph_node (decl)->decl)
00522 {
00523 error ("Edge points to wrong declaration:");
00524 debug_tree (e->callee->decl);
00525 fprintf (stderr," Instead of:");
00526 debug_tree (decl);
00527 }
00528 e->aux = (void *)1;
00529 }
00530 else
00531 {
00532 error ("Missing callgraph edge for call expr:");
00533 debug_tree (t);
00534 error_found = true;
00535 }
00536 }
00537
00538
00539
00540 if (IS_TYPE_OR_DECL_P (*tp))
00541 *walk_subtrees = 0;
00542
00543 return NULL_TREE;
00544 }
00545
00546
00547 void
00548 verify_cgraph_node (struct cgraph_node *node)
00549 {
00550 struct cgraph_edge *e;
00551 struct cgraph_node *main_clone;
00552
00553 timevar_push (TV_CGRAPH_VERIFY);
00554 error_found = false;
00555 for (e = node->callees; e; e = e->next_callee)
00556 if (e->aux)
00557 {
00558 error ("Aux field set for edge %s->%s",
00559 cgraph_node_name (e->caller), cgraph_node_name (e->callee));
00560 error_found = true;
00561 }
00562 for (e = node->callers; e; e = e->next_caller)
00563 {
00564 if (!e->inline_failed)
00565 {
00566 if (node->global.inlined_to
00567 != (e->caller->global.inlined_to
00568 ? e->caller->global.inlined_to : e->caller))
00569 {
00570 error ("Inlined_to pointer is wrong");
00571 error_found = true;
00572 }
00573 if (node->callers->next_caller)
00574 {
00575 error ("Multiple inline callers");
00576 error_found = true;
00577 }
00578 }
00579 else
00580 if (node->global.inlined_to)
00581 {
00582 error ("Inlined_to pointer set for noninline callers");
00583 error_found = true;
00584 }
00585 }
00586 if (!node->callers && node->global.inlined_to)
00587 {
00588 error ("Inlined_to pointer is set but no predecesors found");
00589 error_found = true;
00590 }
00591 if (node->global.inlined_to == node)
00592 {
00593 error ("Inlined_to pointer reffers to itself");
00594 error_found = true;
00595 }
00596
00597 for (main_clone = cgraph_node (node->decl); main_clone;
00598 main_clone = main_clone->next_clone)
00599 if (main_clone == node)
00600 break;
00601 if (!node)
00602 {
00603 error ("Node not found in DECL_ASSEMBLER_NAME hash");
00604 error_found = true;
00605 }
00606
00607 if (node->analyzed
00608 && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl)
00609 && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
00610 {
00611 walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl),
00612 verify_cgraph_node_1, node);
00613 for (e = node->callees; e; e = e->next_callee)
00614 {
00615 if (!e->aux)
00616 {
00617 error ("Edge %s->%s has no corresponding call_expr",
00618 cgraph_node_name (e->caller),
00619 cgraph_node_name (e->callee));
00620 error_found = true;
00621 }
00622 e->aux = 0;
00623 }
00624 }
00625 if (error_found)
00626 {
00627 dump_cgraph_node (stderr, node);
00628 internal_error ("verify_cgraph_node failed.");
00629 }
00630 timevar_pop (TV_CGRAPH_VERIFY);
00631 }
00632
00633
00634 void
00635 verify_cgraph (void)
00636 {
00637 struct cgraph_node *node;
00638
00639 if (sorrycount || errorcount)
00640 return;
00641
00642 for (node = cgraph_nodes; node; node = node->next)
00643 verify_cgraph_node (node);
00644 }
00645
00646
00647 static void
00648 cgraph_analyze_function (struct cgraph_node *node)
00649 {
00650 tree decl = node->decl;
00651 struct cgraph_edge *e;
00652
00653 current_function_decl = decl;
00654
00655
00656 cgraph_create_edges (node, DECL_SAVED_TREE (decl));
00657
00658 node->local.inlinable = tree_inlinable_function_p (decl);
00659 node->local.self_insns = estimate_num_insns (DECL_SAVED_TREE (decl));
00660 if (node->local.inlinable)
00661 node->local.disregard_inline_limits
00662 = lang_hooks.tree_inlining.disregard_inline_limits (decl);
00663 for (e = node->callers; e; e = e->next_caller)
00664 {
00665 if (node->local.redefined_extern_inline)
00666 e->inline_failed = N_("redefined extern inline functions are not "
00667 "considered for inlining");
00668 else if (!node->local.inlinable)
00669 e->inline_failed = N_("function not inlinable");
00670 else
00671 e->inline_failed = N_("function not considered for inlining");
00672 }
00673 if (flag_really_no_inline && !node->local.disregard_inline_limits)
00674 node->local.inlinable = 0;
00675
00676 node->global.insns = node->local.self_insns;
00677
00678 node->analyzed = true;
00679 current_function_decl = NULL;
00680 }
00681
00682
00683
00684 void
00685 cgraph_finalize_compilation_unit (void)
00686 {
00687 struct cgraph_node *node;
00688
00689 finish_aliases_1 ();
00690
00691 if (!flag_unit_at_a_time)
00692 {
00693 cgraph_assemble_pending_functions ();
00694 return;
00695 }
00696
00697 cgraph_varpool_assemble_pending_decls ();
00698 if (!quiet_flag)
00699 fprintf (stderr, "\nAnalyzing compilation unit\n");
00700
00701 timevar_push (TV_CGRAPH);
00702 if (cgraph_dump_file)
00703 {
00704 fprintf (cgraph_dump_file, "Initial entry points:");
00705 for (node = cgraph_nodes; node; node = node->next)
00706 if (node->needed && DECL_SAVED_TREE (node->decl))
00707 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
00708 fprintf (cgraph_dump_file, "\n");
00709 }
00710
00711
00712
00713
00714
00715 while (cgraph_nodes_queue)
00716 {
00717 struct cgraph_edge *edge;
00718 tree decl = cgraph_nodes_queue->decl;
00719
00720 node = cgraph_nodes_queue;
00721 cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
00722 node->next_needed = NULL;
00723
00724
00725
00726
00727 if (!DECL_SAVED_TREE (decl))
00728 continue;
00729
00730 gcc_assert (!node->analyzed && node->reachable);
00731 gcc_assert (DECL_SAVED_TREE (decl));
00732
00733 cgraph_analyze_function (node);
00734
00735 for (edge = node->callees; edge; edge = edge->next_callee)
00736 if (!edge->callee->reachable)
00737 cgraph_mark_reachable_node (edge->callee);
00738
00739 cgraph_varpool_assemble_pending_decls ();
00740 }
00741
00742
00743
00744 if (cgraph_dump_file)
00745 {
00746 fprintf (cgraph_dump_file, "Unit entry points:");
00747 for (node = cgraph_nodes; node; node = node->next)
00748 if (node->needed && DECL_SAVED_TREE (node->decl))
00749 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
00750 fprintf (cgraph_dump_file, "\n\nInitial ");
00751 dump_cgraph (cgraph_dump_file);
00752 }
00753
00754 if (cgraph_dump_file)
00755 fprintf (cgraph_dump_file, "\nReclaiming functions:");
00756
00757 for (node = cgraph_nodes; node; node = node->next)
00758 {
00759 tree decl = node->decl;
00760
00761 if (!node->reachable && DECL_SAVED_TREE (decl))
00762 {
00763 if (cgraph_dump_file)
00764 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
00765 cgraph_remove_node (node);
00766 }
00767 else
00768 node->next_needed = NULL;
00769 }
00770 if (cgraph_dump_file)
00771 {
00772 fprintf (cgraph_dump_file, "\n\nReclaimed ");
00773 dump_cgraph (cgraph_dump_file);
00774 }
00775 ggc_collect ();
00776 timevar_pop (TV_CGRAPH);
00777 }
00778
00779
00780 static void
00781 cgraph_mark_functions_to_output (void)
00782 {
00783 struct cgraph_node *node;
00784
00785 for (node = cgraph_nodes; node; node = node->next)
00786 {
00787 tree decl = node->decl;
00788 struct cgraph_edge *e;
00789
00790 gcc_assert (!node->output);
00791
00792 for (e = node->callers; e; e = e->next_caller)
00793 if (e->inline_failed)
00794 break;
00795
00796
00797
00798
00799 if (DECL_SAVED_TREE (decl)
00800 && !node->global.inlined_to
00801 && (node->needed
00802 || (e && node->reachable))
00803 && !TREE_ASM_WRITTEN (decl)
00804 && !DECL_EXTERNAL (decl))
00805 node->output = 1;
00806 else
00807 {
00808
00809 #ifdef ENABLE_CHECKING
00810 if (!node->global.inlined_to && DECL_SAVED_TREE (decl)
00811 && !DECL_EXTERNAL (decl))
00812 {
00813 dump_cgraph_node (stderr, node);
00814 internal_error ("failed to reclaim unneeded function");
00815 }
00816 #endif
00817 gcc_assert (node->global.inlined_to || !DECL_SAVED_TREE (decl)
00818 || DECL_EXTERNAL (decl));
00819
00820 }
00821
00822 }
00823 }
00824
00825
00826
00827 static void
00828 cgraph_expand_function (struct cgraph_node *node)
00829 {
00830 tree decl = node->decl;
00831
00832
00833 gcc_assert (!node->global.inlined_to);
00834
00835 if (flag_unit_at_a_time)
00836 announce_function (decl);
00837
00838
00839 lang_hooks.callgraph.expand_function (decl);
00840
00841
00842
00843 gcc_assert (TREE_ASM_WRITTEN (node->decl));
00844
00845 current_function_decl = NULL;
00846 if (!cgraph_preserve_function_body_p (node->decl))
00847 {
00848 DECL_SAVED_TREE (node->decl) = NULL;
00849 DECL_STRUCT_FUNCTION (node->decl) = NULL;
00850 DECL_INITIAL (node->decl) = error_mark_node;
00851
00852
00853 cgraph_node_remove_callees (node);
00854 }
00855 }
00856
00857
00858
00859
00860 static int
00861 cgraph_postorder (struct cgraph_node **order)
00862 {
00863 struct cgraph_node *node, *node2;
00864 int stack_size = 0;
00865 int order_pos = 0;
00866 struct cgraph_edge *edge, last;
00867
00868 struct cgraph_node **stack =
00869 xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
00870
00871
00872
00873
00874
00875 for (node = cgraph_nodes; node; node = node->next)
00876 node->aux = NULL;
00877 for (node = cgraph_nodes; node; node = node->next)
00878 if (!node->aux)
00879 {
00880 node2 = node;
00881 if (!node->callers)
00882 node->aux = &last;
00883 else
00884 node->aux = node->callers;
00885 while (node2)
00886 {
00887 while (node2->aux != &last)
00888 {
00889 edge = node2->aux;
00890 if (edge->next_caller)
00891 node2->aux = edge->next_caller;
00892 else
00893 node2->aux = &last;
00894 if (!edge->caller->aux)
00895 {
00896 if (!edge->caller->callers)
00897 edge->caller->aux = &last;
00898 else
00899 edge->caller->aux = edge->caller->callers;
00900 stack[stack_size++] = node2;
00901 node2 = edge->caller;
00902 break;
00903 }
00904 }
00905 if (node2->aux == &last)
00906 {
00907 order[order_pos++] = node2;
00908 if (stack_size)
00909 node2 = stack[--stack_size];
00910 else
00911 node2 = NULL;
00912 }
00913 }
00914 }
00915 free (stack);
00916 return order_pos;
00917 }
00918
00919
00920
00921
00922
00923 static bool
00924 cgraph_remove_unreachable_nodes (void)
00925 {
00926 struct cgraph_node *first = (void *) 1;
00927 struct cgraph_node *node;
00928 bool changed = false;
00929 int insns = 0;
00930
00931 #ifdef ENABLE_CHECKING
00932 verify_cgraph ();
00933 #endif
00934 if (cgraph_dump_file)
00935 fprintf (cgraph_dump_file, "\nReclaiming functions:");
00936 #ifdef ENABLE_CHECKING
00937 for (node = cgraph_nodes; node; node = node->next)
00938 gcc_assert (!node->aux);
00939 #endif
00940 for (node = cgraph_nodes; node; node = node->next)
00941 if (node->needed && !node->global.inlined_to
00942 && (!DECL_EXTERNAL (node->decl) || !node->analyzed))
00943 {
00944 node->aux = first;
00945 first = node;
00946 }
00947 else
00948 gcc_assert (!node->aux);
00949
00950
00951
00952
00953 while (first != (void *) 1)
00954 {
00955 struct cgraph_edge *e;
00956 node = first;
00957 first = first->aux;
00958
00959 for (e = node->callees; e; e = e->next_callee)
00960 if (!e->callee->aux
00961 && node->analyzed
00962 && (!e->inline_failed || !e->callee->analyzed
00963 || !DECL_EXTERNAL (e->callee->decl)))
00964 {
00965 e->callee->aux = first;
00966 first = e->callee;
00967 }
00968 }
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978 for (node = cgraph_nodes; node; node = node->next)
00979 {
00980 if (!node->aux)
00981 {
00982 int local_insns;
00983 tree decl = node->decl;
00984
00985 node->global.inlined_to = NULL;
00986 if (DECL_STRUCT_FUNCTION (decl))
00987 local_insns = node->local.self_insns;
00988 else
00989 local_insns = 0;
00990 if (cgraph_dump_file)
00991 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
00992 if (!node->analyzed || !DECL_EXTERNAL (node->decl))
00993 cgraph_remove_node (node);
00994 else
00995 {
00996 struct cgraph_edge *e;
00997
00998 for (e = node->callers; e; e = e->next_caller)
00999 if (e->caller->aux)
01000 break;
01001 if (e || node->needed)
01002 {
01003 struct cgraph_node *clone;
01004
01005 for (clone = node->next_clone; clone;
01006 clone = clone->next_clone)
01007 if (clone->aux)
01008 break;
01009 if (!clone)
01010 {
01011 DECL_SAVED_TREE (node->decl) = NULL;
01012 DECL_STRUCT_FUNCTION (node->decl) = NULL;
01013 DECL_INITIAL (node->decl) = error_mark_node;
01014 }
01015 cgraph_node_remove_callees (node);
01016 node->analyzed = false;
01017 }
01018 else
01019 cgraph_remove_node (node);
01020 }
01021 if (!DECL_SAVED_TREE (decl))
01022 insns += local_insns;
01023 changed = true;
01024 }
01025 }
01026 for (node = cgraph_nodes; node; node = node->next)
01027 node->aux = NULL;
01028 if (cgraph_dump_file)
01029 fprintf (cgraph_dump_file, "\nReclaimed %i insns", insns);
01030 return changed;
01031 }
01032
01033
01034
01035 static int
01036 cgraph_estimate_size_after_inlining (int times, struct cgraph_node *to,
01037 struct cgraph_node *what)
01038 {
01039 tree fndecl = what->decl;
01040 tree arg;
01041 int call_insns = PARAM_VALUE (PARAM_INLINE_CALL_COST);
01042 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
01043 call_insns += estimate_move_cost (TREE_TYPE (arg));
01044 return (what->global.insns - call_insns) * times + to->global.insns;
01045 }
01046
01047
01048
01049 static int
01050 cgraph_estimate_growth (struct cgraph_node *node)
01051 {
01052 int growth = 0;
01053 struct cgraph_edge *e;
01054
01055 for (e = node->callers; e; e = e->next_caller)
01056 if (e->inline_failed)
01057 growth += (cgraph_estimate_size_after_inlining (1, e->caller, node)
01058 - e->caller->global.insns);
01059
01060
01061
01062
01063 if (!node->needed && !DECL_EXTERNAL (node->decl))
01064 growth -= node->global.insns;
01065
01066 return growth;
01067 }
01068
01069
01070
01071
01072
01073
01074 void
01075 cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate)
01076 {
01077 struct cgraph_node *n;
01078
01079
01080
01081 if (!e->callee->callers->next_caller
01082 && (!e->callee->needed || DECL_EXTERNAL (e->callee->decl))
01083 && duplicate
01084 && flag_unit_at_a_time)
01085 {
01086 gcc_assert (!e->callee->global.inlined_to);
01087 if (!DECL_EXTERNAL (e->callee->decl))
01088 overall_insns -= e->callee->global.insns, nfunctions_inlined++;
01089 duplicate = 0;
01090 }
01091 else if (duplicate)
01092 {
01093 n = cgraph_clone_node (e->callee);
01094 cgraph_redirect_edge_callee (e, n);
01095 }
01096
01097 if (e->caller->global.inlined_to)
01098 e->callee->global.inlined_to = e->caller->global.inlined_to;
01099 else
01100 e->callee->global.inlined_to = e->caller;
01101
01102
01103 for (e = e->callee->callees; e; e = e->next_callee)
01104 if (!e->inline_failed)
01105 cgraph_clone_inlined_nodes (e, duplicate);
01106 }
01107
01108
01109
01110 void
01111 cgraph_mark_inline_edge (struct cgraph_edge *e)
01112 {
01113 int old_insns = 0, new_insns = 0;
01114 struct cgraph_node *to = NULL, *what;
01115
01116 gcc_assert (e->inline_failed);
01117 e->inline_failed = NULL;
01118
01119 if (!e->callee->global.inlined && flag_unit_at_a_time)
01120 DECL_POSSIBLY_INLINED (e->callee->decl) = true;
01121 e->callee->global.inlined = true;
01122
01123 cgraph_clone_inlined_nodes (e, true);
01124
01125 what = e->callee;
01126
01127
01128 for (;e && !e->inline_failed; e = e->caller->callers)
01129 {
01130 old_insns = e->caller->global.insns;
01131 new_insns = cgraph_estimate_size_after_inlining (1, e->caller,
01132 what);
01133 gcc_assert (new_insns >= 0);
01134 to = e->caller;
01135 to->global.insns = new_insns;
01136 }
01137 gcc_assert (what->global.inlined_to == to);
01138 if (new_insns > old_insns)
01139 overall_insns += new_insns - old_insns;
01140 ncalls_inlined++;
01141 }
01142
01143
01144
01145
01146
01147 static struct cgraph_edge *
01148 cgraph_mark_inline (struct cgraph_edge *edge)
01149 {
01150 struct cgraph_node *to = edge->caller;
01151 struct cgraph_node *what = edge->callee;
01152 struct cgraph_edge *e, *next;
01153 int times = 0;
01154
01155
01156
01157 for (e = what->callers; e; e = next)
01158 {
01159 next = e->next_caller;
01160 if (e->caller == to && e->inline_failed)
01161 {
01162 cgraph_mark_inline_edge (e);
01163 if (e == edge)
01164 edge = next;
01165 times++;
01166 }
01167 }
01168 gcc_assert (times);
01169 return edge;
01170 }
01171
01172
01173
01174
01175 static bool
01176 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
01177 const char **reason)
01178 {
01179 int times = 0;
01180 struct cgraph_edge *e;
01181 int newsize;
01182 int limit;
01183
01184 if (to->global.inlined_to)
01185 to = to->global.inlined_to;
01186
01187 for (e = to->callees; e; e = e->next_callee)
01188 if (e->callee == what)
01189 times++;
01190
01191
01192
01193 if (to->local.self_insns > what->local.self_insns)
01194 limit = to->local.self_insns;
01195 else
01196 limit = what->local.self_insns;
01197
01198 limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100;
01199
01200 newsize = cgraph_estimate_size_after_inlining (times, to, what);
01201 if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
01202 && newsize > limit)
01203 {
01204 if (reason)
01205 *reason = N_("--param large-function-growth limit reached");
01206 return false;
01207 }
01208 return true;
01209 }
01210
01211
01212
01213 static bool
01214 cgraph_default_inline_p (struct cgraph_node *n)
01215 {
01216 if (!DECL_INLINE (n->decl) || !DECL_SAVED_TREE (n->decl))
01217 return false;
01218 if (DECL_DECLARED_INLINE_P (n->decl))
01219 return n->global.insns < MAX_INLINE_INSNS_SINGLE;
01220 else
01221 return n->global.insns < MAX_INLINE_INSNS_AUTO;
01222 }
01223
01224
01225
01226
01227
01228 static bool
01229 cgraph_recursive_inlining_p (struct cgraph_node *to,
01230 struct cgraph_node *what,
01231 const char **reason)
01232 {
01233 bool recursive;
01234 if (to->global.inlined_to)
01235 recursive = what->decl == to->global.inlined_to->decl;
01236 else
01237 recursive = what->decl == to->decl;
01238
01239
01240 if (recursive && reason)
01241 *reason = (what->local.disregard_inline_limits
01242 ? N_("recursive inlining") : "");
01243 return recursive;
01244 }
01245
01246
01247 static void
01248 update_callee_keys (fibheap_t heap, struct fibnode **heap_node,
01249 struct cgraph_node *node)
01250 {
01251 struct cgraph_edge *e;
01252
01253 for (e = node->callees; e; e = e->next_callee)
01254 if (e->inline_failed && heap_node[e->callee->uid])
01255 fibheap_replace_key (heap, heap_node[e->callee->uid],
01256 cgraph_estimate_growth (e->callee));
01257 else if (!e->inline_failed)
01258 update_callee_keys (heap, heap_node, e->callee);
01259 }
01260
01261
01262
01263
01264 static void
01265 lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
01266 struct cgraph_edge **first, struct cgraph_edge **last)
01267 {
01268 struct cgraph_edge *e;
01269 for (e = where->callees; e; e = e->next_callee)
01270 if (e->callee == node)
01271 {
01272 if (!*first)
01273 *first = e;
01274 else
01275 (*last)->aux = e;
01276 *last = e;
01277 }
01278 for (e = where->callees; e; e = e->next_callee)
01279 if (!e->inline_failed)
01280 lookup_recursive_calls (node, e->callee, first, last);
01281 }
01282
01283
01284
01285 static void
01286 cgraph_decide_recursive_inlining (struct cgraph_node *node)
01287 {
01288 int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
01289 int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO);
01290 struct cgraph_edge *first_call = NULL, *last_call = NULL;
01291 struct cgraph_edge *last_in_current_depth;
01292 struct cgraph_edge *e;
01293 struct cgraph_node *master_clone;
01294 int depth = 0;
01295 int n = 0;
01296
01297 if (DECL_DECLARED_INLINE_P (node->decl))
01298 {
01299 limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE);
01300 max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH);
01301 }
01302
01303
01304 if (!max_depth
01305 || cgraph_estimate_size_after_inlining (1, node, node) >= limit)
01306 return;
01307 lookup_recursive_calls (node, node, &first_call, &last_call);
01308 if (!first_call)
01309 return;
01310
01311 if (cgraph_dump_file)
01312 fprintf (cgraph_dump_file,
01313 "\nPerforming recursive inlining on %s\n",
01314 cgraph_node_name (node));
01315
01316
01317 master_clone = cgraph_clone_node (node);
01318 master_clone->needed = true;
01319 for (e = master_clone->callees; e; e = e->next_callee)
01320 if (!e->inline_failed)
01321 cgraph_clone_inlined_nodes (e, true);
01322
01323
01324 last_in_current_depth = last_call;
01325 while (first_call
01326 && cgraph_estimate_size_after_inlining (1, node, master_clone) <= limit)
01327 {
01328 struct cgraph_edge *curr = first_call;
01329
01330 first_call = first_call->aux;
01331 curr->aux = NULL;
01332
01333 cgraph_redirect_edge_callee (curr, master_clone);
01334 cgraph_mark_inline_edge (curr);
01335 lookup_recursive_calls (node, curr->callee, &first_call, &last_call);
01336
01337 if (last_in_current_depth
01338 && ++depth >= max_depth)
01339 break;
01340 n++;
01341 }
01342
01343
01344 while (first_call)
01345 {
01346 struct cgraph_edge *next = first_call->aux;
01347 first_call->aux = NULL;
01348 first_call = next;
01349 }
01350 if (cgraph_dump_file)
01351 fprintf (cgraph_dump_file,
01352 "\n Inlined %i times, body grown from %i to %i insns\n", n,
01353 master_clone->global.insns, node->global.insns);
01354
01355
01356
01357
01358 for (node = cgraph_nodes; node != master_clone;
01359 node = node->next)
01360 if (node->global.inlined_to == master_clone)
01361 cgraph_remove_node (node);
01362 cgraph_remove_node (master_clone);
01363 }
01364
01365
01366
01367 static void
01368 cgraph_set_inline_failed (struct cgraph_node *node, const char *reason)
01369 {
01370 struct cgraph_edge *e;
01371
01372 if (cgraph_dump_file)
01373 fprintf (cgraph_dump_file, "Inlining failed: %s\n", reason);
01374 for (e = node->callers; e; e = e->next_caller)
01375 if (e->inline_failed)
01376 e->inline_failed = reason;
01377 }
01378
01379
01380
01381
01382
01383
01384
01385
01386 static void
01387 cgraph_decide_inlining_of_small_functions (void)
01388 {
01389 struct cgraph_node *node;
01390 fibheap_t heap = fibheap_new ();
01391 struct fibnode **heap_node =
01392 xcalloc (cgraph_max_uid, sizeof (struct fibnode *));
01393 int max_insns = ((HOST_WIDEST_INT) initial_insns
01394 * (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH)) / 100);
01395
01396
01397
01398 for (node = cgraph_nodes; node; node = node->next)
01399 {
01400 if (!node->local.inlinable || !node->callers
01401 || node->local.disregard_inline_limits)
01402 continue;
01403
01404 if (!cgraph_default_inline_p (node))
01405 {
01406 cgraph_set_inline_failed (node,
01407 N_("--param max-inline-insns-single limit reached"));
01408 continue;
01409 }
01410 heap_node[node->uid] =
01411 fibheap_insert (heap, cgraph_estimate_growth (node), node);
01412 }
01413
01414 if (cgraph_dump_file)
01415 fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n");
01416 while (overall_insns <= max_insns && (node = fibheap_extract_min (heap)))
01417 {
01418 struct cgraph_edge *e, *next;
01419 int old_insns = overall_insns;
01420
01421 heap_node[node->uid] = NULL;
01422 if (cgraph_dump_file)
01423 fprintf (cgraph_dump_file,
01424 "\nConsidering %s with %i insns\n"
01425 " Estimated growth is %+i insns.\n",
01426 cgraph_node_name (node), node->global.insns,
01427 cgraph_estimate_growth (node));
01428 if (!cgraph_default_inline_p (node))
01429 {
01430 cgraph_set_inline_failed (node,
01431 N_("--param max-inline-insns-single limit reached after inlining into the callee"));
01432 continue;
01433 }
01434 for (e = node->callers; e; e = next)
01435 {
01436 next = e->next_caller;
01437 if (e->inline_failed)
01438 {
01439 struct cgraph_node *where;
01440
01441 if (cgraph_recursive_inlining_p (e->caller, e->callee,
01442 &e->inline_failed)
01443 || !cgraph_check_inline_limits (e->caller, e->callee,
01444 &e->inline_failed))
01445 {
01446 if (cgraph_dump_file)
01447 fprintf (cgraph_dump_file, " Not inlining into %s:%s.\n",
01448 cgraph_node_name (e->caller), e->inline_failed);
01449 continue;
01450 }
01451 next = cgraph_mark_inline (e);
01452 where = e->caller;
01453 if (where->global.inlined_to)
01454 where = where->global.inlined_to;
01455
01456 if (heap_node[where->uid])
01457 fibheap_replace_key (heap, heap_node[where->uid],
01458 cgraph_estimate_growth (where));
01459
01460 if (cgraph_dump_file)
01461 fprintf (cgraph_dump_file,
01462 " Inlined into %s which now has %i insns.\n",
01463 cgraph_node_name (e->caller),
01464 e->caller->global.insns);
01465 }
01466 }
01467
01468 cgraph_decide_recursive_inlining (node);
01469
01470
01471
01472 update_callee_keys (heap, heap_node, node);
01473
01474 if (cgraph_dump_file)
01475 fprintf (cgraph_dump_file,
01476 " Inlined for a net change of %+i insns.\n",
01477 overall_insns - old_insns);
01478 }
01479 while ((node = fibheap_extract_min (heap)) != NULL)
01480 if (!node->local.disregard_inline_limits)
01481 cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached"));
01482 fibheap_delete (heap);
01483 free (heap_node);
01484 }
01485
01486
01487
01488
01489 static void
01490 cgraph_decide_inlining (void)
01491 {
01492 struct cgraph_node *node;
01493 int nnodes;
01494 struct cgraph_node **order =
01495 xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
01496 int old_insns = 0;
01497 int i;
01498
01499 for (node = cgraph_nodes; node; node = node->next)
01500 initial_insns += node->local.self_insns;
01501 overall_insns = initial_insns;
01502
01503 nnodes = cgraph_postorder (order);
01504
01505 if (cgraph_dump_file)
01506 fprintf (cgraph_dump_file,
01507 "\nDeciding on inlining. Starting with %i insns.\n",
01508 initial_insns);
01509
01510 for (node = cgraph_nodes; node; node = node->next)
01511 node->aux = 0;
01512
01513 if (cgraph_dump_file)
01514 fprintf (cgraph_dump_file, "\nInlining always_inline functions:\n");
01515
01516
01517
01518 for (i = nnodes - 1; i >= 0; i--)
01519 {
01520 struct cgraph_edge *e, *next;
01521
01522 node = order[i];
01523
01524 if (!node->local.disregard_inline_limits)
01525 continue;
01526 if (cgraph_dump_file)
01527 fprintf (cgraph_dump_file,
01528 "\nConsidering %s %i insns (always inline)\n",
01529 cgraph_node_name (node), node->global.insns);
01530 old_insns = overall_insns;
01531 for (e = node->callers; e; e = next)
01532 {
01533 next = e->next_caller;
01534 if (!e->inline_failed)
01535 continue;
01536 if (cgraph_recursive_inlining_p (e->caller, e->callee,
01537 &e->inline_failed))
01538 continue;
01539 cgraph_mark_inline_edge (e);
01540 if (cgraph_dump_file)
01541 fprintf (cgraph_dump_file,
01542 " Inlined into %s which now has %i insns.\n",
01543 cgraph_node_name (e->caller),
01544 e->caller->global.insns);
01545 }
01546 if (cgraph_dump_file)
01547 fprintf (cgraph_dump_file,
01548 " Inlined for a net change of %+i insns.\n",
01549 overall_insns - old_insns);
01550 }
01551
01552 if (!flag_really_no_inline)
01553 cgraph_decide_inlining_of_small_functions ();
01554
01555 if (!flag_really_no_inline
01556 && flag_inline_functions_called_once)
01557 {
01558 if (cgraph_dump_file)
01559 fprintf (cgraph_dump_file, "\nDeciding on functions called once:\n");
01560
01561
01562
01563 for (i = nnodes - 1; i >= 0; i--)
01564 {
01565 node = order[i];
01566
01567 if (node->callers && !node->callers->next_caller && !node->needed
01568 && node->local.inlinable && node->callers->inline_failed
01569 && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
01570 {
01571 bool ok = true;
01572 struct cgraph_node *node1;
01573
01574
01575 for (node1 = node->callers->caller;
01576 node1->callers && !node1->callers->inline_failed
01577 && ok; node1 = node1->callers->caller)
01578 if (node1->callers->next_caller || node1->needed)
01579 ok = false;
01580 if (ok)
01581 {
01582 if (cgraph_dump_file)
01583 fprintf (cgraph_dump_file,
01584 "\nConsidering %s %i insns.\n"
01585 " Called once from %s %i insns.\n",
01586 cgraph_node_name (node), node->global.insns,
01587 cgraph_node_name (node->callers->caller),
01588 node->callers->caller->global.insns);
01589
01590 old_insns = overall_insns;
01591
01592 if (cgraph_check_inline_limits (node->callers->caller, node,
01593 NULL))
01594 {
01595 cgraph_mark_inline (node->callers);
01596 if (cgraph_dump_file)
01597 fprintf (cgraph_dump_file,
01598 " Inlined into %s which now has %i insns"
01599 " for a net change of %+i insns.\n",
01600 cgraph_node_name (node->callers->caller),
01601 node->callers->caller->global.insns,
01602 overall_insns - old_insns);
01603 }
01604 else
01605 {
01606 if (cgraph_dump_file)
01607 fprintf (cgraph_dump_file,
01608 " Inline limit reached, not inlined.\n");
01609 }
01610 }
01611 }
01612 }
01613 }
01614
01615
01616
01617
01618 cgraph_remove_unreachable_nodes ();
01619
01620 if (cgraph_dump_file)
01621 fprintf (cgraph_dump_file,
01622 "\nInlined %i calls, eliminated %i functions, "
01623 "%i insns turned to %i insns.\n\n",
01624 ncalls_inlined, nfunctions_inlined, initial_insns,
01625 overall_insns);
01626 free (order);
01627 }
01628
01629
01630
01631
01632 static void
01633 cgraph_decide_inlining_incrementally (struct cgraph_node *node)
01634 {
01635 struct cgraph_edge *e;
01636
01637
01638 for (e = node->callees; e; e = e->next_callee)
01639 if (e->callee->local.disregard_inline_limits
01640 && e->inline_failed
01641 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
01642
01643
01644 && DECL_SAVED_TREE (e->callee->decl))
01645 cgraph_mark_inline (e);
01646
01647
01648 if (!flag_really_no_inline)
01649 for (e = node->callees; e; e = e->next_callee)
01650 if (e->callee->local.inlinable
01651 && e->inline_failed
01652 && !e->callee->local.disregard_inline_limits
01653 && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
01654 && cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
01655 && DECL_SAVED_TREE (e->callee->decl))
01656 {
01657 if (cgraph_default_inline_p (e->callee))
01658 cgraph_mark_inline (e);
01659 else
01660 e->inline_failed
01661 = N_("--param max-inline-insns-single limit reached");
01662 }
01663 }
01664
01665
01666
01667
01668 bool
01669 cgraph_inline_p (struct cgraph_edge *e, const char **reason)
01670 {
01671 *reason = e->inline_failed;
01672 return !e->inline_failed;
01673 }
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687 static void
01688 cgraph_expand_all_functions (void)
01689 {
01690 struct cgraph_node *node;
01691 struct cgraph_node **order =
01692 xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
01693 int order_pos = 0, new_order_pos = 0;
01694 int i;
01695
01696 order_pos = cgraph_postorder (order);
01697 gcc_assert (order_pos == cgraph_n_nodes);
01698
01699
01700
01701 for (i = 0; i < order_pos; i++)
01702 if (order[i]->output)
01703 order[new_order_pos++] = order[i];
01704
01705 for (i = new_order_pos - 1; i >= 0; i--)
01706 {
01707 node = order[i];
01708 if (node->output)
01709 {
01710 gcc_assert (node->reachable);
01711 node->output = 0;
01712 cgraph_expand_function (node);
01713 }
01714 }
01715 free (order);
01716 }
01717
01718
01719
01720
01721
01722
01723
01724
01725 static void
01726 cgraph_mark_local_functions (void)
01727 {
01728 struct cgraph_node *node;
01729
01730
01731 for (node = cgraph_nodes; node; node = node->next)
01732 {
01733 node->local.local = (!node->needed
01734 && DECL_SAVED_TREE (node->decl)
01735 && !TREE_PUBLIC (node->decl));
01736 }
01737
01738 if (cgraph_dump_file)
01739 {
01740 fprintf (cgraph_dump_file, "\nMarking local functions:");
01741 for (node = cgraph_nodes; node; node = node->next)
01742 if (node->local.local)
01743 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
01744 fprintf (cgraph_dump_file, "\n\n");
01745 }
01746 }
01747
01748
01749
01750 bool
01751 cgraph_preserve_function_body_p (tree decl)
01752 {
01753 struct cgraph_node *node;
01754
01755 if (dump_enabled_p (TDI_tree_all))
01756 return true;
01757 if (!cgraph_global_info_ready)
01758 return (DECL_INLINE (decl) && !flag_really_no_inline);
01759
01760 for (node = cgraph_node (decl); node; node = node->next_clone)
01761 if (node->global.inlined_to)
01762 return true;
01763 return false;
01764 }
01765
01766
01767
01768 void
01769 cgraph_optimize (void)
01770 {
01771 #ifdef ENABLE_CHECKING
01772 verify_cgraph ();
01773 #endif
01774 if (!flag_unit_at_a_time)
01775 return;
01776
01777 process_pending_assemble_externals ();
01778
01779 timevar_push (TV_CGRAPHOPT);
01780 if (!quiet_flag)
01781 fprintf (stderr, "Performing intraprocedural optimizations\n");
01782
01783 cgraph_mark_local_functions ();
01784 if (cgraph_dump_file)
01785 {
01786 fprintf (cgraph_dump_file, "Marked ");
01787 dump_cgraph (cgraph_dump_file);
01788 }
01789
01790 if (flag_inline_trees)
01791 cgraph_decide_inlining ();
01792 cgraph_global_info_ready = true;
01793 if (cgraph_dump_file)
01794 {
01795 fprintf (cgraph_dump_file, "Optimized ");
01796 dump_cgraph (cgraph_dump_file);
01797 }
01798 timevar_pop (TV_CGRAPHOPT);
01799
01800
01801 if (!quiet_flag)
01802 fprintf (stderr, "Assembling functions:\n");
01803 #ifdef ENABLE_CHECKING
01804 verify_cgraph ();
01805 #endif
01806
01807 cgraph_mark_functions_to_output ();
01808
01809 cgraph_expand_all_functions ();
01810 if (cgraph_dump_file)
01811 {
01812 fprintf (cgraph_dump_file, "\nFinal ");
01813 dump_cgraph (cgraph_dump_file);
01814 }
01815 #ifdef ENABLE_CHECKING
01816 verify_cgraph ();
01817
01818
01819 if (flag_unit_at_a_time
01820 && !dump_enabled_p (TDI_tree_all)
01821 && !(sorrycount || errorcount))
01822 {
01823 struct cgraph_node *node;
01824 bool error_found = false;
01825
01826 for (node = cgraph_nodes; node; node = node->next)
01827 if (node->analyzed
01828 && (node->global.inlined_to
01829 || DECL_SAVED_TREE (node->decl)))
01830 {
01831 error_found = true;
01832 dump_cgraph_node (stderr, node);
01833 }
01834 if (error_found)
01835 internal_error ("Nodes with no released memory found.");
01836 }
01837 #endif
01838 }
01839
01840
01841
01842
01843
01844 void
01845 cgraph_build_static_cdtor (char which, tree body, int priority)
01846 {
01847 static int counter = 0;
01848 char which_buf[16];
01849 tree decl, name, resdecl;
01850
01851 sprintf (which_buf, "%c_%d", which, counter++);
01852 name = get_file_function_name_long (which_buf);
01853
01854 decl = build_decl (FUNCTION_DECL, name,
01855 build_function_type (void_type_node, void_list_node));
01856 current_function_decl = decl;
01857
01858 resdecl = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
01859 DECL_ARTIFICIAL (resdecl) = 1;
01860 DECL_IGNORED_P (resdecl) = 1;
01861 DECL_RESULT (decl) = resdecl;
01862
01863 allocate_struct_function (decl);
01864
01865 TREE_STATIC (decl) = 1;
01866 TREE_USED (decl) = 1;
01867 DECL_ARTIFICIAL (decl) = 1;
01868 DECL_IGNORED_P (decl) = 1;
01869 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
01870 DECL_SAVED_TREE (decl) = body;
01871 TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors;
01872 DECL_UNINLINABLE (decl) = 1;
01873
01874 DECL_INITIAL (decl) = make_node (BLOCK);
01875 TREE_USED (DECL_INITIAL (decl)) = 1;
01876
01877 DECL_SOURCE_LOCATION (decl) = input_location;
01878 cfun->function_end_locus = input_location;
01879
01880 switch (which)
01881 {
01882 case 'I':
01883 DECL_STATIC_CONSTRUCTOR (decl) = 1;
01884 break;
01885 case 'D':
01886 DECL_STATIC_DESTRUCTOR (decl) = 1;
01887 break;
01888 default:
01889 gcc_unreachable ();
01890 }
01891
01892 gimplify_function_tree (decl);
01893
01894
01895 if (cgraph_global_info_ready)
01896 tree_rest_of_compilation (decl);
01897 else
01898 cgraph_finalize_function (decl, 0);
01899
01900 if (targetm.have_ctors_dtors)
01901 {
01902 void (*fn) (rtx, int);
01903
01904 if (which == 'I')
01905 fn = targetm.asm_out.constructor;
01906 else
01907 fn = targetm.asm_out.destructor;
01908 fn (XEXP (DECL_RTL (decl), 0), priority);
01909 }
01910 }
01911
01912 void
01913 init_cgraph (void)
01914 {
01915 cgraph_dump_file = dump_begin (TDI_cgraph, NULL);
01916 }