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