2003-02-28 Aldy Hernandez <aldyh@redhat.com>
[official-gcc.git] / gcc / cgraphunit.c
blob0a12ddad8563fba8252821e9cd51ebac3c2e5f0c
1 /* Callgraph handling code.
2 Copyright (C) 2003 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
10 version.
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
15 for more details.
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
20 02111-1307, USA. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "tree.h"
27 #include "tree-inline.h"
28 #include "langhooks.h"
29 #include "hashtab.h"
30 #include "toplev.h"
31 #include "flags.h"
32 #include "ggc.h"
33 #include "debug.h"
34 #include "target.h"
35 #include "cgraph.h"
37 static void cgraph_expand_functions PARAMS ((void));
38 static void cgraph_mark_functions_to_output PARAMS ((void));
39 static void cgraph_expand_function PARAMS ((struct cgraph_node *));
40 static tree record_call_1 PARAMS ((tree *, int *, void *));
42 /* Analyze function once it is parsed. Set up the local information
43 available - create cgraph edges for function calles via BODY. */
45 void
46 cgraph_finalize_function (decl, body)
47 tree decl;
48 tree body ATTRIBUTE_UNUSED;
50 struct cgraph_node *node = cgraph_node (decl);
52 node->decl = decl;
54 /* Set TREE_UNINLINABLE flag. */
55 tree_inlinable_function_p (decl);
57 (*debug_hooks->deferred_inline_function) (decl);
60 static struct cgraph_node *queue = NULL;
62 /* Notify finalize_compilation_unit that given node is reachable
63 or needed. */
64 void
65 cgraph_mark_needed_node (node, needed)
66 struct cgraph_node *node;
67 int needed;
69 if (needed)
71 if (DECL_SAVED_TREE (node->decl))
72 announce_function (node->decl);
73 node->needed = 1;
75 if (!node->reachable)
77 node->reachable = 1;
78 if (DECL_SAVED_TREE (node->decl))
80 node->aux = queue;
81 queue = node;
86 /* Walk tree and record all calls. Called via walk_tree. */
87 static tree
88 record_call_1 (tp, walk_subtrees, data)
89 tree *tp;
90 int *walk_subtrees;
91 void *data;
93 /* Record dereferences to the functions. This makes the functions
94 reachable unconditionally. */
95 if (TREE_CODE (*tp) == ADDR_EXPR)
97 tree decl = TREE_OPERAND (*tp, 0);
98 if (TREE_CODE (decl) == FUNCTION_DECL)
99 cgraph_mark_needed_node (cgraph_node (decl), 1);
101 else if (TREE_CODE (*tp) == CALL_EXPR)
103 tree decl = TREE_OPERAND (*tp, 0);
104 if (TREE_CODE (decl) == ADDR_EXPR)
105 decl = TREE_OPERAND (decl, 0);
106 if (TREE_CODE (decl) == FUNCTION_DECL)
108 if (DECL_BUILT_IN (decl))
109 return NULL;
110 cgraph_record_call (data, decl);
111 walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data, NULL);
112 *walk_subtrees = 0;
115 return NULL;
118 /* Create cgraph edges for function calles via BODY. */
120 void
121 cgraph_create_edges (decl, body)
122 tree decl;
123 tree body;
125 walk_tree (&body, record_call_1, decl, NULL);
128 /* Analyze the whole compilation unit once it is parsed completely. */
130 void
131 cgraph_finalize_compilation_unit ()
133 struct cgraph_node *node;
134 struct cgraph_edge *edge;
136 /* Collect entry points to the unit. */
138 if (!quiet_flag)
139 fprintf (stderr, "\n\nUnit entry points:");
141 for (node = cgraph_nodes; node; node = node->next)
143 tree decl = node->decl;
145 if (!DECL_SAVED_TREE (decl))
146 continue;
147 if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
148 || (DECL_ASSEMBLER_NAME_SET_P (decl)
149 && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
151 cgraph_mark_needed_node (node, 1);
155 /* Propagate reachability flag and lower representation of all reachable
156 functions. In the future, lowering will introduce new functions and
157 new entry points on the way (by template instantiation and virtual
158 method table generation for instance). */
159 while (queue)
161 tree decl = queue->decl;
163 node = queue;
164 queue = queue->aux;
165 if (node->lowered || !node->reachable || !DECL_SAVED_TREE (decl))
166 abort ();
168 /* At the moment frontend automatically emits all nested functions. */
169 if (node->nested)
171 struct cgraph_node *node2;
173 for (node2 = node->nested; node2; node2 = node2->next_nested)
174 if (!node2->reachable)
175 cgraph_mark_needed_node (node2, 0);
178 if (lang_hooks.callgraph.lower_function)
179 (*lang_hooks.callgraph.lower_function) (decl);
180 /* First kill forward declaration so reverse inling works properly. */
181 cgraph_create_edges (decl, DECL_SAVED_TREE (decl));
183 for (edge = node->callees; edge; edge = edge->next_callee)
185 if (!edge->callee->reachable)
186 cgraph_mark_needed_node (edge->callee, 0);
188 node->lowered = true;
190 if (!quiet_flag)
191 fprintf (stderr, "\n\nReclaiming functions:");
193 for (node = cgraph_nodes; node; node = node->next)
195 tree decl = node->decl;
197 if (!node->reachable && DECL_SAVED_TREE (decl))
199 DECL_SAVED_TREE (decl) = NULL;
200 announce_function (decl);
203 ggc_collect ();
206 /* Figure out what functions we want to assemble. */
208 static void
209 cgraph_mark_functions_to_output ()
211 struct cgraph_node *node;
213 /* Figure out functions we want to assemble. */
214 for (node = cgraph_nodes; node; node = node->next)
216 tree decl = node->decl;
218 if (DECL_SAVED_TREE (decl)
219 && (node->needed
220 || (DECL_UNINLINABLE (decl) && node->reachable)
221 || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
222 && !TREE_ASM_WRITTEN (decl) && !node->origin
223 && !DECL_EXTERNAL (decl))
224 node->output = 1;
228 /* Expand function specified by NODE. */
229 static void
230 cgraph_expand_function (node)
231 struct cgraph_node *node;
233 tree decl = node->decl;
235 announce_function (decl);
236 if (flag_inline_trees)
237 optimize_inline_calls (decl);
238 (*lang_hooks.callgraph.expand_function) (decl);
239 if (DECL_UNINLINABLE (decl))
240 DECL_SAVED_TREE (decl) = NULL;
241 current_function_decl = NULL;
245 /* Expand all functions that must be output.
247 Attempt to topologically sort the nodes so function is output when
248 all called functions are already assembled to allow data to be propagated
249 accross the callgraph. Use stack to get smaller distance between function
250 and it's callees (later we may use more sophisticated algorithm for
251 function reordering, we will likely want to use subsections to make output
252 functions to appear in top-down order, not bottom-up they are assembled). */
254 static void
255 cgraph_expand_functions ()
257 struct cgraph_node *node, *node2;
258 struct cgraph_node **stack =
259 xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes);
260 struct cgraph_node **order =
261 xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes);
262 int stack_size = 0;
263 int order_pos = 0;
264 struct cgraph_edge *edge, last;
265 int i;
267 cgraph_mark_functions_to_output ();
269 /* We have to deal with cycles nicely, so use depth first traversal
270 algorithm. Ignore the fact that some functions won't need to be output
271 and put them into order as well, so we get dependencies right trought inlined
272 functions. */
273 for (node = cgraph_nodes; node; node = node->next)
274 node->aux = NULL;
275 for (node = cgraph_nodes; node; node = node->next)
276 if (node->output && !node->aux)
278 node2 = node;
279 if (!node->callers)
280 node->aux = &last;
281 else
282 node->aux = node->callers;
283 while (node2)
285 while (node2->aux != &last)
287 edge = node2->aux;
288 if (edge->next_caller)
289 node2->aux = edge->next_caller;
290 else
291 node2->aux = &last;
292 if (!edge->caller->aux)
294 if (!edge->caller->callers)
295 edge->caller->aux = &last;
296 else
297 edge->caller->aux = edge->caller->callers;
298 stack[stack_size++] = node2;
299 node2 = edge->caller;
300 break;
303 if (node2->aux == &last)
305 order[order_pos++] = node2;
306 if (stack_size)
307 node2 = stack[--stack_size];
308 else
309 node2 = NULL;
313 for (i = order_pos - 1; i >=0; i--)
315 node = order[i];
316 if (node->output)
318 if (!node->reachable)
319 abort ();
320 node->output = 0;
321 cgraph_expand_function (node);
324 free (stack);
325 free (order);
328 /* Perform simple optimizations based on callgraph. */
330 void
331 cgraph_optimize ()
333 struct cgraph_node *node;
334 bool changed = true;
335 struct cgraph_edge *edge;
337 if (!quiet_flag)
338 fprintf (stderr, "\n\nAssembling functions:");
340 /* Output everything.
341 ??? Our inline heuristic may decide to not inline functions previously
342 marked as inlinable thus adding new function bodies that must be output.
343 Later we should move all inlining decisions to callgraph code to make
344 this impossible. */
345 cgraph_expand_functions ();
346 while (changed)
348 changed = false;
349 for (node = cgraph_nodes; node; node = node->next)
351 if (!node->needed)
352 continue;
354 for (edge = node->callees; edge; edge = edge->next_callee)
355 if (!edge->callee->needed)
356 changed = edge->callee->needed = true;
359 cgraph_expand_functions ();