]>
Commit | Line | Data |
---|---|---|
e72fcfe8 JH |
1 | /* Callgraph handling code. |
2 | Copyright (C) 2003 Free Software Foundation, Inc. | |
3 | Contributed by Jan Hubicka | |
4 | ||
5 | This file is part of GCC. | |
6 | ||
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. | |
11 | ||
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. | |
16 | ||
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. */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "tm.h" | |
26 | #include "tree.h" | |
e72fcfe8 JH |
27 | #include "langhooks.h" |
28 | #include "hashtab.h" | |
29 | #include "toplev.h" | |
30 | #include "flags.h" | |
31 | #include "ggc.h" | |
32 | #include "debug.h" | |
33 | #include "target.h" | |
1c4a429a | 34 | #include "cgraph.h" |
988d1653 | 35 | #include "varray.h" |
e69529cd | 36 | #include "output.h" |
988d1653 | 37 | |
e72fcfe8 JH |
38 | |
39 | /* Hash table used to convert declarations into nodes. */ | |
ed2df68b | 40 | static GTY((param_is (struct cgraph_node))) htab_t cgraph_hash; |
e72fcfe8 JH |
41 | |
42 | /* The linked list of cgraph nodes. */ | |
1c4a429a | 43 | struct cgraph_node *cgraph_nodes; |
e72fcfe8 | 44 | |
1668aabc JH |
45 | /* Queue of cgraph nodes scheduled to be lowered. */ |
46 | struct cgraph_node *cgraph_nodes_queue; | |
47 | ||
e72fcfe8 | 48 | /* Number of nodes in existence. */ |
1c4a429a | 49 | int cgraph_n_nodes; |
e72fcfe8 | 50 | |
dafc5b82 JH |
51 | /* Set when whole unit has been analyzed so we can access global info. */ |
52 | bool cgraph_global_info_ready = false; | |
53 | ||
e69529cd | 54 | /* Hash table used to convert declarations into nodes. */ |
ed2df68b | 55 | static GTY((param_is (struct cgraph_varpool_node))) htab_t cgraph_varpool_hash; |
e69529cd JH |
56 | |
57 | /* Queue of cgraph nodes scheduled to be lowered and output. */ | |
58 | struct cgraph_varpool_node *cgraph_varpool_nodes_queue; | |
59 | ||
60 | /* Number of nodes in existence. */ | |
61 | int cgraph_varpool_n_nodes; | |
62 | ||
ed2df68b JH |
63 | /* The linked list of cgraph varpool nodes. */ |
64 | static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; | |
65 | ||
e72fcfe8 JH |
66 | static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *, |
67 | struct cgraph_node *)); | |
18d13f34 | 68 | static void cgraph_remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *)); |
fad205ff KG |
69 | static hashval_t hash_node PARAMS ((const void *)); |
70 | static int eq_node PARAMS ((const void *, const void *)); | |
e72fcfe8 JH |
71 | |
72 | /* Returns a hash code for P. */ | |
73 | ||
74 | static hashval_t | |
75 | hash_node (p) | |
fad205ff | 76 | const void *p; |
e72fcfe8 | 77 | { |
ed2df68b JH |
78 | return ((hashval_t) |
79 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
80 | (((struct cgraph_node *) p)->decl))); | |
e72fcfe8 JH |
81 | } |
82 | ||
6356f892 | 83 | /* Returns nonzero if P1 and P2 are equal. */ |
e72fcfe8 JH |
84 | |
85 | static int | |
86 | eq_node (p1, p2) | |
fad205ff KG |
87 | const void *p1; |
88 | const void *p2; | |
e72fcfe8 JH |
89 | { |
90 | return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) == | |
1668aabc | 91 | (tree) p2); |
e72fcfe8 JH |
92 | } |
93 | ||
94 | /* Return cgraph node assigned to DECL. Create new one when needed. */ | |
1c4a429a | 95 | struct cgraph_node * |
e72fcfe8 JH |
96 | cgraph_node (decl) |
97 | tree decl; | |
98 | { | |
99 | struct cgraph_node *node; | |
100 | struct cgraph_node **slot; | |
101 | ||
988d1653 JH |
102 | if (TREE_CODE (decl) != FUNCTION_DECL) |
103 | abort (); | |
104 | ||
e72fcfe8 | 105 | if (!cgraph_hash) |
ed2df68b | 106 | cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); |
e72fcfe8 | 107 | |
ed2df68b JH |
108 | slot = (struct cgraph_node **) |
109 | htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (decl), | |
110 | IDENTIFIER_HASH_VALUE | |
111 | (DECL_ASSEMBLER_NAME (decl)), 1); | |
e72fcfe8 JH |
112 | if (*slot) |
113 | return *slot; | |
ed2df68b | 114 | node = ggc_alloc_cleared (sizeof (*node)); |
e72fcfe8 JH |
115 | node->decl = decl; |
116 | node->next = cgraph_nodes; | |
18d13f34 JH |
117 | if (cgraph_nodes) |
118 | cgraph_nodes->previous = node; | |
119 | node->previous = NULL; | |
e72fcfe8 JH |
120 | cgraph_nodes = node; |
121 | cgraph_n_nodes++; | |
122 | *slot = node; | |
5c2e00ee | 123 | if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) |
e72fcfe8 JH |
124 | { |
125 | node->origin = cgraph_node (DECL_CONTEXT (decl)); | |
126 | node->next_nested = node->origin->nested; | |
127 | node->origin->nested = node; | |
128 | } | |
129 | return node; | |
130 | } | |
131 | ||
1668aabc JH |
132 | /* Try to find existing function for identifier ID. */ |
133 | struct cgraph_node * | |
134 | cgraph_node_for_identifier (id) | |
135 | tree id; | |
136 | { | |
137 | struct cgraph_node **slot; | |
138 | ||
139 | if (TREE_CODE (id) != IDENTIFIER_NODE) | |
140 | abort (); | |
141 | ||
142 | if (!cgraph_hash) | |
e69529cd | 143 | return NULL; |
1668aabc | 144 | |
ed2df68b JH |
145 | slot = (struct cgraph_node **) |
146 | htab_find_slot_with_hash (cgraph_hash, id, | |
147 | IDENTIFIER_HASH_VALUE (id), 0); | |
1668aabc JH |
148 | if (!slot) |
149 | return NULL; | |
150 | return *slot; | |
151 | } | |
152 | ||
e72fcfe8 JH |
153 | /* Create edge from CALLER to CALLEE in the cgraph. */ |
154 | ||
155 | static struct cgraph_edge * | |
156 | create_edge (caller, callee) | |
157 | struct cgraph_node *caller, *callee; | |
158 | { | |
ed2df68b | 159 | struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); |
e72fcfe8 JH |
160 | |
161 | edge->caller = caller; | |
162 | edge->callee = callee; | |
163 | edge->next_caller = callee->callers; | |
164 | edge->next_callee = caller->callees; | |
165 | caller->callees = edge; | |
166 | callee->callers = edge; | |
167 | return edge; | |
168 | } | |
169 | ||
170 | /* Remove the edge from CALLER to CALLEE in the cgraph. */ | |
171 | ||
172 | static void | |
18d13f34 | 173 | cgraph_remove_edge (caller, callee) |
e72fcfe8 JH |
174 | struct cgraph_node *caller, *callee; |
175 | { | |
176 | struct cgraph_edge **edge, **edge2; | |
177 | ||
178 | for (edge = &callee->callers; *edge && (*edge)->caller != caller; | |
179 | edge = &((*edge)->next_caller)) | |
180 | continue; | |
181 | if (!*edge) | |
182 | abort (); | |
183 | *edge = (*edge)->next_caller; | |
184 | for (edge2 = &caller->callees; *edge2 && (*edge2)->callee != callee; | |
185 | edge2 = &(*edge2)->next_callee) | |
186 | continue; | |
187 | if (!*edge2) | |
188 | abort (); | |
189 | *edge2 = (*edge2)->next_callee; | |
190 | } | |
191 | ||
18d13f34 JH |
192 | /* Remove the node from cgraph. */ |
193 | ||
194 | void | |
195 | cgraph_remove_node (node) | |
196 | struct cgraph_node *node; | |
197 | { | |
198 | while (node->callers) | |
199 | cgraph_remove_edge (node->callers->caller, node); | |
200 | while (node->callees) | |
201 | cgraph_remove_edge (node, node->callees->callee); | |
202 | while (node->nested) | |
203 | cgraph_remove_node (node->nested); | |
204 | if (node->origin) | |
205 | { | |
206 | struct cgraph_node **node2 = &node->origin->nested; | |
207 | ||
208 | while (*node2 != node) | |
209 | node2 = &(*node2)->next_nested; | |
210 | *node2 = node->next_nested; | |
211 | } | |
212 | if (node->previous) | |
213 | node->previous->next = node->next; | |
214 | else | |
215 | cgraph_nodes = node; | |
216 | if (node->next) | |
217 | node->next->previous = node->previous; | |
218 | DECL_SAVED_TREE (node->decl) = NULL; | |
219 | /* Do not free the structure itself so the walk over chain can continue. */ | |
220 | } | |
221 | ||
1668aabc JH |
222 | /* Notify finalize_compilation_unit that given node is reachable |
223 | or needed. */ | |
224 | void | |
225 | cgraph_mark_needed_node (node, needed) | |
226 | struct cgraph_node *node; | |
227 | int needed; | |
228 | { | |
229 | if (needed) | |
230 | { | |
231 | node->needed = 1; | |
232 | } | |
233 | if (!node->reachable) | |
234 | { | |
235 | node->reachable = 1; | |
236 | if (DECL_SAVED_TREE (node->decl)) | |
237 | { | |
8bd87c4e | 238 | node->next_needed = cgraph_nodes_queue; |
1668aabc JH |
239 | cgraph_nodes_queue = node; |
240 | } | |
241 | } | |
242 | } | |
243 | ||
18d13f34 | 244 | |
e72fcfe8 JH |
245 | /* Record call from CALLER to CALLEE */ |
246 | ||
1c4a429a JH |
247 | struct cgraph_edge * |
248 | cgraph_record_call (caller, callee) | |
e72fcfe8 JH |
249 | tree caller, callee; |
250 | { | |
251 | return create_edge (cgraph_node (caller), cgraph_node (callee)); | |
252 | } | |
253 | ||
254 | void | |
255 | cgraph_remove_call (caller, callee) | |
256 | tree caller, callee; | |
257 | { | |
18d13f34 | 258 | cgraph_remove_edge (cgraph_node (caller), cgraph_node (callee)); |
e72fcfe8 JH |
259 | } |
260 | ||
261 | /* Return true when CALLER_DECL calls CALLEE_DECL. */ | |
262 | ||
263 | bool | |
264 | cgraph_calls_p (caller_decl, callee_decl) | |
265 | tree caller_decl, callee_decl; | |
266 | { | |
267 | struct cgraph_node *caller = cgraph_node (caller_decl); | |
268 | struct cgraph_node *callee = cgraph_node (callee_decl); | |
269 | struct cgraph_edge *edge; | |
270 | ||
271 | for (edge = callee->callers; edge && (edge)->caller != caller; | |
272 | edge = (edge->next_caller)) | |
273 | continue; | |
274 | return edge != NULL; | |
275 | } | |
276 | ||
dafc5b82 JH |
277 | /* Return local info for the compiled function. */ |
278 | ||
279 | struct cgraph_local_info * | |
280 | cgraph_local_info (decl) | |
281 | tree decl; | |
282 | { | |
283 | struct cgraph_node *node; | |
284 | if (TREE_CODE (decl) != FUNCTION_DECL) | |
285 | abort (); | |
286 | node = cgraph_node (decl); | |
287 | return &node->local; | |
288 | } | |
289 | ||
290 | /* Return local info for the compiled function. */ | |
291 | ||
292 | struct cgraph_global_info * | |
293 | cgraph_global_info (decl) | |
294 | tree decl; | |
295 | { | |
296 | struct cgraph_node *node; | |
297 | if (TREE_CODE (decl) != FUNCTION_DECL || !cgraph_global_info_ready) | |
298 | abort (); | |
299 | node = cgraph_node (decl); | |
300 | return &node->global; | |
301 | } | |
302 | ||
b255a036 JH |
303 | /* Return local info for the compiled function. */ |
304 | ||
305 | struct cgraph_rtl_info * | |
306 | cgraph_rtl_info (decl) | |
307 | tree decl; | |
308 | { | |
309 | struct cgraph_node *node; | |
310 | if (TREE_CODE (decl) != FUNCTION_DECL) | |
311 | abort (); | |
312 | node = cgraph_node (decl); | |
313 | if (decl != current_function_decl | |
314 | && !TREE_ASM_WRITTEN (node->decl)) | |
315 | return NULL; | |
316 | return &node->rtl; | |
317 | } | |
318 | ||
a194aa56 JH |
319 | /* Return name of the node used in debug output. */ |
320 | const char * | |
321 | cgraph_node_name (node) | |
322 | struct cgraph_node *node; | |
323 | { | |
324 | return (*lang_hooks.decl_printable_name) (node->decl, 2); | |
325 | } | |
dafc5b82 | 326 | |
e72fcfe8 JH |
327 | /* Dump the callgraph. */ |
328 | ||
329 | void | |
330 | dump_cgraph (f) | |
331 | FILE *f; | |
332 | { | |
333 | struct cgraph_node *node; | |
334 | ||
335 | fprintf (f, "\nCallgraph:\n\n"); | |
336 | for (node = cgraph_nodes; node; node = node->next) | |
337 | { | |
338 | struct cgraph_edge *edge; | |
a194aa56 | 339 | fprintf (f, "%s", cgraph_node_name (node)); |
e72fcfe8 | 340 | if (node->origin) |
a194aa56 | 341 | fprintf (f, " nested in: %s", cgraph_node_name (node->origin)); |
e72fcfe8 JH |
342 | if (node->needed) |
343 | fprintf (f, " needed"); | |
344 | else if (node->reachable) | |
345 | fprintf (f, " reachable"); | |
346 | if (DECL_SAVED_TREE (node->decl)) | |
347 | fprintf (f, " tree"); | |
348 | ||
349 | fprintf (f, "\n called by :"); | |
350 | for (edge = node->callers; edge; edge = edge->next_caller) | |
a194aa56 | 351 | fprintf (f, "%s ", cgraph_node_name (edge->caller)); |
e72fcfe8 JH |
352 | |
353 | fprintf (f, "\n calls: "); | |
354 | for (edge = node->callees; edge; edge = edge->next_callee) | |
a194aa56 | 355 | fprintf (f, "%s ", cgraph_node_name (edge->callee)); |
e72fcfe8 JH |
356 | fprintf (f, "\n"); |
357 | } | |
358 | } | |
988d1653 | 359 | |
e69529cd JH |
360 | /* Returns a hash code for P. */ |
361 | ||
362 | static hashval_t | |
363 | cgraph_varpool_hash_node (const PTR p) | |
364 | { | |
ed2df68b JH |
365 | return ((hashval_t) |
366 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
367 | (((struct cgraph_varpool_node *) p)->decl))); | |
e69529cd JH |
368 | } |
369 | ||
f1ba665b | 370 | /* Returns nonzero if P1 and P2 are equal. */ |
e69529cd JH |
371 | |
372 | static int | |
373 | eq_cgraph_varpool_node (const PTR p1, const PTR p2) | |
374 | { | |
375 | return ((DECL_ASSEMBLER_NAME (((struct cgraph_varpool_node *) p1)->decl)) == | |
376 | (tree) p2); | |
377 | } | |
378 | ||
379 | /* Return cgraph_varpool node assigned to DECL. Create new one when needed. */ | |
380 | struct cgraph_varpool_node * | |
381 | cgraph_varpool_node (tree decl) | |
382 | { | |
383 | struct cgraph_varpool_node *node; | |
384 | struct cgraph_varpool_node **slot; | |
385 | ||
386 | if (!DECL_P (decl) || TREE_CODE (decl) == FUNCTION_DECL) | |
387 | abort (); | |
388 | ||
389 | if (!cgraph_varpool_hash) | |
ed2df68b JH |
390 | cgraph_varpool_hash = htab_create_ggc (10, cgraph_varpool_hash_node, |
391 | eq_cgraph_varpool_node, NULL); | |
392 | ||
e69529cd | 393 | |
ed2df68b JH |
394 | slot = (struct cgraph_varpool_node **) |
395 | htab_find_slot_with_hash (cgraph_varpool_hash, DECL_ASSEMBLER_NAME (decl), | |
396 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (decl)), | |
397 | 1); | |
e69529cd JH |
398 | if (*slot) |
399 | return *slot; | |
ed2df68b | 400 | node = ggc_alloc_cleared (sizeof (*node)); |
e69529cd JH |
401 | node->decl = decl; |
402 | cgraph_varpool_n_nodes++; | |
ed2df68b | 403 | cgraph_varpool_nodes = node; |
e69529cd | 404 | *slot = node; |
e69529cd JH |
405 | return node; |
406 | } | |
407 | ||
408 | /* Try to find existing function for identifier ID. */ | |
409 | struct cgraph_varpool_node * | |
410 | cgraph_varpool_node_for_identifier (tree id) | |
411 | { | |
412 | struct cgraph_varpool_node **slot; | |
413 | ||
414 | if (TREE_CODE (id) != IDENTIFIER_NODE) | |
415 | abort (); | |
416 | ||
417 | if (!cgraph_varpool_hash) | |
418 | return NULL; | |
419 | ||
ed2df68b JH |
420 | slot = (struct cgraph_varpool_node **) |
421 | htab_find_slot_with_hash (cgraph_varpool_hash, id, | |
422 | IDENTIFIER_HASH_VALUE (id), 0); | |
e69529cd JH |
423 | if (!slot) |
424 | return NULL; | |
425 | return *slot; | |
426 | } | |
427 | ||
428 | /* Notify finalize_compilation_unit that given node is reachable | |
429 | or needed. */ | |
430 | void | |
431 | cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node) | |
432 | { | |
433 | if (!node->needed && node->finalized) | |
434 | { | |
8bd87c4e | 435 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd JH |
436 | cgraph_varpool_nodes_queue = node; |
437 | } | |
438 | node->needed = 1; | |
439 | } | |
440 | ||
441 | void | |
442 | cgraph_varpool_finalize_decl (tree decl) | |
443 | { | |
444 | struct cgraph_varpool_node *node = cgraph_varpool_node (decl); | |
445 | ||
446 | if (node->needed && !node->finalized) | |
447 | { | |
8bd87c4e | 448 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd JH |
449 | cgraph_varpool_nodes_queue = node; |
450 | } | |
451 | node->finalized = true; | |
452 | ||
453 | if (/* Externally visible variables must be output. The exception are | |
454 | COMDAT functions that must be output only when they are needed. */ | |
455 | (TREE_PUBLIC (decl) && !DECL_COMDAT (decl)) | |
456 | /* Function whose name is output to the assembler file must be produced. | |
457 | It is possible to assemble the name later after finalizing the function | |
458 | and the fact is noticed in assemble_name then. */ | |
459 | || (DECL_ASSEMBLER_NAME_SET_P (decl) | |
460 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) | |
461 | { | |
462 | cgraph_varpool_mark_needed_node (node); | |
463 | } | |
464 | } | |
465 | ||
466 | bool | |
467 | cgraph_varpool_assemble_pending_decls () | |
468 | { | |
469 | bool changed = false; | |
470 | ||
471 | while (cgraph_varpool_nodes_queue) | |
472 | { | |
473 | tree decl = cgraph_varpool_nodes_queue->decl; | |
474 | struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue; | |
475 | ||
8bd87c4e | 476 | cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed; |
e69529cd JH |
477 | if (!TREE_ASM_WRITTEN (decl)) |
478 | { | |
479 | assemble_variable (decl, 0, 1, 0); | |
480 | changed = true; | |
481 | } | |
8bd87c4e | 482 | node->next_needed = NULL; |
e69529cd JH |
483 | } |
484 | return changed; | |
485 | } | |
486 | ||
487 | ||
988d1653 | 488 | #include "gt-cgraph.h" |