]>
Commit | Line | Data |
---|---|---|
e72fcfe8 | 1 | /* Callgraph handling code. |
b684a3df | 2 | Copyright (C) 2003, 2004 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 | ||
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 | |
b58b1157 JH |
51 | /* Maximal uid used in cgraph nodes. */ |
52 | int cgraph_max_uid; | |
53 | ||
dafc5b82 JH |
54 | /* Set when whole unit has been analyzed so we can access global info. */ |
55 | bool cgraph_global_info_ready = false; | |
56 | ||
e69529cd | 57 | /* Hash table used to convert declarations into nodes. */ |
ed2df68b | 58 | static GTY((param_is (struct cgraph_varpool_node))) htab_t cgraph_varpool_hash; |
e69529cd JH |
59 | |
60 | /* Queue of cgraph nodes scheduled to be lowered and output. */ | |
61 | struct cgraph_varpool_node *cgraph_varpool_nodes_queue; | |
62 | ||
63 | /* Number of nodes in existence. */ | |
64 | int cgraph_varpool_n_nodes; | |
65 | ||
ed2df68b JH |
66 | /* The linked list of cgraph varpool nodes. */ |
67 | static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; | |
68 | ||
439f7bc3 AJ |
69 | static struct cgraph_edge *create_edge (struct cgraph_node *, |
70 | struct cgraph_node *); | |
439f7bc3 AJ |
71 | static hashval_t hash_node (const void *); |
72 | static int eq_node (const void *, const void *); | |
e72fcfe8 JH |
73 | |
74 | /* Returns a hash code for P. */ | |
75 | ||
76 | static hashval_t | |
439f7bc3 | 77 | hash_node (const void *p) |
e72fcfe8 | 78 | { |
ed2df68b JH |
79 | return ((hashval_t) |
80 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
81 | (((struct cgraph_node *) p)->decl))); | |
e72fcfe8 JH |
82 | } |
83 | ||
6356f892 | 84 | /* Returns nonzero if P1 and P2 are equal. */ |
e72fcfe8 JH |
85 | |
86 | static int | |
439f7bc3 | 87 | eq_node (const void *p1, const void *p2) |
e72fcfe8 JH |
88 | { |
89 | return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) == | |
1668aabc | 90 | (tree) p2); |
e72fcfe8 JH |
91 | } |
92 | ||
93 | /* Return cgraph node assigned to DECL. Create new one when needed. */ | |
1c4a429a | 94 | struct cgraph_node * |
439f7bc3 | 95 | cgraph_node (tree decl) |
e72fcfe8 JH |
96 | { |
97 | struct cgraph_node *node; | |
98 | struct cgraph_node **slot; | |
99 | ||
988d1653 JH |
100 | if (TREE_CODE (decl) != FUNCTION_DECL) |
101 | abort (); | |
102 | ||
e72fcfe8 | 103 | if (!cgraph_hash) |
ed2df68b | 104 | cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); |
e72fcfe8 | 105 | |
ed2df68b JH |
106 | slot = (struct cgraph_node **) |
107 | htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (decl), | |
108 | IDENTIFIER_HASH_VALUE | |
b97e92ed | 109 | (DECL_ASSEMBLER_NAME (decl)), INSERT); |
e72fcfe8 JH |
110 | if (*slot) |
111 | return *slot; | |
ed2df68b | 112 | node = ggc_alloc_cleared (sizeof (*node)); |
e72fcfe8 JH |
113 | node->decl = decl; |
114 | node->next = cgraph_nodes; | |
b58b1157 | 115 | node->uid = cgraph_max_uid++; |
18d13f34 JH |
116 | if (cgraph_nodes) |
117 | cgraph_nodes->previous = node; | |
118 | node->previous = NULL; | |
e72fcfe8 JH |
119 | cgraph_nodes = node; |
120 | cgraph_n_nodes++; | |
121 | *slot = node; | |
5c2e00ee | 122 | if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) |
e72fcfe8 JH |
123 | { |
124 | node->origin = cgraph_node (DECL_CONTEXT (decl)); | |
125 | node->next_nested = node->origin->nested; | |
126 | node->origin->nested = node; | |
127 | } | |
128 | return node; | |
129 | } | |
130 | ||
1668aabc JH |
131 | /* Try to find existing function for identifier ID. */ |
132 | struct cgraph_node * | |
439f7bc3 | 133 | cgraph_node_for_identifier (tree id) |
1668aabc JH |
134 | { |
135 | struct cgraph_node **slot; | |
136 | ||
137 | if (TREE_CODE (id) != IDENTIFIER_NODE) | |
138 | abort (); | |
139 | ||
140 | if (!cgraph_hash) | |
e69529cd | 141 | return NULL; |
1668aabc | 142 | |
ed2df68b JH |
143 | slot = (struct cgraph_node **) |
144 | htab_find_slot_with_hash (cgraph_hash, id, | |
b97e92ed | 145 | IDENTIFIER_HASH_VALUE (id), NO_INSERT); |
1668aabc JH |
146 | if (!slot) |
147 | return NULL; | |
148 | return *slot; | |
149 | } | |
150 | ||
e72fcfe8 JH |
151 | /* Create edge from CALLER to CALLEE in the cgraph. */ |
152 | ||
153 | static struct cgraph_edge * | |
439f7bc3 | 154 | create_edge (struct cgraph_node *caller, struct cgraph_node *callee) |
e72fcfe8 | 155 | { |
ed2df68b | 156 | struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); |
b58b1157 JH |
157 | struct cgraph_edge *edge2; |
158 | ||
159 | edge->inline_call = false; | |
160 | /* At the moment we don't associate calls with specific CALL_EXPRs | |
161 | as we probably ought to, so we must preserve inline_call flags to | |
162 | be the same in all copies of the same edge. */ | |
163 | if (cgraph_global_info_ready) | |
fdacb904 | 164 | for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee) |
b58b1157 JH |
165 | if (edge2->callee == callee) |
166 | { | |
167 | edge->inline_call = edge2->inline_call; | |
168 | break; | |
169 | } | |
e72fcfe8 JH |
170 | |
171 | edge->caller = caller; | |
172 | edge->callee = callee; | |
173 | edge->next_caller = callee->callers; | |
174 | edge->next_callee = caller->callees; | |
175 | caller->callees = edge; | |
176 | callee->callers = edge; | |
177 | return edge; | |
178 | } | |
179 | ||
180 | /* Remove the edge from CALLER to CALLEE in the cgraph. */ | |
181 | ||
cb967da5 | 182 | void |
439f7bc3 | 183 | cgraph_remove_edge (struct cgraph_node *caller, struct cgraph_node *callee) |
e72fcfe8 JH |
184 | { |
185 | struct cgraph_edge **edge, **edge2; | |
186 | ||
187 | for (edge = &callee->callers; *edge && (*edge)->caller != caller; | |
188 | edge = &((*edge)->next_caller)) | |
189 | continue; | |
190 | if (!*edge) | |
191 | abort (); | |
192 | *edge = (*edge)->next_caller; | |
193 | for (edge2 = &caller->callees; *edge2 && (*edge2)->callee != callee; | |
194 | edge2 = &(*edge2)->next_callee) | |
195 | continue; | |
196 | if (!*edge2) | |
197 | abort (); | |
198 | *edge2 = (*edge2)->next_callee; | |
199 | } | |
200 | ||
18d13f34 JH |
201 | /* Remove the node from cgraph. */ |
202 | ||
203 | void | |
439f7bc3 | 204 | cgraph_remove_node (struct cgraph_node *node) |
18d13f34 | 205 | { |
2ee1067b | 206 | void **slot; |
18d13f34 JH |
207 | while (node->callers) |
208 | cgraph_remove_edge (node->callers->caller, node); | |
209 | while (node->callees) | |
210 | cgraph_remove_edge (node, node->callees->callee); | |
211 | while (node->nested) | |
212 | cgraph_remove_node (node->nested); | |
213 | if (node->origin) | |
214 | { | |
215 | struct cgraph_node **node2 = &node->origin->nested; | |
216 | ||
217 | while (*node2 != node) | |
218 | node2 = &(*node2)->next_nested; | |
219 | *node2 = node->next_nested; | |
220 | } | |
221 | if (node->previous) | |
222 | node->previous->next = node->next; | |
223 | else | |
224 | cgraph_nodes = node; | |
225 | if (node->next) | |
226 | node->next->previous = node->previous; | |
227 | DECL_SAVED_TREE (node->decl) = NULL; | |
2ee1067b JH |
228 | slot = |
229 | htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (node->decl), | |
230 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
b97e92ed | 231 | (node->decl)), NO_INSERT); |
2ee1067b | 232 | htab_clear_slot (cgraph_hash, slot); |
18d13f34 JH |
233 | /* Do not free the structure itself so the walk over chain can continue. */ |
234 | } | |
235 | ||
8dafba3c RH |
236 | /* Notify finalize_compilation_unit that given node is reachable. */ |
237 | ||
1668aabc | 238 | void |
8dafba3c | 239 | cgraph_mark_reachable_node (struct cgraph_node *node) |
1668aabc | 240 | { |
ba245151 | 241 | if (!node->reachable && node->local.finalized) |
1668aabc | 242 | { |
ba245151 | 243 | notice_global_symbol (node->decl); |
1668aabc | 244 | node->reachable = 1; |
e767b5be JH |
245 | |
246 | node->next_needed = cgraph_nodes_queue; | |
247 | cgraph_nodes_queue = node; | |
248 | ||
249 | /* At the moment frontend automatically emits all nested functions. */ | |
250 | if (node->nested) | |
1668aabc | 251 | { |
e767b5be JH |
252 | struct cgraph_node *node2; |
253 | ||
254 | for (node2 = node->nested; node2; node2 = node2->next_nested) | |
255 | if (!node2->reachable) | |
8dafba3c | 256 | cgraph_mark_reachable_node (node2); |
e767b5be | 257 | } |
1668aabc JH |
258 | } |
259 | } | |
260 | ||
8dafba3c RH |
261 | /* Likewise indicate that a node is needed, i.e. reachable via some |
262 | external means. */ | |
263 | ||
264 | void | |
265 | cgraph_mark_needed_node (struct cgraph_node *node) | |
266 | { | |
267 | node->needed = 1; | |
268 | cgraph_mark_reachable_node (node); | |
269 | } | |
18d13f34 | 270 | |
6614fd40 | 271 | /* Record call from CALLER to CALLEE. */ |
e72fcfe8 | 272 | |
1c4a429a | 273 | struct cgraph_edge * |
439f7bc3 | 274 | cgraph_record_call (tree caller, tree callee) |
e72fcfe8 JH |
275 | { |
276 | return create_edge (cgraph_node (caller), cgraph_node (callee)); | |
277 | } | |
278 | ||
279 | void | |
439f7bc3 | 280 | cgraph_remove_call (tree caller, tree callee) |
e72fcfe8 | 281 | { |
18d13f34 | 282 | cgraph_remove_edge (cgraph_node (caller), cgraph_node (callee)); |
e72fcfe8 JH |
283 | } |
284 | ||
285 | /* Return true when CALLER_DECL calls CALLEE_DECL. */ | |
286 | ||
287 | bool | |
439f7bc3 | 288 | cgraph_calls_p (tree caller_decl, tree callee_decl) |
e72fcfe8 JH |
289 | { |
290 | struct cgraph_node *caller = cgraph_node (caller_decl); | |
291 | struct cgraph_node *callee = cgraph_node (callee_decl); | |
292 | struct cgraph_edge *edge; | |
293 | ||
294 | for (edge = callee->callers; edge && (edge)->caller != caller; | |
295 | edge = (edge->next_caller)) | |
296 | continue; | |
297 | return edge != NULL; | |
298 | } | |
299 | ||
dafc5b82 JH |
300 | /* Return local info for the compiled function. */ |
301 | ||
302 | struct cgraph_local_info * | |
439f7bc3 | 303 | cgraph_local_info (tree decl) |
dafc5b82 JH |
304 | { |
305 | struct cgraph_node *node; | |
306 | if (TREE_CODE (decl) != FUNCTION_DECL) | |
307 | abort (); | |
308 | node = cgraph_node (decl); | |
309 | return &node->local; | |
310 | } | |
311 | ||
312 | /* Return local info for the compiled function. */ | |
313 | ||
314 | struct cgraph_global_info * | |
439f7bc3 | 315 | cgraph_global_info (tree decl) |
dafc5b82 JH |
316 | { |
317 | struct cgraph_node *node; | |
318 | if (TREE_CODE (decl) != FUNCTION_DECL || !cgraph_global_info_ready) | |
319 | abort (); | |
320 | node = cgraph_node (decl); | |
321 | return &node->global; | |
322 | } | |
323 | ||
b255a036 JH |
324 | /* Return local info for the compiled function. */ |
325 | ||
326 | struct cgraph_rtl_info * | |
439f7bc3 | 327 | cgraph_rtl_info (tree decl) |
b255a036 JH |
328 | { |
329 | struct cgraph_node *node; | |
330 | if (TREE_CODE (decl) != FUNCTION_DECL) | |
331 | abort (); | |
332 | node = cgraph_node (decl); | |
333 | if (decl != current_function_decl | |
334 | && !TREE_ASM_WRITTEN (node->decl)) | |
335 | return NULL; | |
336 | return &node->rtl; | |
337 | } | |
338 | ||
a194aa56 JH |
339 | /* Return name of the node used in debug output. */ |
340 | const char * | |
439f7bc3 | 341 | cgraph_node_name (struct cgraph_node *node) |
a194aa56 JH |
342 | { |
343 | return (*lang_hooks.decl_printable_name) (node->decl, 2); | |
344 | } | |
dafc5b82 | 345 | |
e72fcfe8 JH |
346 | /* Dump the callgraph. */ |
347 | ||
348 | void | |
439f7bc3 | 349 | dump_cgraph (FILE *f) |
e72fcfe8 JH |
350 | { |
351 | struct cgraph_node *node; | |
352 | ||
7d82fe7c | 353 | fprintf (f, "callgraph:\n\n"); |
e72fcfe8 JH |
354 | for (node = cgraph_nodes; node; node = node->next) |
355 | { | |
356 | struct cgraph_edge *edge; | |
7d82fe7c | 357 | fprintf (f, "%s:", cgraph_node_name (node)); |
b58b1157 JH |
358 | if (node->local.self_insns) |
359 | fprintf (f, " %i insns", node->local.self_insns); | |
7d82fe7c KC |
360 | if (node->global.insns && node->global.insns != node->local.self_insns) |
361 | fprintf (f, " (%i after inlining)", node->global.insns); | |
e72fcfe8 | 362 | if (node->origin) |
a194aa56 | 363 | fprintf (f, " nested in: %s", cgraph_node_name (node->origin)); |
e72fcfe8 JH |
364 | if (node->needed) |
365 | fprintf (f, " needed"); | |
366 | else if (node->reachable) | |
367 | fprintf (f, " reachable"); | |
368 | if (DECL_SAVED_TREE (node->decl)) | |
369 | fprintf (f, " tree"); | |
370 | ||
7d82fe7c KC |
371 | if (node->local.local) |
372 | fprintf (f, " local"); | |
b3c3af2f | 373 | if (node->local.disregard_inline_limits) |
b58b1157 JH |
374 | fprintf (f, " always_inline"); |
375 | else if (node->local.inlinable) | |
376 | fprintf (f, " inlinable"); | |
b58b1157 JH |
377 | if (node->global.cloned_times > 1) |
378 | fprintf (f, " cloned %ix", node->global.cloned_times); | |
b58b1157 | 379 | |
7dd87381 | 380 | fprintf (f, "\n called by: "); |
e72fcfe8 | 381 | for (edge = node->callers; edge; edge = edge->next_caller) |
b58b1157 JH |
382 | { |
383 | fprintf (f, "%s ", cgraph_node_name (edge->caller)); | |
384 | if (edge->inline_call) | |
385 | fprintf(f, "(inlined) "); | |
386 | } | |
e72fcfe8 JH |
387 | |
388 | fprintf (f, "\n calls: "); | |
389 | for (edge = node->callees; edge; edge = edge->next_callee) | |
b58b1157 JH |
390 | { |
391 | fprintf (f, "%s ", cgraph_node_name (edge->callee)); | |
392 | if (edge->inline_call) | |
393 | fprintf(f, "(inlined) "); | |
394 | } | |
e72fcfe8 JH |
395 | fprintf (f, "\n"); |
396 | } | |
397 | } | |
988d1653 | 398 | |
e69529cd JH |
399 | /* Returns a hash code for P. */ |
400 | ||
401 | static hashval_t | |
439f7bc3 | 402 | cgraph_varpool_hash_node (const void *p) |
e69529cd | 403 | { |
ed2df68b JH |
404 | return ((hashval_t) |
405 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
406 | (((struct cgraph_varpool_node *) p)->decl))); | |
e69529cd JH |
407 | } |
408 | ||
f1ba665b | 409 | /* Returns nonzero if P1 and P2 are equal. */ |
e69529cd JH |
410 | |
411 | static int | |
439f7bc3 | 412 | eq_cgraph_varpool_node (const void *p1, const void *p2) |
e69529cd JH |
413 | { |
414 | return ((DECL_ASSEMBLER_NAME (((struct cgraph_varpool_node *) p1)->decl)) == | |
415 | (tree) p2); | |
416 | } | |
417 | ||
418 | /* Return cgraph_varpool node assigned to DECL. Create new one when needed. */ | |
419 | struct cgraph_varpool_node * | |
420 | cgraph_varpool_node (tree decl) | |
421 | { | |
422 | struct cgraph_varpool_node *node; | |
423 | struct cgraph_varpool_node **slot; | |
424 | ||
425 | if (!DECL_P (decl) || TREE_CODE (decl) == FUNCTION_DECL) | |
426 | abort (); | |
427 | ||
428 | if (!cgraph_varpool_hash) | |
ed2df68b JH |
429 | cgraph_varpool_hash = htab_create_ggc (10, cgraph_varpool_hash_node, |
430 | eq_cgraph_varpool_node, NULL); | |
ed2df68b JH |
431 | slot = (struct cgraph_varpool_node **) |
432 | htab_find_slot_with_hash (cgraph_varpool_hash, DECL_ASSEMBLER_NAME (decl), | |
433 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (decl)), | |
b97e92ed | 434 | INSERT); |
e69529cd JH |
435 | if (*slot) |
436 | return *slot; | |
ed2df68b | 437 | node = ggc_alloc_cleared (sizeof (*node)); |
e69529cd JH |
438 | node->decl = decl; |
439 | cgraph_varpool_n_nodes++; | |
ed2df68b | 440 | cgraph_varpool_nodes = node; |
e69529cd | 441 | *slot = node; |
e69529cd JH |
442 | return node; |
443 | } | |
444 | ||
fccc4eb2 JH |
445 | /* Set the DECL_ASSEMBLER_NAME and update cgraph hashtables. */ |
446 | void | |
447 | change_decl_assembler_name (tree decl, tree name) | |
448 | { | |
449 | struct cgraph_node *node = NULL; | |
450 | struct cgraph_varpool_node *vnode = NULL; | |
451 | void **slot; | |
452 | ||
453 | if (!DECL_ASSEMBLER_NAME_SET_P (decl)) | |
454 | { | |
455 | SET_DECL_ASSEMBLER_NAME (decl, name); | |
456 | return; | |
457 | } | |
458 | if (name == DECL_ASSEMBLER_NAME (decl)) | |
459 | return; | |
460 | ||
df964a18 JH |
461 | if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) |
462 | && DECL_RTL_SET_P (decl)) | |
fccc4eb2 JH |
463 | warning ("%D renamed after being referenced in assembly", decl); |
464 | ||
465 | if (TREE_CODE (decl) == FUNCTION_DECL && cgraph_hash) | |
466 | { | |
467 | /* Take a look whether declaration is in the cgraph structure. */ | |
468 | slot = | |
469 | htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (decl), | |
470 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
471 | (decl)), NO_INSERT); | |
472 | if (slot) | |
473 | node = *slot; | |
474 | ||
475 | /* It is, verify that we are the canonical node for this decl. */ | |
476 | if (node && node->decl == decl) | |
477 | { | |
478 | node = *slot; | |
479 | htab_clear_slot (cgraph_hash, slot); | |
480 | } | |
481 | else | |
482 | node = NULL; | |
483 | } | |
484 | if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) && cgraph_varpool_hash) | |
485 | { | |
486 | /* Take a look whether declaration is in the cgraph structure. */ | |
487 | slot = | |
488 | htab_find_slot_with_hash (cgraph_varpool_hash, DECL_ASSEMBLER_NAME (decl), | |
489 | IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME | |
490 | (decl)), NO_INSERT); | |
491 | if (slot) | |
492 | vnode = *slot; | |
493 | ||
494 | /* It is, verify that we are the canonical vnode for this decl. */ | |
495 | if (vnode && vnode->decl == decl) | |
496 | { | |
497 | vnode = *slot; | |
498 | htab_clear_slot (cgraph_varpool_hash, slot); | |
499 | } | |
500 | else | |
501 | vnode = NULL; | |
502 | } | |
503 | SET_DECL_ASSEMBLER_NAME (decl, name); | |
504 | if (node) | |
505 | { | |
506 | slot = | |
507 | htab_find_slot_with_hash (cgraph_hash, name, | |
508 | IDENTIFIER_HASH_VALUE (name), INSERT); | |
509 | if (*slot) | |
510 | abort (); | |
511 | *slot = node; | |
512 | } | |
513 | if (vnode) | |
514 | { | |
515 | slot = | |
516 | htab_find_slot_with_hash (cgraph_varpool_hash, name, | |
517 | IDENTIFIER_HASH_VALUE (name), INSERT); | |
518 | if (*slot) | |
519 | abort (); | |
520 | *slot = vnode; | |
521 | } | |
522 | } | |
523 | ||
e69529cd JH |
524 | /* Try to find existing function for identifier ID. */ |
525 | struct cgraph_varpool_node * | |
526 | cgraph_varpool_node_for_identifier (tree id) | |
527 | { | |
528 | struct cgraph_varpool_node **slot; | |
529 | ||
530 | if (TREE_CODE (id) != IDENTIFIER_NODE) | |
531 | abort (); | |
532 | ||
533 | if (!cgraph_varpool_hash) | |
534 | return NULL; | |
535 | ||
ed2df68b JH |
536 | slot = (struct cgraph_varpool_node **) |
537 | htab_find_slot_with_hash (cgraph_varpool_hash, id, | |
b97e92ed | 538 | IDENTIFIER_HASH_VALUE (id), NO_INSERT); |
e69529cd JH |
539 | if (!slot) |
540 | return NULL; | |
541 | return *slot; | |
542 | } | |
543 | ||
544 | /* Notify finalize_compilation_unit that given node is reachable | |
545 | or needed. */ | |
546 | void | |
547 | cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node) | |
548 | { | |
549 | if (!node->needed && node->finalized) | |
550 | { | |
8bd87c4e | 551 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd | 552 | cgraph_varpool_nodes_queue = node; |
810db579 | 553 | notice_global_symbol (node->decl); |
e69529cd JH |
554 | } |
555 | node->needed = 1; | |
556 | } | |
557 | ||
558 | void | |
559 | cgraph_varpool_finalize_decl (tree decl) | |
560 | { | |
561 | struct cgraph_varpool_node *node = cgraph_varpool_node (decl); | |
d853a20e JH |
562 | |
563 | /* The first declaration of a variable that comes through this function | |
564 | decides whether it is global (in C, has external linkage) | |
565 | or local (in C, has internal linkage). So do nothing more | |
566 | if this function has already run. */ | |
567 | if (node->finalized) | |
568 | return; | |
569 | if (node->needed) | |
e69529cd | 570 | { |
8bd87c4e | 571 | node->next_needed = cgraph_varpool_nodes_queue; |
e69529cd | 572 | cgraph_varpool_nodes_queue = node; |
ba245151 | 573 | notice_global_symbol (decl); |
e69529cd JH |
574 | } |
575 | node->finalized = true; | |
576 | ||
577 | if (/* Externally visible variables must be output. The exception are | |
578 | COMDAT functions that must be output only when they are needed. */ | |
579 | (TREE_PUBLIC (decl) && !DECL_COMDAT (decl)) | |
580 | /* Function whose name is output to the assembler file must be produced. | |
581 | It is possible to assemble the name later after finalizing the function | |
582 | and the fact is noticed in assemble_name then. */ | |
583 | || (DECL_ASSEMBLER_NAME_SET_P (decl) | |
584 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) | |
585 | { | |
586 | cgraph_varpool_mark_needed_node (node); | |
587 | } | |
588 | } | |
589 | ||
590 | bool | |
439f7bc3 | 591 | cgraph_varpool_assemble_pending_decls (void) |
e69529cd JH |
592 | { |
593 | bool changed = false; | |
594 | ||
595 | while (cgraph_varpool_nodes_queue) | |
596 | { | |
597 | tree decl = cgraph_varpool_nodes_queue->decl; | |
598 | struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue; | |
599 | ||
8bd87c4e | 600 | cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed; |
e69529cd JH |
601 | if (!TREE_ASM_WRITTEN (decl)) |
602 | { | |
603 | assemble_variable (decl, 0, 1, 0); | |
604 | changed = true; | |
605 | } | |
8bd87c4e | 606 | node->next_needed = NULL; |
e69529cd JH |
607 | } |
608 | return changed; | |
609 | } | |
610 | ||
1bb17c21 JH |
611 | /* Return true when the DECL can possibly be inlined. */ |
612 | bool | |
613 | cgraph_function_possibly_inlined_p (tree decl) | |
614 | { | |
1bb17c21 | 615 | if (!cgraph_global_info_ready) |
b684a3df JH |
616 | return (DECL_INLINE (decl) |
617 | && (!flag_really_no_inline | |
618 | || (*lang_hooks.tree_inlining.disregard_inline_limits) (decl))); | |
1bb17c21 JH |
619 | return cgraph_node (decl)->global.inlined; |
620 | } | |
e69529cd | 621 | |
988d1653 | 622 | #include "gt-cgraph.h" |