]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/cgraphunit.c
PR target/21888
[thirdparty/gcc.git] / gcc / cgraphunit.c
CommitLineData
d7c6d889 1/* Callgraph based intraprocedural optimizations.
dfbf3d71 2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
ae01b312 3 Contributed by Jan Hubicka
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
b0cdf642 22/* This module implements main driver of compilation process as well as
23 few basic intraprocedural optimizers.
24
25 The main scope of this file is to act as an interface in between
26 tree based frontends and the backend (and middle end)
27
28 The front-end is supposed to use following functionality:
29
30 - cgraph_finalize_function
31
32 This function is called once front-end has parsed whole body of function
33 and it is certain that the function body nor the declaration will change.
34
35 (There is one exception needed for implementing GCC extern inline function.)
36
37 - cgraph_varpool_finalize_variable
38
7bd28bba 39 This function has same behavior as the above but is used for static
b0cdf642 40 variables.
41
42 - cgraph_finalize_compilation_unit
43
44 This function is called once compilation unit is finalized and it will
45 no longer change.
46
47 In the unit-at-a-time the call-graph construction and local function
48 analysis takes place here. Bodies of unreachable functions are released
49 to conserve memory usage.
50
51 ??? The compilation unit in this point of view should be compilation
52 unit as defined by the language - for instance C frontend allows multiple
53 compilation units to be parsed at once and it should call function each
54 time parsing is done so we save memory.
55
56 - cgraph_optimize
57
58 In this unit-at-a-time compilation the intra procedural analysis takes
59 place here. In particular the static functions whose address is never
60 taken are marked as local. Backend can then use this information to
61 modify calling conventions, do better inlining or similar optimizations.
62
63 - cgraph_assemble_pending_functions
64 - cgraph_varpool_assemble_pending_variables
65
66 In non-unit-at-a-time mode these functions can be used to force compilation
67 of functions or variables that are known to be needed at given stage
68 of compilation
69
70 - cgraph_mark_needed_node
71 - cgraph_varpool_mark_needed_node
72
73 When function or variable is referenced by some hidden way (for instance
74 via assembly code and marked by attribute "used"), the call-graph data structure
75 must be updated accordingly by this function.
76
77 - analyze_expr callback
78
79 This function is responsible for lowering tree nodes not understood by
80 generic code into understandable ones or alternatively marking
81 callgraph and varpool nodes referenced by the as needed.
82
83 ??? On the tree-ssa genericizing should take place here and we will avoid
84 need for these hooks (replacing them by genericizing hook)
85
86 - expand_function callback
87
88 This function is used to expand function and pass it into RTL back-end.
89 Front-end should not make any assumptions about when this function can be
90 called. In particular cgraph_assemble_pending_functions,
91 cgraph_varpool_assemble_pending_variables, cgraph_finalize_function,
92 cgraph_varpool_finalize_function, cgraph_optimize can cause arbitrarily
93 previously finalized functions to be expanded.
94
95 We implement two compilation modes.
96
97 - unit-at-a-time: In this mode analyzing of all functions is deferred
98 to cgraph_finalize_compilation_unit and expansion into cgraph_optimize.
99
100 In cgraph_finalize_compilation_unit the reachable functions are
101 analyzed. During analysis the call-graph edges from reachable
102 functions are constructed and their destinations are marked as
103 reachable. References to functions and variables are discovered too
104 and variables found to be needed output to the assembly file. Via
105 mark_referenced call in assemble_variable functions referenced by
106 static variables are noticed too.
107
ca67a72b 108 The intra-procedural information is produced and its existence
b0cdf642 109 indicated by global_info_ready. Once this flag is set it is impossible
110 to change function from !reachable to reachable and thus
111 assemble_variable no longer call mark_referenced.
112
113 Finally the call-graph is topologically sorted and all reachable functions
114 that has not been completely inlined or are not external are output.
115
116 ??? It is possible that reference to function or variable is optimized
117 out. We can not deal with this nicely because topological order is not
118 suitable for it. For tree-ssa we may consider another pass doing
119 optimization and re-discovering reachable functions.
120
121 ??? Reorganize code so variables are output very last and only if they
122 really has been referenced by produced code, so we catch more cases
123 where reference has been optimized out.
124
125 - non-unit-at-a-time
126
127 All functions are variables are output as early as possible to conserve
128 memory consumption. This may or may not result in less memory used but
129 it is still needed for some legacy code that rely on particular ordering
130 of things output from the compiler.
131
132 Varpool data structures are not used and variables are output directly.
133
134 Functions are output early using call of
135 cgraph_assemble_pending_function from cgraph_finalize_function. The
136 decision on whether function is needed is made more conservative so
137 uninlininable static functions are needed too. During the call-graph
138 construction the edge destinations are not marked as reachable and it
edc6a4c0 139 is completely relied upn assemble_variable to mark them. */
121f3051 140
acc70efa 141
ae01b312 142#include "config.h"
143#include "system.h"
144#include "coretypes.h"
145#include "tm.h"
146#include "tree.h"
b5530559 147#include "rtl.h"
acc70efa 148#include "tree-flow.h"
ae01b312 149#include "tree-inline.h"
150#include "langhooks.h"
c6224531 151#include "pointer-set.h"
ae01b312 152#include "toplev.h"
153#include "flags.h"
154#include "ggc.h"
155#include "debug.h"
156#include "target.h"
157#include "cgraph.h"
80a85d8a 158#include "diagnostic.h"
f79b6507 159#include "timevar.h"
d7c6d889 160#include "params.h"
161#include "fibheap.h"
162#include "c-common.h"
611e5405 163#include "intl.h"
b69eb0ff 164#include "function.h"
acc70efa 165#include "tree-gimple.h"
f1e2a033 166#include "tree-pass.h"
c1dcd13c 167#include "output.h"
d7c6d889 168
a6868229 169static void cgraph_expand_all_functions (void);
d9d9733a 170static void cgraph_mark_functions_to_output (void);
171static void cgraph_expand_function (struct cgraph_node *);
9bfec7c2 172static tree record_reference (tree *, int *, void *);
2ff66ee0 173static void cgraph_analyze_function (struct cgraph_node *node);
d7c6d889 174
9bfec7c2 175/* Records tree nodes seen in record_reference. Simply using
25bb88de 176 walk_tree_without_duplicates doesn't guarantee each node is visited
177 once because it gets a new htab upon each recursive call from
9bfec7c2 178 record_reference itself. */
c6224531 179static struct pointer_set_t *visited_nodes;
25bb88de 180
121f3051 181static FILE *cgraph_dump_file;
182
2c0b522d 183/* Determine if function DECL is needed. That is, visible to something
184 either outside this translation unit, something magic in the system
185 configury, or (if not doing unit-at-a-time) to something we havn't
186 seen yet. */
187
188static bool
189decide_is_function_needed (struct cgraph_node *node, tree decl)
190{
9d95b2b0 191 tree origin;
4ee9c684 192
3f82b628 193 /* If the user told us it is used, then it must be so. */
194 if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
195 return true;
196
197 /* ??? If the assembler name is set by hand, it is possible to assemble
198 the name later after finalizing the function and the fact is noticed
199 in assemble_name then. This is arguably a bug. */
200 if (DECL_ASSEMBLER_NAME_SET_P (decl)
201 && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
202 return true;
203
2c0b522d 204 /* If we decided it was needed before, but at the time we didn't have
205 the body of the function available, then it's still needed. We have
206 to go back and re-check its dependencies now. */
207 if (node->needed)
208 return true;
209
210 /* Externally visible functions must be output. The exception is
211 COMDAT functions that must be output only when they are needed. */
212 if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
213 return true;
214
215 /* Constructors and destructors are reachable from the runtime by
216 some mechanism. */
217 if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))
218 return true;
219
2c0b522d 220 if (flag_unit_at_a_time)
221 return false;
222
223 /* If not doing unit at a time, then we'll only defer this function
224 if its marked for inlining. Otherwise we want to emit it now. */
225
226 /* "extern inline" functions are never output locally. */
227 if (DECL_EXTERNAL (decl))
228 return false;
4ee9c684 229 /* Nested functions of extern inline function shall not be emit unless
230 we inlined the origin. */
9d95b2b0 231 for (origin = decl_function_context (decl); origin;
232 origin = decl_function_context (origin))
233 if (DECL_EXTERNAL (origin))
4ee9c684 234 return false;
f024691d 235 /* We want to emit COMDAT functions only when absolutely necessary. */
c08871a9 236 if (DECL_COMDAT (decl))
2c0b522d 237 return false;
238 if (!DECL_INLINE (decl)
239 || (!node->local.disregard_inline_limits
240 /* When declared inline, defer even the uninlinable functions.
e4200070 241 This allows them to be eliminated when unused. */
2c0b522d 242 && !DECL_DECLARED_INLINE_P (decl)
19489abd 243 && (!node->local.inlinable || !cgraph_default_inline_p (node))))
2c0b522d 244 return true;
245
246 return false;
247}
248
06b27565 249/* Walk the decls we marked as necessary and see if they reference new
250 variables or functions and add them into the worklists. */
c1dcd13c 251static bool
252cgraph_varpool_analyze_pending_decls (void)
253{
254 bool changed = false;
255 timevar_push (TV_CGRAPH);
256
257 while (cgraph_varpool_first_unanalyzed_node)
258 {
259 tree decl = cgraph_varpool_first_unanalyzed_node->decl;
260
261 cgraph_varpool_first_unanalyzed_node->analyzed = true;
262
263 cgraph_varpool_first_unanalyzed_node = cgraph_varpool_first_unanalyzed_node->next_needed;
264
265 if (DECL_INITIAL (decl))
9bfec7c2 266 {
267 visited_nodes = pointer_set_create ();
268 walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes);
269 pointer_set_destroy (visited_nodes);
270 visited_nodes = NULL;
271 }
c1dcd13c 272 changed = true;
273 }
274 timevar_pop (TV_CGRAPH);
275 return changed;
276}
277
278/* Optimization of function bodies might've rendered some variables as
06b27565 279 unnecessary so we want to avoid these from being compiled.
c1dcd13c 280
442e3cb9 281 This is done by pruning the queue and keeping only the variables that
06b27565 282 really appear needed (ie they are either externally visible or referenced
c1dcd13c 283 by compiled function). Re-doing the reachability analysis on variables
284 brings back the remaining variables referenced by these. */
285static void
286cgraph_varpool_remove_unreferenced_decls (void)
287{
288 struct cgraph_varpool_node *next, *node = cgraph_varpool_nodes_queue;
289
290 cgraph_varpool_reset_queue ();
291
292 if (errorcount || sorrycount)
293 return;
294
295 while (node)
296 {
297 tree decl = node->decl;
298 next = node->next_needed;
299 node->needed = 0;
300
301 if (node->finalized
302 && ((DECL_ASSEMBLER_NAME_SET_P (decl)
303 && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
304 || node->force_output
305 || decide_is_variable_needed (node, decl)))
306 cgraph_varpool_mark_needed_node (node);
307
308 node = next;
309 }
310 cgraph_varpool_analyze_pending_decls ();
311}
acc70efa 312
acc70efa 313
c08871a9 314/* When not doing unit-at-a-time, output all functions enqueued.
315 Return true when such a functions were found. */
050e11c9 316
317bool
c08871a9 318cgraph_assemble_pending_functions (void)
319{
320 bool output = false;
321
322 if (flag_unit_at_a_time)
323 return false;
324
325 while (cgraph_nodes_queue)
326 {
327 struct cgraph_node *n = cgraph_nodes_queue;
328
329 cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
b0cdf642 330 n->next_needed = NULL;
1d09f0e6 331 if (!n->global.inlined_to
332 && !n->alias
333 && !DECL_EXTERNAL (n->decl))
050e11c9 334 {
335 cgraph_expand_function (n);
336 output = true;
337 }
c08871a9 338 }
050e11c9 339
c08871a9 340 return output;
341}
342
28df663b 343/* DECL has been parsed. Take it, queue it, compile it at the whim of the
344 logic in effect. If NESTED is true, then our caller cannot stand to have
345 the garbage collector run at the moment. We would need to either create
346 a new GC context, or just not compile right now. */
ae01b312 347
348void
28df663b 349cgraph_finalize_function (tree decl, bool nested)
ae01b312 350{
351 struct cgraph_node *node = cgraph_node (decl);
352
c08871a9 353 if (node->local.finalized)
354 {
355 /* As an GCC extension we allow redefinition of the function. The
28df663b 356 semantics when both copies of bodies differ is not well defined.
357 We replace the old body with new body so in unit at a time mode
358 we always use new body, while in normal mode we may end up with
359 old body inlined into some functions and new body expanded and
360 inlined in others.
c08871a9 361
28df663b 362 ??? It may make more sense to use one body for inlining and other
f024691d 363 body for expanding the function but this is difficult to do. */
28df663b 364
050e11c9 365 /* If node->output is set, then this is a unit-at-a-time compilation
366 and we have already begun whole-unit analysis. This is *not*
367 testing for whether we've already emitted the function. That
368 case can be sort-of legitimately seen with real function
369 redefinition errors. I would argue that the front end should
370 never present us with such a case, but don't enforce that for now. */
cc636d56 371 gcc_assert (!node->output);
28df663b 372
7bd28bba 373 /* Reset our data structures so we can analyze the function again. */
638531ad 374 memset (&node->local, 0, sizeof (node->local));
375 memset (&node->global, 0, sizeof (node->global));
376 memset (&node->rtl, 0, sizeof (node->rtl));
ec1e35b2 377 node->analyzed = false;
69435b7f 378 node->local.redefined_extern_inline = true;
06bf91cb 379
380 if (!flag_unit_at_a_time)
381 {
382 struct cgraph_node *n;
383
384 for (n = cgraph_nodes; n; n = n->next)
385 if (n->global.inlined_to == node)
386 cgraph_remove_node (n);
387 }
388
bb4c7a44 389 cgraph_node_remove_callees (node);
28df663b 390
638531ad 391 /* We may need to re-queue the node for assembling in case
392 we already proceeded it and ignored as not needed. */
393 if (node->reachable && !flag_unit_at_a_time)
c08871a9 394 {
638531ad 395 struct cgraph_node *n;
396
397 for (n = cgraph_nodes_queue; n; n = n->next_needed)
398 if (n == node)
399 break;
400 if (!n)
401 node->reachable = 0;
c08871a9 402 }
c08871a9 403 }
28df663b 404
c08871a9 405 notice_global_symbol (decl);
ae01b312 406 node->decl = decl;
79bb87b4 407 node->local.finalized = true;
e27482aa 408 node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
9d95b2b0 409 if (node->nested)
410 lower_nested_functions (decl);
411 gcc_assert (!node->nested);
ae01b312 412
2c0b522d 413 /* If not unit at a time, then we need to create the call graph
414 now, so that called functions can be queued and emitted now. */
2ff66ee0 415 if (!flag_unit_at_a_time)
19489abd 416 {
417 cgraph_analyze_function (node);
418 cgraph_decide_inlining_incrementally (node);
419 }
2ff66ee0 420
2c0b522d 421 if (decide_is_function_needed (node, decl))
422 cgraph_mark_needed_node (node);
423
ecda6e51 424 /* Since we reclaim unreachable nodes at the end of every language
3f82b628 425 level unit, we need to be conservative about possible entry points
426 there. */
427 if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
428 cgraph_mark_reachable_node (node);
429
28df663b 430 /* If not unit at a time, go ahead and emit everything we've found
431 to be reachable at this time. */
432 if (!nested)
dc721f36 433 {
434 if (!cgraph_assemble_pending_functions ())
435 ggc_collect ();
436 }
3d7bfc56 437
2c0b522d 438 /* If we've not yet emitted decl, tell the debug info about it. */
28df663b 439 if (!TREE_ASM_WRITTEN (decl))
2c0b522d 440 (*debug_hooks->deferred_inline_function) (decl);
4e8871a0 441
b69eb0ff 442 /* Possibly warn about unused parameters. */
443 if (warn_unused_parameter)
444 do_warn_unused_parameter (decl);
ae01b312 445}
446
e27482aa 447void
448cgraph_lower_function (struct cgraph_node *node)
449{
450 if (node->lowered)
451 return;
452 tree_lowering_passes (node->decl);
453 node->lowered = true;
454}
455
ae01b312 456/* Walk tree and record all calls. Called via walk_tree. */
457static tree
9bfec7c2 458record_reference (tree *tp, int *walk_subtrees, void *data)
ae01b312 459{
ec1e35b2 460 tree t = *tp;
461
462 switch (TREE_CODE (t))
ae01b312 463 {
ec1e35b2 464 case VAR_DECL:
465 /* ??? Really, we should mark this decl as *potentially* referenced
466 by this function and re-examine whether the decl is actually used
467 after rtl has been generated. */
c1dcd13c 468 if (TREE_STATIC (t) || DECL_EXTERNAL (t))
caa6fdce 469 {
470 cgraph_varpool_mark_needed_node (cgraph_varpool_node (t));
471 if (lang_hooks.callgraph.analyze_expr)
472 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees,
473 data);
474 }
ec1e35b2 475 break;
476
4e4ac74b 477 case FDESC_EXPR:
ec1e35b2 478 case ADDR_EXPR:
479 if (flag_unit_at_a_time)
480 {
481 /* Record dereferences to the functions. This makes the
482 functions reachable unconditionally. */
483 tree decl = TREE_OPERAND (*tp, 0);
484 if (TREE_CODE (decl) == FUNCTION_DECL)
485 cgraph_mark_needed_node (cgraph_node (decl));
486 }
487 break;
488
ec1e35b2 489 default:
490 /* Save some cycles by not walking types and declaration as we
491 won't find anything useful there anyway. */
ce45a448 492 if (IS_TYPE_OR_DECL_P (*tp))
ae01b312 493 {
ae01b312 494 *walk_subtrees = 0;
ec1e35b2 495 break;
ae01b312 496 }
ec1e35b2 497
498 if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
dc24ddbd 499 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data);
ec1e35b2 500 break;
ae01b312 501 }
ec1e35b2 502
ae01b312 503 return NULL;
504}
505
b0cdf642 506/* Create cgraph edges for function calls inside BODY from NODE. */
ae01b312 507
edc6a4c0 508static void
b0cdf642 509cgraph_create_edges (struct cgraph_node *node, tree body)
ae01b312 510{
9bfec7c2 511 basic_block bb;
512
513 struct function *this_cfun = DECL_STRUCT_FUNCTION (body);
514 block_stmt_iterator bsi;
515 tree step;
c6224531 516 visited_nodes = pointer_set_create ();
e27482aa 517
9bfec7c2 518 /* Reach the trees by walking over the CFG, and note the
519 enclosing basic-blocks in the call edges. */
520 FOR_EACH_BB_FN (bb, this_cfun)
521 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
522 {
523 tree stmt = bsi_stmt (bsi);
524 tree call = get_call_expr_in (stmt);
525 tree decl;
526
527 if (call && (decl = get_callee_fndecl (call)))
e27482aa 528 {
9bfec7c2 529 cgraph_create_edge (node, cgraph_node (decl), stmt,
530 bb->count,
531 bb->loop_depth);
532 walk_tree (&TREE_OPERAND (call, 1),
533 record_reference, node, visited_nodes);
534 if (TREE_CODE (stmt) == MODIFY_EXPR)
535 walk_tree (&TREE_OPERAND (stmt, 0),
536 record_reference, node, visited_nodes);
e27482aa 537 }
9bfec7c2 538 else
539 walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes);
540 }
541
542 /* Walk over any private statics that may take addresses of functions. */
543 if (TREE_CODE (DECL_INITIAL (body)) == BLOCK)
544 {
545 for (step = BLOCK_VARS (DECL_INITIAL (body));
546 step;
547 step = TREE_CHAIN (step))
548 if (DECL_INITIAL (step))
549 walk_tree (&DECL_INITIAL (step), record_reference, node, visited_nodes);
e27482aa 550 }
9bfec7c2 551
552 /* Also look here for private statics. */
553 if (DECL_STRUCT_FUNCTION (body))
554 for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list;
555 step;
556 step = TREE_CHAIN (step))
557 {
558 tree decl = TREE_VALUE (step);
559 if (DECL_INITIAL (decl) && TREE_STATIC (decl))
560 walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
561 }
e27482aa 562
c6224531 563 pointer_set_destroy (visited_nodes);
25bb88de 564 visited_nodes = NULL;
ae01b312 565}
566
b0cdf642 567
568/* Verify cgraph nodes of given cgraph node. */
569void
570verify_cgraph_node (struct cgraph_node *node)
571{
572 struct cgraph_edge *e;
573 struct cgraph_node *main_clone;
e27482aa 574 struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl);
575 basic_block this_block;
576 block_stmt_iterator bsi;
9bfec7c2 577 bool error_found = false;
b0cdf642 578
579 timevar_push (TV_CGRAPH_VERIFY);
b0cdf642 580 for (e = node->callees; e; e = e->next_callee)
581 if (e->aux)
582 {
583 error ("Aux field set for edge %s->%s",
584 cgraph_node_name (e->caller), cgraph_node_name (e->callee));
585 error_found = true;
586 }
587 for (e = node->callers; e; e = e->next_caller)
588 {
589 if (!e->inline_failed)
590 {
591 if (node->global.inlined_to
592 != (e->caller->global.inlined_to
593 ? e->caller->global.inlined_to : e->caller))
594 {
595 error ("Inlined_to pointer is wrong");
596 error_found = true;
597 }
598 if (node->callers->next_caller)
599 {
600 error ("Multiple inline callers");
601 error_found = true;
602 }
603 }
604 else
605 if (node->global.inlined_to)
606 {
607 error ("Inlined_to pointer set for noninline callers");
608 error_found = true;
609 }
610 }
611 if (!node->callers && node->global.inlined_to)
612 {
613 error ("Inlined_to pointer is set but no predecesors found");
614 error_found = true;
615 }
616 if (node->global.inlined_to == node)
617 {
4133d091 618 error ("Inlined_to pointer refers to itself");
b0cdf642 619 error_found = true;
620 }
621
622 for (main_clone = cgraph_node (node->decl); main_clone;
623 main_clone = main_clone->next_clone)
624 if (main_clone == node)
625 break;
626 if (!node)
627 {
628 error ("Node not found in DECL_ASSEMBLER_NAME hash");
629 error_found = true;
630 }
631
632 if (node->analyzed
633 && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl)
634 && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
635 {
e27482aa 636 if (this_cfun->cfg)
637 {
638 /* The nodes we're interested in are never shared, so walk
639 the tree ignoring duplicates. */
640 visited_nodes = pointer_set_create ();
641 /* Reach the trees by walking over the CFG, and note the
642 enclosing basic-blocks in the call edges. */
643 FOR_EACH_BB_FN (this_block, this_cfun)
644 for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
9bfec7c2 645 {
646 tree stmt = bsi_stmt (bsi);
647 tree call = get_call_expr_in (stmt);
648 tree decl;
649 if (call && (decl = get_callee_fndecl (call)))
650 {
651 struct cgraph_edge *e = cgraph_edge (node, stmt);
652 if (e)
653 {
654 if (e->aux)
655 {
656 error ("Shared call_stmt:");
657 debug_generic_stmt (stmt);
658 error_found = true;
659 }
660 if (e->callee->decl != cgraph_node (decl)->decl)
661 {
662 error ("Edge points to wrong declaration:");
663 debug_tree (e->callee->decl);
664 fprintf (stderr," Instead of:");
665 debug_tree (decl);
666 }
667 e->aux = (void *)1;
668 }
669 else
670 {
671 error ("Missing callgraph edge for call stmt:");
672 debug_generic_stmt (stmt);
673 error_found = true;
674 }
675 }
676 }
e27482aa 677 pointer_set_destroy (visited_nodes);
678 visited_nodes = NULL;
679 }
680 else
681 /* No CFG available?! */
682 gcc_unreachable ();
683
b0cdf642 684 for (e = node->callees; e; e = e->next_callee)
685 {
686 if (!e->aux)
687 {
9bfec7c2 688 error ("Edge %s->%s has no corresponding call_stmt",
b0cdf642 689 cgraph_node_name (e->caller),
690 cgraph_node_name (e->callee));
9bfec7c2 691 debug_generic_stmt (e->call_stmt);
b0cdf642 692 error_found = true;
693 }
694 e->aux = 0;
695 }
696 }
697 if (error_found)
698 {
699 dump_cgraph_node (stderr, node);
700 internal_error ("verify_cgraph_node failed.");
701 }
702 timevar_pop (TV_CGRAPH_VERIFY);
703}
704
705/* Verify whole cgraph structure. */
706void
707verify_cgraph (void)
708{
709 struct cgraph_node *node;
710
8ec2a798 711 if (sorrycount || errorcount)
712 return;
713
b0cdf642 714 for (node = cgraph_nodes; node; node = node->next)
715 verify_cgraph_node (node);
716}
717
c1dcd13c 718
719/* Output all variables enqueued to be assembled. */
720bool
721cgraph_varpool_assemble_pending_decls (void)
722{
723 bool changed = false;
724
725 if (errorcount || sorrycount)
726 return false;
727
728 /* EH might mark decls as needed during expansion. This should be safe since
729 we don't create references to new function, but it should not be used
730 elsewhere. */
731 cgraph_varpool_analyze_pending_decls ();
732
733 while (cgraph_varpool_nodes_queue)
734 {
735 tree decl = cgraph_varpool_nodes_queue->decl;
736 struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue;
737
738 cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed;
739 if (!TREE_ASM_WRITTEN (decl) && !node->alias && !DECL_EXTERNAL (decl))
740 {
741 assemble_variable (decl, 0, 1, 0);
742 changed = true;
743 }
744 node->next_needed = NULL;
745 }
746 return changed;
747}
748
0785e435 749/* Analyze the function scheduled to be output. */
750static void
751cgraph_analyze_function (struct cgraph_node *node)
752{
753 tree decl = node->decl;
611e5405 754 struct cgraph_edge *e;
0785e435 755
ec1e35b2 756 current_function_decl = decl;
e27482aa 757 push_cfun (DECL_STRUCT_FUNCTION (decl));
758 cgraph_lower_function (node);
0785e435 759
760 /* First kill forward declaration so reverse inlining works properly. */
e27482aa 761 cgraph_create_edges (node, decl);
0785e435 762
763 node->local.inlinable = tree_inlinable_function_p (decl);
e27482aa 764 node->local.self_insns = estimate_num_insns (decl);
0785e435 765 if (node->local.inlinable)
766 node->local.disregard_inline_limits
dc24ddbd 767 = lang_hooks.tree_inlining.disregard_inline_limits (decl);
611e5405 768 for (e = node->callers; e; e = e->next_caller)
b0cdf642 769 {
770 if (node->local.redefined_extern_inline)
771 e->inline_failed = N_("redefined extern inline functions are not "
772 "considered for inlining");
773 else if (!node->local.inlinable)
774 e->inline_failed = N_("function not inlinable");
775 else
776 e->inline_failed = N_("function not considered for inlining");
777 }
99cf25d0 778 if (flag_really_no_inline && !node->local.disregard_inline_limits)
779 node->local.inlinable = 0;
0785e435 780 /* Inlining characteristics are maintained by the cgraph_mark_inline. */
781 node->global.insns = node->local.self_insns;
0785e435 782
ec1e35b2 783 node->analyzed = true;
e27482aa 784 pop_cfun ();
c08871a9 785 current_function_decl = NULL;
0785e435 786}
787
ae01b312 788/* Analyze the whole compilation unit once it is parsed completely. */
789
790void
d9d9733a 791cgraph_finalize_compilation_unit (void)
ae01b312 792{
793 struct cgraph_node *node;
c1dcd13c 794 /* Keep track of already processed nodes when called multiple times for
06b27565 795 intermodule optimization. */
c1dcd13c 796 static struct cgraph_node *first_analyzed;
ae01b312 797
d7401838 798 finish_aliases_1 ();
799
2ff66ee0 800 if (!flag_unit_at_a_time)
c08871a9 801 {
802 cgraph_assemble_pending_functions ();
803 return;
804 }
2ff66ee0 805
d7c6d889 806 if (!quiet_flag)
c1dcd13c 807 {
808 fprintf (stderr, "\nAnalyzing compilation unit");
809 fflush (stderr);
810 }
229dcfae 811
f79b6507 812 timevar_push (TV_CGRAPH);
c1dcd13c 813 cgraph_varpool_analyze_pending_decls ();
f79b6507 814 if (cgraph_dump_file)
ae01b312 815 {
e4200070 816 fprintf (cgraph_dump_file, "Initial entry points:");
c1dcd13c 817 for (node = cgraph_nodes; node != first_analyzed; node = node->next)
3d7bfc56 818 if (node->needed && DECL_SAVED_TREE (node->decl))
f79b6507 819 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
820 fprintf (cgraph_dump_file, "\n");
ae01b312 821 }
822
e6d2b2d8 823 /* Propagate reachability flag and lower representation of all reachable
824 functions. In the future, lowering will introduce new functions and
825 new entry points on the way (by template instantiation and virtual
826 method table generation for instance). */
3d7bfc56 827 while (cgraph_nodes_queue)
ae01b312 828 {
0785e435 829 struct cgraph_edge *edge;
3d7bfc56 830 tree decl = cgraph_nodes_queue->decl;
831
832 node = cgraph_nodes_queue;
d87976fb 833 cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
b0cdf642 834 node->next_needed = NULL;
ae01b312 835
638531ad 836 /* ??? It is possible to create extern inline function and later using
bbd5cba2 837 weak alias attribute to kill its body. See
638531ad 838 gcc.c-torture/compile/20011119-1.c */
839 if (!DECL_SAVED_TREE (decl))
840 continue;
841
cc636d56 842 gcc_assert (!node->analyzed && node->reachable);
843 gcc_assert (DECL_SAVED_TREE (decl));
ae01b312 844
0785e435 845 cgraph_analyze_function (node);
2c0b522d 846
ae01b312 847 for (edge = node->callees; edge; edge = edge->next_callee)
0785e435 848 if (!edge->callee->reachable)
2c0b522d 849 cgraph_mark_reachable_node (edge->callee);
850
c1dcd13c 851 cgraph_varpool_analyze_pending_decls ();
ae01b312 852 }
2c0b522d 853
3d7bfc56 854 /* Collect entry points to the unit. */
855
f79b6507 856 if (cgraph_dump_file)
3d7bfc56 857 {
e4200070 858 fprintf (cgraph_dump_file, "Unit entry points:");
c1dcd13c 859 for (node = cgraph_nodes; node != first_analyzed; node = node->next)
3d7bfc56 860 if (node->needed && DECL_SAVED_TREE (node->decl))
f79b6507 861 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
e4200070 862 fprintf (cgraph_dump_file, "\n\nInitial ");
0785e435 863 dump_cgraph (cgraph_dump_file);
3d7bfc56 864 }
e6d2b2d8 865
f79b6507 866 if (cgraph_dump_file)
867 fprintf (cgraph_dump_file, "\nReclaiming functions:");
ae01b312 868
c1dcd13c 869 for (node = cgraph_nodes; node != first_analyzed; node = node->next)
ae01b312 870 {
871 tree decl = node->decl;
872
873 if (!node->reachable && DECL_SAVED_TREE (decl))
874 {
f79b6507 875 if (cgraph_dump_file)
876 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
b0cdf642 877 cgraph_remove_node (node);
ae01b312 878 }
bc5cab3b 879 else
880 node->next_needed = NULL;
ae01b312 881 }
f79b6507 882 if (cgraph_dump_file)
e4200070 883 {
884 fprintf (cgraph_dump_file, "\n\nReclaimed ");
885 dump_cgraph (cgraph_dump_file);
886 }
c1dcd13c 887 first_analyzed = cgraph_nodes;
ae01b312 888 ggc_collect ();
f79b6507 889 timevar_pop (TV_CGRAPH);
ae01b312 890}
ae01b312 891/* Figure out what functions we want to assemble. */
892
893static void
d9d9733a 894cgraph_mark_functions_to_output (void)
ae01b312 895{
896 struct cgraph_node *node;
897
ae01b312 898 for (node = cgraph_nodes; node; node = node->next)
899 {
900 tree decl = node->decl;
d7c6d889 901 struct cgraph_edge *e;
cc636d56 902
903 gcc_assert (!node->output);
d7c6d889 904
905 for (e = node->callers; e; e = e->next_caller)
611e5405 906 if (e->inline_failed)
d7c6d889 907 break;
ae01b312 908
e6d2b2d8 909 /* We need to output all local functions that are used and not
910 always inlined, as well as those that are reachable from
911 outside the current compilation unit. */
ae01b312 912 if (DECL_SAVED_TREE (decl)
b0cdf642 913 && !node->global.inlined_to
ae01b312 914 && (node->needed
d7c6d889 915 || (e && node->reachable))
4ee9c684 916 && !TREE_ASM_WRITTEN (decl)
ae01b312 917 && !DECL_EXTERNAL (decl))
918 node->output = 1;
cc636d56 919 else
9cee7c3f 920 {
921 /* We should've reclaimed all functions that are not needed. */
922#ifdef ENABLE_CHECKING
923 if (!node->global.inlined_to && DECL_SAVED_TREE (decl)
924 && !DECL_EXTERNAL (decl))
925 {
926 dump_cgraph_node (stderr, node);
927 internal_error ("failed to reclaim unneeded function");
928 }
929#endif
930 gcc_assert (node->global.inlined_to || !DECL_SAVED_TREE (decl)
931 || DECL_EXTERNAL (decl));
932
933 }
934
961e3b13 935 }
936}
937
ae01b312 938/* Expand function specified by NODE. */
e6d2b2d8 939
ae01b312 940static void
d9d9733a 941cgraph_expand_function (struct cgraph_node *node)
ae01b312 942{
943 tree decl = node->decl;
944
b0cdf642 945 /* We ought to not compile any inline clones. */
cc636d56 946 gcc_assert (!node->global.inlined_to);
b0cdf642 947
28df663b 948 if (flag_unit_at_a_time)
949 announce_function (decl);
961e3b13 950
f8deefc1 951 cgraph_lower_function (node);
952
794da2bb 953 /* Generate RTL for the body of DECL. */
dc24ddbd 954 lang_hooks.callgraph.expand_function (decl);
961e3b13 955
4ee9c684 956 /* Make sure that BE didn't give up on compiling. */
957 /* ??? Can happen with nested function of extern inline. */
cc636d56 958 gcc_assert (TREE_ASM_WRITTEN (node->decl));
b0cdf642 959
ae01b312 960 current_function_decl = NULL;
8ec2a798 961 if (!cgraph_preserve_function_body_p (node->decl))
4ee9c684 962 {
963 DECL_SAVED_TREE (node->decl) = NULL;
964 DECL_STRUCT_FUNCTION (node->decl) = NULL;
4ee9c684 965 DECL_INITIAL (node->decl) = error_mark_node;
7edd21a5 966 /* Eliminate all call edges. This is important so the call_expr no longer
8ec2a798 967 points to the dead function body. */
bb4c7a44 968 cgraph_node_remove_callees (node);
4ee9c684 969 }
e1be32b8 970
971 cgraph_function_flags_ready = true;
ae01b312 972}
973
b0cdf642 974/* Return true when CALLER_DECL should be inlined into CALLEE_DECL. */
d7c6d889 975
976bool
b0cdf642 977cgraph_inline_p (struct cgraph_edge *e, const char **reason)
d7c6d889 978{
b0cdf642 979 *reason = e->inline_failed;
980 return !e->inline_failed;
d7c6d889 981}
b0cdf642 982
acc70efa 983
acc70efa 984
d9d9733a 985/* Expand all functions that must be output.
986
d7c6d889 987 Attempt to topologically sort the nodes so function is output when
988 all called functions are already assembled to allow data to be
91c82c20 989 propagated across the callgraph. Use a stack to get smaller distance
3927afe0 990 between a function and its callees (later we may choose to use a more
d7c6d889 991 sophisticated algorithm for function reordering; we will likely want
992 to use subsections to make the output functions appear in top-down
993 order). */
994
995static void
a6868229 996cgraph_expand_all_functions (void)
d7c6d889 997{
998 struct cgraph_node *node;
999 struct cgraph_node **order =
746149b7 1000 xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
b0cdf642 1001 int order_pos = 0, new_order_pos = 0;
d7c6d889 1002 int i;
1003
d7c6d889 1004 order_pos = cgraph_postorder (order);
cc636d56 1005 gcc_assert (order_pos == cgraph_n_nodes);
d7c6d889 1006
7bd28bba 1007 /* Garbage collector may remove inline clones we eliminate during
b0cdf642 1008 optimization. So we must be sure to not reference them. */
1009 for (i = 0; i < order_pos; i++)
1010 if (order[i]->output)
1011 order[new_order_pos++] = order[i];
1012
1013 for (i = new_order_pos - 1; i >= 0; i--)
d7c6d889 1014 {
1015 node = order[i];
1016 if (node->output)
1017 {
cc636d56 1018 gcc_assert (node->reachable);
d7c6d889 1019 node->output = 0;
1020 cgraph_expand_function (node);
1021 }
1022 }
1023 free (order);
1024}
1025
3f82b628 1026/* Mark visibility of all functions.
acc70efa 1027
1028 A local function is one whose calls can occur only in the current
1029 compilation unit and all its calls are explicit, so we can change
1030 its calling convention. We simply mark all static functions whose
3f82b628 1031 address is not taken as local.
1032
1033 We also change the TREE_PUBLIC flag of all declarations that are public
1034 in language point of view but we want to overwrite this default
1035 via visibilities for the backend point of view. */
d7c6d889 1036
1037static void
3f82b628 1038cgraph_function_and_variable_visibility (void)
d7c6d889 1039{
1040 struct cgraph_node *node;
3f82b628 1041 struct cgraph_varpool_node *vnode;
d7c6d889 1042
d7c6d889 1043 for (node = cgraph_nodes; node; node = node->next)
1044 {
3f82b628 1045 if (node->reachable
1046 && (DECL_COMDAT (node->decl)
1047 || (TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
1048 node->local.externally_visible = 1;
d7c6d889 1049 node->local.local = (!node->needed
3f82b628 1050 && node->analyzed
e6ad3175 1051 && !DECL_EXTERNAL (node->decl)
8b4f617c 1052 && !node->local.externally_visible);
3f82b628 1053 }
1054 for (vnode = cgraph_varpool_nodes_queue; vnode; vnode = vnode->next_needed)
1055 {
1056 if (vnode->needed
1057 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
1058 vnode->externally_visible = 1;
1059 gcc_assert (TREE_STATIC (vnode->decl));
d7c6d889 1060 }
acc70efa 1061
3f82b628 1062 /* Because we have to be conservative on the boundaries of source
1063 level units, it is possible that we marked some functions in
1064 reachable just because they might be used later via external
1065 linkage, but after making them local they are really unreachable
1066 now. */
1067 cgraph_remove_unreachable_nodes (true, cgraph_dump_file);
1068
d7c6d889 1069 if (cgraph_dump_file)
acc70efa 1070 {
1071 fprintf (cgraph_dump_file, "\nMarking local functions:");
1072 for (node = cgraph_nodes; node; node = node->next)
1073 if (node->local.local)
1074 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
1075 fprintf (cgraph_dump_file, "\n\n");
3f82b628 1076 fprintf (cgraph_dump_file, "\nMarking externally visible functions:");
1077 for (node = cgraph_nodes; node; node = node->next)
1078 if (node->local.externally_visible)
1079 fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
1080 fprintf (cgraph_dump_file, "\n\n");
58f1b650 1081 }
3f82b628 1082 cgraph_function_flags_ready = true;
acc70efa 1083}
80a85d8a 1084
b0cdf642 1085/* Return true when function body of DECL still needs to be kept around
1086 for later re-use. */
1087bool
1088cgraph_preserve_function_body_p (tree decl)
1089{
1090 struct cgraph_node *node;
1091 /* Keep the body; we're going to dump it. */
0f9005dd 1092 if (dump_enabled_p (TDI_tree_all))
b0cdf642 1093 return true;
1094 if (!cgraph_global_info_ready)
1095 return (DECL_INLINE (decl) && !flag_really_no_inline);
1096 /* Look if there is any clone around. */
1097 for (node = cgraph_node (decl); node; node = node->next_clone)
1098 if (node->global.inlined_to)
1099 return true;
1100 return false;
1101}
1102
ae01b312 1103/* Perform simple optimizations based on callgraph. */
1104
1105void
d9d9733a 1106cgraph_optimize (void)
ae01b312 1107{
b0cdf642 1108#ifdef ENABLE_CHECKING
1109 verify_cgraph ();
1110#endif
2ff66ee0 1111 if (!flag_unit_at_a_time)
c1dcd13c 1112 {
1113 cgraph_varpool_assemble_pending_decls ();
1114 return;
1115 }
e9f08e82 1116
1117 process_pending_assemble_externals ();
c1dcd13c 1118
1119 /* Frontend may output common variables after the unit has been finalized.
1120 It is safe to deal with them here as they are always zero initialized. */
1121 cgraph_varpool_analyze_pending_decls ();
e9f08e82 1122
f79b6507 1123 timevar_push (TV_CGRAPHOPT);
d7c6d889 1124 if (!quiet_flag)
1125 fprintf (stderr, "Performing intraprocedural optimizations\n");
e4200070 1126
3f82b628 1127 cgraph_function_and_variable_visibility ();
f79b6507 1128 if (cgraph_dump_file)
1129 {
e4200070 1130 fprintf (cgraph_dump_file, "Marked ");
f79b6507 1131 dump_cgraph (cgraph_dump_file);
1132 }
f1e2a033 1133 ipa_passes ();
e1be32b8 1134 /* This pass remove bodies of extern inline functions we never inlined.
1135 Do this later so other IPA passes see what is really going on. */
1136 cgraph_remove_unreachable_nodes (false, dump_file);
80a85d8a 1137 cgraph_global_info_ready = true;
f79b6507 1138 if (cgraph_dump_file)
1139 {
e4200070 1140 fprintf (cgraph_dump_file, "Optimized ");
f79b6507 1141 dump_cgraph (cgraph_dump_file);
c1dcd13c 1142 dump_varpool (cgraph_dump_file);
f79b6507 1143 }
1144 timevar_pop (TV_CGRAPHOPT);
ae01b312 1145
d7c6d889 1146 /* Output everything. */
e4200070 1147 if (!quiet_flag)
1148 fprintf (stderr, "Assembling functions:\n");
b0cdf642 1149#ifdef ENABLE_CHECKING
1150 verify_cgraph ();
1151#endif
acc70efa 1152
acc70efa 1153 cgraph_mark_functions_to_output ();
a6868229 1154 cgraph_expand_all_functions ();
c1dcd13c 1155 cgraph_varpool_remove_unreferenced_decls ();
1156
1157 cgraph_varpool_assemble_pending_decls ();
1158
f79b6507 1159 if (cgraph_dump_file)
1160 {
e4200070 1161 fprintf (cgraph_dump_file, "\nFinal ");
f79b6507 1162 dump_cgraph (cgraph_dump_file);
1163 }
b0cdf642 1164#ifdef ENABLE_CHECKING
1165 verify_cgraph ();
4ee9c684 1166 /* Double check that all inline clones are gone and that all
1167 function bodies have been released from memory. */
1168 if (flag_unit_at_a_time
0f9005dd 1169 && !dump_enabled_p (TDI_tree_all)
4ee9c684 1170 && !(sorrycount || errorcount))
1171 {
1172 struct cgraph_node *node;
1173 bool error_found = false;
1174
1175 for (node = cgraph_nodes; node; node = node->next)
1176 if (node->analyzed
1177 && (node->global.inlined_to
1178 || DECL_SAVED_TREE (node->decl)))
1179 {
1180 error_found = true;
1181 dump_cgraph_node (stderr, node);
1182 }
1183 if (error_found)
1184 internal_error ("Nodes with no released memory found.");
1185 }
b0cdf642 1186#endif
ae01b312 1187}
b5530559 1188
1189/* Generate and emit a static constructor or destructor. WHICH must be
1190 one of 'I' or 'D'. BODY should be a STATEMENT_LIST containing
1191 GENERIC statements. */
1192
1193void
c5344b58 1194cgraph_build_static_cdtor (char which, tree body, int priority)
b5530559 1195{
1196 static int counter = 0;
1197 char which_buf[16];
540edea7 1198 tree decl, name, resdecl;
b5530559 1199
1200 sprintf (which_buf, "%c_%d", which, counter++);
1201 name = get_file_function_name_long (which_buf);
1202
1203 decl = build_decl (FUNCTION_DECL, name,
1204 build_function_type (void_type_node, void_list_node));
1205 current_function_decl = decl;
1206
540edea7 1207 resdecl = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
1208 DECL_ARTIFICIAL (resdecl) = 1;
1209 DECL_IGNORED_P (resdecl) = 1;
1210 DECL_RESULT (decl) = resdecl;
1211
b5530559 1212 allocate_struct_function (decl);
1213
1214 TREE_STATIC (decl) = 1;
1215 TREE_USED (decl) = 1;
1216 DECL_ARTIFICIAL (decl) = 1;
1217 DECL_IGNORED_P (decl) = 1;
1218 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
1219 DECL_SAVED_TREE (decl) = body;
1220 TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors;
1221 DECL_UNINLINABLE (decl) = 1;
1222
1223 DECL_INITIAL (decl) = make_node (BLOCK);
1224 TREE_USED (DECL_INITIAL (decl)) = 1;
1225
1226 DECL_SOURCE_LOCATION (decl) = input_location;
1227 cfun->function_end_locus = input_location;
1228
cc636d56 1229 switch (which)
1230 {
1231 case 'I':
1232 DECL_STATIC_CONSTRUCTOR (decl) = 1;
1233 break;
1234 case 'D':
1235 DECL_STATIC_DESTRUCTOR (decl) = 1;
1236 break;
1237 default:
1238 gcc_unreachable ();
1239 }
b5530559 1240
1241 gimplify_function_tree (decl);
1242
1243 /* ??? We will get called LATE in the compilation process. */
1244 if (cgraph_global_info_ready)
e27482aa 1245 {
1246 tree_lowering_passes (decl);
1247 tree_rest_of_compilation (decl);
1248 }
b5530559 1249 else
1250 cgraph_finalize_function (decl, 0);
1251
1252 if (targetm.have_ctors_dtors)
1253 {
1254 void (*fn) (rtx, int);
1255
1256 if (which == 'I')
1257 fn = targetm.asm_out.constructor;
1258 else
1259 fn = targetm.asm_out.destructor;
c5344b58 1260 fn (XEXP (DECL_RTL (decl), 0), priority);
b5530559 1261 }
1262}
121f3051 1263
1264void
1265init_cgraph (void)
1266{
1267 cgraph_dump_file = dump_begin (TDI_cgraph, NULL);
1268}