]>
Commit | Line | Data |
---|---|---|
e72fcfe8 | 1 | /* Callgraph handling code. |
ad616de1 | 2 | Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. |
e72fcfe8 JH |
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 | ||
18c6ada9 JH |
22 | /* This file contains basic routines manipulating call graph and variable pool |
23 | ||
24 | The callgraph: | |
25 | ||
26 | The call-graph is data structure designed for intra-procedural optimization | |
27 | but it is also used in non-unit-at-a-time compilation to allow easier code | |
28 | sharing. | |
29 | ||
30 | The call-graph consist of nodes and edges represented via linked lists. | |
31 | Each function (external or not) corresponds to the unique node (in | |
32 | contrast to tree DECL nodes where we can have multiple nodes for each | |
33 | function). | |
34 | ||
35 | The mapping from declarations to call-graph nodes is done using hash table | |
36 | based on DECL_ASSEMBLER_NAME, so it is essential for assembler name to | |
37 | not change once the declaration is inserted into the call-graph. | |
38 | The call-graph nodes are created lazily using cgraph_node function when | |
39 | called for unknown declaration. | |
40 | ||
41 | When built, there is one edge for each direct call. It is possible that | |
42 | the reference will be later optimized out. The call-graph is built | |
43 | conservatively in order to make conservative data flow analysis possible. | |
44 | ||
45 | The callgraph at the moment does not represent indirect calls or calls | |
46 | from other compilation unit. Flag NEEDED is set for each node that may | |
1f838355 | 47 | be accessed in such an invisible way and it shall be considered an |
18c6ada9 JH |
48 | entry point to the callgraph. |
49 | ||
50 | Intraprocedural information: | |
51 | ||
52 | Callgraph is place to store data needed for intraprocedural optimization. | |
1ae58c30 | 53 | All data structures are divided into three components: local_info that |
18c6ada9 | 54 | is produced while analyzing the function, global_info that is result |
1ae58c30 | 55 | of global walking of the callgraph on the end of compilation and |
18c6ada9 JH |
56 | rtl_info used by RTL backend to propagate data from already compiled |
57 | functions to their callers. | |
58 | ||
59 | Inlining plans: | |
60 | ||
61 | The function inlining information is decided in advance and maintained | |
62 | in the callgraph as so called inline plan. | |
1ae58c30 | 63 | For each inlined call, the callee's node is cloned to represent the |
1ea7e6ad | 64 | new function copy produced by inliner. |
1ae58c30 KH |
65 | Each inlined call gets a unique corresponding clone node of the callee |
66 | and the data structure is updated while inlining is performed, so | |
67 | the clones are eliminated and their callee edges redirected to the | |
18c6ada9 JH |
68 | caller. |
69 | ||
70 | Each edge has "inline_failed" field. When the field is set to NULL, | |
2b8a92de KH |
71 | the call will be inlined. When it is non-NULL it contains a reason |
72 | why inlining wasn't performed. | |
18c6ada9 JH |
73 | |
74 | ||
75 | The varpool data structure: | |
76 | ||
77 | Varpool is used to maintain variables in similar manner as call-graph | |
78 | is used for functions. Most of the API is symmetric replacing cgraph | |
79 | function prefix by cgraph_varpool */ | |
80 | ||
81 | ||
e72fcfe8 JH |
82 | #include "config.h" |
83 | #include "system.h" | |
84 | #include "coretypes.h" | |
85 | #include "tm.h" | |
86 | #include "tree.h" | |
e72fcfe8 JH |
87 | #include "langhooks.h" |
88 | #include "hashtab.h" | |
89 | #include "toplev.h" | |
90 | #include "flags.h" | |
91 | #include "ggc.h" | |
92 | #include "debug.h" | |
93 | #include "target.h" | |
1c4a429a | 94 | #include "cgraph.h" |
988d1653 | 95 | #include "varray.h" |
e69529cd | 96 | #include "output.h" |
dc0bfe6a | 97 | #include "intl.h" |
988d1653 | 98 | |
e72fcfe8 | 99 | /* Hash table used to convert declarations into nodes. */ |
ed2df68b | 100 | static GTY((param_is (struct cgraph_node))) htab_t cgraph_hash; |
e72fcfe8 JH |
101 | |
102 | /* The linked list of cgraph nodes. */ | |
1c4a429a | 103 | struct cgraph_node *cgraph_nodes; |
e72fcfe8 | 104 | |
1668aabc JH |
105 | /* Queue of cgraph nodes scheduled to be lowered. */ |
106 | struct cgraph_node *cgraph_nodes_queue; | |
107 | ||
e72fcfe8 | 108 | /* Number of nodes in existence. */ |
1c4a429a | 109 | int cgraph_n_nodes; |
e72fcfe8 | 110 | |
b58b1157 JH |
111 | /* Maximal uid used in cgraph nodes. */ |
112 | int cgraph_max_uid; | |
113 | ||
dafc5b82 JH |
114 | /* Set when whole unit has been analyzed so we can access global info. */ |
115 | bool cgraph_global_info_ready = false; | |
116 | ||
e69529cd | 117 | /* Hash table used to convert declarations into nodes. */ |
ed2df68b | 118 | static GTY((param_is (struct cgraph_varpool_node))) htab_t cgraph_varpool_hash; |
e69529cd JH |
119 | |
120 | /* Queue of cgraph nodes scheduled to be lowered and output. */ | |
121 | struct cgraph_varpool_node *cgraph_varpool_nodes_queue; | |
122 | ||
ed2df68b JH |
123 | /* The linked list of cgraph varpool nodes. */ |
124 | static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; | |
125 | ||
439f7bc3 AJ |
126 | static hashval_t hash_node (const void *); |
127 | static int eq_node (const void *, const void *); | |
e72fcfe8 JH |
128 | |
129 | /* Returns a hash code for P. */ | |
130 | ||
131 | static hashval_t | |
439f7bc3 | 132 | hash_node (const void *p) |
e72fcfe8 | 133 | { |
6f312d18 ZW |
134 | const struct cgraph_node *n = p; |
135 | return (hashval_t) DECL_UID (n->decl); | |
e72fcfe8 JH |
136 | } |
137 | ||
6356f892 | 138 | /* Returns nonzero if P1 and P2 are equal. */ |
e72fcfe8 JH |
139 | |
140 | static int | |
439f7bc3 | 141 | eq_node (const void *p1, const void *p2) |
e72fcfe8 | 142 | { |
6f312d18 ZW |
143 | const struct cgraph_node *n1 = p1, *n2 = p2; |
144 | return DECL_UID (n1->decl) == DECL_UID (n2->decl); | |
e72fcfe8 JH |
145 | } |
146 | ||
1ae58c30 | 147 | /* Allocate new callgraph node and insert it into basic data structures. */ |
18c6ada9 JH |
148 | static struct cgraph_node * |
149 | cgraph_create_node (void) | |
150 | { | |
151 | struct cgraph_node *node; | |
152 | ||
153 | node = ggc_alloc_cleared (sizeof (*node)); | |
154 | node->next = cgraph_nodes; | |
155 | node->uid = cgraph_max_uid++; | |
156 | if (cgraph_nodes) | |
157 | cgraph_nodes->previous = node; | |
158 | node->previous = NULL; | |
159 | cgraph_nodes = node; | |
160 | cgraph_n_nodes++; | |
161 | return node; | |
162 | } | |
163 | ||
e72fcfe8 | 164 | /* Return cgraph node assigned to DECL. Create new one when needed. */ |
1c4a429a | 165 | struct cgraph_node * |
439f7bc3 | 166 | cgraph_node (tree decl) |
e72fcfe8 | 167 | { |
6f312d18 | 168 | struct cgraph_node key, *node, **slot; |
e72fcfe8 | 169 | |
341c100f | 170 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); |
988d1653 | 171 | |
e72fcfe8 | 172 | if (!cgraph_hash) |
ed2df68b | 173 | cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); |
e72fcfe8 | 174 | |
6f312d18 ZW |
175 | key.decl = decl; |
176 | ||
177 | slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); | |
178 | ||
e72fcfe8 JH |
179 | if (*slot) |
180 | return *slot; | |
18c6ada9 JH |
181 | |
182 | node = cgraph_create_node (); | |
e72fcfe8 | 183 | node->decl = decl; |
e72fcfe8 | 184 | *slot = node; |
5c2e00ee | 185 | if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) |
e72fcfe8 JH |
186 | { |
187 | node->origin = cgraph_node (DECL_CONTEXT (decl)); | |
188 | node->next_nested = node->origin->nested; | |
189 | node->origin->nested = node; | |
190 | } | |
191 | return node; | |
192 | } | |
193 | ||
bedb9fc0 RH |
194 | /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */ |
195 | ||
196 | static bool | |
197 | decl_assembler_name_equal (tree decl, tree asmname) | |
198 | { | |
199 | tree decl_asmname = DECL_ASSEMBLER_NAME (decl); | |
200 | ||
201 | if (decl_asmname == asmname) | |
202 | return true; | |
203 | ||
204 | /* If the target assembler name was set by the user, things are trickier. | |
205 | We have a leading '*' to begin with. After that, it's arguable what | |
206 | is the correct thing to do with -fleading-underscore. Arguably, we've | |
207 | historically been doing the wrong thing in assemble_alias by always | |
208 | printing the leading underscore. Since we're not changing that, make | |
209 | sure user_label_prefix follows the '*' before matching. */ | |
210 | if (IDENTIFIER_POINTER (decl_asmname)[0] == '*') | |
211 | { | |
212 | const char *decl_str = IDENTIFIER_POINTER (decl_asmname) + 1; | |
213 | size_t ulp_len = strlen (user_label_prefix); | |
214 | ||
215 | if (ulp_len == 0) | |
216 | ; | |
217 | else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0) | |
218 | decl_str += ulp_len; | |
219 | else | |
220 | return false; | |
221 | ||
222 | return strcmp (decl_str, IDENTIFIER_POINTER (asmname)) == 0; | |
223 | } | |
224 | ||
225 | return false; | |
226 | } | |
227 | ||
228 | ||
229 | /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. | |
230 | Return NULL if there's no such node. */ | |
231 | ||
232 | struct cgraph_node * | |
233 | cgraph_node_for_asm (tree asmname) | |
234 | { | |
235 | struct cgraph_node *node; | |
236 | ||
237 | for (node = cgraph_nodes; node ; node = node->next) | |
238 | if (decl_assembler_name_equal (node->decl, asmname)) | |
239 | return node; | |
240 | ||
241 | return NULL; | |
242 | } | |
243 | ||
18c6ada9 JH |
244 | /* Return callgraph edge representing CALL_EXPR. */ |
245 | struct cgraph_edge * | |
246 | cgraph_edge (struct cgraph_node *node, tree call_expr) | |
247 | { | |
248 | struct cgraph_edge *e; | |
249 | ||
250 | /* This loop may turn out to be performance problem. In such case adding | |
251 | hashtables into call nodes with very many edges is probably best | |
2b8a92de | 252 | solution. It is not good idea to add pointer into CALL_EXPR itself |
18c6ada9 JH |
253 | because we want to make possible having multiple cgraph nodes representing |
254 | different clones of the same body before the body is actually cloned. */ | |
255 | for (e = node->callees; e; e= e->next_callee) | |
256 | if (e->call_expr == call_expr) | |
257 | break; | |
258 | return e; | |
259 | } | |
260 | ||
e72fcfe8 JH |
261 | /* Create edge from CALLER to CALLEE in the cgraph. */ |
262 | ||
18c6ada9 JH |
263 | struct cgraph_edge * |
264 | cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, | |
265 | tree call_expr) | |
e72fcfe8 | 266 | { |
ed2df68b | 267 | struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); |
18c6ada9 JH |
268 | #ifdef ENABLE_CHECKING |
269 | struct cgraph_edge *e; | |
270 | ||
271 | for (e = caller->callees; e; e = e->next_callee) | |
341c100f | 272 | gcc_assert (e->call_expr != call_expr); |
18c6ada9 JH |
273 | #endif |
274 | ||
341c100f | 275 | gcc_assert (TREE_CODE (call_expr) == CALL_EXPR); |
b58b1157 | 276 | |
dc0bfe6a JH |
277 | if (!DECL_SAVED_TREE (callee->decl)) |
278 | edge->inline_failed = N_("function body not available"); | |
95c755e9 JH |
279 | else if (callee->local.redefined_extern_inline) |
280 | edge->inline_failed = N_("redefined extern inline functions are not " | |
281 | "considered for inlining"); | |
dc0bfe6a JH |
282 | else if (callee->local.inlinable) |
283 | edge->inline_failed = N_("function not considered for inlining"); | |
284 | else | |
285 | edge->inline_failed = N_("function not inlinable"); | |
286 | ||
18c6ada9 | 287 | edge->aux = NULL; |
e72fcfe8 JH |
288 | |
289 | edge->caller = caller; | |
290 | edge->callee = callee; | |
18c6ada9 | 291 | edge->call_expr = call_expr; |
e72fcfe8 JH |
292 | edge->next_caller = callee->callers; |
293 | edge->next_callee = caller->callees; | |
294 | caller->callees = edge; | |
295 | callee->callers = edge; | |
296 | return edge; | |
297 | } | |
298 | ||
18c6ada9 | 299 | /* Remove the edge E the cgraph. */ |
e72fcfe8 | 300 | |
cb967da5 | 301 | void |
18c6ada9 | 302 | cgraph_remove_edge (struct cgraph_edge *e) |
e72fcfe8 JH |
303 | { |
304 | struct cgraph_edge **edge, **edge2; | |
305 | ||
18c6ada9 | 306 | for (edge = &e->callee->callers; *edge && *edge != e; |
e72fcfe8 JH |
307 | edge = &((*edge)->next_caller)) |
308 | continue; | |
341c100f | 309 | gcc_assert (*edge); |
e72fcfe8 | 310 | *edge = (*edge)->next_caller; |
18c6ada9 | 311 | for (edge2 = &e->caller->callees; *edge2 && *edge2 != e; |
e72fcfe8 JH |
312 | edge2 = &(*edge2)->next_callee) |
313 | continue; | |
341c100f | 314 | gcc_assert (*edge2); |
e72fcfe8 JH |
315 | *edge2 = (*edge2)->next_callee; |
316 | } | |
317 | ||
18c6ada9 JH |
318 | /* Redirect callee of E to N. The function does not update underlying |
319 | call expression. */ | |
320 | ||
321 | void | |
322 | cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) | |
323 | { | |
324 | struct cgraph_edge **edge; | |
325 | ||
326 | for (edge = &e->callee->callers; *edge && *edge != e; | |
327 | edge = &((*edge)->next_caller)) | |
328 | continue; | |
341c100f | 329 | gcc_assert (*edge); |
18c6ada9 JH |
330 | *edge = (*edge)->next_caller; |
331 | e->callee = n; | |
332 | e->next_caller = n->callers; | |
333 | n->callers = e; | |
334 | } | |
335 | ||
18d13f34 JH |
336 | /* Remove the node from cgraph. */ |
337 | ||
338 | void | |
439f7bc3 | 339 | cgraph_remove_node (struct cgraph_node *node) |
18d13f34 | 340 | { |
2ee1067b | 341 | void **slot; |
18c6ada9 JH |
342 | bool check_dead = 1; |
343 | ||
18d13f34 | 344 | while (node->callers) |
18c6ada9 | 345 | cgraph_remove_edge (node->callers); |
18d13f34 | 346 | while (node->callees) |
18c6ada9 | 347 | cgraph_remove_edge (node->callees); |
18d13f34 JH |
348 | while (node->nested) |
349 | cgraph_remove_node (node->nested); | |
350 | if (node->origin) | |
351 | { | |
352 | struct cgraph_node **node2 = &node->origin->nested; | |
353 | ||
354 | while (*node2 != node) | |
355 | node2 = &(*node2)->next_nested; | |
356 | *node2 = node->next_nested; | |
357 | } | |
358 | if (node->previous) | |
359 | node->previous->next = node->next; | |
360 | else | |
9b0436b7 | 361 | cgraph_nodes = node->next; |
18d13f34 JH |
362 | if (node->next) |
363 | node->next->previous = node->previous; | |
6f312d18 | 364 | slot = htab_find_slot (cgraph_hash, node, NO_INSERT); |
18c6ada9 JH |
365 | if (*slot == node) |
366 | { | |
367 | if (node->next_clone) | |
368 | *slot = node->next_clone; | |
369 | else | |
370 | { | |
371 | htab_clear_slot (cgraph_hash, slot); | |
9f8628ba | 372 | if (!dump_enabled_p (TDI_tree_all)) |
18c6ada9 JH |
373 | { |
374 | DECL_SAVED_TREE (node->decl) = NULL; | |
375 | DECL_STRUCT_FUNCTION (node->decl) = NULL; | |
376 | } | |
377 | check_dead = false; | |
378 | } | |
379 | } | |
380 | else | |
381 | { | |
382 | struct cgraph_node *n; | |
383 | ||
384 | for (n = *slot; n->next_clone != node; n = n->next_clone) | |
385 | continue; | |
386 | n->next_clone = node->next_clone; | |
387 | } | |
388 | ||
389 | /* Work out whether we still need a function body (either there is inline | |
390 | clone or there is out of line function whose body is not written). */ | |
391 | if (check_dead && flag_unit_at_a_time) | |
392 | { | |
393 | struct cgraph_node *n; | |
394 | ||
395 | for (n = *slot; n; n = n->next_clone) | |
396 | if (n->global.inlined_to | |
397 | || (!n->global.inlined_to | |
398 | && !TREE_ASM_WRITTEN (n->decl) && !DECL_EXTERNAL (n->decl))) | |
399 | break; | |
9f8628ba | 400 | if (!n && !dump_enabled_p (TDI_tree_all)) |
18c6ada9 JH |
401 | { |
402 | DECL_SAVED_TREE (node->decl) = NULL; | |
403 | DECL_STRUCT_FUNCTION (node->decl) = NULL; | |
89480522 | 404 | DECL_INITIAL (node->decl) = error_mark_node; |
18c6ada9 JH |
405 | } |
406 | } | |
407 | cgraph_n_nodes--; | |
18d13f34 JH |
408 | /* Do not free the structure itself so the walk over chain can continue. */ |
409 | } | |
410 | ||
8dafba3c RH |
411 | /* Notify finalize_compilation_unit that given node is reachable. */ |
412 | ||
1668aabc | 413 | void |
8dafba3c | 414 | cgraph_mark_reachable_node (struct cgraph_node *node) |
1668aabc | 415 | { |
ba245151 | 416 | if (!node->reachable && node->local.finalized) |
1668aabc | 417 | { |
ba245151 | 418 | notice_global_symbol (node->decl); |
1668aabc | 419 | node->reachable = 1; |
e767b5be JH |
420 | |
421 | node->next_needed = cgraph_nodes_queue; | |
422 | cgraph_nodes_queue = node; | |
1668aabc JH |
423 | } |
424 | } | |
425 | ||
8dafba3c RH |
426 | /* Likewise indicate that a node is needed, i.e. reachable via some |
427 | external means. */ | |
428 | ||
429 | void | |
430 | cgraph_mark_needed_node (struct cgraph_node *node) | |
431 | { | |
432 | node->needed = 1; | |
433 | cgraph_mark_reachable_node (node); | |
434 | } | |
18d13f34 | 435 | |
dafc5b82 JH |
436 | /* Return local info for the compiled function. */ |
437 | ||
438 | struct cgraph_local_info * | |
439f7bc3 | 439 | cgraph_local_info (tree decl) |
dafc5b82 JH |
440 | { |
441 | struct cgraph_node *node; | |
341c100f NS |
442 | |
443 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); | |
dafc5b82 JH |
444 | node = cgraph_node (decl); |
445 | return &node->local; | |
446 | } | |
447 | ||
448 | /* Return local info for the compiled function. */ | |
449 | ||
450 | struct cgraph_global_info * | |
439f7bc3 | 451 | cgraph_global_info (tree decl) |
dafc5b82 JH |
452 | { |
453 | struct cgraph_node *node; | |
341c100f NS |
454 | |
455 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL && cgraph_global_info_ready); | |
dafc5b82 JH |
456 | node = cgraph_node (decl); |
457 | return &node->global; | |
458 | } | |
459 | ||
b255a036 JH |
460 | /* Return local info for the compiled function. */ |
461 | ||
462 | struct cgraph_rtl_info * | |
439f7bc3 | 463 | cgraph_rtl_info (tree decl) |
b255a036 JH |
464 | { |
465 | struct cgraph_node *node; | |
341c100f NS |
466 | |
467 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); | |
b255a036 JH |
468 | node = cgraph_node (decl); |
469 | if (decl != current_function_decl | |
470 | && !TREE_ASM_WRITTEN (node->decl)) | |
471 | return NULL; | |
472 | return &node->rtl; | |
473 | } | |
474 | ||
a194aa56 JH |
475 | /* Return name of the node used in debug output. */ |
476 | const char * | |
439f7bc3 | 477 | cgraph_node_name (struct cgraph_node *node) |
a194aa56 | 478 | { |
ae2bcd98 | 479 | return lang_hooks.decl_printable_name (node->decl, 2); |
a194aa56 | 480 | } |
dafc5b82 | 481 | |
18c6ada9 JH |
482 | /* Dump given cgraph node. */ |
483 | void | |
484 | dump_cgraph_node (FILE *f, struct cgraph_node *node) | |
485 | { | |
486 | struct cgraph_edge *edge; | |
487 | fprintf (f, "%s/%i:", cgraph_node_name (node), node->uid); | |
488 | if (node->global.inlined_to) | |
489 | fprintf (f, " (inline copy in %s/%i)", | |
490 | cgraph_node_name (node->global.inlined_to), | |
491 | node->global.inlined_to->uid); | |
492 | if (node->local.self_insns) | |
493 | fprintf (f, " %i insns", node->local.self_insns); | |
494 | if (node->global.insns && node->global.insns != node->local.self_insns) | |
495 | fprintf (f, " (%i after inlining)", node->global.insns); | |
496 | if (node->origin) | |
497 | fprintf (f, " nested in: %s", cgraph_node_name (node->origin)); | |
498 | if (node->needed) | |
499 | fprintf (f, " needed"); | |
500 | else if (node->reachable) | |
501 | fprintf (f, " reachable"); | |
502 | if (DECL_SAVED_TREE (node->decl)) | |
503 | fprintf (f, " tree"); | |
504 | if (node->output) | |
505 | fprintf (f, " output"); | |
18c6ada9 JH |
506 | if (node->local.local) |
507 | fprintf (f, " local"); | |
508 | if (node->local.disregard_inline_limits) | |
509 | fprintf (f, " always_inline"); | |
510 | else if (node->local.inlinable) | |
511 | fprintf (f, " inlinable"); | |
512 | if (TREE_ASM_WRITTEN (node->decl)) | |
513 | fprintf (f, " asm_written"); | |
514 | ||
515 | fprintf (f, "\n called by: "); | |
516 | for (edge = node->callers; edge; edge = edge->next_caller) | |
517 | { | |
518 | fprintf (f, "%s/%i ", cgraph_node_name (edge->caller), | |
519 | edge->caller->uid); | |
520 | if (!edge->inline_failed) | |
521 | fprintf(f, "(inlined) "); | |
522 | } | |
523 | ||
524 | fprintf (f, "\n calls: "); | |
525 | for (edge = node->callees; edge; edge = edge->next_callee) | |
526 | { | |
527 | fprintf (f, "%s/%i ", cgraph_node_name (edge->callee), | |
528 | edge->callee->uid); | |
529 | if (!edge->inline_failed) | |
530 | fprintf(f, "(inlined) "); | |
531 | } | |
532 | fprintf (f, "\n"); | |
533 | } | |
534 | ||
e72fcfe8 JH |
535 | /* Dump the callgraph. */ |
536 | ||
537 | void | |
439f7bc3 | 538 | dump_cgraph (FILE *f) |
e72fcfe8 JH |
539 | { |
540 | struct cgraph_node *node; | |
541 | ||
7d82fe7c | 542 | fprintf (f, "callgraph:\n\n"); |
e72fcfe8 | 543 | for (node = cgraph_nodes; node; node = node->next) |
18c6ada9 | 544 | dump_cgraph_node (f, node); |
e72fcfe8 | 545 | } |
988d1653 | 546 | |
e69529cd JH |
547 | /* Returns a hash code for P. */ |
548 | ||
549 | static hashval_t | |
6f312d18 | 550 | hash_varpool_node (const void *p) |
e69529cd | 551 | { |
6f312d18 ZW |
552 | const struct cgraph_varpool_node *n = p; |
553 | return (hashval_t) DECL_UID (n->decl); | |
e69529cd JH |
554 | } |
555 | ||
f1ba665b | 556 | /* Returns nonzero if P1 and P2 are equal. */ |
e69529cd JH |
557 | |
558 | static int | |
6f312d18 | 559 | eq_varpool_node (const void *p1, const void *p2) |
e69529cd | 560 | { |
6f312d18 ZW |
561 | const struct cgraph_varpool_node *n1 = p1, *n2 = p2; |
562 | return DECL_UID (n1->decl) == DECL_UID (n2->decl); | |
e69529cd JH |
563 | } |
564 | ||
565 | /* Return cgraph_varpool node assigned to DECL. Create new one when needed. */ | |
566 | struct cgraph_varpool_node * | |
567 | cgraph_varpool_node (tree decl) | |
568 | { | |
6f312d18 | 569 | struct cgraph_varpool_node key, *node, **slot; |
e69529cd | 570 | |
341c100f | 571 | gcc_assert (DECL_P (decl) && TREE_CODE (decl) != FUNCTION_DECL); |
e69529cd JH |
572 | |
573 | if (!cgraph_varpool_hash) | |
6f312d18 ZW |
574 | cgraph_varpool_hash = htab_create_ggc (10, hash_varpool_node, |
575 | eq_varpool_node, NULL); | |
576 | key.decl = decl; | |
ed2df68b | 577 | slot = (struct cgraph_varpool_node **) |
6f312d18 | 578 | htab_find_slot (cgraph_varpool_hash, &key, INSERT); |
e69529cd JH |
579 | if (*slot) |
580 | return *slot; | |
ed2df68b | 581 | node = ggc_alloc_cleared (sizeof (*node)); |
e69529cd | 582 | node->decl = decl; |
bedb9fc0 | 583 | node->next = cgraph_varpool_nodes; |
ed2df68b | 584 | cgraph_varpool_nodes = node; |
e69529cd | 585 | *slot = node; |
e69529cd JH |
586 | return node; |
587 | } | |
588 | ||
bedb9fc0 RH |
589 | struct cgraph_varpool_node * |
590 | cgraph_varpool_node_for_asm (tree asmname) | |
591 | { | |
592 | struct cgraph_varpool_node *node; | |
593 | ||
594 | for (node = cgraph_varpool_nodes; node ; node = node->next) | |
595 | if (decl_assembler_name_equal (node->decl, asmname)) | |
596 | return node; | |
597 | ||
598 | return NULL; | |
599 | } | |
600 | ||
fccc4eb2 JH |
601 | /* Set the DECL_ASSEMBLER_NAME and update cgraph hashtables. */ |
602 | void | |
603 | change_decl_assembler_name (tree decl, tree name) | |
604 | { | |
fccc4eb2 JH |
605 | if (!DECL_ASSEMBLER_NAME_SET_P (decl)) |
606 | { | |
607 | SET_DECL_ASSEMBLER_NAME (decl, name); | |
608 | return; | |
609 | } | |
610 | if (name == DECL_ASSEMBLER_NAME (decl)) | |
611 | return; | |
612 | ||
df964a18 JH |
613 | if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) |
614 | && DECL_RTL_SET_P (decl)) | |
fccc4eb2 JH |
615 | warning ("%D renamed after being referenced in assembly", decl); |
616 | ||
fccc4eb2 | 617 | SET_DECL_ASSEMBLER_NAME (decl, name); |
e69529cd JH |
618 | } |
619 | ||
620 | /* Notify finalize_compilation_unit that given node is reachable | |
621 | or needed. */ | |
622 | void | |
623 | cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node) | |
624 | { | |
625 | if (!node->needed && node->finalized) | |
626 | { | |
8bd87c4e | 627 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd | 628 | cgraph_varpool_nodes_queue = node; |
810db579 | 629 | notice_global_symbol (node->decl); |
e69529cd JH |
630 | } |
631 | node->needed = 1; | |
632 | } | |
633 | ||
634 | void | |
635 | cgraph_varpool_finalize_decl (tree decl) | |
636 | { | |
637 | struct cgraph_varpool_node *node = cgraph_varpool_node (decl); | |
d853a20e JH |
638 | |
639 | /* The first declaration of a variable that comes through this function | |
640 | decides whether it is global (in C, has external linkage) | |
641 | or local (in C, has internal linkage). So do nothing more | |
642 | if this function has already run. */ | |
643 | if (node->finalized) | |
644 | return; | |
645 | if (node->needed) | |
e69529cd | 646 | { |
8bd87c4e | 647 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd | 648 | cgraph_varpool_nodes_queue = node; |
ba245151 | 649 | notice_global_symbol (decl); |
e69529cd JH |
650 | } |
651 | node->finalized = true; | |
652 | ||
653 | if (/* Externally visible variables must be output. The exception are | |
654 | COMDAT functions that must be output only when they are needed. */ | |
655 | (TREE_PUBLIC (decl) && !DECL_COMDAT (decl)) | |
656 | /* Function whose name is output to the assembler file must be produced. | |
657 | It is possible to assemble the name later after finalizing the function | |
658 | and the fact is noticed in assemble_name then. */ | |
659 | || (DECL_ASSEMBLER_NAME_SET_P (decl) | |
660 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) | |
661 | { | |
662 | cgraph_varpool_mark_needed_node (node); | |
663 | } | |
664 | } | |
665 | ||
666 | bool | |
439f7bc3 | 667 | cgraph_varpool_assemble_pending_decls (void) |
e69529cd JH |
668 | { |
669 | bool changed = false; | |
670 | ||
671 | while (cgraph_varpool_nodes_queue) | |
672 | { | |
673 | tree decl = cgraph_varpool_nodes_queue->decl; | |
674 | struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue; | |
675 | ||
8bd87c4e | 676 | cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed; |
e69529cd JH |
677 | if (!TREE_ASM_WRITTEN (decl)) |
678 | { | |
679 | assemble_variable (decl, 0, 1, 0); | |
680 | changed = true; | |
681 | } | |
8bd87c4e | 682 | node->next_needed = NULL; |
e69529cd JH |
683 | } |
684 | return changed; | |
685 | } | |
686 | ||
1bb17c21 JH |
687 | /* Return true when the DECL can possibly be inlined. */ |
688 | bool | |
689 | cgraph_function_possibly_inlined_p (tree decl) | |
690 | { | |
1bb17c21 | 691 | if (!cgraph_global_info_ready) |
18c6ada9 | 692 | return (DECL_INLINE (decl) && !flag_really_no_inline); |
6f312d18 | 693 | return DECL_POSSIBLY_INLINED (decl); |
18c6ada9 JH |
694 | } |
695 | ||
696 | /* Create clone of E in the node N represented by CALL_EXPR the callgraph. */ | |
697 | struct cgraph_edge * | |
698 | cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, tree call_expr) | |
699 | { | |
700 | struct cgraph_edge *new = cgraph_create_edge (n, e->callee, call_expr); | |
701 | ||
702 | new->inline_failed = e->inline_failed; | |
703 | return new; | |
1bb17c21 | 704 | } |
e69529cd | 705 | |
18c6ada9 JH |
706 | /* Create node representing clone of N. */ |
707 | struct cgraph_node * | |
708 | cgraph_clone_node (struct cgraph_node *n) | |
709 | { | |
710 | struct cgraph_node *new = cgraph_create_node (); | |
711 | struct cgraph_edge *e; | |
712 | ||
713 | new->decl = n->decl; | |
714 | new->origin = n->origin; | |
715 | if (new->origin) | |
716 | { | |
717 | new->next_nested = new->origin->nested; | |
718 | new->origin->nested = new; | |
719 | } | |
720 | new->analyzed = n->analyzed; | |
721 | new->local = n->local; | |
722 | new->global = n->global; | |
723 | new->rtl = n->rtl; | |
724 | ||
725 | for (e = n->callees;e; e=e->next_callee) | |
726 | cgraph_clone_edge (e, new, e->call_expr); | |
727 | ||
728 | new->next_clone = n->next_clone; | |
729 | n->next_clone = new; | |
730 | ||
731 | return new; | |
732 | } | |
8f235343 JH |
733 | |
734 | /* NODE is no longer nested function; update cgraph accordingly. */ | |
735 | void | |
736 | cgraph_unnest_node (struct cgraph_node *node) | |
737 | { | |
738 | struct cgraph_node **node2 = &node->origin->nested; | |
739 | gcc_assert (node->origin); | |
740 | ||
741 | while (*node2 != node) | |
742 | node2 = &(*node2)->next_nested; | |
743 | *node2 = node->next_nested; | |
744 | node->origin = NULL; | |
745 | } | |
988d1653 | 746 | #include "gt-cgraph.h" |