1 /* Callgraph based intraprocedural optimizations.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "coretypes.h"
27 #include "tree-inline.h"
28 #include "langhooks.h"
36 #include "diagnostic.h"
43 #define INSNS_PER_CALL 10
45 static void cgraph_expand_all_functions (void);
46 static void cgraph_mark_functions_to_output (void);
47 static void cgraph_expand_function (struct cgraph_node
*);
48 static tree
record_call_1 (tree
*, int *, void *);
49 static void cgraph_mark_local_functions (void);
50 static void cgraph_optimize_function (struct cgraph_node
*);
51 static bool cgraph_default_inline_p (struct cgraph_node
*n
);
52 static void cgraph_analyze_function (struct cgraph_node
*node
);
53 static void cgraph_decide_inlining_incrementally (struct cgraph_node
*);
55 /* Statistics we collect about inlining algorithm. */
56 static int ncalls_inlined
;
57 static int nfunctions_inlined
;
58 static int initial_insns
;
59 static int overall_insns
;
61 /* Records tree nodes seen in cgraph_create_edges. Simply using
62 walk_tree_without_duplicates doesn't guarantee each node is visited
63 once because it gets a new htab upon each recursive call from
65 static htab_t visited_nodes
;
67 /* Determine if function DECL is needed. That is, visible to something
68 either outside this translation unit, something magic in the system
69 configury, or (if not doing unit-at-a-time) to something we havn't
73 decide_is_function_needed (struct cgraph_node
*node
, tree decl
)
75 /* If we decided it was needed before, but at the time we didn't have
76 the body of the function available, then it's still needed. We have
77 to go back and re-check its dependencies now. */
81 /* Externally visible functions must be output. The exception is
82 COMDAT functions that must be output only when they are needed. */
83 if (TREE_PUBLIC (decl
) && !DECL_COMDAT (decl
) && !DECL_EXTERNAL (decl
))
86 /* Constructors and destructors are reachable from the runtime by
88 if (DECL_STATIC_CONSTRUCTOR (decl
) || DECL_STATIC_DESTRUCTOR (decl
))
91 /* If the user told us it is used, then it must be so. */
92 if (lookup_attribute ("used", DECL_ATTRIBUTES (decl
)))
95 /* ??? If the assembler name is set by hand, it is possible to assemble
96 the name later after finalizing the function and the fact is noticed
97 in assemble_name then. This is arguably a bug. */
98 if (DECL_ASSEMBLER_NAME_SET_P (decl
)
99 && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl
)))
102 if (flag_unit_at_a_time
)
105 /* If not doing unit at a time, then we'll only defer this function
106 if its marked for inlining. Otherwise we want to emit it now. */
108 /* "extern inline" functions are never output locally. */
109 if (DECL_EXTERNAL (decl
))
111 /* We want to emit COMDAT functions only when absolutely necessary. */
112 if (DECL_COMDAT (decl
))
114 if (!DECL_INLINE (decl
)
115 || (!node
->local
.disregard_inline_limits
116 /* When declared inline, defer even the uninlinable functions.
117 This allows them to be eliminated when unused. */
118 && !DECL_DECLARED_INLINE_P (decl
)
119 && (!node
->local
.inlinable
|| !cgraph_default_inline_p (node
))))
125 /* When not doing unit-at-a-time, output all functions enqueued.
126 Return true when such a functions were found. */
129 cgraph_assemble_pending_functions (void)
133 if (flag_unit_at_a_time
)
136 while (cgraph_nodes_queue
)
138 struct cgraph_node
*n
= cgraph_nodes_queue
;
140 cgraph_nodes_queue
= cgraph_nodes_queue
->next_needed
;
141 if (!n
->origin
&& !DECL_EXTERNAL (n
->decl
))
143 cgraph_expand_function (n
);
151 /* DECL has been parsed. Take it, queue it, compile it at the whim of the
152 logic in effect. If NESTED is true, then our caller cannot stand to have
153 the garbage collector run at the moment. We would need to either create
154 a new GC context, or just not compile right now. */
157 cgraph_finalize_function (tree decl
, bool nested
)
159 struct cgraph_node
*node
= cgraph_node (decl
);
161 if (node
->local
.finalized
)
163 /* As an GCC extension we allow redefinition of the function. The
164 semantics when both copies of bodies differ is not well defined.
165 We replace the old body with new body so in unit at a time mode
166 we always use new body, while in normal mode we may end up with
167 old body inlined into some functions and new body expanded and
170 ??? It may make more sense to use one body for inlining and other
171 body for expanding the function but this is difficult to do. */
173 /* If node->output is set, then this is a unit-at-a-time compilation
174 and we have already begun whole-unit analysis. This is *not*
175 testing for whether we've already emitted the function. That
176 case can be sort-of legitimately seen with real function
177 redefinition errors. I would argue that the front end should
178 never present us with such a case, but don't enforce that for now. */
182 /* Reset our datastructures so we can analyze the function again. */
183 memset (&node
->local
, 0, sizeof (node
->local
));
184 memset (&node
->global
, 0, sizeof (node
->global
));
185 memset (&node
->rtl
, 0, sizeof (node
->rtl
));
186 node
->analyzed
= false;
187 node
->local
.redefined_extern_inline
= true;
188 while (node
->callees
)
189 cgraph_remove_edge (node
, node
->callees
->callee
);
191 /* We may need to re-queue the node for assembling in case
192 we already proceeded it and ignored as not needed. */
193 if (node
->reachable
&& !flag_unit_at_a_time
)
195 struct cgraph_node
*n
;
197 for (n
= cgraph_nodes_queue
; n
; n
= n
->next_needed
)
205 notice_global_symbol (decl
);
207 node
->local
.finalized
= true;
209 /* If not unit at a time, then we need to create the call graph
210 now, so that called functions can be queued and emitted now. */
211 if (!flag_unit_at_a_time
)
213 cgraph_analyze_function (node
);
214 cgraph_decide_inlining_incrementally (node
);
217 if (decide_is_function_needed (node
, decl
))
218 cgraph_mark_needed_node (node
);
220 /* If not unit at a time, go ahead and emit everything we've found
221 to be reachable at this time. */
224 if (!cgraph_assemble_pending_functions ())
228 /* If we've not yet emitted decl, tell the debug info about it. */
229 if (!TREE_ASM_WRITTEN (decl
))
230 (*debug_hooks
->deferred_inline_function
) (decl
);
232 /* We will never really output the function body, clear the SAVED_INSNS array
234 if (DECL_EXTERNAL (decl
))
235 DECL_STRUCT_FUNCTION (decl
) = NULL
;
238 /* Walk tree and record all calls. Called via walk_tree. */
240 record_call_1 (tree
*tp
, int *walk_subtrees
, void *data
)
244 switch (TREE_CODE (t
))
247 /* ??? Really, we should mark this decl as *potentially* referenced
248 by this function and re-examine whether the decl is actually used
249 after rtl has been generated. */
251 cgraph_varpool_mark_needed_node (cgraph_varpool_node (t
));
255 if (flag_unit_at_a_time
)
257 /* Record dereferences to the functions. This makes the
258 functions reachable unconditionally. */
259 tree decl
= TREE_OPERAND (*tp
, 0);
260 if (TREE_CODE (decl
) == FUNCTION_DECL
)
261 cgraph_mark_needed_node (cgraph_node (decl
));
267 tree decl
= get_callee_fndecl (*tp
);
268 if (decl
&& TREE_CODE (decl
) == FUNCTION_DECL
)
270 cgraph_record_call (data
, decl
);
272 /* When we see a function call, we don't want to look at the
273 function reference in the ADDR_EXPR that is hanging from
274 the CALL_EXPR we're examining here, because we would
275 conclude incorrectly that the function's address could be
276 taken by something that is not a function call. So only
277 walk the function parameter list, skip the other subtrees. */
279 walk_tree (&TREE_OPERAND (*tp
, 1), record_call_1
, data
,
287 /* Save some cycles by not walking types and declaration as we
288 won't find anything useful there anyway. */
289 if (DECL_P (*tp
) || TYPE_P (*tp
))
295 if ((unsigned int) TREE_CODE (t
) >= LAST_AND_UNUSED_TREE_CODE
)
296 return lang_hooks
.callgraph
.analyze_expr (tp
, walk_subtrees
, data
);
303 /* Create cgraph edges for function calls inside BODY from DECL. */
306 cgraph_create_edges (tree decl
, tree body
)
308 /* The nodes we're interested in are never shared, so walk
309 the tree ignoring duplicates. */
310 visited_nodes
= htab_create (37, htab_hash_pointer
,
311 htab_eq_pointer
, NULL
);
312 walk_tree (&body
, record_call_1
, decl
, visited_nodes
);
313 htab_delete (visited_nodes
);
314 visited_nodes
= NULL
;
317 /* Analyze the function scheduled to be output. */
319 cgraph_analyze_function (struct cgraph_node
*node
)
321 tree decl
= node
->decl
;
322 struct cgraph_edge
*e
;
324 current_function_decl
= decl
;
326 /* First kill forward declaration so reverse inlining works properly. */
327 cgraph_create_edges (decl
, DECL_SAVED_TREE (decl
));
329 node
->local
.inlinable
= tree_inlinable_function_p (decl
);
330 if (!node
->local
.self_insns
)
331 node
->local
.self_insns
332 = lang_hooks
.tree_inlining
.estimate_num_insns (decl
);
333 if (node
->local
.inlinable
)
334 node
->local
.disregard_inline_limits
335 = lang_hooks
.tree_inlining
.disregard_inline_limits (decl
);
336 for (e
= node
->callers
; e
; e
= e
->next_caller
)
337 if (e
->inline_failed
)
339 if (node
->local
.redefined_extern_inline
)
340 e
->inline_failed
= N_("redefined extern inline functions are not "
341 "considered for inlining");
342 else if (!node
->local
.inlinable
)
343 e
->inline_failed
= N_("function not inlinable");
345 e
->inline_failed
= N_("function not considered for inlining");
347 if (flag_really_no_inline
&& !node
->local
.disregard_inline_limits
)
348 node
->local
.inlinable
= 0;
349 /* Inlining characteristics are maintained by the cgraph_mark_inline. */
350 node
->global
.insns
= node
->local
.self_insns
;
351 if (!DECL_EXTERNAL (decl
))
353 node
->global
.cloned_times
= 1;
354 node
->global
.will_be_output
= true;
357 node
->analyzed
= true;
358 current_function_decl
= NULL
;
361 /* Analyze the whole compilation unit once it is parsed completely. */
364 cgraph_finalize_compilation_unit (void)
366 struct cgraph_node
*node
;
368 if (!flag_unit_at_a_time
)
370 cgraph_assemble_pending_functions ();
374 cgraph_varpool_assemble_pending_decls ();
376 fprintf (stderr
, "\nAnalyzing compilation unit\n");
378 timevar_push (TV_CGRAPH
);
379 if (cgraph_dump_file
)
381 fprintf (cgraph_dump_file
, "Initial entry points:");
382 for (node
= cgraph_nodes
; node
; node
= node
->next
)
383 if (node
->needed
&& DECL_SAVED_TREE (node
->decl
))
384 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (node
));
385 fprintf (cgraph_dump_file
, "\n");
388 /* Propagate reachability flag and lower representation of all reachable
389 functions. In the future, lowering will introduce new functions and
390 new entry points on the way (by template instantiation and virtual
391 method table generation for instance). */
392 while (cgraph_nodes_queue
)
394 struct cgraph_edge
*edge
;
395 tree decl
= cgraph_nodes_queue
->decl
;
397 node
= cgraph_nodes_queue
;
398 cgraph_nodes_queue
= cgraph_nodes_queue
->next_needed
;
400 /* ??? It is possible to create extern inline function and later using
401 weak alas attribute to kill it's body. See
402 gcc.c-torture/compile/20011119-1.c */
403 if (!DECL_SAVED_TREE (decl
))
406 if (node
->analyzed
|| !node
->reachable
|| !DECL_SAVED_TREE (decl
))
409 cgraph_analyze_function (node
);
411 for (edge
= node
->callees
; edge
; edge
= edge
->next_callee
)
412 if (!edge
->callee
->reachable
)
413 cgraph_mark_reachable_node (edge
->callee
);
415 cgraph_varpool_assemble_pending_decls ();
418 /* Collect entry points to the unit. */
420 if (cgraph_dump_file
)
422 fprintf (cgraph_dump_file
, "Unit entry points:");
423 for (node
= cgraph_nodes
; node
; node
= node
->next
)
424 if (node
->needed
&& DECL_SAVED_TREE (node
->decl
))
425 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (node
));
426 fprintf (cgraph_dump_file
, "\n\nInitial ");
427 dump_cgraph (cgraph_dump_file
);
430 if (cgraph_dump_file
)
431 fprintf (cgraph_dump_file
, "\nReclaiming functions:");
433 for (node
= cgraph_nodes
; node
; node
= node
->next
)
435 tree decl
= node
->decl
;
437 if (!node
->reachable
&& DECL_SAVED_TREE (decl
))
439 cgraph_remove_node (node
);
440 if (cgraph_dump_file
)
441 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (node
));
444 node
->next_needed
= NULL
;
446 if (cgraph_dump_file
)
448 fprintf (cgraph_dump_file
, "\n\nReclaimed ");
449 dump_cgraph (cgraph_dump_file
);
452 timevar_pop (TV_CGRAPH
);
455 /* Figure out what functions we want to assemble. */
458 cgraph_mark_functions_to_output (void)
460 struct cgraph_node
*node
;
462 for (node
= cgraph_nodes
; node
; node
= node
->next
)
464 tree decl
= node
->decl
;
465 struct cgraph_edge
*e
;
470 for (e
= node
->callers
; e
; e
= e
->next_caller
)
471 if (e
->inline_failed
)
474 /* We need to output all local functions that are used and not
475 always inlined, as well as those that are reachable from
476 outside the current compilation unit. */
477 if (DECL_SAVED_TREE (decl
)
479 || (e
&& node
->reachable
))
480 && !TREE_ASM_WRITTEN (decl
) && !node
->origin
481 && !DECL_EXTERNAL (decl
))
484 DECL_STRUCT_FUNCTION (decl
) = NULL
;
488 /* Optimize the function before expansion. */
491 cgraph_optimize_function (struct cgraph_node
*node
)
493 tree decl
= node
->decl
;
495 timevar_push (TV_INTEGRATION
);
496 /* optimize_inline_calls avoids inlining of current_function_decl. */
497 current_function_decl
= decl
;
498 if (flag_inline_trees
)
500 struct cgraph_edge
*e
;
502 for (e
= node
->callees
; e
; e
= e
->next_callee
)
503 if (!e
->inline_failed
|| warn_inline
504 || (DECL_DECLARED_INLINE_P (e
->callee
->decl
)
505 && lookup_attribute ("always_inline",
506 DECL_ATTRIBUTES (e
->callee
->decl
))))
509 optimize_inline_calls (decl
);
513 for (node
= node
->nested
; node
; node
= node
->next_nested
)
514 cgraph_optimize_function (node
);
516 timevar_pop (TV_INTEGRATION
);
519 /* Expand function specified by NODE. */
522 cgraph_expand_function (struct cgraph_node
*node
)
524 tree decl
= node
->decl
;
526 if (flag_unit_at_a_time
)
527 announce_function (decl
);
529 cgraph_optimize_function (node
);
531 /* Generate RTL for the body of DECL. Nested functions are expanded
532 via lang_expand_decl_stmt. */
533 lang_hooks
.callgraph
.expand_function (decl
);
534 if (DECL_DEFER_OUTPUT (decl
))
537 current_function_decl
= NULL
;
540 /* Fill array order with all nodes with output flag set in the reverse
541 topological order. */
544 cgraph_postorder (struct cgraph_node
**order
)
546 struct cgraph_node
*node
, *node2
;
549 struct cgraph_edge
*edge
, last
;
551 struct cgraph_node
**stack
=
552 xcalloc (cgraph_n_nodes
, sizeof (struct cgraph_node
*));
554 /* We have to deal with cycles nicely, so use a depth first traversal
555 output algorithm. Ignore the fact that some functions won't need
556 to be output and put them into order as well, so we get dependencies
557 right throughout inline functions. */
558 for (node
= cgraph_nodes
; node
; node
= node
->next
)
560 for (node
= cgraph_nodes
; node
; node
= node
->next
)
567 node
->aux
= node
->callers
;
570 while (node2
->aux
!= &last
)
573 if (edge
->next_caller
)
574 node2
->aux
= edge
->next_caller
;
577 if (!edge
->caller
->aux
)
579 if (!edge
->caller
->callers
)
580 edge
->caller
->aux
= &last
;
582 edge
->caller
->aux
= edge
->caller
->callers
;
583 stack
[stack_size
++] = node2
;
584 node2
= edge
->caller
;
588 if (node2
->aux
== &last
)
590 order
[order_pos
++] = node2
;
592 node2
= stack
[--stack_size
];
602 #define INLINED_TIMES(node) ((size_t)(node)->aux)
603 #define SET_INLINED_TIMES(node,times) ((node)->aux = (void *)(times))
605 /* Return list of nodes we decided to inline NODE into, set their output
606 flag and compute INLINED_TIMES.
608 We do simple backtracing to get INLINED_TIMES right. This should not be
609 expensive as we limit the amount of inlining. Alternatively we may first
610 discover set of nodes, topologically sort these and propagate
614 cgraph_inlined_into (struct cgraph_node
*node
, struct cgraph_node
**array
)
617 struct cgraph_edge
**stack
;
618 struct cgraph_edge
*e
, *e1
;
622 /* Fast path: since we traverse in mostly topological order, we will likely
624 for (e
= node
->callers
; e
; e
= e
->next_caller
)
625 if (!e
->inline_failed
)
631 /* Allocate stack for back-tracking up callgraph. */
632 stack
= xmalloc ((cgraph_n_nodes
+ 1) * sizeof (struct cgraph_edge
));
635 /* Push the first edge on to the stack. */
640 struct cgraph_node
*caller
;
642 /* Look at the edge on the top of the stack. */
646 /* Check if the caller destination has been visited yet. */
649 array
[nfound
++] = e
->caller
;
650 /* Mark that we have visited the destination. */
651 caller
->output
= true;
652 SET_INLINED_TIMES (caller
, 0);
654 SET_INLINED_TIMES (caller
, INLINED_TIMES (caller
) + 1);
656 for (e1
= caller
->callers
; e1
; e1
= e1
->next_caller
)
657 if (!e1
->inline_failed
)
666 for (e1
= e
->next_caller
; e1
; e1
= e1
->next_caller
)
667 if (!e1
->inline_failed
)
689 if (cgraph_dump_file
)
691 fprintf (cgraph_dump_file
, " Found inline predecesors of %s:",
692 cgraph_node_name (node
));
693 for (i
= 0; i
< nfound
; i
++)
695 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (array
[i
]));
696 if (INLINED_TIMES (array
[i
]) != 1)
697 fprintf (cgraph_dump_file
, " (%i times)",
698 (int)INLINED_TIMES (array
[i
]));
700 fprintf (cgraph_dump_file
, "\n");
706 /* Return list of nodes we decided to inline into NODE, set their output
707 flag and compute INLINED_TIMES.
709 This function is identical to cgraph_inlined_into with callers and callees
713 cgraph_inlined_callees (struct cgraph_node
*node
, struct cgraph_node
**array
)
716 struct cgraph_edge
**stack
;
717 struct cgraph_edge
*e
, *e1
;
721 /* Fast path: since we traverse in mostly topological order, we will likely
723 for (e
= node
->callees
; e
; e
= e
->next_callee
)
724 if (!e
->inline_failed
)
730 /* Allocate stack for back-tracking up callgraph. */
731 stack
= xmalloc ((cgraph_n_nodes
+ 1) * sizeof (struct cgraph_edge
));
734 /* Push the first edge on to the stack. */
739 struct cgraph_node
*callee
;
741 /* Look at the edge on the top of the stack. */
745 /* Check if the callee destination has been visited yet. */
748 array
[nfound
++] = e
->callee
;
749 /* Mark that we have visited the destination. */
750 callee
->output
= true;
751 SET_INLINED_TIMES (callee
, 0);
753 SET_INLINED_TIMES (callee
, INLINED_TIMES (callee
) + 1);
755 for (e1
= callee
->callees
; e1
; e1
= e1
->next_callee
)
756 if (!e1
->inline_failed
)
764 for (e1
= e
->next_callee
; e1
; e1
= e1
->next_callee
)
765 if (!e1
->inline_failed
)
786 if (cgraph_dump_file
)
788 fprintf (cgraph_dump_file
, " Found inline successors of %s:",
789 cgraph_node_name (node
));
790 for (i
= 0; i
< nfound
; i
++)
792 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (array
[i
]));
793 if (INLINED_TIMES (array
[i
]) != 1)
794 fprintf (cgraph_dump_file
, " (%i times)",
795 (int)INLINED_TIMES (array
[i
]));
797 fprintf (cgraph_dump_file
, "\n");
803 /* Perform reachability analysis and reclaim all unreachable nodes.
804 This function also remove unneeded bodies of extern inline functions
805 and thus needs to be done only after inlining decisions has been made. */
807 cgraph_remove_unreachable_nodes (void)
809 struct cgraph_node
*first
= (void *) 1;
810 struct cgraph_node
*node
;
811 bool changed
= false;
814 if (cgraph_dump_file
)
815 fprintf (cgraph_dump_file
, "\nReclaiming functions:");
816 #ifdef ENABLE_CHECKING
817 for (node
= cgraph_nodes
; node
; node
= node
->next
)
821 for (node
= cgraph_nodes
; node
; node
= node
->next
)
822 if (node
->needed
&& (!DECL_EXTERNAL (node
->decl
) || !node
->analyzed
))
830 /* Perform reachability analysis. As a special case do not consider
831 extern inline functions not inlined as live because we won't output
833 while (first
!= (void *) 1)
835 struct cgraph_edge
*e
;
839 for (e
= node
->callees
; e
; e
= e
->next_callee
)
842 && (!e
->inline_failed
|| !e
->callee
->analyzed
843 || !DECL_EXTERNAL (e
->callee
->decl
)))
845 e
->callee
->aux
= first
;
850 /* Remove unreachable nodes. Extern inline functions need special care;
851 Unreachable extern inline functions shall be removed.
852 Reachable extern inline functions we never inlined shall get their bodies
854 Reachable extern inline functions we sometimes inlined will be turned into
855 unanalyzed nodes so they look like for true extern functions to the rest
857 for (node
= cgraph_nodes
; node
; node
= node
->next
)
862 tree decl
= node
->decl
;
864 if (DECL_STRUCT_FUNCTION (decl
))
865 local_insns
= node
->local
.self_insns
;
868 if (cgraph_dump_file
)
869 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (node
));
870 if (!node
->analyzed
|| !DECL_EXTERNAL (node
->decl
))
871 cgraph_remove_node (node
);
874 struct cgraph_edge
*e
;
876 for (e
= node
->callers
; e
; e
= e
->next_caller
)
879 if (e
|| node
->needed
)
881 DECL_SAVED_TREE (node
->decl
) = NULL_TREE
;
882 while (node
->callees
)
883 cgraph_remove_edge (node
, node
->callees
->callee
);
884 node
->analyzed
= false;
887 cgraph_remove_node (node
);
889 if (!DECL_SAVED_TREE (decl
))
890 insns
+= local_insns
;
894 for (node
= cgraph_nodes
; node
; node
= node
->next
)
896 if (cgraph_dump_file
)
897 fprintf (cgraph_dump_file
, "\nReclaimed %i insns", insns
);
902 /* Estimate size of the function after inlining WHAT into TO. */
905 cgraph_estimate_size_after_inlining (int times
, struct cgraph_node
*to
,
906 struct cgraph_node
*what
)
908 return (what
->global
.insns
- INSNS_PER_CALL
) * times
+ to
->global
.insns
;
911 /* Estimate the growth caused by inlining NODE into all callees. */
914 cgraph_estimate_growth (struct cgraph_node
*node
)
918 int clones_added
= 0;
919 struct cgraph_edge
*e
;
921 for (e
= node
->callers
; e
; e
= e
->next_caller
)
922 if (e
->inline_failed
)
924 growth
+= ((cgraph_estimate_size_after_inlining (1, e
->caller
, node
)
926 e
->caller
->global
.insns
) *e
->caller
->global
.cloned_times
);
927 calls_saved
+= e
->caller
->global
.cloned_times
;
928 clones_added
+= e
->caller
->global
.cloned_times
;
931 /* ??? Wrong for self recursive functions or cases where we decide to not
932 inline for different reasons, but it is not big deal as in that case
933 we will keep the body around, but we will also avoid some inlining. */
934 if (!node
->needed
&& !node
->origin
&& !DECL_EXTERNAL (node
->decl
))
935 growth
-= node
->global
.insns
, clones_added
--;
943 /* Update insn sizes after inlining WHAT into TO that is already inlined into
944 all nodes in INLINED array. */
947 cgraph_mark_inline (struct cgraph_node
*to
, struct cgraph_node
*what
,
948 struct cgraph_node
**inlined
, int ninlined
,
949 struct cgraph_node
**inlined_callees
,
950 int ninlined_callees
)
955 struct cgraph_edge
*e
;
959 what
->global
.inlined
= 1;
960 for (e
= what
->callers
; e
; e
= e
->next_caller
)
964 if (!e
->inline_failed
)
966 e
->inline_failed
= NULL
;
968 clones
+= e
->caller
->global
.cloned_times
;
970 else if (e
->inline_failed
)
975 ncalls_inlined
+= times
;
977 new_insns
= cgraph_estimate_size_after_inlining (times
, to
, what
);
978 if (to
->global
.will_be_output
)
979 overall_insns
+= new_insns
- to
->global
.insns
;
980 to
->global
.insns
= new_insns
;
982 if (!called
&& !what
->needed
&& !what
->origin
983 && flag_unit_at_a_time
984 && !DECL_EXTERNAL (what
->decl
))
986 if (!what
->global
.will_be_output
)
989 nfunctions_inlined
++;
990 what
->global
.will_be_output
= 0;
991 overall_insns
-= what
->global
.insns
;
993 what
->global
.cloned_times
+= clones
;
994 for (i
= 0; i
< ninlined
; i
++)
997 cgraph_estimate_size_after_inlining (INLINED_TIMES (inlined
[i
]) *
998 times
, inlined
[i
], what
);
999 if (inlined
[i
]->global
.will_be_output
)
1000 overall_insns
+= new_insns
- inlined
[i
]->global
.insns
;
1001 inlined
[i
]->global
.insns
= new_insns
;
1003 for (i
= 0; i
< ninlined_callees
; i
++)
1005 inlined_callees
[i
]->global
.cloned_times
+=
1006 INLINED_TIMES (inlined_callees
[i
]) * clones
;
1010 /* Return false when inlining WHAT into TO is not good idea as it would cause
1011 too large growth of function bodies. */
1014 cgraph_check_inline_limits (struct cgraph_node
*to
, struct cgraph_node
*what
,
1015 struct cgraph_node
**inlined
, int ninlined
,
1016 const char **reason
)
1020 struct cgraph_edge
*e
;
1024 for (e
= to
->callees
; e
; e
= e
->next_callee
)
1025 if (e
->callee
== what
)
1028 /* When inlining large function body called once into small function,
1029 take the inlined function as base for limiting the growth. */
1030 if (to
->local
.self_insns
> what
->local
.self_insns
)
1031 limit
= to
->local
.self_insns
;
1033 limit
= what
->local
.self_insns
;
1035 limit
+= limit
* PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH
) / 100;
1037 newsize
= cgraph_estimate_size_after_inlining (times
, to
, what
);
1038 if (newsize
> PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS
)
1041 *reason
= N_("--param large-function-growth limit reached");
1044 for (i
= 0; i
< ninlined
; i
++)
1047 cgraph_estimate_size_after_inlining (INLINED_TIMES (inlined
[i
]) *
1048 times
, inlined
[i
], what
);
1049 if (newsize
> PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS
)
1051 inlined
[i
]->local
.self_insns
*
1052 (100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH
)) / 100)
1054 *reason
= N_("--param large-function-growth limit reached while inlining the caller");
1061 /* Return true when function N is small enough to be inlined. */
1064 cgraph_default_inline_p (struct cgraph_node
*n
)
1066 if (!DECL_INLINE (n
->decl
) || !DECL_SAVED_TREE (n
->decl
))
1068 if (DECL_DECLARED_INLINE_P (n
->decl
))
1069 return n
->global
.insns
< MAX_INLINE_INSNS_SINGLE
;
1071 return n
->global
.insns
< MAX_INLINE_INSNS_AUTO
;
1074 /* Set inline_failed for all callers of given function to REASON. */
1077 cgraph_set_inline_failed (struct cgraph_node
*node
, const char *reason
)
1079 struct cgraph_edge
*e
;
1081 if (cgraph_dump_file
)
1082 fprintf (cgraph_dump_file
, "Inlining failed: %s\n", reason
);
1083 for (e
= node
->callers
; e
; e
= e
->next_caller
)
1084 if (e
->inline_failed
)
1085 e
->inline_failed
= reason
;
1088 /* We use greedy algorithm for inlining of small functions:
1089 All inline candidates are put into prioritized heap based on estimated
1090 growth of the overall number of instructions and then update the estimates.
1092 INLINED and INLINED_CALEES are just pointers to arrays large enough
1093 to be passed to cgraph_inlined_into and cgraph_inlined_callees. */
1096 cgraph_decide_inlining_of_small_functions (struct cgraph_node
**inlined
,
1097 struct cgraph_node
**inlined_callees
)
1100 struct cgraph_node
*node
;
1101 fibheap_t heap
= fibheap_new ();
1102 struct fibnode
**heap_node
=
1103 xcalloc (cgraph_max_uid
, sizeof (struct fibnode
*));
1104 int ninlined
, ninlined_callees
;
1105 int max_insns
= ((HOST_WIDEST_INT
) initial_insns
1106 * (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH
)) / 100);
1108 /* Put all inline candidates into the heap. */
1110 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1112 if (!node
->local
.inlinable
|| !node
->callers
1113 || node
->local
.disregard_inline_limits
)
1116 if (!cgraph_default_inline_p (node
))
1118 cgraph_set_inline_failed (node
,
1119 N_("--param max-inline-insns-single limit reached"));
1122 heap_node
[node
->uid
] =
1123 fibheap_insert (heap
, cgraph_estimate_growth (node
), node
);
1126 if (cgraph_dump_file
)
1127 fprintf (cgraph_dump_file
, "\nDeciding on smaller functions:\n");
1128 while (overall_insns
<= max_insns
&& (node
= fibheap_extract_min (heap
)))
1130 struct cgraph_edge
*e
;
1131 int old_insns
= overall_insns
;
1133 heap_node
[node
->uid
] = NULL
;
1134 if (cgraph_dump_file
)
1135 fprintf (cgraph_dump_file
,
1136 "\nConsidering %s with %i insns\n"
1137 " Estimated growth is %+i insns.\n",
1138 cgraph_node_name (node
), node
->global
.insns
,
1139 cgraph_estimate_growth (node
));
1140 if (!cgraph_default_inline_p (node
))
1142 cgraph_set_inline_failed (node
,
1143 N_("--param max-inline-insns-single limit reached after inlining into the callee"));
1146 ninlined_callees
= cgraph_inlined_callees (node
, inlined_callees
);
1147 for (e
= node
->callers
; e
; e
= e
->next_caller
)
1148 if (e
->inline_failed
)
1150 /* Marking recursive function inlinine has sane semantic and
1151 thus we should not warn on it. */
1152 if (e
->caller
== node
)
1154 e
->inline_failed
= "";
1157 ninlined
= cgraph_inlined_into (e
->caller
, inlined
);
1158 if (e
->callee
->output
)
1159 e
->inline_failed
= "";
1160 if (e
->callee
->output
1161 || !cgraph_check_inline_limits (e
->caller
, node
, inlined
,
1162 ninlined
, &e
->inline_failed
))
1164 for (i
= 0; i
< ninlined
; i
++)
1165 inlined
[i
]->output
= 0, inlined
[i
]->aux
= 0;
1166 if (cgraph_dump_file
)
1167 fprintf (cgraph_dump_file
, " Not inlining into %s.\n",
1168 cgraph_node_name (e
->caller
));
1171 cgraph_mark_inline (e
->caller
, node
, inlined
, ninlined
,
1172 inlined_callees
, ninlined_callees
);
1173 if (heap_node
[e
->caller
->uid
])
1174 fibheap_replace_key (heap
, heap_node
[e
->caller
->uid
],
1175 cgraph_estimate_growth (e
->caller
));
1177 /* Size of the functions we updated into has changed, so update
1179 for (i
= 0; i
< ninlined
; i
++)
1181 inlined
[i
]->output
= 0, inlined
[i
]->aux
= 0;
1182 if (heap_node
[inlined
[i
]->uid
])
1183 fibheap_replace_key (heap
, heap_node
[inlined
[i
]->uid
],
1184 cgraph_estimate_growth (inlined
[i
]));
1186 if (cgraph_dump_file
)
1187 fprintf (cgraph_dump_file
,
1188 " Inlined into %s which now has %i insns.\n",
1189 cgraph_node_name (e
->caller
),
1190 e
->caller
->global
.insns
);
1193 /* Similarly all functions called by the function we just inlined
1194 are now called more times; update keys. */
1196 for (e
= node
->callees
; e
; e
= e
->next_callee
)
1197 if (e
->inline_failed
&& heap_node
[e
->callee
->uid
])
1198 fibheap_replace_key (heap
, heap_node
[e
->callee
->uid
],
1199 cgraph_estimate_growth (e
->callee
));
1201 for (i
= 0; i
< ninlined_callees
; i
++)
1203 struct cgraph_edge
*e
;
1205 for (e
= inlined_callees
[i
]->callees
; e
; e
= e
->next_callee
)
1206 if (e
->inline_failed
&& heap_node
[e
->callee
->uid
])
1207 fibheap_replace_key (heap
, heap_node
[e
->callee
->uid
],
1208 cgraph_estimate_growth (e
->callee
));
1210 inlined_callees
[i
]->output
= 0;
1211 inlined_callees
[i
]->aux
= 0;
1213 if (cgraph_dump_file
)
1214 fprintf (cgraph_dump_file
,
1215 " Inlined %i times for a net change of %+i insns.\n",
1216 node
->global
.cloned_times
, overall_insns
- old_insns
);
1218 while ((node
= fibheap_extract_min (heap
)) != NULL
)
1219 if (!node
->local
.disregard_inline_limits
)
1220 cgraph_set_inline_failed (node
, N_("--param inline-unit-growth limit reached"));
1221 fibheap_delete (heap
);
1225 /* Decide on the inlining. We do so in the topological order to avoid
1226 expenses on updating datastructures. */
1229 cgraph_decide_inlining (void)
1231 struct cgraph_node
*node
;
1233 struct cgraph_node
**order
=
1234 xcalloc (cgraph_n_nodes
, sizeof (struct cgraph_node
*));
1235 struct cgraph_node
**inlined
=
1236 xcalloc (cgraph_n_nodes
, sizeof (struct cgraph_node
*));
1237 struct cgraph_node
**inlined_callees
=
1238 xcalloc (cgraph_n_nodes
, sizeof (struct cgraph_node
*));
1240 int ninlined_callees
;
1244 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1245 initial_insns
+= node
->local
.self_insns
;
1246 overall_insns
= initial_insns
;
1248 nnodes
= cgraph_postorder (order
);
1250 if (cgraph_dump_file
)
1251 fprintf (cgraph_dump_file
,
1252 "\nDeciding on inlining. Starting with %i insns.\n",
1255 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1258 if (cgraph_dump_file
)
1259 fprintf (cgraph_dump_file
, "\nInlining always_inline functions:\n");
1260 #ifdef ENABLE_CHECKING
1261 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1262 if (node
->aux
|| node
->output
)
1266 /* In the first pass mark all always_inline edges. Do this with a priority
1267 so none of our later choices will make this impossible. */
1268 for (i
= nnodes
- 1; i
>= 0; i
--)
1270 struct cgraph_edge
*e
;
1274 for (e
= node
->callees
; e
; e
= e
->next_callee
)
1275 if (e
->callee
->local
.disregard_inline_limits
)
1279 if (cgraph_dump_file
)
1280 fprintf (cgraph_dump_file
,
1281 "\nConsidering %s %i insns (always inline)\n",
1282 cgraph_node_name (e
->callee
), e
->callee
->global
.insns
);
1283 ninlined
= cgraph_inlined_into (order
[i
], inlined
);
1284 for (; e
; e
= e
->next_callee
)
1286 old_insns
= overall_insns
;
1287 if (!e
->inline_failed
|| !e
->callee
->local
.inlinable
1288 || !e
->callee
->local
.disregard_inline_limits
)
1290 if (e
->callee
->output
|| e
->callee
== node
)
1292 e
->inline_failed
= N_("recursive inlining");
1296 cgraph_inlined_callees (e
->callee
, inlined_callees
);
1297 cgraph_mark_inline (node
, e
->callee
, inlined
, ninlined
,
1298 inlined_callees
, ninlined_callees
);
1299 for (y
= 0; y
< ninlined_callees
; y
++)
1300 inlined_callees
[y
]->output
= 0, inlined_callees
[y
]->aux
= 0;
1301 if (cgraph_dump_file
)
1302 fprintf (cgraph_dump_file
,
1303 " Inlined into %s which now has %i insns.\n",
1304 cgraph_node_name (node
->callees
->caller
),
1305 node
->callees
->caller
->global
.insns
);
1307 if (cgraph_dump_file
&& node
->global
.cloned_times
> 0)
1308 fprintf (cgraph_dump_file
,
1309 " Inlined %i times for a net change of %+i insns.\n",
1310 node
->global
.cloned_times
, overall_insns
- old_insns
);
1311 for (y
= 0; y
< ninlined
; y
++)
1312 inlined
[y
]->output
= 0, inlined
[y
]->aux
= 0;
1314 #ifdef ENABLE_CHECKING
1315 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1316 if (node
->aux
|| node
->output
)
1320 if (!flag_really_no_inline
)
1322 cgraph_decide_inlining_of_small_functions (inlined
, inlined_callees
);
1323 #ifdef ENABLE_CHECKING
1324 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1325 if (node
->aux
|| node
->output
)
1329 if (cgraph_dump_file
)
1330 fprintf (cgraph_dump_file
, "\nDeciding on functions called once:\n");
1332 /* And finally decide what functions are called once. */
1334 for (i
= nnodes
- 1; i
>= 0; i
--)
1338 if (node
->callers
&& !node
->callers
->next_caller
&& !node
->needed
1339 && node
->local
.inlinable
&& node
->callers
->inline_failed
1340 && !DECL_EXTERNAL (node
->decl
) && !DECL_COMDAT (node
->decl
))
1343 struct cgraph_node
*node1
;
1345 /* Verify that we won't duplicate the caller. */
1346 for (node1
= node
->callers
->caller
;
1347 node1
->callers
&& !node1
->callers
->inline_failed
1348 && ok
; node1
= node1
->callers
->caller
)
1349 if (node1
->callers
->next_caller
|| node1
->needed
)
1353 const char *dummy_reason
;
1354 if (cgraph_dump_file
)
1355 fprintf (cgraph_dump_file
,
1356 "\nConsidering %s %i insns.\n"
1357 " Called once from %s %i insns.\n",
1358 cgraph_node_name (node
), node
->global
.insns
,
1359 cgraph_node_name (node
->callers
->caller
),
1360 node
->callers
->caller
->global
.insns
);
1361 ninlined
= cgraph_inlined_into (node
->callers
->caller
,
1363 old_insns
= overall_insns
;
1365 /* Inlining functions once would never cause inlining warnings. */
1366 if (cgraph_check_inline_limits
1367 (node
->callers
->caller
, node
, inlined
, ninlined
,
1371 cgraph_inlined_callees (node
, inlined_callees
);
1372 cgraph_mark_inline (node
->callers
->caller
, node
, inlined
,
1373 ninlined
, inlined_callees
,
1375 for (y
= 0; y
< ninlined_callees
; y
++)
1376 inlined_callees
[y
]->output
= 0, inlined_callees
[y
]->aux
= 0;
1377 if (cgraph_dump_file
)
1378 fprintf (cgraph_dump_file
,
1379 " Inlined into %s which now has %i insns"
1380 " for a net change of %+i insns.\n",
1381 cgraph_node_name (node
->callers
->caller
),
1382 node
->callers
->caller
->global
.insns
,
1383 overall_insns
- old_insns
);
1387 if (cgraph_dump_file
)
1388 fprintf (cgraph_dump_file
,
1389 " Inline limit reached, not inlined.\n");
1391 for (y
= 0; y
< ninlined
; y
++)
1392 inlined
[y
]->output
= 0, inlined
[y
]->aux
= 0;
1397 cgraph_remove_unreachable_nodes ();
1399 if (cgraph_dump_file
)
1400 fprintf (cgraph_dump_file
,
1401 "\nInlined %i calls, eliminated %i functions, "
1402 "%i insns turned to %i insns.\n\n",
1403 ncalls_inlined
, nfunctions_inlined
, initial_insns
,
1407 free (inlined_callees
);
1410 /* Decide on the inlining. We do so in the topological order to avoid
1411 expenses on updating datastructures. */
1414 cgraph_decide_inlining_incrementally (struct cgraph_node
*node
)
1416 struct cgraph_edge
*e
;
1417 struct cgraph_node
**inlined
=
1418 xmalloc (sizeof (struct cgraph_node
*) * cgraph_n_nodes
);
1419 struct cgraph_node
**inlined_callees
=
1420 xmalloc (sizeof (struct cgraph_node
*) * cgraph_n_nodes
);
1422 int ninlined_callees
;
1425 ninlined
= cgraph_inlined_into (node
, inlined
);
1427 /* First of all look for always inline functions. */
1428 for (e
= node
->callees
; e
; e
= e
->next_callee
)
1429 if (e
->callee
->local
.disregard_inline_limits
&& e
->inline_failed
1430 /* ??? It is possible that renaming variable removed the function body
1431 in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */
1432 && DECL_SAVED_TREE (e
->callee
->decl
))
1434 if (e
->callee
->output
|| e
->callee
== node
)
1436 e
->inline_failed
= N_("recursive inlining");
1439 ninlined_callees
= cgraph_inlined_callees (e
->callee
, inlined_callees
);
1440 cgraph_mark_inline (node
, e
->callee
, inlined
, ninlined
,
1441 inlined_callees
, ninlined_callees
);
1442 for (y
= 0; y
< ninlined_callees
; y
++)
1443 inlined_callees
[y
]->output
= 0, inlined_callees
[y
]->aux
= 0;
1446 if (!flag_really_no_inline
)
1448 /* Now do the automatic inlining. */
1449 for (e
= node
->callees
; e
; e
= e
->next_callee
)
1450 if (e
->callee
->local
.inlinable
&& e
->inline_failed
1451 && cgraph_default_inline_p (e
->callee
)
1452 && cgraph_check_inline_limits (node
, e
->callee
, inlined
,
1453 ninlined
, &e
->inline_failed
)
1454 && DECL_SAVED_TREE (e
->callee
->decl
))
1456 /* Marking recursive function inlinine has sane semantic and thus
1457 we should not warn on it. */
1458 if (e
->callee
->output
|| e
->callee
== node
)
1460 e
->inline_failed
= "";
1463 ninlined_callees
= cgraph_inlined_callees (e
->callee
,
1465 cgraph_mark_inline (node
, e
->callee
, inlined
, ninlined
,
1466 inlined_callees
, ninlined_callees
);
1467 for (y
= 0; y
< ninlined_callees
; y
++)
1468 inlined_callees
[y
]->output
= 0, inlined_callees
[y
]->aux
= 0;
1472 /* Clear the flags set by cgraph_inlined_into. */
1473 for (y
= 0; y
< ninlined
; y
++)
1474 inlined
[y
]->output
= 0, inlined
[y
]->aux
= 0;
1477 free (inlined_callees
);
1481 /* Return true when CALLER_DECL should be inlined into CALLEE_DECL.
1482 When returned false and reason is non-NULL, set it to the reason
1483 why the call was not inlined. */
1486 cgraph_inline_p (tree caller_decl
, tree callee_decl
, const char **reason
)
1488 struct cgraph_node
*caller
= cgraph_node (caller_decl
);
1489 struct cgraph_node
*callee
= cgraph_node (callee_decl
);
1490 struct cgraph_edge
*e
;
1492 for (e
= caller
->callees
; e
; e
= e
->next_callee
)
1493 if (e
->callee
== callee
)
1495 if (e
->inline_failed
&& reason
)
1496 *reason
= e
->inline_failed
;
1497 return !e
->inline_failed
;
1499 /* We do not record builtins in the callgraph. Perhaps it would make more
1500 sense to do so and then prune out those not overwritten by explicit
1503 *reason
= "originally indirect function calls never inlined";
1506 /* Expand all functions that must be output.
1508 Attempt to topologically sort the nodes so function is output when
1509 all called functions are already assembled to allow data to be
1510 propagated across the callgraph. Use a stack to get smaller distance
1511 between a function and it's callees (later we may choose to use a more
1512 sophisticated algorithm for function reordering; we will likely want
1513 to use subsections to make the output functions appear in top-down
1517 cgraph_expand_all_functions (void)
1519 struct cgraph_node
*node
;
1520 struct cgraph_node
**order
=
1521 xcalloc (cgraph_n_nodes
, sizeof (struct cgraph_node
*));
1525 cgraph_mark_functions_to_output ();
1527 order_pos
= cgraph_postorder (order
);
1529 for (i
= order_pos
- 1; i
>= 0; i
--)
1534 if (!node
->reachable
)
1537 cgraph_expand_function (node
);
1543 /* Mark all local functions.
1545 A local function is one whose calls can occur only in the
1546 current compilation unit and all it's calls are explicit,
1547 so we can change its calling convention.
1548 We simply mark all static functions whose address is not taken
1552 cgraph_mark_local_functions (void)
1554 struct cgraph_node
*node
;
1556 if (cgraph_dump_file
)
1557 fprintf (cgraph_dump_file
, "\nMarking local functions:");
1559 /* Figure out functions we want to assemble. */
1560 for (node
= cgraph_nodes
; node
; node
= node
->next
)
1562 node
->local
.local
= (!node
->needed
1563 && DECL_SAVED_TREE (node
->decl
)
1564 && !TREE_PUBLIC (node
->decl
));
1565 if (cgraph_dump_file
&& node
->local
.local
)
1566 fprintf (cgraph_dump_file
, " %s", cgraph_node_name (node
));
1568 if (cgraph_dump_file
)
1569 fprintf (cgraph_dump_file
, "\n\n");
1572 /* Perform simple optimizations based on callgraph. */
1575 cgraph_optimize (void)
1577 if (!flag_unit_at_a_time
)
1579 timevar_push (TV_CGRAPHOPT
);
1581 fprintf (stderr
, "Performing intraprocedural optimizations\n");
1583 cgraph_mark_local_functions ();
1584 if (cgraph_dump_file
)
1586 fprintf (cgraph_dump_file
, "Marked ");
1587 dump_cgraph (cgraph_dump_file
);
1590 cgraph_decide_inlining ();
1591 cgraph_global_info_ready
= true;
1592 if (cgraph_dump_file
)
1594 fprintf (cgraph_dump_file
, "Optimized ");
1595 dump_cgraph (cgraph_dump_file
);
1597 timevar_pop (TV_CGRAPHOPT
);
1599 /* Output everything. */
1601 fprintf (stderr
, "Assembling functions:\n");
1602 cgraph_expand_all_functions ();
1603 if (cgraph_dump_file
)
1605 fprintf (cgraph_dump_file
, "\nFinal ");
1606 dump_cgraph (cgraph_dump_file
);