]>
Commit | Line | Data |
---|---|---|
e72fcfe8 | 1 | /* Callgraph handling code. |
4139c7ef | 2 | Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
2bafad93 | 3 | Free Software Foundation, Inc. |
e72fcfe8 JH |
4 | Contributed by Jan Hubicka |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 10 | Software Foundation; either version 3, or (at your option) any later |
e72fcfe8 JH |
11 | version. |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
e72fcfe8 | 21 | |
8a4a83ed | 22 | /* This file contains basic routines manipulating call graph |
c22cacf3 | 23 | |
18c6ada9 JH |
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. | |
0550e7b7 | 31 | Each function (external or not) corresponds to the unique node. |
18c6ada9 JH |
32 | |
33 | The mapping from declarations to call-graph nodes is done using hash table | |
0550e7b7 JH |
34 | based on DECL_UID. The call-graph nodes are created lazily using |
35 | cgraph_node function when called for unknown declaration. | |
18c6ada9 | 36 | |
e33c6cd6 MJ |
37 | The callgraph at the moment does not represent all indirect calls or calls |
38 | from other compilation units. Flag NEEDED is set for each node that may be | |
39 | accessed in such an invisible way and it shall be considered an entry point | |
40 | to the callgraph. | |
41 | ||
42 | On the other hand, the callgraph currently does contain some edges for | |
43 | indirect calls with unknown callees which can be accessed through | |
44 | indirect_calls field of a node. It should be noted however that at the | |
45 | moment only calls which are potential candidates for indirect inlining are | |
46 | added there. | |
18c6ada9 | 47 | |
a418679d | 48 | Interprocedural information: |
18c6ada9 | 49 | |
a418679d | 50 | Callgraph is place to store data needed for interprocedural optimization. |
1ae58c30 | 51 | All data structures are divided into three components: local_info that |
18c6ada9 | 52 | is produced while analyzing the function, global_info that is result |
1ae58c30 | 53 | of global walking of the callgraph on the end of compilation and |
18c6ada9 JH |
54 | rtl_info used by RTL backend to propagate data from already compiled |
55 | functions to their callers. | |
56 | ||
e33c6cd6 MJ |
57 | Moreover, each node has a uid which can be used to keep information in |
58 | on-the-side arrays. UIDs are reused and therefore reasonably dense. | |
59 | ||
18c6ada9 JH |
60 | Inlining plans: |
61 | ||
62 | The function inlining information is decided in advance and maintained | |
63 | in the callgraph as so called inline plan. | |
1ae58c30 | 64 | For each inlined call, the callee's node is cloned to represent the |
1ea7e6ad | 65 | new function copy produced by inliner. |
1ae58c30 KH |
66 | Each inlined call gets a unique corresponding clone node of the callee |
67 | and the data structure is updated while inlining is performed, so | |
68 | the clones are eliminated and their callee edges redirected to the | |
c22cacf3 | 69 | caller. |
18c6ada9 JH |
70 | |
71 | Each edge has "inline_failed" field. When the field is set to NULL, | |
2b8a92de | 72 | the call will be inlined. When it is non-NULL it contains a reason |
8a4a83ed | 73 | why inlining wasn't performed. */ |
18c6ada9 | 74 | |
e72fcfe8 JH |
75 | #include "config.h" |
76 | #include "system.h" | |
77 | #include "coretypes.h" | |
78 | #include "tm.h" | |
79 | #include "tree.h" | |
cd9c7bd2 | 80 | #include "tree-inline.h" |
e72fcfe8 JH |
81 | #include "langhooks.h" |
82 | #include "hashtab.h" | |
83 | #include "toplev.h" | |
84 | #include "flags.h" | |
85 | #include "ggc.h" | |
86 | #include "debug.h" | |
87 | #include "target.h" | |
cd9c7bd2 | 88 | #include "basic-block.h" |
1c4a429a | 89 | #include "cgraph.h" |
e69529cd | 90 | #include "output.h" |
dc0bfe6a | 91 | #include "intl.h" |
726a989a | 92 | #include "gimple.h" |
ef330312 | 93 | #include "tree-dump.h" |
7a388ee4 | 94 | #include "tree-flow.h" |
a63f2942 | 95 | #include "value-prof.h" |
f9417da1 | 96 | #include "except.h" |
1da2ed5f | 97 | #include "diagnostic-core.h" |
715a4e08 | 98 | #include "rtl.h" |
a940b4d9 | 99 | #include "ipa-utils.h" |
99fecd47 | 100 | #include "lto-streamer.h" |
e7f23018 | 101 | #include "ipa-inline.h" |
988d1653 | 102 | |
671769c3 JH |
103 | const char * const ld_plugin_symbol_resolution_names[]= |
104 | { | |
105 | "", | |
106 | "undef", | |
107 | "prevailing_def", | |
108 | "prevailing_def_ironly", | |
109 | "preempted_reg", | |
110 | "preempted_ir", | |
111 | "resolved_ir", | |
112 | "resolved_exec", | |
ed0d2da0 JH |
113 | "resolved_dyn", |
114 | "prevailing_def_ironly_exp" | |
671769c3 JH |
115 | }; |
116 | ||
2563c224 RG |
117 | static void cgraph_node_remove_callers (struct cgraph_node *node); |
118 | static inline void cgraph_edge_remove_caller (struct cgraph_edge *e); | |
119 | static inline void cgraph_edge_remove_callee (struct cgraph_edge *e); | |
120 | ||
e72fcfe8 | 121 | /* Hash table used to convert declarations into nodes. */ |
ed2df68b | 122 | static GTY((param_is (struct cgraph_node))) htab_t cgraph_hash; |
266ad5c8 JH |
123 | /* Hash table used to convert assembler names into nodes. */ |
124 | static GTY((param_is (struct cgraph_node))) htab_t assembler_name_hash; | |
e72fcfe8 JH |
125 | |
126 | /* The linked list of cgraph nodes. */ | |
1c4a429a | 127 | struct cgraph_node *cgraph_nodes; |
e72fcfe8 | 128 | |
1668aabc JH |
129 | /* Queue of cgraph nodes scheduled to be lowered. */ |
130 | struct cgraph_node *cgraph_nodes_queue; | |
131 | ||
f45e0ad1 | 132 | /* Queue of cgraph nodes scheduled to be added into cgraph. This is a |
c0220ea4 | 133 | secondary queue used during optimization to accommodate passes that |
50674e96 | 134 | may generate new functions that need to be optimized and expanded. */ |
f45e0ad1 | 135 | struct cgraph_node *cgraph_new_nodes; |
953ff289 | 136 | |
e72fcfe8 | 137 | /* Number of nodes in existence. */ |
1c4a429a | 138 | int cgraph_n_nodes; |
e72fcfe8 | 139 | |
b58b1157 JH |
140 | /* Maximal uid used in cgraph nodes. */ |
141 | int cgraph_max_uid; | |
142 | ||
9088c1cc MJ |
143 | /* Maximal uid used in cgraph edges. */ |
144 | int cgraph_edge_max_uid; | |
145 | ||
dafc5b82 JH |
146 | /* Set when whole unit has been analyzed so we can access global info. */ |
147 | bool cgraph_global_info_ready = false; | |
148 | ||
f45e0ad1 JH |
149 | /* What state callgraph is in right now. */ |
150 | enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION; | |
151 | ||
cd9c7bd2 JH |
152 | /* Set when the cgraph is fully build and the basic flags are computed. */ |
153 | bool cgraph_function_flags_ready = false; | |
154 | ||
474eccc6 ILT |
155 | /* Linked list of cgraph asm nodes. */ |
156 | struct cgraph_asm_node *cgraph_asm_nodes; | |
157 | ||
158 | /* Last node in cgraph_asm_nodes. */ | |
159 | static GTY(()) struct cgraph_asm_node *cgraph_asm_last_node; | |
160 | ||
161 | /* The order index of the next cgraph node to be created. This is | |
162 | used so that we can sort the cgraph nodes in order by when we saw | |
163 | them, to support -fno-toplevel-reorder. */ | |
164 | int cgraph_order; | |
165 | ||
61502ca8 | 166 | /* List of hooks triggered on cgraph_edge events. */ |
9088c1cc MJ |
167 | struct cgraph_edge_hook_list { |
168 | cgraph_edge_hook hook; | |
169 | void *data; | |
170 | struct cgraph_edge_hook_list *next; | |
171 | }; | |
172 | ||
61502ca8 | 173 | /* List of hooks triggered on cgraph_node events. */ |
9088c1cc MJ |
174 | struct cgraph_node_hook_list { |
175 | cgraph_node_hook hook; | |
176 | void *data; | |
177 | struct cgraph_node_hook_list *next; | |
178 | }; | |
179 | ||
61502ca8 | 180 | /* List of hooks triggered on events involving two cgraph_edges. */ |
9088c1cc MJ |
181 | struct cgraph_2edge_hook_list { |
182 | cgraph_2edge_hook hook; | |
183 | void *data; | |
184 | struct cgraph_2edge_hook_list *next; | |
185 | }; | |
186 | ||
61502ca8 | 187 | /* List of hooks triggered on events involving two cgraph_nodes. */ |
9088c1cc MJ |
188 | struct cgraph_2node_hook_list { |
189 | cgraph_2node_hook hook; | |
190 | void *data; | |
191 | struct cgraph_2node_hook_list *next; | |
192 | }; | |
193 | ||
194 | /* List of hooks triggered when an edge is removed. */ | |
195 | struct cgraph_edge_hook_list *first_cgraph_edge_removal_hook; | |
196 | /* List of hooks triggered when a node is removed. */ | |
197 | struct cgraph_node_hook_list *first_cgraph_node_removal_hook; | |
198 | /* List of hooks triggered when an edge is duplicated. */ | |
199 | struct cgraph_2edge_hook_list *first_cgraph_edge_duplicated_hook; | |
200 | /* List of hooks triggered when a node is duplicated. */ | |
201 | struct cgraph_2node_hook_list *first_cgraph_node_duplicated_hook; | |
129a37fc JH |
202 | /* List of hooks triggered when an function is inserted. */ |
203 | struct cgraph_node_hook_list *first_cgraph_function_insertion_hook; | |
9088c1cc | 204 | |
2fb16412 MJ |
205 | /* Head of a linked list of unused (freed) call graph nodes. |
206 | Do not GTY((delete)) this list so UIDs gets reliably recycled. */ | |
207 | static GTY(()) struct cgraph_node *free_nodes; | |
934cb78a MJ |
208 | /* Head of a linked list of unused (freed) call graph edges. |
209 | Do not GTY((delete)) this list so UIDs gets reliably recycled. */ | |
210 | static GTY(()) struct cgraph_edge *free_edges; | |
211 | ||
39e2db00 JH |
212 | /* Did procss_same_body_aliases run? */ |
213 | bool same_body_aliases_done; | |
214 | ||
2fb16412 MJ |
215 | /* Macros to access the next item in the list of free cgraph nodes and |
216 | edges. */ | |
217 | #define NEXT_FREE_NODE(NODE) (NODE)->next | |
934cb78a | 218 | #define NEXT_FREE_EDGE(EDGE) (EDGE)->prev_caller |
9088c1cc MJ |
219 | |
220 | /* Register HOOK to be called with DATA on each removed edge. */ | |
221 | struct cgraph_edge_hook_list * | |
222 | cgraph_add_edge_removal_hook (cgraph_edge_hook hook, void *data) | |
223 | { | |
224 | struct cgraph_edge_hook_list *entry; | |
225 | struct cgraph_edge_hook_list **ptr = &first_cgraph_edge_removal_hook; | |
226 | ||
227 | entry = (struct cgraph_edge_hook_list *) xmalloc (sizeof (*entry)); | |
228 | entry->hook = hook; | |
229 | entry->data = data; | |
230 | entry->next = NULL; | |
231 | while (*ptr) | |
232 | ptr = &(*ptr)->next; | |
233 | *ptr = entry; | |
234 | return entry; | |
235 | } | |
236 | ||
237 | /* Remove ENTRY from the list of hooks called on removing edges. */ | |
238 | void | |
239 | cgraph_remove_edge_removal_hook (struct cgraph_edge_hook_list *entry) | |
240 | { | |
241 | struct cgraph_edge_hook_list **ptr = &first_cgraph_edge_removal_hook; | |
242 | ||
243 | while (*ptr != entry) | |
244 | ptr = &(*ptr)->next; | |
245 | *ptr = entry->next; | |
934cb78a | 246 | free (entry); |
9088c1cc MJ |
247 | } |
248 | ||
249 | /* Call all edge removal hooks. */ | |
250 | static void | |
251 | cgraph_call_edge_removal_hooks (struct cgraph_edge *e) | |
252 | { | |
253 | struct cgraph_edge_hook_list *entry = first_cgraph_edge_removal_hook; | |
254 | while (entry) | |
255 | { | |
256 | entry->hook (e, entry->data); | |
257 | entry = entry->next; | |
258 | } | |
259 | } | |
260 | ||
261 | /* Register HOOK to be called with DATA on each removed node. */ | |
262 | struct cgraph_node_hook_list * | |
263 | cgraph_add_node_removal_hook (cgraph_node_hook hook, void *data) | |
264 | { | |
265 | struct cgraph_node_hook_list *entry; | |
266 | struct cgraph_node_hook_list **ptr = &first_cgraph_node_removal_hook; | |
267 | ||
268 | entry = (struct cgraph_node_hook_list *) xmalloc (sizeof (*entry)); | |
269 | entry->hook = hook; | |
270 | entry->data = data; | |
271 | entry->next = NULL; | |
272 | while (*ptr) | |
273 | ptr = &(*ptr)->next; | |
274 | *ptr = entry; | |
275 | return entry; | |
276 | } | |
277 | ||
278 | /* Remove ENTRY from the list of hooks called on removing nodes. */ | |
279 | void | |
280 | cgraph_remove_node_removal_hook (struct cgraph_node_hook_list *entry) | |
281 | { | |
282 | struct cgraph_node_hook_list **ptr = &first_cgraph_node_removal_hook; | |
283 | ||
284 | while (*ptr != entry) | |
285 | ptr = &(*ptr)->next; | |
286 | *ptr = entry->next; | |
934cb78a | 287 | free (entry); |
9088c1cc MJ |
288 | } |
289 | ||
290 | /* Call all node removal hooks. */ | |
291 | static void | |
292 | cgraph_call_node_removal_hooks (struct cgraph_node *node) | |
293 | { | |
294 | struct cgraph_node_hook_list *entry = first_cgraph_node_removal_hook; | |
295 | while (entry) | |
296 | { | |
297 | entry->hook (node, entry->data); | |
298 | entry = entry->next; | |
299 | } | |
300 | } | |
301 | ||
6544865a | 302 | /* Register HOOK to be called with DATA on each inserted node. */ |
129a37fc JH |
303 | struct cgraph_node_hook_list * |
304 | cgraph_add_function_insertion_hook (cgraph_node_hook hook, void *data) | |
305 | { | |
306 | struct cgraph_node_hook_list *entry; | |
307 | struct cgraph_node_hook_list **ptr = &first_cgraph_function_insertion_hook; | |
308 | ||
309 | entry = (struct cgraph_node_hook_list *) xmalloc (sizeof (*entry)); | |
310 | entry->hook = hook; | |
311 | entry->data = data; | |
312 | entry->next = NULL; | |
313 | while (*ptr) | |
314 | ptr = &(*ptr)->next; | |
315 | *ptr = entry; | |
316 | return entry; | |
317 | } | |
318 | ||
6544865a | 319 | /* Remove ENTRY from the list of hooks called on inserted nodes. */ |
129a37fc JH |
320 | void |
321 | cgraph_remove_function_insertion_hook (struct cgraph_node_hook_list *entry) | |
322 | { | |
323 | struct cgraph_node_hook_list **ptr = &first_cgraph_function_insertion_hook; | |
324 | ||
325 | while (*ptr != entry) | |
326 | ptr = &(*ptr)->next; | |
327 | *ptr = entry->next; | |
934cb78a | 328 | free (entry); |
129a37fc JH |
329 | } |
330 | ||
6544865a | 331 | /* Call all node insertion hooks. */ |
129a37fc JH |
332 | void |
333 | cgraph_call_function_insertion_hooks (struct cgraph_node *node) | |
334 | { | |
335 | struct cgraph_node_hook_list *entry = first_cgraph_function_insertion_hook; | |
336 | while (entry) | |
337 | { | |
338 | entry->hook (node, entry->data); | |
339 | entry = entry->next; | |
340 | } | |
341 | } | |
342 | ||
9088c1cc MJ |
343 | /* Register HOOK to be called with DATA on each duplicated edge. */ |
344 | struct cgraph_2edge_hook_list * | |
345 | cgraph_add_edge_duplication_hook (cgraph_2edge_hook hook, void *data) | |
346 | { | |
347 | struct cgraph_2edge_hook_list *entry; | |
348 | struct cgraph_2edge_hook_list **ptr = &first_cgraph_edge_duplicated_hook; | |
349 | ||
350 | entry = (struct cgraph_2edge_hook_list *) xmalloc (sizeof (*entry)); | |
351 | entry->hook = hook; | |
352 | entry->data = data; | |
353 | entry->next = NULL; | |
354 | while (*ptr) | |
355 | ptr = &(*ptr)->next; | |
356 | *ptr = entry; | |
357 | return entry; | |
358 | } | |
359 | ||
360 | /* Remove ENTRY from the list of hooks called on duplicating edges. */ | |
361 | void | |
362 | cgraph_remove_edge_duplication_hook (struct cgraph_2edge_hook_list *entry) | |
363 | { | |
364 | struct cgraph_2edge_hook_list **ptr = &first_cgraph_edge_duplicated_hook; | |
365 | ||
366 | while (*ptr != entry) | |
367 | ptr = &(*ptr)->next; | |
368 | *ptr = entry->next; | |
934cb78a | 369 | free (entry); |
9088c1cc MJ |
370 | } |
371 | ||
372 | /* Call all edge duplication hooks. */ | |
373 | static void | |
374 | cgraph_call_edge_duplication_hooks (struct cgraph_edge *cs1, | |
375 | struct cgraph_edge *cs2) | |
376 | { | |
377 | struct cgraph_2edge_hook_list *entry = first_cgraph_edge_duplicated_hook; | |
378 | while (entry) | |
379 | { | |
380 | entry->hook (cs1, cs2, entry->data); | |
381 | entry = entry->next; | |
382 | } | |
383 | } | |
384 | ||
385 | /* Register HOOK to be called with DATA on each duplicated node. */ | |
386 | struct cgraph_2node_hook_list * | |
387 | cgraph_add_node_duplication_hook (cgraph_2node_hook hook, void *data) | |
388 | { | |
389 | struct cgraph_2node_hook_list *entry; | |
390 | struct cgraph_2node_hook_list **ptr = &first_cgraph_node_duplicated_hook; | |
391 | ||
392 | entry = (struct cgraph_2node_hook_list *) xmalloc (sizeof (*entry)); | |
393 | entry->hook = hook; | |
394 | entry->data = data; | |
395 | entry->next = NULL; | |
396 | while (*ptr) | |
397 | ptr = &(*ptr)->next; | |
398 | *ptr = entry; | |
399 | return entry; | |
400 | } | |
401 | ||
402 | /* Remove ENTRY from the list of hooks called on duplicating nodes. */ | |
403 | void | |
404 | cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *entry) | |
405 | { | |
406 | struct cgraph_2node_hook_list **ptr = &first_cgraph_node_duplicated_hook; | |
407 | ||
408 | while (*ptr != entry) | |
409 | ptr = &(*ptr)->next; | |
410 | *ptr = entry->next; | |
934cb78a | 411 | free (entry); |
9088c1cc MJ |
412 | } |
413 | ||
414 | /* Call all node duplication hooks. */ | |
415 | static void | |
416 | cgraph_call_node_duplication_hooks (struct cgraph_node *node1, | |
417 | struct cgraph_node *node2) | |
418 | { | |
419 | struct cgraph_2node_hook_list *entry = first_cgraph_node_duplicated_hook; | |
420 | while (entry) | |
421 | { | |
422 | entry->hook (node1, node2, entry->data); | |
423 | entry = entry->next; | |
424 | } | |
425 | } | |
426 | ||
e72fcfe8 JH |
427 | /* Returns a hash code for P. */ |
428 | ||
429 | static hashval_t | |
439f7bc3 | 430 | hash_node (const void *p) |
e72fcfe8 | 431 | { |
cceb1885 | 432 | const struct cgraph_node *n = (const struct cgraph_node *) p; |
6f312d18 | 433 | return (hashval_t) DECL_UID (n->decl); |
e72fcfe8 JH |
434 | } |
435 | ||
4537ec0c | 436 | |
6356f892 | 437 | /* Returns nonzero if P1 and P2 are equal. */ |
e72fcfe8 JH |
438 | |
439 | static int | |
439f7bc3 | 440 | eq_node (const void *p1, const void *p2) |
e72fcfe8 | 441 | { |
cceb1885 GDR |
442 | const struct cgraph_node *n1 = (const struct cgraph_node *) p1; |
443 | const struct cgraph_node *n2 = (const struct cgraph_node *) p2; | |
6f312d18 | 444 | return DECL_UID (n1->decl) == DECL_UID (n2->decl); |
e72fcfe8 JH |
445 | } |
446 | ||
b2583345 | 447 | /* Allocate new callgraph node. */ |
0550e7b7 | 448 | |
b2583345 JJ |
449 | static inline struct cgraph_node * |
450 | cgraph_allocate_node (void) | |
18c6ada9 JH |
451 | { |
452 | struct cgraph_node *node; | |
453 | ||
2fb16412 MJ |
454 | if (free_nodes) |
455 | { | |
456 | node = free_nodes; | |
457 | free_nodes = NEXT_FREE_NODE (node); | |
458 | } | |
459 | else | |
460 | { | |
a9429e29 | 461 | node = ggc_alloc_cleared_cgraph_node (); |
2fb16412 MJ |
462 | node->uid = cgraph_max_uid++; |
463 | } | |
464 | ||
b2583345 JJ |
465 | return node; |
466 | } | |
467 | ||
468 | /* Allocate new callgraph node and insert it into basic data structures. */ | |
469 | ||
470 | static struct cgraph_node * | |
a358e188 | 471 | cgraph_create_node_1 (void) |
b2583345 JJ |
472 | { |
473 | struct cgraph_node *node = cgraph_allocate_node (); | |
474 | ||
18c6ada9 | 475 | node->next = cgraph_nodes; |
474eccc6 | 476 | node->order = cgraph_order++; |
18c6ada9 JH |
477 | if (cgraph_nodes) |
478 | cgraph_nodes->previous = node; | |
479 | node->previous = NULL; | |
5fefcf92 | 480 | node->frequency = NODE_FREQUENCY_NORMAL; |
db0bf14f | 481 | node->count_materialization_scale = REG_BR_PROB_BASE; |
369451ec | 482 | ipa_empty_ref_list (&node->ref_list); |
18c6ada9 JH |
483 | cgraph_nodes = node; |
484 | cgraph_n_nodes++; | |
485 | return node; | |
486 | } | |
487 | ||
e72fcfe8 | 488 | /* Return cgraph node assigned to DECL. Create new one when needed. */ |
0550e7b7 | 489 | |
1c4a429a | 490 | struct cgraph_node * |
a358e188 | 491 | cgraph_create_node (tree decl) |
e72fcfe8 | 492 | { |
6f312d18 | 493 | struct cgraph_node key, *node, **slot; |
e72fcfe8 | 494 | |
341c100f | 495 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); |
988d1653 | 496 | |
e72fcfe8 | 497 | if (!cgraph_hash) |
ed2df68b | 498 | cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); |
e72fcfe8 | 499 | |
6f312d18 | 500 | key.decl = decl; |
6f312d18 | 501 | slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); |
a358e188 | 502 | gcc_assert (!*slot); |
6f312d18 | 503 | |
a358e188 | 504 | node = cgraph_create_node_1 (); |
e72fcfe8 | 505 | node->decl = decl; |
e72fcfe8 | 506 | *slot = node; |
5c2e00ee | 507 | if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) |
e72fcfe8 | 508 | { |
a358e188 | 509 | node->origin = cgraph_get_create_node (DECL_CONTEXT (decl)); |
e72fcfe8 JH |
510 | node->next_nested = node->origin->nested; |
511 | node->origin->nested = node; | |
512 | } | |
1aeaf0f7 JJ |
513 | if (assembler_name_hash) |
514 | { | |
515 | void **aslot; | |
516 | tree name = DECL_ASSEMBLER_NAME (decl); | |
517 | ||
518 | aslot = htab_find_slot_with_hash (assembler_name_hash, name, | |
519 | decl_assembler_name_hash (name), | |
520 | INSERT); | |
521 | /* We can have multiple declarations with same assembler name. For C++ | |
522 | it is __builtin_strlen and strlen, for instance. Do we need to | |
523 | record them all? Original implementation marked just first one | |
524 | so lets hope for the best. */ | |
525 | if (*aslot == NULL) | |
526 | *aslot = node; | |
527 | } | |
e72fcfe8 JH |
528 | return node; |
529 | } | |
530 | ||
a358e188 MJ |
531 | /* Try to find a call graph node for declaration DECL and if it does not exist, |
532 | create it. */ | |
533 | ||
534 | struct cgraph_node * | |
535 | cgraph_get_create_node (tree decl) | |
536 | { | |
537 | struct cgraph_node *node; | |
538 | ||
539 | node = cgraph_get_node (decl); | |
540 | if (node) | |
541 | return node; | |
542 | ||
543 | return cgraph_create_node (decl); | |
544 | } | |
545 | ||
87e7b310 JH |
546 | /* Mark ALIAS as an alias to DECL. DECL_NODE is cgraph node representing |
547 | the function body is associated with (not neccesarily cgraph_node (DECL). */ | |
b2583345 | 548 | |
39e2db00 JH |
549 | struct cgraph_node * |
550 | cgraph_create_function_alias (tree alias, tree decl) | |
b2583345 | 551 | { |
39e2db00 | 552 | struct cgraph_node *alias_node; |
b2583345 JJ |
553 | |
554 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); | |
555 | gcc_assert (TREE_CODE (alias) == FUNCTION_DECL); | |
39e2db00 JH |
556 | alias_node = cgraph_get_create_node (alias); |
557 | gcc_assert (!alias_node->local.finalized); | |
6744a6ab | 558 | alias_node->thunk.alias = decl; |
39e2db00 JH |
559 | alias_node->local.finalized = true; |
560 | alias_node->alias = 1; | |
561 | ||
562 | if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias)) | |
563 | || (DECL_VIRTUAL_P (alias) | |
564 | && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias)))) | |
565 | cgraph_mark_reachable_node (alias_node); | |
6744a6ab JH |
566 | return alias_node; |
567 | } | |
568 | ||
051f8cc6 | 569 | /* Attempt to mark ALIAS as an alias to DECL. Return alias node if successful |
a358e188 | 570 | and NULL otherwise. |
6744a6ab | 571 | Same body aliases are output whenever the body of DECL is output, |
a358e188 | 572 | and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL). */ |
6744a6ab | 573 | |
051f8cc6 | 574 | struct cgraph_node * |
39e2db00 | 575 | cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree alias, tree decl) |
6744a6ab | 576 | { |
39e2db00 | 577 | struct cgraph_node *n; |
6744a6ab JH |
578 | #ifndef ASM_OUTPUT_DEF |
579 | /* If aliases aren't supported by the assembler, fail. */ | |
051f8cc6 | 580 | return NULL; |
6744a6ab | 581 | #endif |
39e2db00 JH |
582 | /* Langhooks can create same body aliases of symbols not defined. |
583 | Those are useless. Drop them on the floor. */ | |
584 | if (cgraph_global_info_ready) | |
585 | return NULL; | |
6744a6ab | 586 | |
39e2db00 JH |
587 | n = cgraph_create_function_alias (alias, decl); |
588 | n->same_body_alias = true; | |
589 | if (same_body_aliases_done) | |
590 | ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS, | |
591 | NULL); | |
592 | return n; | |
6744a6ab JH |
593 | } |
594 | ||
051f8cc6 | 595 | /* Add thunk alias into callgraph. The alias declaration is ALIAS and it |
61502ca8 | 596 | aliases DECL with an adjustments made into the first parameter. |
051f8cc6 JH |
597 | See comments in thunk_adjust for detail on the parameters. */ |
598 | ||
599 | struct cgraph_node * | |
c47d0034 JH |
600 | cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, |
601 | tree alias, tree decl, | |
87e7b310 | 602 | bool this_adjusting, |
6744a6ab JH |
603 | HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value, |
604 | tree virtual_offset, | |
605 | tree real_alias) | |
606 | { | |
c47d0034 | 607 | struct cgraph_node *node; |
6744a6ab | 608 | |
c47d0034 | 609 | node = cgraph_get_node (alias); |
6744a6ab JH |
610 | if (node) |
611 | { | |
612 | gcc_assert (node->local.finalized); | |
be330ed4 JH |
613 | gcc_assert (!node->alias); |
614 | gcc_assert (!node->thunk.thunk_p); | |
6744a6ab JH |
615 | cgraph_remove_node (node); |
616 | } | |
617 | ||
c47d0034 | 618 | node = cgraph_create_node (alias); |
77a74ed7 | 619 | gcc_checking_assert (!virtual_offset |
e562bf36 RG |
620 | || double_int_equal_p |
621 | (tree_to_double_int (virtual_offset), | |
622 | shwi_to_double_int (virtual_value))); | |
6744a6ab JH |
623 | node->thunk.fixed_offset = fixed_offset; |
624 | node->thunk.this_adjusting = this_adjusting; | |
625 | node->thunk.virtual_value = virtual_value; | |
626 | node->thunk.virtual_offset_p = virtual_offset != NULL; | |
627 | node->thunk.alias = real_alias; | |
628 | node->thunk.thunk_p = true; | |
c47d0034 JH |
629 | node->local.finalized = true; |
630 | ||
631 | if (cgraph_decide_is_function_needed (node, decl)) | |
632 | cgraph_mark_needed_node (node); | |
633 | ||
634 | if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) | |
635 | || (DECL_VIRTUAL_P (decl) | |
636 | && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) | |
637 | cgraph_mark_reachable_node (node); | |
39e2db00 | 638 | |
051f8cc6 | 639 | return node; |
b2583345 JJ |
640 | } |
641 | ||
f9329c35 DS |
642 | /* Returns the cgraph node assigned to DECL or NULL if no cgraph node |
643 | is assigned. */ | |
644 | ||
645 | struct cgraph_node * | |
051f8cc6 | 646 | cgraph_get_node (const_tree decl) |
f9329c35 DS |
647 | { |
648 | struct cgraph_node key, *node = NULL, **slot; | |
649 | ||
650 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); | |
651 | ||
652 | if (!cgraph_hash) | |
986ad133 | 653 | return NULL; |
f9329c35 | 654 | |
051f8cc6 | 655 | key.decl = CONST_CAST2 (tree, const_tree, decl); |
f9329c35 DS |
656 | |
657 | slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, | |
658 | NO_INSERT); | |
659 | ||
660 | if (slot && *slot) | |
39e2db00 | 661 | node = *slot; |
f9329c35 DS |
662 | return node; |
663 | } | |
664 | ||
ea99e0be JH |
665 | /* Insert already constructed node into hashtable. */ |
666 | ||
667 | void | |
668 | cgraph_insert_node_to_hashtable (struct cgraph_node *node) | |
669 | { | |
670 | struct cgraph_node **slot; | |
671 | ||
672 | slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, node, INSERT); | |
673 | ||
674 | gcc_assert (!*slot); | |
675 | *slot = node; | |
676 | } | |
677 | ||
266ad5c8 JH |
678 | /* Returns a hash code for P. */ |
679 | ||
680 | static hashval_t | |
681 | hash_node_by_assembler_name (const void *p) | |
682 | { | |
683 | const struct cgraph_node *n = (const struct cgraph_node *) p; | |
684 | return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->decl)); | |
685 | } | |
686 | ||
687 | /* Returns nonzero if P1 and P2 are equal. */ | |
688 | ||
689 | static int | |
690 | eq_assembler_name (const void *p1, const void *p2) | |
691 | { | |
692 | const struct cgraph_node *n1 = (const struct cgraph_node *) p1; | |
693 | const_tree name = (const_tree)p2; | |
694 | return (decl_assembler_name_equal (n1->decl, name)); | |
695 | } | |
bedb9fc0 RH |
696 | |
697 | /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. | |
698 | Return NULL if there's no such node. */ | |
699 | ||
700 | struct cgraph_node * | |
701 | cgraph_node_for_asm (tree asmname) | |
702 | { | |
703 | struct cgraph_node *node; | |
266ad5c8 | 704 | void **slot; |
bedb9fc0 | 705 | |
266ad5c8 JH |
706 | if (!assembler_name_hash) |
707 | { | |
708 | assembler_name_hash = | |
709 | htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name, | |
710 | NULL); | |
711 | for (node = cgraph_nodes; node; node = node->next) | |
712 | if (!node->global.inlined_to) | |
713 | { | |
714 | tree name = DECL_ASSEMBLER_NAME (node->decl); | |
715 | slot = htab_find_slot_with_hash (assembler_name_hash, name, | |
716 | decl_assembler_name_hash (name), | |
717 | INSERT); | |
718 | /* We can have multiple declarations with same assembler name. For C++ | |
719 | it is __builtin_strlen and strlen, for instance. Do we need to | |
720 | record them all? Original implementation marked just first one | |
721 | so lets hope for the best. */ | |
b2583345 JJ |
722 | if (!*slot) |
723 | *slot = node; | |
266ad5c8 JH |
724 | } |
725 | } | |
726 | ||
727 | slot = htab_find_slot_with_hash (assembler_name_hash, asmname, | |
728 | decl_assembler_name_hash (asmname), | |
729 | NO_INSERT); | |
bedb9fc0 | 730 | |
266ad5c8 | 731 | if (slot) |
b2583345 JJ |
732 | { |
733 | node = (struct cgraph_node *) *slot; | |
b2583345 JJ |
734 | return node; |
735 | } | |
bedb9fc0 RH |
736 | return NULL; |
737 | } | |
738 | ||
70d539ce JH |
739 | /* Returns a hash value for X (which really is a die_struct). */ |
740 | ||
741 | static hashval_t | |
742 | edge_hash (const void *x) | |
743 | { | |
741ac903 | 744 | return htab_hash_pointer (((const struct cgraph_edge *) x)->call_stmt); |
70d539ce JH |
745 | } |
746 | ||
747 | /* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y. */ | |
748 | ||
749 | static int | |
750 | edge_eq (const void *x, const void *y) | |
751 | { | |
741ac903 | 752 | return ((const struct cgraph_edge *) x)->call_stmt == y; |
70d539ce JH |
753 | } |
754 | ||
e33c6cd6 MJ |
755 | /* Add call graph edge E to call site hash of its caller. */ |
756 | ||
757 | static inline void | |
758 | cgraph_add_edge_to_call_site_hash (struct cgraph_edge *e) | |
759 | { | |
760 | void **slot; | |
761 | slot = htab_find_slot_with_hash (e->caller->call_site_hash, | |
762 | e->call_stmt, | |
763 | htab_hash_pointer (e->call_stmt), | |
764 | INSERT); | |
765 | gcc_assert (!*slot); | |
766 | *slot = e; | |
767 | } | |
726a989a RB |
768 | |
769 | /* Return the callgraph edge representing the GIMPLE_CALL statement | |
770 | CALL_STMT. */ | |
771 | ||
18c6ada9 | 772 | struct cgraph_edge * |
726a989a | 773 | cgraph_edge (struct cgraph_node *node, gimple call_stmt) |
18c6ada9 | 774 | { |
70d539ce JH |
775 | struct cgraph_edge *e, *e2; |
776 | int n = 0; | |
777 | ||
778 | if (node->call_site_hash) | |
f883e0a7 KG |
779 | return (struct cgraph_edge *) |
780 | htab_find_with_hash (node->call_site_hash, call_stmt, | |
52c76998 | 781 | htab_hash_pointer (call_stmt)); |
18c6ada9 JH |
782 | |
783 | /* This loop may turn out to be performance problem. In such case adding | |
784 | hashtables into call nodes with very many edges is probably best | |
2b8a92de | 785 | solution. It is not good idea to add pointer into CALL_EXPR itself |
18c6ada9 JH |
786 | because we want to make possible having multiple cgraph nodes representing |
787 | different clones of the same body before the body is actually cloned. */ | |
e33c6cd6 | 788 | for (e = node->callees; e; e = e->next_callee) |
70d539ce JH |
789 | { |
790 | if (e->call_stmt == call_stmt) | |
791 | break; | |
792 | n++; | |
793 | } | |
726a989a | 794 | |
e33c6cd6 MJ |
795 | if (!e) |
796 | for (e = node->indirect_calls; e; e = e->next_callee) | |
797 | { | |
798 | if (e->call_stmt == call_stmt) | |
799 | break; | |
800 | n++; | |
801 | } | |
802 | ||
70d539ce JH |
803 | if (n > 100) |
804 | { | |
805 | node->call_site_hash = htab_create_ggc (120, edge_hash, edge_eq, NULL); | |
806 | for (e2 = node->callees; e2; e2 = e2->next_callee) | |
e33c6cd6 MJ |
807 | cgraph_add_edge_to_call_site_hash (e2); |
808 | for (e2 = node->indirect_calls; e2; e2 = e2->next_callee) | |
809 | cgraph_add_edge_to_call_site_hash (e2); | |
70d539ce | 810 | } |
726a989a | 811 | |
18c6ada9 JH |
812 | return e; |
813 | } | |
814 | ||
726a989a | 815 | |
9187e02d | 816 | /* Change field call_stmt of edge E to NEW_STMT. */ |
0550e7b7 | 817 | |
70d539ce | 818 | void |
726a989a | 819 | cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) |
70d539ce | 820 | { |
e33c6cd6 MJ |
821 | tree decl; |
822 | ||
70d539ce JH |
823 | if (e->caller->call_site_hash) |
824 | { | |
825 | htab_remove_elt_with_hash (e->caller->call_site_hash, | |
826 | e->call_stmt, | |
827 | htab_hash_pointer (e->call_stmt)); | |
828 | } | |
e33c6cd6 | 829 | |
70d539ce | 830 | e->call_stmt = new_stmt; |
e33c6cd6 MJ |
831 | if (e->indirect_unknown_callee |
832 | && (decl = gimple_call_fndecl (new_stmt))) | |
833 | { | |
834 | /* Constant propagation (and possibly also inlining?) can turn an | |
835 | indirect call into a direct one. */ | |
a358e188 | 836 | struct cgraph_node *new_callee = cgraph_get_node (decl); |
e33c6cd6 | 837 | |
a358e188 | 838 | gcc_checking_assert (new_callee); |
81fa35bd | 839 | cgraph_make_edge_direct (e, new_callee); |
e33c6cd6 MJ |
840 | } |
841 | ||
b6fa5b01 | 842 | push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); |
2505c5ed | 843 | e->can_throw_external = stmt_can_throw_external (new_stmt); |
b6fa5b01 | 844 | pop_cfun (); |
70d539ce | 845 | if (e->caller->call_site_hash) |
e33c6cd6 | 846 | cgraph_add_edge_to_call_site_hash (e); |
70d539ce JH |
847 | } |
848 | ||
9b2a5ef7 RH |
849 | /* Like cgraph_set_call_stmt but walk the clone tree and update all |
850 | clones sharing the same function body. */ | |
9187e02d JH |
851 | |
852 | void | |
853 | cgraph_set_call_stmt_including_clones (struct cgraph_node *orig, | |
854 | gimple old_stmt, gimple new_stmt) | |
855 | { | |
856 | struct cgraph_node *node; | |
857 | struct cgraph_edge *edge = cgraph_edge (orig, old_stmt); | |
858 | ||
859 | if (edge) | |
860 | cgraph_set_call_stmt (edge, new_stmt); | |
9b2a5ef7 RH |
861 | |
862 | node = orig->clones; | |
863 | if (node) | |
864 | while (node != orig) | |
9187e02d JH |
865 | { |
866 | struct cgraph_edge *edge = cgraph_edge (node, old_stmt); | |
867 | if (edge) | |
868 | cgraph_set_call_stmt (edge, new_stmt); | |
869 | if (node->clones) | |
870 | node = node->clones; | |
871 | else if (node->next_sibling_clone) | |
872 | node = node->next_sibling_clone; | |
873 | else | |
874 | { | |
875 | while (node != orig && !node->next_sibling_clone) | |
876 | node = node->clone_of; | |
877 | if (node != orig) | |
878 | node = node->next_sibling_clone; | |
879 | } | |
880 | } | |
881 | } | |
882 | ||
883 | /* Like cgraph_create_edge walk the clone tree and update all clones sharing | |
47cb0d7d JH |
884 | same function body. If clones already have edge for OLD_STMT; only |
885 | update the edge same way as cgraph_set_call_stmt_including_clones does. | |
b8698a0f | 886 | |
9187e02d | 887 | TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative |
9b2a5ef7 | 888 | frequencies of the clones. */ |
9187e02d JH |
889 | |
890 | void | |
9b2a5ef7 RH |
891 | cgraph_create_edge_including_clones (struct cgraph_node *orig, |
892 | struct cgraph_node *callee, | |
47cb0d7d | 893 | gimple old_stmt, |
9b2a5ef7 | 894 | gimple stmt, gcov_type count, |
898b8927 | 895 | int freq, |
9187e02d JH |
896 | cgraph_inline_failed_t reason) |
897 | { | |
898 | struct cgraph_node *node; | |
9b2a5ef7 | 899 | struct cgraph_edge *edge; |
9187e02d | 900 | |
6ce2002b | 901 | if (!cgraph_edge (orig, stmt)) |
9b2a5ef7 | 902 | { |
898b8927 | 903 | edge = cgraph_create_edge (orig, callee, stmt, count, freq); |
9b2a5ef7 RH |
904 | edge->inline_failed = reason; |
905 | } | |
9187e02d | 906 | |
9b2a5ef7 RH |
907 | node = orig->clones; |
908 | if (node) | |
909 | while (node != orig) | |
9187e02d | 910 | { |
47cb0d7d JH |
911 | struct cgraph_edge *edge = cgraph_edge (node, old_stmt); |
912 | ||
913 | /* It is possible that clones already contain the edge while | |
914 | master didn't. Either we promoted indirect call into direct | |
915 | call in the clone or we are processing clones of unreachable | |
61502ca8 | 916 | master where edges has been removed. */ |
47cb0d7d JH |
917 | if (edge) |
918 | cgraph_set_call_stmt (edge, stmt); | |
919 | else if (!cgraph_edge (node, stmt)) | |
9b2a5ef7 RH |
920 | { |
921 | edge = cgraph_create_edge (node, callee, stmt, count, | |
898b8927 | 922 | freq); |
9b2a5ef7 RH |
923 | edge->inline_failed = reason; |
924 | } | |
9187e02d JH |
925 | |
926 | if (node->clones) | |
927 | node = node->clones; | |
928 | else if (node->next_sibling_clone) | |
929 | node = node->next_sibling_clone; | |
930 | else | |
931 | { | |
932 | while (node != orig && !node->next_sibling_clone) | |
933 | node = node->clone_of; | |
934 | if (node != orig) | |
935 | node = node->next_sibling_clone; | |
936 | } | |
937 | } | |
938 | } | |
939 | ||
e33c6cd6 MJ |
940 | /* Allocate a cgraph_edge structure and fill it with data according to the |
941 | parameters of which only CALLEE can be NULL (when creating an indirect call | |
942 | edge). */ | |
e72fcfe8 | 943 | |
e33c6cd6 MJ |
944 | static struct cgraph_edge * |
945 | cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee, | |
898b8927 | 946 | gimple call_stmt, gcov_type count, int freq) |
e72fcfe8 | 947 | { |
934cb78a | 948 | struct cgraph_edge *edge; |
18c6ada9 | 949 | |
d7f09764 DN |
950 | /* LTO does not actually have access to the call_stmt since these |
951 | have not been loaded yet. */ | |
952 | if (call_stmt) | |
953 | { | |
61502ca8 | 954 | /* This is a rather expensive check possibly triggering |
77a74ed7 NF |
955 | construction of call stmt hashtable. */ |
956 | gcc_checking_assert (!cgraph_edge (caller, call_stmt)); | |
18c6ada9 | 957 | |
d7f09764 DN |
958 | gcc_assert (is_gimple_call (call_stmt)); |
959 | } | |
b58b1157 | 960 | |
934cb78a MJ |
961 | if (free_edges) |
962 | { | |
963 | edge = free_edges; | |
964 | free_edges = NEXT_FREE_EDGE (edge); | |
965 | } | |
966 | else | |
967 | { | |
a9429e29 | 968 | edge = ggc_alloc_cgraph_edge (); |
934cb78a MJ |
969 | edge->uid = cgraph_edge_max_uid++; |
970 | } | |
971 | ||
18c6ada9 | 972 | edge->aux = NULL; |
e72fcfe8 JH |
973 | edge->caller = caller; |
974 | edge->callee = callee; | |
e33c6cd6 MJ |
975 | edge->prev_caller = NULL; |
976 | edge->next_caller = NULL; | |
977 | edge->prev_callee = NULL; | |
978 | edge->next_callee = NULL; | |
979 | ||
980 | edge->count = count; | |
981 | gcc_assert (count >= 0); | |
982 | edge->frequency = freq; | |
983 | gcc_assert (freq >= 0); | |
984 | gcc_assert (freq <= CGRAPH_FREQ_MAX); | |
e33c6cd6 | 985 | |
e0704a46 | 986 | edge->call_stmt = call_stmt; |
b6fa5b01 | 987 | push_cfun (DECL_STRUCT_FUNCTION (caller->decl)); |
9f3f7d13 RG |
988 | edge->can_throw_external |
989 | = call_stmt ? stmt_can_throw_external (call_stmt) : false; | |
b6fa5b01 | 990 | pop_cfun (); |
e33c6cd6 MJ |
991 | edge->call_stmt_cannot_inline_p = |
992 | (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false); | |
993 | if (call_stmt && caller->call_site_hash) | |
994 | cgraph_add_edge_to_call_site_hash (edge); | |
995 | ||
996 | edge->indirect_info = NULL; | |
997 | edge->indirect_inlining_edge = 0; | |
998 | ||
999 | return edge; | |
1000 | } | |
1001 | ||
1002 | /* Create edge from CALLER to CALLEE in the cgraph. */ | |
1003 | ||
1004 | struct cgraph_edge * | |
1005 | cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, | |
898b8927 | 1006 | gimple call_stmt, gcov_type count, int freq) |
e33c6cd6 MJ |
1007 | { |
1008 | struct cgraph_edge *edge = cgraph_create_edge_1 (caller, callee, call_stmt, | |
898b8927 | 1009 | count, freq); |
e33c6cd6 MJ |
1010 | |
1011 | edge->indirect_unknown_callee = 0; | |
1012 | initialize_inline_failed (edge); | |
1013 | ||
e72fcfe8 | 1014 | edge->next_caller = callee->callers; |
2563c224 RG |
1015 | if (callee->callers) |
1016 | callee->callers->prev_caller = edge; | |
e72fcfe8 | 1017 | edge->next_callee = caller->callees; |
2563c224 RG |
1018 | if (caller->callees) |
1019 | caller->callees->prev_callee = edge; | |
e72fcfe8 JH |
1020 | caller->callees = edge; |
1021 | callee->callers = edge; | |
3dc9eaa6 | 1022 | |
e33c6cd6 MJ |
1023 | return edge; |
1024 | } | |
1025 | ||
ce47fda3 MJ |
1026 | /* Allocate cgraph_indirect_call_info and set its fields to default values. */ |
1027 | ||
1028 | struct cgraph_indirect_call_info * | |
1029 | cgraph_allocate_init_indirect_info (void) | |
1030 | { | |
1031 | struct cgraph_indirect_call_info *ii; | |
1032 | ||
1033 | ii = ggc_alloc_cleared_cgraph_indirect_call_info (); | |
1034 | ii->param_index = -1; | |
1035 | return ii; | |
1036 | } | |
e33c6cd6 MJ |
1037 | |
1038 | /* Create an indirect edge with a yet-undetermined callee where the call | |
1039 | statement destination is a formal parameter of the caller with index | |
1040 | PARAM_INDEX. */ | |
1041 | ||
1042 | struct cgraph_edge * | |
1043 | cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt, | |
5f902d76 | 1044 | int ecf_flags, |
898b8927 | 1045 | gcov_type count, int freq) |
e33c6cd6 MJ |
1046 | { |
1047 | struct cgraph_edge *edge = cgraph_create_edge_1 (caller, NULL, call_stmt, | |
898b8927 | 1048 | count, freq); |
e33c6cd6 MJ |
1049 | |
1050 | edge->indirect_unknown_callee = 1; | |
3dc9eaa6 AN |
1051 | initialize_inline_failed (edge); |
1052 | ||
ce47fda3 | 1053 | edge->indirect_info = cgraph_allocate_init_indirect_info (); |
5f902d76 | 1054 | edge->indirect_info->ecf_flags = ecf_flags; |
e33c6cd6 MJ |
1055 | |
1056 | edge->next_callee = caller->indirect_calls; | |
1057 | if (caller->indirect_calls) | |
1058 | caller->indirect_calls->prev_callee = edge; | |
1059 | caller->indirect_calls = edge; | |
1060 | ||
e72fcfe8 JH |
1061 | return edge; |
1062 | } | |
1063 | ||
2563c224 RG |
1064 | /* Remove the edge E from the list of the callers of the callee. */ |
1065 | ||
1066 | static inline void | |
1067 | cgraph_edge_remove_callee (struct cgraph_edge *e) | |
1068 | { | |
e33c6cd6 | 1069 | gcc_assert (!e->indirect_unknown_callee); |
2563c224 RG |
1070 | if (e->prev_caller) |
1071 | e->prev_caller->next_caller = e->next_caller; | |
1072 | if (e->next_caller) | |
1073 | e->next_caller->prev_caller = e->prev_caller; | |
1074 | if (!e->prev_caller) | |
1075 | e->callee->callers = e->next_caller; | |
1076 | } | |
1077 | ||
1078 | /* Remove the edge E from the list of the callees of the caller. */ | |
1079 | ||
1080 | static inline void | |
1081 | cgraph_edge_remove_caller (struct cgraph_edge *e) | |
1082 | { | |
1083 | if (e->prev_callee) | |
1084 | e->prev_callee->next_callee = e->next_callee; | |
1085 | if (e->next_callee) | |
1086 | e->next_callee->prev_callee = e->prev_callee; | |
1087 | if (!e->prev_callee) | |
e33c6cd6 MJ |
1088 | { |
1089 | if (e->indirect_unknown_callee) | |
1090 | e->caller->indirect_calls = e->next_callee; | |
1091 | else | |
1092 | e->caller->callees = e->next_callee; | |
1093 | } | |
70d539ce JH |
1094 | if (e->caller->call_site_hash) |
1095 | htab_remove_elt_with_hash (e->caller->call_site_hash, | |
1096 | e->call_stmt, | |
1097 | htab_hash_pointer (e->call_stmt)); | |
2563c224 RG |
1098 | } |
1099 | ||
934cb78a MJ |
1100 | /* Put the edge onto the free list. */ |
1101 | ||
1102 | static void | |
1103 | cgraph_free_edge (struct cgraph_edge *e) | |
1104 | { | |
1105 | int uid = e->uid; | |
1106 | ||
1107 | /* Clear out the edge so we do not dangle pointers. */ | |
5c0466b5 | 1108 | memset (e, 0, sizeof (*e)); |
934cb78a MJ |
1109 | e->uid = uid; |
1110 | NEXT_FREE_EDGE (e) = free_edges; | |
1111 | free_edges = e; | |
1112 | } | |
1113 | ||
2563c224 | 1114 | /* Remove the edge E in the cgraph. */ |
e72fcfe8 | 1115 | |
cb967da5 | 1116 | void |
18c6ada9 | 1117 | cgraph_remove_edge (struct cgraph_edge *e) |
e72fcfe8 | 1118 | { |
934cb78a | 1119 | /* Call all edge removal hooks. */ |
9088c1cc | 1120 | cgraph_call_edge_removal_hooks (e); |
934cb78a | 1121 | |
e33c6cd6 MJ |
1122 | if (!e->indirect_unknown_callee) |
1123 | /* Remove from callers list of the callee. */ | |
1124 | cgraph_edge_remove_callee (e); | |
2563c224 RG |
1125 | |
1126 | /* Remove from callees list of the callers. */ | |
1127 | cgraph_edge_remove_caller (e); | |
934cb78a MJ |
1128 | |
1129 | /* Put the edge onto the free list. */ | |
1130 | cgraph_free_edge (e); | |
e72fcfe8 JH |
1131 | } |
1132 | ||
e33c6cd6 MJ |
1133 | /* Set callee of call graph edge E and add it to the corresponding set of |
1134 | callers. */ | |
1135 | ||
1136 | static void | |
1137 | cgraph_set_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) | |
1138 | { | |
1139 | e->prev_caller = NULL; | |
1140 | if (n->callers) | |
1141 | n->callers->prev_caller = e; | |
1142 | e->next_caller = n->callers; | |
1143 | n->callers = e; | |
1144 | e->callee = n; | |
1145 | } | |
1146 | ||
18c6ada9 JH |
1147 | /* Redirect callee of E to N. The function does not update underlying |
1148 | call expression. */ | |
1149 | ||
1150 | void | |
1151 | cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) | |
1152 | { | |
2563c224 RG |
1153 | /* Remove from callers list of the current callee. */ |
1154 | cgraph_edge_remove_callee (e); | |
18c6ada9 | 1155 | |
2563c224 | 1156 | /* Insert to callers list of the new callee. */ |
e33c6cd6 MJ |
1157 | cgraph_set_edge_callee (e, n); |
1158 | } | |
1159 | ||
1160 | /* Make an indirect EDGE with an unknown callee an ordinary edge leading to | |
ce47fda3 MJ |
1161 | CALLEE. DELTA is an integer constant that is to be added to the this |
1162 | pointer (first parameter) to compensate for skipping a thunk adjustment. */ | |
e33c6cd6 MJ |
1163 | |
1164 | void | |
81fa35bd | 1165 | cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee) |
e33c6cd6 MJ |
1166 | { |
1167 | edge->indirect_unknown_callee = 0; | |
1168 | ||
1169 | /* Get the edge out of the indirect edge list. */ | |
1170 | if (edge->prev_callee) | |
1171 | edge->prev_callee->next_callee = edge->next_callee; | |
1172 | if (edge->next_callee) | |
1173 | edge->next_callee->prev_callee = edge->prev_callee; | |
1174 | if (!edge->prev_callee) | |
1175 | edge->caller->indirect_calls = edge->next_callee; | |
1176 | ||
1177 | /* Put it into the normal callee list */ | |
1178 | edge->prev_callee = NULL; | |
1179 | edge->next_callee = edge->caller->callees; | |
1180 | if (edge->caller->callees) | |
1181 | edge->caller->callees->prev_callee = edge; | |
1182 | edge->caller->callees = edge; | |
1183 | ||
1184 | /* Insert to callers list of the new callee. */ | |
1185 | cgraph_set_edge_callee (edge, callee); | |
1186 | ||
1187 | /* We need to re-determine the inlining status of the edge. */ | |
1188 | initialize_inline_failed (edge); | |
2563c224 RG |
1189 | } |
1190 | ||
726a989a RB |
1191 | |
1192 | /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL | |
4b685e14 | 1193 | OLD_STMT changed into NEW_STMT. OLD_CALL is gimple_call_fndecl |
a9d24544 JJ |
1194 | of OLD_STMT if it was previously call statement. |
1195 | If NEW_STMT is NULL, the call has been dropped without any | |
1196 | replacement. */ | |
2bafad93 | 1197 | |
9187e02d JH |
1198 | static void |
1199 | cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node, | |
a9d24544 JJ |
1200 | gimple old_stmt, tree old_call, |
1201 | gimple new_stmt) | |
2bafad93 | 1202 | { |
a9d24544 JJ |
1203 | tree new_call = (new_stmt && is_gimple_call (new_stmt)) |
1204 | ? gimple_call_fndecl (new_stmt) : 0; | |
2bafad93 | 1205 | |
4b685e14 JH |
1206 | /* We are seeing indirect calls, then there is nothing to update. */ |
1207 | if (!new_call && !old_call) | |
1208 | return; | |
1209 | /* See if we turned indirect call into direct call or folded call to one builtin | |
61502ca8 | 1210 | into different builtin. */ |
2bafad93 JJ |
1211 | if (old_call != new_call) |
1212 | { | |
1213 | struct cgraph_edge *e = cgraph_edge (node, old_stmt); | |
1214 | struct cgraph_edge *ne = NULL; | |
4b685e14 JH |
1215 | gcov_type count; |
1216 | int frequency; | |
2bafad93 JJ |
1217 | |
1218 | if (e) | |
1219 | { | |
e33c6cd6 MJ |
1220 | /* See if the edge is already there and has the correct callee. It |
1221 | might be so because of indirect inlining has already updated | |
97ba0040 JH |
1222 | it. We also might've cloned and redirected the edge. */ |
1223 | if (new_call && e->callee) | |
1224 | { | |
1225 | struct cgraph_node *callee = e->callee; | |
1226 | while (callee) | |
1227 | { | |
1228 | if (callee->decl == new_call | |
1229 | || callee->former_clone_of == new_call) | |
1230 | return; | |
1231 | callee = callee->clone_of; | |
1232 | } | |
1233 | } | |
4b685e14 JH |
1234 | |
1235 | /* Otherwise remove edge and create new one; we can't simply redirect | |
1236 | since function has changed, so inline plan and other information | |
1237 | attached to edge is invalid. */ | |
4b685e14 JH |
1238 | count = e->count; |
1239 | frequency = e->frequency; | |
f8754107 | 1240 | cgraph_remove_edge (e); |
4b685e14 | 1241 | } |
a9d24544 | 1242 | else if (new_call) |
4b685e14 JH |
1243 | { |
1244 | /* We are seeing new direct call; compute profile info based on BB. */ | |
1245 | basic_block bb = gimple_bb (new_stmt); | |
1246 | count = bb->count; | |
1247 | frequency = compute_call_stmt_bb_frequency (current_function_decl, | |
1248 | bb); | |
2bafad93 | 1249 | } |
2bafad93 | 1250 | |
4b685e14 JH |
1251 | if (new_call) |
1252 | { | |
a358e188 | 1253 | ne = cgraph_create_edge (node, cgraph_get_create_node (new_call), |
898b8927 | 1254 | new_stmt, count, frequency); |
4b685e14 JH |
1255 | gcc_assert (ne->inline_failed); |
1256 | } | |
2bafad93 | 1257 | } |
4b685e14 JH |
1258 | /* We only updated the call stmt; update pointer in cgraph edge.. */ |
1259 | else if (old_stmt != new_stmt) | |
1260 | cgraph_set_call_stmt (cgraph_edge (node, old_stmt), new_stmt); | |
2bafad93 JJ |
1261 | } |
1262 | ||
9187e02d | 1263 | /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL |
4b685e14 JH |
1264 | OLD_STMT changed into NEW_STMT. OLD_DECL is gimple_call_fndecl |
1265 | of OLD_STMT before it was updated (updating can happen inplace). */ | |
9187e02d JH |
1266 | |
1267 | void | |
4b685e14 | 1268 | cgraph_update_edges_for_call_stmt (gimple old_stmt, tree old_decl, gimple new_stmt) |
9187e02d | 1269 | { |
a358e188 | 1270 | struct cgraph_node *orig = cgraph_get_node (cfun->decl); |
9187e02d JH |
1271 | struct cgraph_node *node; |
1272 | ||
a358e188 | 1273 | gcc_checking_assert (orig); |
4b685e14 | 1274 | cgraph_update_edges_for_call_stmt_node (orig, old_stmt, old_decl, new_stmt); |
9187e02d JH |
1275 | if (orig->clones) |
1276 | for (node = orig->clones; node != orig;) | |
1277 | { | |
4b685e14 | 1278 | cgraph_update_edges_for_call_stmt_node (node, old_stmt, old_decl, new_stmt); |
9187e02d JH |
1279 | if (node->clones) |
1280 | node = node->clones; | |
1281 | else if (node->next_sibling_clone) | |
1282 | node = node->next_sibling_clone; | |
1283 | else | |
1284 | { | |
1285 | while (node != orig && !node->next_sibling_clone) | |
1286 | node = node->clone_of; | |
1287 | if (node != orig) | |
1288 | node = node->next_sibling_clone; | |
1289 | } | |
1290 | } | |
1291 | } | |
1292 | ||
726a989a | 1293 | |
2563c224 RG |
1294 | /* Remove all callees from the node. */ |
1295 | ||
1296 | void | |
1297 | cgraph_node_remove_callees (struct cgraph_node *node) | |
1298 | { | |
5c0466b5 | 1299 | struct cgraph_edge *e, *f; |
2563c224 RG |
1300 | |
1301 | /* It is sufficient to remove the edges from the lists of callers of | |
1302 | the callees. The callee list of the node can be zapped with one | |
1303 | assignment. */ | |
5c0466b5 | 1304 | for (e = node->callees; e; e = f) |
9088c1cc | 1305 | { |
5c0466b5 | 1306 | f = e->next_callee; |
9088c1cc | 1307 | cgraph_call_edge_removal_hooks (e); |
e33c6cd6 MJ |
1308 | if (!e->indirect_unknown_callee) |
1309 | cgraph_edge_remove_callee (e); | |
934cb78a | 1310 | cgraph_free_edge (e); |
9088c1cc | 1311 | } |
5f902d76 JH |
1312 | for (e = node->indirect_calls; e; e = f) |
1313 | { | |
1314 | f = e->next_callee; | |
1315 | cgraph_call_edge_removal_hooks (e); | |
1316 | if (!e->indirect_unknown_callee) | |
1317 | cgraph_edge_remove_callee (e); | |
1318 | cgraph_free_edge (e); | |
1319 | } | |
1320 | node->indirect_calls = NULL; | |
2563c224 | 1321 | node->callees = NULL; |
70d539ce JH |
1322 | if (node->call_site_hash) |
1323 | { | |
1324 | htab_delete (node->call_site_hash); | |
1325 | node->call_site_hash = NULL; | |
1326 | } | |
2563c224 RG |
1327 | } |
1328 | ||
1329 | /* Remove all callers from the node. */ | |
1330 | ||
1331 | static void | |
1332 | cgraph_node_remove_callers (struct cgraph_node *node) | |
1333 | { | |
5c0466b5 | 1334 | struct cgraph_edge *e, *f; |
2563c224 RG |
1335 | |
1336 | /* It is sufficient to remove the edges from the lists of callees of | |
1337 | the callers. The caller list of the node can be zapped with one | |
1338 | assignment. */ | |
5c0466b5 | 1339 | for (e = node->callers; e; e = f) |
9088c1cc | 1340 | { |
5c0466b5 | 1341 | f = e->next_caller; |
9088c1cc MJ |
1342 | cgraph_call_edge_removal_hooks (e); |
1343 | cgraph_edge_remove_caller (e); | |
934cb78a | 1344 | cgraph_free_edge (e); |
9088c1cc | 1345 | } |
2563c224 | 1346 | node->callers = NULL; |
18c6ada9 JH |
1347 | } |
1348 | ||
3a40c18a JH |
1349 | /* Release memory used to represent body of function NODE. */ |
1350 | ||
1351 | void | |
1352 | cgraph_release_function_body (struct cgraph_node *node) | |
1353 | { | |
936fc9ba | 1354 | if (DECL_STRUCT_FUNCTION (node->decl)) |
3a40c18a JH |
1355 | { |
1356 | tree old_decl = current_function_decl; | |
1357 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); | |
936fc9ba JH |
1358 | if (cfun->gimple_df) |
1359 | { | |
1360 | current_function_decl = node->decl; | |
1361 | delete_tree_ssa (); | |
1362 | delete_tree_cfg_annotations (); | |
1363 | cfun->eh = NULL; | |
1364 | current_function_decl = old_decl; | |
1365 | } | |
1366 | if (cfun->cfg) | |
1367 | { | |
1368 | gcc_assert (dom_computed[0] == DOM_NONE); | |
1369 | gcc_assert (dom_computed[1] == DOM_NONE); | |
1370 | clear_edges (); | |
1371 | } | |
a63f2942 JH |
1372 | if (cfun->value_histograms) |
1373 | free_histograms (); | |
1374 | gcc_assert (!current_loops); | |
3a40c18a | 1375 | pop_cfun(); |
936fc9ba JH |
1376 | gimple_set_body (node->decl, NULL); |
1377 | VEC_free (ipa_opt_pass, heap, | |
0e3776db | 1378 | node->ipa_transforms_to_apply); |
936fc9ba JH |
1379 | /* Struct function hangs a lot of data that would leak if we didn't |
1380 | removed all pointers to it. */ | |
1381 | ggc_free (DECL_STRUCT_FUNCTION (node->decl)); | |
1382 | DECL_STRUCT_FUNCTION (node->decl) = NULL; | |
3a40c18a JH |
1383 | } |
1384 | DECL_SAVED_TREE (node->decl) = NULL; | |
6b20f353 DS |
1385 | /* If the node is abstract and needed, then do not clear DECL_INITIAL |
1386 | of its associated function function declaration because it's | |
1387 | needed to emit debug info later. */ | |
1388 | if (!node->abstract_and_needed) | |
1389 | DECL_INITIAL (node->decl) = error_mark_node; | |
3a40c18a JH |
1390 | } |
1391 | ||
18d13f34 JH |
1392 | /* Remove the node from cgraph. */ |
1393 | ||
1394 | void | |
439f7bc3 | 1395 | cgraph_remove_node (struct cgraph_node *node) |
18d13f34 | 1396 | { |
2ee1067b | 1397 | void **slot; |
4a76d91a | 1398 | bool kill_body = false; |
ca30a539 | 1399 | struct cgraph_node *n; |
2fb16412 | 1400 | int uid = node->uid; |
18c6ada9 | 1401 | |
9088c1cc | 1402 | cgraph_call_node_removal_hooks (node); |
2563c224 RG |
1403 | cgraph_node_remove_callers (node); |
1404 | cgraph_node_remove_callees (node); | |
369451ec JH |
1405 | ipa_remove_all_references (&node->ref_list); |
1406 | ipa_remove_all_refering (&node->ref_list); | |
0e3776db JH |
1407 | VEC_free (ipa_opt_pass, heap, |
1408 | node->ipa_transforms_to_apply); | |
266ad5c8 | 1409 | |
96fc428c JH |
1410 | /* Incremental inlining access removed nodes stored in the postorder list. |
1411 | */ | |
1412 | node->needed = node->reachable = false; | |
ca30a539 JH |
1413 | for (n = node->nested; n; n = n->next_nested) |
1414 | n->origin = NULL; | |
1415 | node->nested = NULL; | |
18d13f34 JH |
1416 | if (node->origin) |
1417 | { | |
1418 | struct cgraph_node **node2 = &node->origin->nested; | |
1419 | ||
1420 | while (*node2 != node) | |
1421 | node2 = &(*node2)->next_nested; | |
1422 | *node2 = node->next_nested; | |
1423 | } | |
1424 | if (node->previous) | |
1425 | node->previous->next = node->next; | |
1426 | else | |
9b0436b7 | 1427 | cgraph_nodes = node->next; |
18d13f34 JH |
1428 | if (node->next) |
1429 | node->next->previous = node->previous; | |
96fc428c JH |
1430 | node->next = NULL; |
1431 | node->previous = NULL; | |
6f312d18 | 1432 | slot = htab_find_slot (cgraph_hash, node, NO_INSERT); |
18c6ada9 JH |
1433 | if (*slot == node) |
1434 | { | |
9187e02d | 1435 | struct cgraph_node *next_inline_clone; |
c22cacf3 | 1436 | |
9187e02d JH |
1437 | for (next_inline_clone = node->clones; |
1438 | next_inline_clone && next_inline_clone->decl != node->decl; | |
1439 | next_inline_clone = next_inline_clone->next_sibling_clone) | |
1440 | ; | |
1441 | ||
1442 | /* If there is inline clone of the node being removed, we need | |
1443 | to put it into the position of removed node and reorganize all | |
1444 | other clones to be based on it. */ | |
1445 | if (next_inline_clone) | |
1446 | { | |
1447 | struct cgraph_node *n; | |
1448 | struct cgraph_node *new_clones; | |
1449 | ||
1450 | *slot = next_inline_clone; | |
1451 | ||
1452 | /* Unlink inline clone from the list of clones of removed node. */ | |
1453 | if (next_inline_clone->next_sibling_clone) | |
1454 | next_inline_clone->next_sibling_clone->prev_sibling_clone | |
1455 | = next_inline_clone->prev_sibling_clone; | |
1456 | if (next_inline_clone->prev_sibling_clone) | |
1457 | { | |
47cb0d7d | 1458 | gcc_assert (node->clones != next_inline_clone); |
9187e02d JH |
1459 | next_inline_clone->prev_sibling_clone->next_sibling_clone |
1460 | = next_inline_clone->next_sibling_clone; | |
1461 | } | |
1462 | else | |
47cb0d7d JH |
1463 | { |
1464 | gcc_assert (node->clones == next_inline_clone); | |
1465 | node->clones = next_inline_clone->next_sibling_clone; | |
1466 | } | |
9187e02d JH |
1467 | |
1468 | new_clones = node->clones; | |
1469 | node->clones = NULL; | |
1470 | ||
1471 | /* Copy clone info. */ | |
1472 | next_inline_clone->clone = node->clone; | |
1473 | ||
1474 | /* Now place it into clone tree at same level at NODE. */ | |
1475 | next_inline_clone->clone_of = node->clone_of; | |
1476 | next_inline_clone->prev_sibling_clone = NULL; | |
1477 | next_inline_clone->next_sibling_clone = NULL; | |
1478 | if (node->clone_of) | |
1479 | { | |
47cb0d7d JH |
1480 | if (node->clone_of->clones) |
1481 | node->clone_of->clones->prev_sibling_clone = next_inline_clone; | |
9187e02d JH |
1482 | next_inline_clone->next_sibling_clone = node->clone_of->clones; |
1483 | node->clone_of->clones = next_inline_clone; | |
1484 | } | |
1485 | ||
1486 | /* Merge the clone list. */ | |
1487 | if (new_clones) | |
1488 | { | |
1489 | if (!next_inline_clone->clones) | |
1490 | next_inline_clone->clones = new_clones; | |
1491 | else | |
1492 | { | |
1493 | n = next_inline_clone->clones; | |
1494 | while (n->next_sibling_clone) | |
1495 | n = n->next_sibling_clone; | |
1496 | n->next_sibling_clone = new_clones; | |
1497 | new_clones->prev_sibling_clone = n; | |
1498 | } | |
1499 | } | |
1500 | ||
1501 | /* Update clone_of pointers. */ | |
1502 | n = new_clones; | |
1503 | while (n) | |
1504 | { | |
1505 | n->clone_of = next_inline_clone; | |
1506 | n = n->next_sibling_clone; | |
1507 | } | |
1508 | } | |
18c6ada9 JH |
1509 | else |
1510 | { | |
c22cacf3 | 1511 | htab_clear_slot (cgraph_hash, slot); |
4a76d91a | 1512 | kill_body = true; |
18c6ada9 | 1513 | } |
9187e02d | 1514 | |
18c6ada9 | 1515 | } |
9187e02d JH |
1516 | if (node->prev_sibling_clone) |
1517 | node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; | |
1518 | else if (node->clone_of) | |
1519 | node->clone_of->clones = node->next_sibling_clone; | |
1520 | if (node->next_sibling_clone) | |
1521 | node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; | |
1522 | if (node->clones) | |
18c6ada9 | 1523 | { |
47cb0d7d JH |
1524 | struct cgraph_node *n, *next; |
1525 | ||
1526 | if (node->clone_of) | |
1527 | { | |
1528 | for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone) | |
1529 | n->clone_of = node->clone_of; | |
1530 | n->clone_of = node->clone_of; | |
1531 | n->next_sibling_clone = node->clone_of->clones; | |
1532 | if (node->clone_of->clones) | |
1533 | node->clone_of->clones->prev_sibling_clone = n; | |
1534 | node->clone_of->clones = node->clones; | |
1535 | } | |
1536 | else | |
1537 | { | |
1538 | /* We are removing node with clones. this makes clones inconsistent, | |
1539 | but assume they will be removed subsequently and just keep clone | |
1540 | tree intact. This can happen in unreachable function removal since | |
1541 | we remove unreachable functions in random order, not by bottom-up | |
1542 | walk of clone trees. */ | |
1543 | for (n = node->clones; n; n = next) | |
1544 | { | |
1545 | next = n->next_sibling_clone; | |
1546 | n->next_sibling_clone = NULL; | |
1547 | n->prev_sibling_clone = NULL; | |
1548 | n->clone_of = NULL; | |
1549 | } | |
1550 | } | |
18c6ada9 JH |
1551 | } |
1552 | ||
b66887e4 JJ |
1553 | if (node->same_comdat_group) |
1554 | { | |
1555 | struct cgraph_node *prev; | |
1556 | for (prev = node->same_comdat_group; | |
1557 | prev->same_comdat_group != node; | |
1558 | prev = prev->same_comdat_group) | |
1559 | ; | |
1560 | if (node->same_comdat_group == prev) | |
1561 | prev->same_comdat_group = NULL; | |
1562 | else | |
1563 | prev->same_comdat_group = node->same_comdat_group; | |
1564 | node->same_comdat_group = NULL; | |
1565 | } | |
1566 | ||
c22cacf3 | 1567 | /* While all the clones are removed after being proceeded, the function |
4a76d91a JH |
1568 | itself is kept in the cgraph even after it is compiled. Check whether |
1569 | we are done with this body and reclaim it proactively if this is the case. | |
1570 | */ | |
1571 | if (!kill_body && *slot) | |
18c6ada9 | 1572 | { |
cceb1885 | 1573 | struct cgraph_node *n = (struct cgraph_node *) *slot; |
9187e02d | 1574 | if (!n->clones && !n->clone_of && !n->global.inlined_to |
d63db217 | 1575 | && (cgraph_global_info_ready |
a837268b JH |
1576 | && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl) |
1577 | || n->in_other_partition))) | |
4a76d91a JH |
1578 | kill_body = true; |
1579 | } | |
266ad5c8 JH |
1580 | if (assembler_name_hash) |
1581 | { | |
1582 | tree name = DECL_ASSEMBLER_NAME (node->decl); | |
1583 | slot = htab_find_slot_with_hash (assembler_name_hash, name, | |
1584 | decl_assembler_name_hash (name), | |
1585 | NO_INSERT); | |
1586 | /* Inline clones are not hashed. */ | |
1587 | if (slot && *slot == node) | |
1588 | htab_clear_slot (assembler_name_hash, slot); | |
1589 | } | |
18c6ada9 | 1590 | |
7e8b322a | 1591 | if (kill_body) |
3a40c18a | 1592 | cgraph_release_function_body (node); |
96fc428c | 1593 | node->decl = NULL; |
70d539ce JH |
1594 | if (node->call_site_hash) |
1595 | { | |
1596 | htab_delete (node->call_site_hash); | |
1597 | node->call_site_hash = NULL; | |
1598 | } | |
18c6ada9 | 1599 | cgraph_n_nodes--; |
2fb16412 MJ |
1600 | |
1601 | /* Clear out the node to NULL all pointers and add the node to the free | |
1602 | list. */ | |
1603 | memset (node, 0, sizeof(*node)); | |
1604 | node->uid = uid; | |
1605 | NEXT_FREE_NODE (node) = free_nodes; | |
1606 | free_nodes = node; | |
18d13f34 JH |
1607 | } |
1608 | ||
2fda8e14 JM |
1609 | /* Add NEW_ to the same comdat group that OLD is in. */ |
1610 | ||
1611 | void | |
1612 | cgraph_add_to_same_comdat_group (struct cgraph_node *new_, | |
1613 | struct cgraph_node *old) | |
1614 | { | |
1615 | gcc_assert (DECL_ONE_ONLY (old->decl)); | |
1616 | gcc_assert (!new_->same_comdat_group); | |
1617 | gcc_assert (new_ != old); | |
1618 | ||
1619 | DECL_COMDAT_GROUP (new_->decl) = DECL_COMDAT_GROUP (old->decl); | |
1620 | new_->same_comdat_group = old; | |
1621 | if (!old->same_comdat_group) | |
1622 | old->same_comdat_group = new_; | |
1623 | else | |
1624 | { | |
1625 | struct cgraph_node *n; | |
1626 | for (n = old->same_comdat_group; | |
1627 | n->same_comdat_group != old; | |
1628 | n = n->same_comdat_group) | |
1629 | ; | |
1630 | n->same_comdat_group = new_; | |
1631 | } | |
1632 | } | |
1633 | ||
9187e02d JH |
1634 | /* Remove the node from cgraph. */ |
1635 | ||
1636 | void | |
1637 | cgraph_remove_node_and_inline_clones (struct cgraph_node *node) | |
1638 | { | |
1639 | struct cgraph_edge *e, *next; | |
1640 | for (e = node->callees; e; e = next) | |
1641 | { | |
1642 | next = e->next_callee; | |
1643 | if (!e->inline_failed) | |
1644 | cgraph_remove_node_and_inline_clones (e->callee); | |
1645 | } | |
1646 | cgraph_remove_node (node); | |
1647 | } | |
1648 | ||
8dafba3c RH |
1649 | /* Notify finalize_compilation_unit that given node is reachable. */ |
1650 | ||
1668aabc | 1651 | void |
8dafba3c | 1652 | cgraph_mark_reachable_node (struct cgraph_node *node) |
1668aabc | 1653 | { |
ba245151 | 1654 | if (!node->reachable && node->local.finalized) |
1668aabc | 1655 | { |
a2acdf1f JH |
1656 | if (cgraph_global_info_ready) |
1657 | { | |
1658 | /* Verify that function does not appear to be needed out of blue | |
1659 | during the optimization process. This can happen for extern | |
1660 | inlines when bodies was removed after inlining. */ | |
7baeea85 JH |
1661 | gcc_assert ((node->analyzed || node->in_other_partition |
1662 | || DECL_EXTERNAL (node->decl))); | |
a2acdf1f JH |
1663 | } |
1664 | else | |
1665 | notice_global_symbol (node->decl); | |
1668aabc | 1666 | node->reachable = 1; |
e767b5be JH |
1667 | |
1668 | node->next_needed = cgraph_nodes_queue; | |
1669 | cgraph_nodes_queue = node; | |
1668aabc JH |
1670 | } |
1671 | } | |
1672 | ||
8dafba3c RH |
1673 | /* Likewise indicate that a node is needed, i.e. reachable via some |
1674 | external means. */ | |
1675 | ||
1676 | void | |
1677 | cgraph_mark_needed_node (struct cgraph_node *node) | |
1678 | { | |
1679 | node->needed = 1; | |
b20996ff | 1680 | gcc_assert (!node->global.inlined_to); |
8dafba3c RH |
1681 | cgraph_mark_reachable_node (node); |
1682 | } | |
18d13f34 | 1683 | |
39ff5a96 JH |
1684 | /* Likewise indicate that a node is having address taken. */ |
1685 | ||
1686 | void | |
1687 | cgraph_mark_address_taken_node (struct cgraph_node *node) | |
1688 | { | |
530f3a1b | 1689 | gcc_assert (!node->global.inlined_to); |
bd3cdcc0 | 1690 | cgraph_mark_reachable_node (node); |
39e2db00 JH |
1691 | /* FIXME: address_taken flag is used both as a shortcut for testing whether |
1692 | IPA_REF_ADDR reference exists (and thus it should be set on node | |
1693 | representing alias we take address of) and as a test whether address | |
1694 | of the object was taken (and thus it should be set on node alias is | |
1695 | referring to). We should remove the first use and the remove the | |
1696 | following set. */ | |
1697 | node->address_taken = 1; | |
1698 | node = cgraph_function_or_thunk_node (node, NULL); | |
39ff5a96 | 1699 | node->address_taken = 1; |
39ff5a96 JH |
1700 | } |
1701 | ||
dafc5b82 JH |
1702 | /* Return local info for the compiled function. */ |
1703 | ||
1704 | struct cgraph_local_info * | |
439f7bc3 | 1705 | cgraph_local_info (tree decl) |
dafc5b82 JH |
1706 | { |
1707 | struct cgraph_node *node; | |
c22cacf3 | 1708 | |
341c100f | 1709 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); |
9f9ebcdf MJ |
1710 | node = cgraph_get_node (decl); |
1711 | if (!node) | |
1712 | return NULL; | |
dafc5b82 JH |
1713 | return &node->local; |
1714 | } | |
1715 | ||
1716 | /* Return local info for the compiled function. */ | |
1717 | ||
1718 | struct cgraph_global_info * | |
439f7bc3 | 1719 | cgraph_global_info (tree decl) |
dafc5b82 JH |
1720 | { |
1721 | struct cgraph_node *node; | |
c22cacf3 | 1722 | |
341c100f | 1723 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL && cgraph_global_info_ready); |
9f9ebcdf MJ |
1724 | node = cgraph_get_node (decl); |
1725 | if (!node) | |
1726 | return NULL; | |
dafc5b82 JH |
1727 | return &node->global; |
1728 | } | |
1729 | ||
b255a036 JH |
1730 | /* Return local info for the compiled function. */ |
1731 | ||
1732 | struct cgraph_rtl_info * | |
439f7bc3 | 1733 | cgraph_rtl_info (tree decl) |
b255a036 JH |
1734 | { |
1735 | struct cgraph_node *node; | |
c22cacf3 | 1736 | |
341c100f | 1737 | gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); |
9f9ebcdf MJ |
1738 | node = cgraph_get_node (decl); |
1739 | if (!node | |
1740 | || (decl != current_function_decl | |
1741 | && !TREE_ASM_WRITTEN (node->decl))) | |
b255a036 JH |
1742 | return NULL; |
1743 | return &node->rtl; | |
1744 | } | |
1745 | ||
61a05df1 JH |
1746 | /* Return a string describing the failure REASON. */ |
1747 | ||
1748 | const char* | |
1749 | cgraph_inline_failed_string (cgraph_inline_failed_t reason) | |
1750 | { | |
1751 | #undef DEFCIFCODE | |
1752 | #define DEFCIFCODE(code, string) string, | |
1753 | ||
1754 | static const char *cif_string_table[CIF_N_REASONS] = { | |
1755 | #include "cif-code.def" | |
1756 | }; | |
1757 | ||
1758 | /* Signedness of an enum type is implementation defined, so cast it | |
1759 | to unsigned before testing. */ | |
1760 | gcc_assert ((unsigned) reason < CIF_N_REASONS); | |
1761 | return cif_string_table[reason]; | |
1762 | } | |
1763 | ||
a194aa56 JH |
1764 | /* Return name of the node used in debug output. */ |
1765 | const char * | |
439f7bc3 | 1766 | cgraph_node_name (struct cgraph_node *node) |
a194aa56 | 1767 | { |
ae2bcd98 | 1768 | return lang_hooks.decl_printable_name (node->decl, 2); |
a194aa56 | 1769 | } |
dafc5b82 | 1770 | |
6b02a499 | 1771 | /* Names used to print out the availability enum. */ |
8a4a83ed | 1772 | const char * const cgraph_availability_names[] = |
fa10beec | 1773 | {"unset", "not_available", "overwritable", "available", "local"}; |
6b02a499 | 1774 | |
c4e622b6 DN |
1775 | |
1776 | /* Dump call graph node NODE to file F. */ | |
1777 | ||
18c6ada9 JH |
1778 | void |
1779 | dump_cgraph_node (FILE *f, struct cgraph_node *node) | |
1780 | { | |
1781 | struct cgraph_edge *edge; | |
e33c6cd6 MJ |
1782 | int indirect_calls_count = 0; |
1783 | ||
903d1e67 | 1784 | fprintf (f, "%s/%i", cgraph_node_name (node), node->uid); |
82f331ff | 1785 | dump_addr (f, " @", (void *)node); |
0115e6c7 JH |
1786 | if (DECL_ASSEMBLER_NAME_SET_P (node->decl)) |
1787 | fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))); | |
18c6ada9 JH |
1788 | if (node->global.inlined_to) |
1789 | fprintf (f, " (inline copy in %s/%i)", | |
1790 | cgraph_node_name (node->global.inlined_to), | |
1791 | node->global.inlined_to->uid); | |
844db5d0 JH |
1792 | if (node->same_comdat_group) |
1793 | fprintf (f, " (same comdat group as %s/%i)", | |
1794 | cgraph_node_name (node->same_comdat_group), | |
1795 | node->same_comdat_group->uid); | |
9187e02d JH |
1796 | if (node->clone_of) |
1797 | fprintf (f, " (clone of %s/%i)", | |
1798 | cgraph_node_name (node->clone_of), | |
1799 | node->clone_of->uid); | |
6b02a499 | 1800 | if (cgraph_function_flags_ready) |
c22cacf3 | 1801 | fprintf (f, " availability:%s", |
8a4a83ed | 1802 | cgraph_availability_names [cgraph_function_body_availability (node)]); |
a837268b JH |
1803 | if (node->analyzed) |
1804 | fprintf (f, " analyzed"); | |
1805 | if (node->in_other_partition) | |
1806 | fprintf (f, " in_other_partition"); | |
e42922b1 JH |
1807 | if (node->count) |
1808 | fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x", | |
1809 | (HOST_WIDEST_INT)node->count); | |
18c6ada9 JH |
1810 | if (node->origin) |
1811 | fprintf (f, " nested in: %s", cgraph_node_name (node->origin)); | |
1812 | if (node->needed) | |
1813 | fprintf (f, " needed"); | |
39ff5a96 JH |
1814 | if (node->address_taken) |
1815 | fprintf (f, " address_taken"); | |
18c6ada9 JH |
1816 | else if (node->reachable) |
1817 | fprintf (f, " reachable"); | |
a837268b JH |
1818 | else if (node->reachable_from_other_partition) |
1819 | fprintf (f, " reachable_from_other_partition"); | |
39ecc018 | 1820 | if (gimple_has_body_p (node->decl)) |
726a989a | 1821 | fprintf (f, " body"); |
257eb6e3 JH |
1822 | if (node->process) |
1823 | fprintf (f, " process"); | |
18c6ada9 JH |
1824 | if (node->local.local) |
1825 | fprintf (f, " local"); | |
e7d6beb0 JH |
1826 | if (node->local.externally_visible) |
1827 | fprintf (f, " externally_visible"); | |
671769c3 JH |
1828 | if (node->resolution != LDPR_UNKNOWN) |
1829 | fprintf (f, " %s", | |
1830 | ld_plugin_symbol_resolution_names[(int)node->resolution]); | |
e7d6beb0 JH |
1831 | if (node->local.finalized) |
1832 | fprintf (f, " finalized"); | |
e7d6beb0 JH |
1833 | if (node->local.redefined_extern_inline) |
1834 | fprintf (f, " redefined_extern_inline"); | |
18c6ada9 JH |
1835 | if (TREE_ASM_WRITTEN (node->decl)) |
1836 | fprintf (f, " asm_written"); | |
844db5d0 JH |
1837 | if (node->only_called_at_startup) |
1838 | fprintf (f, " only_called_at_startup"); | |
1839 | if (node->only_called_at_exit) | |
1840 | fprintf (f, " only_called_at_exit"); | |
25e2c40d JH |
1841 | else if (node->alias) |
1842 | fprintf (f, " alias"); | |
0a35513e AH |
1843 | if (node->tm_clone) |
1844 | fprintf (f, " tm_clone"); | |
18c6ada9 | 1845 | |
c47d0034 JH |
1846 | fprintf (f, "\n"); |
1847 | ||
1848 | if (node->thunk.thunk_p) | |
1849 | { | |
1850 | fprintf (f, " thunk of %s (asm: %s) fixed offset %i virtual value %i has " | |
1851 | "virtual offset %i)\n", | |
1852 | lang_hooks.decl_printable_name (node->thunk.alias, 2), | |
1853 | IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)), | |
1854 | (int)node->thunk.fixed_offset, | |
1855 | (int)node->thunk.virtual_value, | |
1856 | (int)node->thunk.virtual_offset_p); | |
1857 | } | |
39e2db00 JH |
1858 | if (node->alias && node->thunk.alias) |
1859 | { | |
1860 | fprintf (f, " alias of %s", | |
1861 | lang_hooks.decl_printable_name (node->thunk.alias, 2)); | |
1862 | if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias)) | |
1863 | fprintf (f, " (asm: %s)", | |
1864 | IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias))); | |
1865 | fprintf (f, "\n"); | |
1866 | } | |
c47d0034 JH |
1867 | |
1868 | fprintf (f, " called by: "); | |
1869 | ||
18c6ada9 JH |
1870 | for (edge = node->callers; edge; edge = edge->next_caller) |
1871 | { | |
1872 | fprintf (f, "%s/%i ", cgraph_node_name (edge->caller), | |
1873 | edge->caller->uid); | |
e42922b1 JH |
1874 | if (edge->count) |
1875 | fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ", | |
1876 | (HOST_WIDEST_INT)edge->count); | |
45a80bb9 JH |
1877 | if (edge->frequency) |
1878 | fprintf (f, "(%.2f per call) ", | |
1879 | edge->frequency / (double)CGRAPH_FREQ_BASE); | |
18c6ada9 JH |
1880 | if (!edge->inline_failed) |
1881 | fprintf(f, "(inlined) "); | |
e33c6cd6 MJ |
1882 | if (edge->indirect_inlining_edge) |
1883 | fprintf(f, "(indirect_inlining) "); | |
2505c5ed JH |
1884 | if (edge->can_throw_external) |
1885 | fprintf(f, "(can throw external) "); | |
18c6ada9 JH |
1886 | } |
1887 | ||
1888 | fprintf (f, "\n calls: "); | |
1889 | for (edge = node->callees; edge; edge = edge->next_callee) | |
1890 | { | |
1891 | fprintf (f, "%s/%i ", cgraph_node_name (edge->callee), | |
1892 | edge->callee->uid); | |
1893 | if (!edge->inline_failed) | |
1894 | fprintf(f, "(inlined) "); | |
e33c6cd6 MJ |
1895 | if (edge->indirect_inlining_edge) |
1896 | fprintf(f, "(indirect_inlining) "); | |
6b02a499 JH |
1897 | if (edge->count) |
1898 | fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ", | |
1899 | (HOST_WIDEST_INT)edge->count); | |
45a80bb9 JH |
1900 | if (edge->frequency) |
1901 | fprintf (f, "(%.2f per call) ", | |
1902 | edge->frequency / (double)CGRAPH_FREQ_BASE); | |
b6fa5b01 JH |
1903 | if (edge->can_throw_external) |
1904 | fprintf(f, "(can throw external) "); | |
18c6ada9 JH |
1905 | } |
1906 | fprintf (f, "\n"); | |
369451ec JH |
1907 | fprintf (f, " References: "); |
1908 | ipa_dump_references (f, &node->ref_list); | |
1909 | fprintf (f, " Refering this function: "); | |
1910 | ipa_dump_refering (f, &node->ref_list); | |
6744a6ab | 1911 | |
e33c6cd6 MJ |
1912 | for (edge = node->indirect_calls; edge; edge = edge->next_callee) |
1913 | indirect_calls_count++; | |
1914 | if (indirect_calls_count) | |
1915 | fprintf (f, " has %i outgoing edges for indirect calls.\n", | |
1916 | indirect_calls_count); | |
18c6ada9 JH |
1917 | } |
1918 | ||
c4e622b6 DN |
1919 | |
1920 | /* Dump call graph node NODE to stderr. */ | |
1921 | ||
24e47c76 | 1922 | DEBUG_FUNCTION void |
c4e622b6 DN |
1923 | debug_cgraph_node (struct cgraph_node *node) |
1924 | { | |
1925 | dump_cgraph_node (stderr, node); | |
1926 | } | |
1927 | ||
1928 | ||
1929 | /* Dump the callgraph to file F. */ | |
e72fcfe8 JH |
1930 | |
1931 | void | |
439f7bc3 | 1932 | dump_cgraph (FILE *f) |
e72fcfe8 JH |
1933 | { |
1934 | struct cgraph_node *node; | |
1935 | ||
7d82fe7c | 1936 | fprintf (f, "callgraph:\n\n"); |
e72fcfe8 | 1937 | for (node = cgraph_nodes; node; node = node->next) |
18c6ada9 | 1938 | dump_cgraph_node (f, node); |
e72fcfe8 | 1939 | } |
988d1653 | 1940 | |
c4e622b6 DN |
1941 | |
1942 | /* Dump the call graph to stderr. */ | |
1943 | ||
24e47c76 | 1944 | DEBUG_FUNCTION void |
c4e622b6 DN |
1945 | debug_cgraph (void) |
1946 | { | |
1947 | dump_cgraph (stderr); | |
1948 | } | |
1949 | ||
1950 | ||
fccc4eb2 | 1951 | /* Set the DECL_ASSEMBLER_NAME and update cgraph hashtables. */ |
c4e622b6 | 1952 | |
fccc4eb2 JH |
1953 | void |
1954 | change_decl_assembler_name (tree decl, tree name) | |
1955 | { | |
99fecd47 JH |
1956 | struct cgraph_node *node; |
1957 | void **slot; | |
fccc4eb2 | 1958 | if (!DECL_ASSEMBLER_NAME_SET_P (decl)) |
99fecd47 JH |
1959 | SET_DECL_ASSEMBLER_NAME (decl, name); |
1960 | else | |
fccc4eb2 | 1961 | { |
99fecd47 JH |
1962 | if (name == DECL_ASSEMBLER_NAME (decl)) |
1963 | return; | |
fccc4eb2 | 1964 | |
99fecd47 JH |
1965 | if (assembler_name_hash |
1966 | && TREE_CODE (decl) == FUNCTION_DECL | |
ab079773 | 1967 | && (node = cgraph_get_node (decl)) != NULL) |
99fecd47 JH |
1968 | { |
1969 | tree old_name = DECL_ASSEMBLER_NAME (decl); | |
1970 | slot = htab_find_slot_with_hash (assembler_name_hash, old_name, | |
1971 | decl_assembler_name_hash (old_name), | |
1972 | NO_INSERT); | |
1973 | /* Inline clones are not hashed. */ | |
1974 | if (slot && *slot == node) | |
1975 | htab_clear_slot (assembler_name_hash, slot); | |
1976 | } | |
1977 | if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) | |
1978 | && DECL_RTL_SET_P (decl)) | |
1979 | warning (0, "%D renamed after being referenced in assembly", decl); | |
fccc4eb2 | 1980 | |
99fecd47 JH |
1981 | SET_DECL_ASSEMBLER_NAME (decl, name); |
1982 | } | |
1983 | if (assembler_name_hash | |
1984 | && TREE_CODE (decl) == FUNCTION_DECL | |
ab079773 | 1985 | && (node = cgraph_get_node (decl)) != NULL) |
99fecd47 JH |
1986 | { |
1987 | slot = htab_find_slot_with_hash (assembler_name_hash, name, | |
1988 | decl_assembler_name_hash (name), | |
1989 | INSERT); | |
1990 | gcc_assert (!*slot); | |
1991 | *slot = node; | |
1992 | } | |
e69529cd JH |
1993 | } |
1994 | ||
474eccc6 ILT |
1995 | /* Add a top-level asm statement to the list. */ |
1996 | ||
1997 | struct cgraph_asm_node * | |
1998 | cgraph_add_asm_node (tree asm_str) | |
1999 | { | |
2000 | struct cgraph_asm_node *node; | |
2001 | ||
a9429e29 | 2002 | node = ggc_alloc_cleared_cgraph_asm_node (); |
474eccc6 ILT |
2003 | node->asm_str = asm_str; |
2004 | node->order = cgraph_order++; | |
2005 | node->next = NULL; | |
2006 | if (cgraph_asm_nodes == NULL) | |
2007 | cgraph_asm_nodes = node; | |
2008 | else | |
2009 | cgraph_asm_last_node->next = node; | |
2010 | cgraph_asm_last_node = node; | |
2011 | return node; | |
2012 | } | |
2013 | ||
1bb17c21 JH |
2014 | /* Return true when the DECL can possibly be inlined. */ |
2015 | bool | |
2016 | cgraph_function_possibly_inlined_p (tree decl) | |
2017 | { | |
1bb17c21 | 2018 | if (!cgraph_global_info_ready) |
e90acd93 | 2019 | return !DECL_UNINLINABLE (decl); |
6f312d18 | 2020 | return DECL_POSSIBLY_INLINED (decl); |
18c6ada9 JH |
2021 | } |
2022 | ||
2023 | /* Create clone of E in the node N represented by CALL_EXPR the callgraph. */ | |
2024 | struct cgraph_edge * | |
e42922b1 | 2025 | cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, |
d7f09764 | 2026 | gimple call_stmt, unsigned stmt_uid, gcov_type count_scale, |
898b8927 | 2027 | int freq_scale, bool update_original) |
18c6ada9 | 2028 | { |
82d6e6fc | 2029 | struct cgraph_edge *new_edge; |
45a80bb9 | 2030 | gcov_type count = e->count * count_scale / REG_BR_PROB_BASE; |
0d63a740 | 2031 | gcov_type freq; |
e42922b1 | 2032 | |
0d63a740 JH |
2033 | /* We do not want to ignore loop nest after frequency drops to 0. */ |
2034 | if (!freq_scale) | |
2035 | freq_scale = 1; | |
2036 | freq = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE; | |
45a80bb9 JH |
2037 | if (freq > CGRAPH_FREQ_MAX) |
2038 | freq = CGRAPH_FREQ_MAX; | |
e33c6cd6 MJ |
2039 | |
2040 | if (e->indirect_unknown_callee) | |
2041 | { | |
2042 | tree decl; | |
2043 | ||
2044 | if (call_stmt && (decl = gimple_call_fndecl (call_stmt))) | |
2045 | { | |
a358e188 MJ |
2046 | struct cgraph_node *callee = cgraph_get_node (decl); |
2047 | gcc_checking_assert (callee); | |
898b8927 | 2048 | new_edge = cgraph_create_edge (n, callee, call_stmt, count, freq); |
e33c6cd6 MJ |
2049 | } |
2050 | else | |
2051 | { | |
5f902d76 JH |
2052 | new_edge = cgraph_create_indirect_edge (n, call_stmt, |
2053 | e->indirect_info->ecf_flags, | |
898b8927 | 2054 | count, freq); |
b258210c | 2055 | *new_edge->indirect_info = *e->indirect_info; |
e33c6cd6 MJ |
2056 | } |
2057 | } | |
2058 | else | |
ceeffab0 | 2059 | { |
898b8927 | 2060 | new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq); |
ceeffab0 MJ |
2061 | if (e->indirect_info) |
2062 | { | |
2063 | new_edge->indirect_info | |
2064 | = ggc_alloc_cleared_cgraph_indirect_call_info (); | |
2065 | *new_edge->indirect_info = *e->indirect_info; | |
2066 | } | |
2067 | } | |
18c6ada9 | 2068 | |
82d6e6fc | 2069 | new_edge->inline_failed = e->inline_failed; |
e33c6cd6 | 2070 | new_edge->indirect_inlining_edge = e->indirect_inlining_edge; |
d7f09764 | 2071 | new_edge->lto_stmt_uid = stmt_uid; |
41c8e948 RG |
2072 | /* Clone flags that depend on call_stmt availability manually. */ |
2073 | new_edge->can_throw_external = e->can_throw_external; | |
2074 | new_edge->call_stmt_cannot_inline_p = e->call_stmt_cannot_inline_p; | |
c5a4444c | 2075 | if (update_original) |
d63f0fe5 | 2076 | { |
82d6e6fc | 2077 | e->count -= new_edge->count; |
d63f0fe5 JH |
2078 | if (e->count < 0) |
2079 | e->count = 0; | |
2080 | } | |
82d6e6fc KG |
2081 | cgraph_call_edge_duplication_hooks (e, new_edge); |
2082 | return new_edge; | |
1bb17c21 | 2083 | } |
e69529cd | 2084 | |
74605a11 | 2085 | |
e42922b1 | 2086 | /* Create node representing clone of N executed COUNT times. Decrease |
c22cacf3 | 2087 | the execution counts from original node too. |
ccbbf8a2 JH |
2088 | The new clone will have decl set to DECL that may or may not be the same |
2089 | as decl of N. | |
c5a4444c JH |
2090 | |
2091 | When UPDATE_ORIGINAL is true, the counts are subtracted from the original | |
2092 | function's profile to reflect the fact that part of execution is handled | |
74605a11 JH |
2093 | by node. |
2094 | When CALL_DUPLICATOIN_HOOK is true, the ipa passes are acknowledged about | |
2095 | the new clone. Otherwise the caller is responsible for doing so later. */ | |
2096 | ||
18c6ada9 | 2097 | struct cgraph_node * |
91fbf0c7 | 2098 | cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, |
898b8927 | 2099 | bool update_original, |
74605a11 JH |
2100 | VEC(cgraph_edge_p,heap) *redirect_callers, |
2101 | bool call_duplication_hook) | |
18c6ada9 | 2102 | { |
a358e188 | 2103 | struct cgraph_node *new_node = cgraph_create_node_1 (); |
18c6ada9 | 2104 | struct cgraph_edge *e; |
06191a23 | 2105 | gcov_type count_scale; |
03ec7d01 | 2106 | unsigned i; |
18c6ada9 | 2107 | |
91fbf0c7 | 2108 | new_node->decl = decl; |
82d6e6fc KG |
2109 | new_node->origin = n->origin; |
2110 | if (new_node->origin) | |
18c6ada9 | 2111 | { |
82d6e6fc KG |
2112 | new_node->next_nested = new_node->origin->nested; |
2113 | new_node->origin->nested = new_node; | |
18c6ada9 | 2114 | } |
82d6e6fc KG |
2115 | new_node->analyzed = n->analyzed; |
2116 | new_node->local = n->local; | |
b20996ff | 2117 | new_node->local.externally_visible = false; |
e65bb9be | 2118 | new_node->local.local = true; |
82d6e6fc KG |
2119 | new_node->global = n->global; |
2120 | new_node->rtl = n->rtl; | |
82d6e6fc | 2121 | new_node->count = count; |
5fefcf92 | 2122 | new_node->frequency = n->frequency; |
9187e02d | 2123 | new_node->clone = n->clone; |
88cc1e04 | 2124 | new_node->clone.tree_map = 0; |
e42922b1 | 2125 | if (n->count) |
52c76998 PY |
2126 | { |
2127 | if (new_node->count > n->count) | |
2128 | count_scale = REG_BR_PROB_BASE; | |
2129 | else | |
2130 | count_scale = new_node->count * REG_BR_PROB_BASE / n->count; | |
2131 | } | |
e42922b1 JH |
2132 | else |
2133 | count_scale = 0; | |
c5a4444c | 2134 | if (update_original) |
d63f0fe5 JH |
2135 | { |
2136 | n->count -= count; | |
2137 | if (n->count < 0) | |
2138 | n->count = 0; | |
2139 | } | |
18c6ada9 | 2140 | |
ac47786e | 2141 | FOR_EACH_VEC_ELT (cgraph_edge_p, redirect_callers, i, e) |
03ec7d01 JH |
2142 | { |
2143 | /* Redirect calls to the old version node to point to its new | |
2144 | version. */ | |
2145 | cgraph_redirect_edge_callee (e, new_node); | |
2146 | } | |
2147 | ||
2148 | ||
18c6ada9 | 2149 | for (e = n->callees;e; e=e->next_callee) |
d7f09764 | 2150 | cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, |
898b8927 | 2151 | count_scale, freq, update_original); |
18c6ada9 | 2152 | |
e33c6cd6 MJ |
2153 | for (e = n->indirect_calls; e; e = e->next_callee) |
2154 | cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, | |
898b8927 | 2155 | count_scale, freq, update_original); |
369451ec | 2156 | ipa_clone_references (new_node, NULL, &n->ref_list); |
e33c6cd6 | 2157 | |
9187e02d JH |
2158 | new_node->next_sibling_clone = n->clones; |
2159 | if (n->clones) | |
2160 | n->clones->prev_sibling_clone = new_node; | |
2161 | n->clones = new_node; | |
2162 | new_node->clone_of = n; | |
18c6ada9 | 2163 | |
91fbf0c7 JH |
2164 | if (n->decl != decl) |
2165 | { | |
2166 | struct cgraph_node **slot; | |
2167 | slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, new_node, INSERT); | |
2168 | gcc_assert (!*slot); | |
2169 | *slot = new_node; | |
2170 | if (assembler_name_hash) | |
2171 | { | |
2172 | void **aslot; | |
2173 | tree name = DECL_ASSEMBLER_NAME (decl); | |
2174 | ||
2175 | aslot = htab_find_slot_with_hash (assembler_name_hash, name, | |
2176 | decl_assembler_name_hash (name), | |
2177 | INSERT); | |
2178 | gcc_assert (!*aslot); | |
2179 | *aslot = new_node; | |
2180 | } | |
2181 | } | |
74605a11 JH |
2182 | |
2183 | if (call_duplication_hook) | |
2184 | cgraph_call_node_duplication_hooks (n, new_node); | |
82d6e6fc | 2185 | return new_node; |
18c6ada9 | 2186 | } |
8f235343 | 2187 | |
036546e5 | 2188 | /* Create a new name for clone of DECL, add SUFFIX. Returns an identifier. */ |
9187e02d JH |
2189 | |
2190 | static GTY(()) unsigned int clone_fn_id_num; | |
2191 | ||
036546e5 JH |
2192 | tree |
2193 | clone_function_name (tree decl, const char *suffix) | |
9187e02d JH |
2194 | { |
2195 | tree name = DECL_ASSEMBLER_NAME (decl); | |
2196 | size_t len = IDENTIFIER_LENGTH (name); | |
2197 | char *tmp_name, *prefix; | |
2198 | ||
036546e5 | 2199 | prefix = XALLOCAVEC (char, len + strlen (suffix) + 2); |
9187e02d | 2200 | memcpy (prefix, IDENTIFIER_POINTER (name), len); |
036546e5 | 2201 | strcpy (prefix + len + 1, suffix); |
9187e02d JH |
2202 | #ifndef NO_DOT_IN_LABEL |
2203 | prefix[len] = '.'; | |
2204 | #elif !defined NO_DOLLAR_IN_LABEL | |
2205 | prefix[len] = '$'; | |
036546e5 JH |
2206 | #else |
2207 | prefix[len] = '_'; | |
9187e02d JH |
2208 | #endif |
2209 | ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++); | |
2210 | return get_identifier (tmp_name); | |
2211 | } | |
2212 | ||
2213 | /* Create callgraph node clone with new declaration. The actual body will | |
b8698a0f | 2214 | be copied later at compilation stage. |
9187e02d JH |
2215 | |
2216 | TODO: after merging in ipa-sra use function call notes instead of args_to_skip | |
2217 | bitmap interface. | |
2218 | */ | |
2219 | struct cgraph_node * | |
2220 | cgraph_create_virtual_clone (struct cgraph_node *old_node, | |
2221 | VEC(cgraph_edge_p,heap) *redirect_callers, | |
2222 | VEC(ipa_replace_map_p,gc) *tree_map, | |
036546e5 JH |
2223 | bitmap args_to_skip, |
2224 | const char * suffix) | |
9187e02d JH |
2225 | { |
2226 | tree old_decl = old_node->decl; | |
2227 | struct cgraph_node *new_node = NULL; | |
2228 | tree new_decl; | |
a940b4d9 JH |
2229 | size_t i; |
2230 | struct ipa_replace_map *map; | |
9187e02d | 2231 | |
36576655 | 2232 | if (!flag_wpa) |
77a74ed7 | 2233 | gcc_checking_assert (tree_versionable_function_p (old_decl)); |
9187e02d | 2234 | |
61e03ffc JH |
2235 | gcc_assert (old_node->local.can_change_signature || !args_to_skip); |
2236 | ||
9187e02d JH |
2237 | /* Make a new FUNCTION_DECL tree node */ |
2238 | if (!args_to_skip) | |
2239 | new_decl = copy_node (old_decl); | |
2240 | else | |
2241 | new_decl = build_function_decl_skip_args (old_decl, args_to_skip); | |
2242 | DECL_STRUCT_FUNCTION (new_decl) = NULL; | |
2243 | ||
2244 | /* Generate a new name for the new version. */ | |
036546e5 | 2245 | DECL_NAME (new_decl) = clone_function_name (old_decl, suffix); |
9187e02d JH |
2246 | SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); |
2247 | SET_DECL_RTL (new_decl, NULL); | |
2248 | ||
91fbf0c7 | 2249 | new_node = cgraph_clone_node (old_node, new_decl, old_node->count, |
898b8927 | 2250 | CGRAPH_FREQ_BASE, false, |
74605a11 | 2251 | redirect_callers, false); |
9187e02d JH |
2252 | /* Update the properties. |
2253 | Make clone visible only within this translation unit. Make sure | |
2254 | that is not weak also. | |
2255 | ??? We cannot use COMDAT linkage because there is no | |
2256 | ABI support for this. */ | |
2257 | DECL_EXTERNAL (new_node->decl) = 0; | |
087fa34b JJ |
2258 | if (DECL_ONE_ONLY (old_decl)) |
2259 | DECL_SECTION_NAME (new_node->decl) = NULL; | |
fc26fae3 | 2260 | DECL_COMDAT_GROUP (new_node->decl) = 0; |
9187e02d JH |
2261 | TREE_PUBLIC (new_node->decl) = 0; |
2262 | DECL_COMDAT (new_node->decl) = 0; | |
2263 | DECL_WEAK (new_node->decl) = 0; | |
dd8352ee JH |
2264 | DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0; |
2265 | DECL_STATIC_DESTRUCTOR (new_node->decl) = 0; | |
9187e02d JH |
2266 | new_node->clone.tree_map = tree_map; |
2267 | new_node->clone.args_to_skip = args_to_skip; | |
ac47786e | 2268 | FOR_EACH_VEC_ELT (ipa_replace_map_p, tree_map, i, map) |
a940b4d9 JH |
2269 | { |
2270 | tree var = map->new_tree; | |
2271 | ||
2272 | STRIP_NOPS (var); | |
2273 | if (TREE_CODE (var) != ADDR_EXPR) | |
2274 | continue; | |
2275 | var = get_base_var (var); | |
2276 | if (!var) | |
2277 | continue; | |
2278 | ||
2279 | /* Record references of the future statement initializing the constant | |
2280 | argument. */ | |
2281 | if (TREE_CODE (var) == FUNCTION_DECL) | |
a358e188 MJ |
2282 | { |
2283 | struct cgraph_node *ref_node = cgraph_get_node (var); | |
2284 | gcc_checking_assert (ref_node); | |
2285 | ipa_record_reference (new_node, NULL, ref_node, NULL, IPA_REF_ADDR, | |
2286 | NULL); | |
2287 | } | |
a940b4d9 JH |
2288 | else if (TREE_CODE (var) == VAR_DECL) |
2289 | ipa_record_reference (new_node, NULL, NULL, varpool_node (var), | |
2290 | IPA_REF_ADDR, NULL); | |
2291 | } | |
08ad1d6d JH |
2292 | if (!args_to_skip) |
2293 | new_node->clone.combined_args_to_skip = old_node->clone.combined_args_to_skip; | |
2294 | else if (old_node->clone.combined_args_to_skip) | |
2295 | { | |
2296 | int newi = 0, oldi = 0; | |
2297 | tree arg; | |
2298 | bitmap new_args_to_skip = BITMAP_GGC_ALLOC (); | |
2299 | struct cgraph_node *orig_node; | |
2300 | for (orig_node = old_node; orig_node->clone_of; orig_node = orig_node->clone_of) | |
2301 | ; | |
910ad8de | 2302 | for (arg = DECL_ARGUMENTS (orig_node->decl); arg; arg = DECL_CHAIN (arg), oldi++) |
08ad1d6d JH |
2303 | { |
2304 | if (bitmap_bit_p (old_node->clone.combined_args_to_skip, oldi)) | |
2305 | { | |
2306 | bitmap_set_bit (new_args_to_skip, oldi); | |
2307 | continue; | |
2308 | } | |
2309 | if (bitmap_bit_p (args_to_skip, newi)) | |
2310 | bitmap_set_bit (new_args_to_skip, oldi); | |
2311 | newi++; | |
2312 | } | |
2313 | new_node->clone.combined_args_to_skip = new_args_to_skip; | |
2314 | } | |
2315 | else | |
2316 | new_node->clone.combined_args_to_skip = args_to_skip; | |
9187e02d JH |
2317 | new_node->local.externally_visible = 0; |
2318 | new_node->local.local = 1; | |
2319 | new_node->lowered = true; | |
2320 | new_node->reachable = true; | |
2321 | ||
74605a11 JH |
2322 | cgraph_call_node_duplication_hooks (old_node, new_node); |
2323 | ||
03ec7d01 | 2324 | |
9187e02d JH |
2325 | return new_node; |
2326 | } | |
2327 | ||
8f235343 JH |
2328 | /* NODE is no longer nested function; update cgraph accordingly. */ |
2329 | void | |
2330 | cgraph_unnest_node (struct cgraph_node *node) | |
2331 | { | |
2332 | struct cgraph_node **node2 = &node->origin->nested; | |
2333 | gcc_assert (node->origin); | |
2334 | ||
2335 | while (*node2 != node) | |
2336 | node2 = &(*node2)->next_nested; | |
2337 | *node2 = node->next_nested; | |
2338 | node->origin = NULL; | |
2339 | } | |
6b02a499 JH |
2340 | |
2341 | /* Return function availability. See cgraph.h for description of individual | |
2342 | return values. */ | |
2343 | enum availability | |
2344 | cgraph_function_body_availability (struct cgraph_node *node) | |
2345 | { | |
2346 | enum availability avail; | |
2347 | gcc_assert (cgraph_function_flags_ready); | |
093c2329 | 2348 | if (!node->analyzed) |
6b02a499 JH |
2349 | avail = AVAIL_NOT_AVAILABLE; |
2350 | else if (node->local.local) | |
2351 | avail = AVAIL_LOCAL; | |
d3ea650c | 2352 | else if (!node->local.externally_visible) |
6b02a499 | 2353 | avail = AVAIL_AVAILABLE; |
61502ca8 NF |
2354 | /* Inline functions are safe to be analyzed even if their symbol can |
2355 | be overwritten at runtime. It is not meaningful to enforce any sane | |
4a371c8d JH |
2356 | behaviour on replacing inline function by different body. */ |
2357 | else if (DECL_DECLARED_INLINE_P (node->decl)) | |
2358 | avail = AVAIL_AVAILABLE; | |
6b02a499 JH |
2359 | |
2360 | /* If the function can be overwritten, return OVERWRITABLE. Take | |
2361 | care at least of two notable extensions - the COMDAT functions | |
2362 | used to share template instantiations in C++ (this is symmetric | |
2363 | to code cp_cannot_inline_tree_fn and probably shall be shared and | |
ff5c4582 | 2364 | the inlinability hooks completely eliminated). |
6b02a499 JH |
2365 | |
2366 | ??? Does the C++ one definition rule allow us to always return | |
2367 | AVAIL_AVAILABLE here? That would be good reason to preserve this | |
4a371c8d JH |
2368 | bit. */ |
2369 | ||
051f8cc6 | 2370 | else if (decl_replaceable_p (node->decl) && !DECL_EXTERNAL (node->decl)) |
6b02a499 JH |
2371 | avail = AVAIL_OVERWRITABLE; |
2372 | else avail = AVAIL_AVAILABLE; | |
2373 | ||
2374 | return avail; | |
2375 | } | |
2376 | ||
f45e0ad1 JH |
2377 | /* Add the function FNDECL to the call graph. |
2378 | Unlike cgraph_finalize_function, this function is intended to be used | |
2379 | by middle end and allows insertion of new function at arbitrary point | |
2380 | of compilation. The function can be either in high, low or SSA form | |
2381 | GIMPLE. | |
50674e96 | 2382 | |
f45e0ad1 | 2383 | The function is assumed to be reachable and have address taken (so no |
b8698a0f | 2384 | API breaking optimizations are performed on it). |
50674e96 | 2385 | |
f45e0ad1 JH |
2386 | Main work done by this function is to enqueue the function for later |
2387 | processing to avoid need the passes to be re-entrant. */ | |
953ff289 DN |
2388 | |
2389 | void | |
f45e0ad1 | 2390 | cgraph_add_new_function (tree fndecl, bool lowered) |
953ff289 | 2391 | { |
f45e0ad1 JH |
2392 | struct cgraph_node *node; |
2393 | switch (cgraph_state) | |
2394 | { | |
2395 | case CGRAPH_STATE_CONSTRUCTION: | |
fa10beec | 2396 | /* Just enqueue function to be processed at nearest occurrence. */ |
a358e188 | 2397 | node = cgraph_create_node (fndecl); |
f45e0ad1 JH |
2398 | node->next_needed = cgraph_new_nodes; |
2399 | if (lowered) | |
2400 | node->lowered = true; | |
2401 | cgraph_new_nodes = node; | |
2402 | break; | |
2403 | ||
2404 | case CGRAPH_STATE_IPA: | |
7a388ee4 | 2405 | case CGRAPH_STATE_IPA_SSA: |
f45e0ad1 JH |
2406 | case CGRAPH_STATE_EXPANSION: |
2407 | /* Bring the function into finalized state and enqueue for later | |
2408 | analyzing and compilation. */ | |
a358e188 | 2409 | node = cgraph_get_create_node (fndecl); |
f45e0ad1 JH |
2410 | node->local.local = false; |
2411 | node->local.finalized = true; | |
2412 | node->reachable = node->needed = true; | |
ff2c88a5 JH |
2413 | if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION) |
2414 | { | |
2415 | push_cfun (DECL_STRUCT_FUNCTION (fndecl)); | |
2416 | current_function_decl = fndecl; | |
726a989a RB |
2417 | gimple_register_cfg_hooks (); |
2418 | tree_lowering_passes (fndecl); | |
ff2c88a5 JH |
2419 | bitmap_obstack_initialize (NULL); |
2420 | if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) | |
2421 | execute_pass_list (pass_early_local_passes.pass.sub); | |
2422 | bitmap_obstack_release (NULL); | |
2423 | pop_cfun (); | |
2424 | current_function_decl = NULL; | |
2425 | ||
2426 | lowered = true; | |
2427 | } | |
f45e0ad1 JH |
2428 | if (lowered) |
2429 | node->lowered = true; | |
2430 | node->next_needed = cgraph_new_nodes; | |
2431 | cgraph_new_nodes = node; | |
2432 | break; | |
2433 | ||
2434 | case CGRAPH_STATE_FINISHED: | |
2435 | /* At the very end of compilation we have to do all the work up | |
2436 | to expansion. */ | |
a358e188 | 2437 | node = cgraph_create_node (fndecl); |
322dd859 MJ |
2438 | if (lowered) |
2439 | node->lowered = true; | |
2440 | cgraph_analyze_function (node); | |
f45e0ad1 JH |
2441 | push_cfun (DECL_STRUCT_FUNCTION (fndecl)); |
2442 | current_function_decl = fndecl; | |
726a989a | 2443 | gimple_register_cfg_hooks (); |
7a388ee4 | 2444 | bitmap_obstack_initialize (NULL); |
c72321c9 | 2445 | if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) |
8ddbbcae | 2446 | execute_pass_list (pass_early_local_passes.pass.sub); |
7a388ee4 | 2447 | bitmap_obstack_release (NULL); |
f45e0ad1 JH |
2448 | tree_rest_of_compilation (fndecl); |
2449 | pop_cfun (); | |
2450 | current_function_decl = NULL; | |
2451 | break; | |
2452 | } | |
f9417da1 RG |
2453 | |
2454 | /* Set a personality if required and we already passed EH lowering. */ | |
2455 | if (lowered | |
2456 | && (function_needs_eh_personality (DECL_STRUCT_FUNCTION (fndecl)) | |
2457 | == eh_personality_lang)) | |
2458 | DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality (); | |
953ff289 DN |
2459 | } |
2460 | ||
be330ed4 JH |
2461 | /* Worker for cgraph_node_can_be_local_p. */ |
2462 | static bool | |
2463 | cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node, | |
2464 | void *data ATTRIBUTE_UNUSED) | |
2465 | { | |
2466 | return !(!node->needed | |
2467 | && ((DECL_COMDAT (node->decl) && !node->same_comdat_group) | |
2468 | || !node->local.externally_visible)); | |
2469 | } | |
2470 | ||
a550d677 MJ |
2471 | /* Return true if NODE can be made local for API change. |
2472 | Extern inline functions and C++ COMDAT functions can be made local | |
2473 | at the expense of possible code size growth if function is used in multiple | |
2474 | compilation units. */ | |
2475 | bool | |
2476 | cgraph_node_can_be_local_p (struct cgraph_node *node) | |
2477 | { | |
be330ed4 JH |
2478 | return (!node->address_taken |
2479 | && !cgraph_for_node_and_aliases (node, | |
2480 | cgraph_node_cannot_be_local_p_1, | |
2481 | NULL, true)); | |
a550d677 MJ |
2482 | } |
2483 | ||
715a4e08 AM |
2484 | /* Make DECL local. FIXME: We shouldn't need to mess with rtl this early, |
2485 | but other code such as notice_global_symbol generates rtl. */ | |
2486 | void | |
2487 | cgraph_make_decl_local (tree decl) | |
2488 | { | |
2489 | rtx rtl, symbol; | |
2490 | ||
2491 | if (TREE_CODE (decl) == VAR_DECL) | |
2492 | DECL_COMMON (decl) = 0; | |
5dde3b01 JH |
2493 | else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); |
2494 | ||
ee6f1177 | 2495 | if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl)) |
715a4e08 | 2496 | { |
99fecd47 JH |
2497 | /* It is possible that we are linking against library defining same COMDAT |
2498 | function. To avoid conflict we need to rename our local name of the | |
2499 | function just in the case WHOPR partitioning decide to make it hidden | |
2500 | to avoid cross partition references. */ | |
2501 | if (flag_wpa) | |
2502 | { | |
2503 | const char *old_name; | |
2504 | ||
2505 | old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); | |
2506 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
2507 | { | |
ab079773 | 2508 | struct cgraph_node *node = cgraph_get_node (decl); |
99fecd47 JH |
2509 | change_decl_assembler_name (decl, |
2510 | clone_function_name (decl, "local")); | |
2511 | if (node->local.lto_file_data) | |
2512 | lto_record_renamed_decl (node->local.lto_file_data, | |
2513 | old_name, | |
2514 | IDENTIFIER_POINTER | |
2515 | (DECL_ASSEMBLER_NAME (decl))); | |
2516 | } | |
2517 | else if (TREE_CODE (decl) == VAR_DECL) | |
2518 | { | |
2519 | struct varpool_node *vnode = varpool_get_node (decl); | |
2520 | /* change_decl_assembler_name will warn here on vtables because | |
2521 | C++ frontend still sets TREE_SYMBOL_REFERENCED on them. */ | |
2522 | SET_DECL_ASSEMBLER_NAME (decl, | |
2523 | clone_function_name (decl, "local")); | |
2524 | if (vnode->lto_file_data) | |
2525 | lto_record_renamed_decl (vnode->lto_file_data, | |
2526 | old_name, | |
2527 | IDENTIFIER_POINTER | |
2528 | (DECL_ASSEMBLER_NAME (decl))); | |
2529 | } | |
2530 | } | |
5dde3b01 | 2531 | DECL_SECTION_NAME (decl) = 0; |
715a4e08 | 2532 | DECL_COMDAT (decl) = 0; |
715a4e08 | 2533 | } |
5dde3b01 JH |
2534 | DECL_COMDAT_GROUP (decl) = 0; |
2535 | DECL_WEAK (decl) = 0; | |
2536 | DECL_EXTERNAL (decl) = 0; | |
715a4e08 AM |
2537 | TREE_PUBLIC (decl) = 0; |
2538 | if (!DECL_RTL_SET_P (decl)) | |
2539 | return; | |
2540 | ||
2541 | /* Update rtl flags. */ | |
2542 | make_decl_rtl (decl); | |
2543 | ||
2544 | rtl = DECL_RTL (decl); | |
2545 | if (!MEM_P (rtl)) | |
2546 | return; | |
2547 | ||
2548 | symbol = XEXP (rtl, 0); | |
2549 | if (GET_CODE (symbol) != SYMBOL_REF) | |
2550 | return; | |
2551 | ||
2552 | SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); | |
2553 | } | |
2554 | ||
be330ed4 JH |
2555 | /* Call calback on NODE, thunks and aliases asociated to NODE. |
2556 | When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are | |
2557 | skipped. */ | |
2558 | ||
2559 | bool | |
2560 | cgraph_for_node_thunks_and_aliases (struct cgraph_node *node, | |
2561 | bool (*callback) (struct cgraph_node *, void *), | |
2562 | void *data, | |
2563 | bool include_overwritable) | |
2564 | { | |
2565 | struct cgraph_edge *e; | |
39e2db00 JH |
2566 | int i; |
2567 | struct ipa_ref *ref; | |
be330ed4 JH |
2568 | |
2569 | if (callback (node, data)) | |
2570 | return true; | |
be330ed4 JH |
2571 | for (e = node->callers; e; e = e->next_caller) |
2572 | if (e->caller->thunk.thunk_p | |
2573 | && (include_overwritable | |
25e2c40d | 2574 | || cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE)) |
9aa3f5c5 JH |
2575 | if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data, |
2576 | include_overwritable)) | |
2577 | return true; | |
39e2db00 JH |
2578 | for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) |
2579 | if (ref->use == IPA_REF_ALIAS) | |
2580 | { | |
2581 | struct cgraph_node *alias = ipa_ref_refering_node (ref); | |
2582 | if (include_overwritable | |
2583 | || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) | |
9aa3f5c5 JH |
2584 | if (cgraph_for_node_thunks_and_aliases (alias, callback, data, |
2585 | include_overwritable)) | |
2586 | return true; | |
39e2db00 | 2587 | } |
be330ed4 JH |
2588 | return false; |
2589 | } | |
2590 | ||
2591 | /* Call calback on NODE and aliases asociated to NODE. | |
2592 | When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are | |
2593 | skipped. */ | |
2594 | ||
2595 | bool | |
2596 | cgraph_for_node_and_aliases (struct cgraph_node *node, | |
2597 | bool (*callback) (struct cgraph_node *, void *), | |
2598 | void *data, | |
39e2db00 | 2599 | bool include_overwritable) |
a550d677 | 2600 | { |
39e2db00 JH |
2601 | int i; |
2602 | struct ipa_ref *ref; | |
be330ed4 JH |
2603 | |
2604 | if (callback (node, data)) | |
2605 | return true; | |
39e2db00 JH |
2606 | for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) |
2607 | if (ref->use == IPA_REF_ALIAS) | |
2608 | { | |
2609 | struct cgraph_node *alias = ipa_ref_refering_node (ref); | |
2610 | if (include_overwritable | |
2611 | || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) | |
9aa3f5c5 JH |
2612 | if (cgraph_for_node_and_aliases (alias, callback, data, |
2613 | include_overwritable)) | |
2614 | return true; | |
39e2db00 | 2615 | } |
be330ed4 JH |
2616 | return false; |
2617 | } | |
2618 | ||
2619 | /* Worker to bring NODE local. */ | |
2620 | ||
2621 | static bool | |
2622 | cgraph_make_node_local_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
2623 | { | |
2624 | gcc_checking_assert (cgraph_node_can_be_local_p (node)); | |
a550d677 MJ |
2625 | if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)) |
2626 | { | |
715a4e08 AM |
2627 | cgraph_make_decl_local (node->decl); |
2628 | ||
a550d677 MJ |
2629 | node->local.externally_visible = false; |
2630 | node->local.local = true; | |
051f8cc6 | 2631 | node->resolution = LDPR_PREVAILING_DEF_IRONLY; |
a550d677 MJ |
2632 | gcc_assert (cgraph_function_body_availability (node) == AVAIL_LOCAL); |
2633 | } | |
be330ed4 | 2634 | return false; |
a550d677 MJ |
2635 | } |
2636 | ||
be330ed4 JH |
2637 | /* Bring NODE local. */ |
2638 | ||
2639 | void | |
2640 | cgraph_make_node_local (struct cgraph_node *node) | |
2641 | { | |
2642 | cgraph_for_node_thunks_and_aliases (node, cgraph_make_node_local_1, | |
2643 | NULL, true); | |
2644 | } | |
2645 | ||
2646 | /* Worker to set nothrow flag. */ | |
2647 | ||
2648 | static bool | |
2649 | cgraph_set_nothrow_flag_1 (struct cgraph_node *node, void *data) | |
2650 | { | |
71fb4f92 JH |
2651 | struct cgraph_edge *e; |
2652 | ||
be330ed4 | 2653 | TREE_NOTHROW (node->decl) = data != NULL; |
71fb4f92 JH |
2654 | |
2655 | if (data != NULL) | |
2656 | for (e = node->callers; e; e = e->next_caller) | |
2657 | e->can_throw_external = false; | |
be330ed4 JH |
2658 | return false; |
2659 | } | |
2660 | ||
2661 | /* Set TREE_NOTHROW on NODE's decl and on aliases of NODE | |
20cdc2be JJ |
2662 | if any to NOTHROW. */ |
2663 | ||
2664 | void | |
2665 | cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow) | |
2666 | { | |
be330ed4 JH |
2667 | cgraph_for_node_thunks_and_aliases (node, cgraph_set_nothrow_flag_1, |
2668 | (void *)(size_t)nothrow, false); | |
20cdc2be JJ |
2669 | } |
2670 | ||
be330ed4 | 2671 | /* Worker to set const flag. */ |
20cdc2be | 2672 | |
be330ed4 JH |
2673 | static bool |
2674 | cgraph_set_const_flag_1 (struct cgraph_node *node, void *data) | |
20cdc2be | 2675 | { |
530f3a1b JH |
2676 | /* Static constructors and destructors without a side effect can be |
2677 | optimized out. */ | |
be330ed4 | 2678 | if (data && !((size_t)data & 2)) |
530f3a1b JH |
2679 | { |
2680 | if (DECL_STATIC_CONSTRUCTOR (node->decl)) | |
2681 | DECL_STATIC_CONSTRUCTOR (node->decl) = 0; | |
2682 | if (DECL_STATIC_DESTRUCTOR (node->decl)) | |
2683 | DECL_STATIC_DESTRUCTOR (node->decl) = 0; | |
2684 | } | |
be330ed4 JH |
2685 | TREE_READONLY (node->decl) = data != NULL; |
2686 | DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0; | |
2687 | return false; | |
20cdc2be JJ |
2688 | } |
2689 | ||
be330ed4 JH |
2690 | /* Set TREE_READONLY on NODE's decl and on aliases of NODE |
2691 | if any to READONLY. */ | |
20cdc2be JJ |
2692 | |
2693 | void | |
be330ed4 | 2694 | cgraph_set_const_flag (struct cgraph_node *node, bool readonly, bool looping) |
20cdc2be | 2695 | { |
be330ed4 JH |
2696 | cgraph_for_node_thunks_and_aliases (node, cgraph_set_const_flag_1, |
2697 | (void *)(size_t)(readonly + (int)looping * 2), | |
2698 | false); | |
2699 | } | |
2700 | ||
2701 | /* Worker to set pure flag. */ | |
2702 | ||
2703 | static bool | |
2704 | cgraph_set_pure_flag_1 (struct cgraph_node *node, void *data) | |
2705 | { | |
2706 | /* Static pureructors and destructors without a side effect can be | |
530f3a1b | 2707 | optimized out. */ |
be330ed4 | 2708 | if (data && !((size_t)data & 2)) |
530f3a1b JH |
2709 | { |
2710 | if (DECL_STATIC_CONSTRUCTOR (node->decl)) | |
2711 | DECL_STATIC_CONSTRUCTOR (node->decl) = 0; | |
2712 | if (DECL_STATIC_DESTRUCTOR (node->decl)) | |
2713 | DECL_STATIC_DESTRUCTOR (node->decl) = 0; | |
2714 | } | |
be330ed4 JH |
2715 | DECL_PURE_P (node->decl) = data != NULL; |
2716 | DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0; | |
2717 | return false; | |
20cdc2be JJ |
2718 | } |
2719 | ||
be330ed4 JH |
2720 | /* Set DECL_PURE_P on NODE's decl and on aliases of NODE |
2721 | if any to PURE. */ | |
2722 | ||
2723 | void | |
2724 | cgraph_set_pure_flag (struct cgraph_node *node, bool pure, bool looping) | |
fa5f5e27 | 2725 | { |
be330ed4 JH |
2726 | cgraph_for_node_thunks_and_aliases (node, cgraph_set_pure_flag_1, |
2727 | (void *)(size_t)(pure + (int)looping * 2), | |
2728 | false); | |
2729 | } | |
844db5d0 | 2730 | |
be330ed4 | 2731 | /* Data used by cgraph_propagate_frequency. */ |
844db5d0 | 2732 | |
be330ed4 JH |
2733 | struct cgraph_propagate_frequency_data |
2734 | { | |
2735 | bool maybe_unlikely_executed; | |
2736 | bool maybe_executed_once; | |
2737 | bool only_called_at_startup; | |
2738 | bool only_called_at_exit; | |
2739 | }; | |
2740 | ||
2741 | /* Worker for cgraph_propagate_frequency_1. */ | |
2742 | ||
2743 | static bool | |
2744 | cgraph_propagate_frequency_1 (struct cgraph_node *node, void *data) | |
2745 | { | |
2746 | struct cgraph_propagate_frequency_data *d; | |
2747 | struct cgraph_edge *edge; | |
2748 | ||
2749 | d = (struct cgraph_propagate_frequency_data *)data; | |
fa5f5e27 | 2750 | for (edge = node->callers; |
be330ed4 JH |
2751 | edge && (d->maybe_unlikely_executed || d->maybe_executed_once |
2752 | || d->only_called_at_startup || d->only_called_at_exit); | |
fa5f5e27 JH |
2753 | edge = edge->next_caller) |
2754 | { | |
844db5d0 JH |
2755 | if (edge->caller != node) |
2756 | { | |
be330ed4 | 2757 | d->only_called_at_startup &= edge->caller->only_called_at_startup; |
61502ca8 | 2758 | /* It makes sense to put main() together with the static constructors. |
844db5d0 | 2759 | It will be executed for sure, but rest of functions called from |
61502ca8 | 2760 | main are definitely not at startup only. */ |
844db5d0 | 2761 | if (MAIN_NAME_P (DECL_NAME (edge->caller->decl))) |
be330ed4 JH |
2762 | d->only_called_at_startup = 0; |
2763 | d->only_called_at_exit &= edge->caller->only_called_at_exit; | |
844db5d0 | 2764 | } |
fa5f5e27 JH |
2765 | if (!edge->frequency) |
2766 | continue; | |
2767 | switch (edge->caller->frequency) | |
2768 | { | |
2769 | case NODE_FREQUENCY_UNLIKELY_EXECUTED: | |
2770 | break; | |
2771 | case NODE_FREQUENCY_EXECUTED_ONCE: | |
2772 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
844db5d0 | 2773 | fprintf (dump_file, " Called by %s that is executed once\n", |
87e7b310 | 2774 | cgraph_node_name (edge->caller)); |
be330ed4 | 2775 | d->maybe_unlikely_executed = false; |
898b8927 | 2776 | if (inline_edge_summary (edge)->loop_depth) |
fa5f5e27 | 2777 | { |
be330ed4 | 2778 | d->maybe_executed_once = false; |
fa5f5e27 JH |
2779 | if (dump_file && (dump_flags & TDF_DETAILS)) |
2780 | fprintf (dump_file, " Called in loop\n"); | |
2781 | } | |
2782 | break; | |
2783 | case NODE_FREQUENCY_HOT: | |
2784 | case NODE_FREQUENCY_NORMAL: | |
2785 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
844db5d0 | 2786 | fprintf (dump_file, " Called by %s that is normal or hot\n", |
87e7b310 | 2787 | cgraph_node_name (edge->caller)); |
be330ed4 JH |
2788 | d->maybe_unlikely_executed = false; |
2789 | d->maybe_executed_once = false; | |
fa5f5e27 JH |
2790 | break; |
2791 | } | |
2792 | } | |
be330ed4 JH |
2793 | return edge != NULL; |
2794 | } | |
2795 | ||
2796 | /* See if the frequency of NODE can be updated based on frequencies of its | |
2797 | callers. */ | |
2798 | bool | |
2799 | cgraph_propagate_frequency (struct cgraph_node *node) | |
2800 | { | |
2801 | struct cgraph_propagate_frequency_data d = {true, true, true, true}; | |
2802 | bool changed = false; | |
2803 | ||
2804 | if (!node->local.local) | |
2805 | return false; | |
2806 | gcc_assert (node->analyzed); | |
2807 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2808 | fprintf (dump_file, "Processing frequency %s\n", cgraph_node_name (node)); | |
2809 | ||
2810 | cgraph_for_node_and_aliases (node, cgraph_propagate_frequency_1, &d, true); | |
2811 | ||
2812 | if ((d.only_called_at_startup && !d.only_called_at_exit) | |
844db5d0 JH |
2813 | && !node->only_called_at_startup) |
2814 | { | |
2815 | node->only_called_at_startup = true; | |
fa5f5e27 | 2816 | if (dump_file) |
844db5d0 JH |
2817 | fprintf (dump_file, "Node %s promoted to only called at startup.\n", |
2818 | cgraph_node_name (node)); | |
2819 | changed = true; | |
2820 | } | |
be330ed4 | 2821 | if ((d.only_called_at_exit && !d.only_called_at_startup) |
844db5d0 JH |
2822 | && !node->only_called_at_exit) |
2823 | { | |
2824 | node->only_called_at_exit = true; | |
fa5f5e27 | 2825 | if (dump_file) |
844db5d0 JH |
2826 | fprintf (dump_file, "Node %s promoted to only called at exit.\n", |
2827 | cgraph_node_name (node)); | |
2828 | changed = true; | |
2829 | } | |
2830 | /* These come either from profile or user hints; never update them. */ | |
2831 | if (node->frequency == NODE_FREQUENCY_HOT | |
2832 | || node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) | |
2833 | return changed; | |
be330ed4 | 2834 | if (d.maybe_unlikely_executed) |
844db5d0 JH |
2835 | { |
2836 | node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; | |
2837 | if (dump_file) | |
2838 | fprintf (dump_file, "Node %s promoted to unlikely executed.\n", | |
2839 | cgraph_node_name (node)); | |
2840 | changed = true; | |
2841 | } | |
be330ed4 | 2842 | else if (d.maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE) |
844db5d0 JH |
2843 | { |
2844 | node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; | |
2845 | if (dump_file) | |
2846 | fprintf (dump_file, "Node %s promoted to executed once.\n", | |
2847 | cgraph_node_name (node)); | |
2848 | changed = true; | |
2849 | } | |
2850 | return changed; | |
fa5f5e27 JH |
2851 | } |
2852 | ||
d56026c2 JH |
2853 | /* Return true when NODE can not return or throw and thus |
2854 | it is safe to ignore its side effects for IPA analysis. */ | |
2855 | ||
2856 | bool | |
2857 | cgraph_node_cannot_return (struct cgraph_node *node) | |
2858 | { | |
2859 | int flags = flags_from_decl_or_type (node->decl); | |
2860 | if (!flag_exceptions) | |
2861 | return (flags & ECF_NORETURN) != 0; | |
2862 | else | |
2863 | return ((flags & (ECF_NORETURN | ECF_NOTHROW)) | |
2864 | == (ECF_NORETURN | ECF_NOTHROW)); | |
2865 | } | |
2866 | ||
2867 | /* Return true when call of E can not lead to return from caller | |
2868 | and thus it is safe to ignore its side effects for IPA analysis | |
2869 | when computing side effects of the caller. | |
2870 | FIXME: We could actually mark all edges that have no reaching | |
2871 | patch to EXIT_BLOCK_PTR or throw to get better results. */ | |
2872 | bool | |
2873 | cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e) | |
2874 | { | |
f10ea640 JH |
2875 | if (cgraph_node_cannot_return (e->caller)) |
2876 | return true; | |
d56026c2 JH |
2877 | if (e->indirect_unknown_callee) |
2878 | { | |
2879 | int flags = e->indirect_info->ecf_flags; | |
2880 | if (!flag_exceptions) | |
2881 | return (flags & ECF_NORETURN) != 0; | |
2882 | else | |
2883 | return ((flags & (ECF_NORETURN | ECF_NOTHROW)) | |
2884 | == (ECF_NORETURN | ECF_NOTHROW)); | |
2885 | } | |
2886 | else | |
2887 | return cgraph_node_cannot_return (e->callee); | |
2888 | } | |
2889 | ||
508e4757 JH |
2890 | /* Return true when function NODE can be removed from callgraph |
2891 | if all direct calls are eliminated. */ | |
2892 | ||
2893 | bool | |
2894 | cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) | |
2895 | { | |
530f3a1b JH |
2896 | gcc_assert (!node->global.inlined_to); |
2897 | /* Extern inlines can always go, we will use the external definition. */ | |
2898 | if (DECL_EXTERNAL (node->decl)) | |
2899 | return true; | |
508e4757 JH |
2900 | /* When function is needed, we can not remove it. */ |
2901 | if (node->needed || node->reachable_from_other_partition) | |
2902 | return false; | |
530f3a1b JH |
2903 | if (DECL_STATIC_CONSTRUCTOR (node->decl) |
2904 | || DECL_STATIC_DESTRUCTOR (node->decl)) | |
2905 | return false; | |
508e4757 JH |
2906 | /* Only COMDAT functions can be removed if externally visible. */ |
2907 | if (node->local.externally_visible | |
051f8cc6 JH |
2908 | && (!DECL_COMDAT (node->decl) |
2909 | || cgraph_used_from_object_file_p (node))) | |
508e4757 | 2910 | return false; |
508e4757 JH |
2911 | return true; |
2912 | } | |
2913 | ||
9aa3f5c5 JH |
2914 | /* Worker for cgraph_can_remove_if_no_direct_calls_p. */ |
2915 | ||
2916 | static bool | |
2917 | nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
2918 | { | |
2919 | return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node); | |
2920 | } | |
2921 | ||
2922 | /* Return true when function NODE and its aliases can be removed from callgraph | |
2923 | if all direct calls are eliminated. */ | |
2924 | ||
2925 | bool | |
2926 | cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) | |
2927 | { | |
2928 | /* Extern inlines can always go, we will use the external definition. */ | |
2929 | if (DECL_EXTERNAL (node->decl)) | |
2930 | return true; | |
2931 | if (node->address_taken) | |
2932 | return false; | |
2933 | return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true); | |
2934 | } | |
2935 | ||
2936 | /* Worker for cgraph_can_remove_if_no_direct_calls_p. */ | |
2937 | ||
2938 | static bool | |
2939 | used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
2940 | { | |
2941 | return cgraph_used_from_object_file_p (node); | |
2942 | } | |
2943 | ||
61502ca8 | 2944 | /* Return true when function NODE can be expected to be removed |
09411461 JH |
2945 | from program when direct calls in this compilation unit are removed. |
2946 | ||
2947 | As a special case COMDAT functions are | |
2948 | cgraph_can_remove_if_no_direct_calls_p while the are not | |
2949 | cgraph_only_called_directly_p (it is possible they are called from other | |
2950 | unit) | |
2951 | ||
2952 | This function behaves as cgraph_only_called_directly_p because eliminating | |
61502ca8 | 2953 | all uses of COMDAT function does not make it necessarily disappear from |
09411461 JH |
2954 | the program unless we are compiling whole program or we do LTO. In this |
2955 | case we know we win since dynamic linking will not really discard the | |
2956 | linkonce section. */ | |
2957 | ||
2958 | bool | |
2959 | cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) | |
2960 | { | |
530f3a1b | 2961 | gcc_assert (!node->global.inlined_to); |
9aa3f5c5 | 2962 | if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true)) |
09411461 JH |
2963 | return false; |
2964 | if (!in_lto_p && !flag_whole_program) | |
2965 | return cgraph_only_called_directly_p (node); | |
2966 | else | |
530f3a1b JH |
2967 | { |
2968 | if (DECL_EXTERNAL (node->decl)) | |
2969 | return true; | |
2970 | return cgraph_can_remove_if_no_direct_calls_p (node); | |
2971 | } | |
09411461 JH |
2972 | } |
2973 | ||
051f8cc6 | 2974 | /* Return true when RESOLUTION indicate that linker will use |
61502ca8 | 2975 | the symbol from non-LTO object files. */ |
051f8cc6 JH |
2976 | |
2977 | bool | |
2978 | resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution) | |
2979 | { | |
2980 | return (resolution == LDPR_PREVAILING_DEF | |
2981 | || resolution == LDPR_PREEMPTED_REG | |
2982 | || resolution == LDPR_RESOLVED_EXEC | |
2983 | || resolution == LDPR_RESOLVED_DYN); | |
2984 | } | |
2985 | ||
be330ed4 | 2986 | |
051f8cc6 JH |
2987 | /* Return true when NODE is known to be used from other (non-LTO) object file. |
2988 | Known only when doing LTO via linker plugin. */ | |
2989 | ||
2990 | bool | |
2991 | cgraph_used_from_object_file_p (struct cgraph_node *node) | |
2992 | { | |
530f3a1b JH |
2993 | gcc_assert (!node->global.inlined_to); |
2994 | if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)) | |
051f8cc6 JH |
2995 | return false; |
2996 | if (resolution_used_from_other_file_p (node->resolution)) | |
2997 | return true; | |
051f8cc6 JH |
2998 | return false; |
2999 | } | |
3000 | ||
be330ed4 JH |
3001 | /* Worker for cgraph_only_called_directly_p. */ |
3002 | ||
3003 | static bool | |
3004 | cgraph_not_only_called_directly_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
3005 | { | |
3006 | return !cgraph_only_called_directly_or_aliased_p (node); | |
3007 | } | |
3008 | ||
3009 | /* Return true when function NODE and all its aliases are only called | |
3010 | directly. | |
3011 | i.e. it is not externally visible, address was not taken and | |
3012 | it is not used in any other non-standard way. */ | |
3013 | ||
3014 | bool | |
3015 | cgraph_only_called_directly_p (struct cgraph_node *node) | |
3016 | { | |
3017 | gcc_assert (cgraph_function_or_thunk_node (node, NULL) == node); | |
3018 | return !cgraph_for_node_and_aliases (node, cgraph_not_only_called_directly_p_1, | |
3019 | NULL, true); | |
3020 | } | |
3021 | ||
3022 | ||
3023 | /* Collect all callers of NODE. Worker for collect_callers_of_node. */ | |
3024 | ||
3025 | static bool | |
3026 | collect_callers_of_node_1 (struct cgraph_node *node, void *data) | |
3027 | { | |
3028 | VEC (cgraph_edge_p, heap) ** redirect_callers = (VEC (cgraph_edge_p, heap) **)data; | |
3029 | struct cgraph_edge *cs; | |
3030 | enum availability avail; | |
3031 | cgraph_function_or_thunk_node (node, &avail); | |
3032 | ||
3033 | if (avail > AVAIL_OVERWRITABLE) | |
3034 | for (cs = node->callers; cs != NULL; cs = cs->next_caller) | |
3035 | if (!cs->indirect_inlining_edge) | |
3036 | VEC_safe_push (cgraph_edge_p, heap, *redirect_callers, cs); | |
3037 | return false; | |
3038 | } | |
3039 | ||
3040 | /* Collect all callers of NODE and its aliases that are known to lead to NODE | |
3041 | (i.e. are not overwritable). */ | |
3042 | ||
3043 | VEC (cgraph_edge_p, heap) * | |
3044 | collect_callers_of_node (struct cgraph_node *node) | |
3045 | { | |
3046 | VEC (cgraph_edge_p, heap) * redirect_callers = NULL; | |
3047 | cgraph_for_node_and_aliases (node, collect_callers_of_node_1, | |
3048 | &redirect_callers, false); | |
3049 | return redirect_callers; | |
3050 | } | |
3051 | ||
988d1653 | 3052 | #include "gt-cgraph.h" |