* gcc-plugin.h (enum plugin_event): Add PLUGIN_ALL_IPA_PASSES_START,
[official-gcc.git] / gcc / ipa.c
blobc859242fa70137c8115e19cc80f310c90c4052b7
1 /* Basic IPA optimizations and utilities.
2 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
3 Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "cgraph.h"
26 #include "tree-pass.h"
27 #include "timevar.h"
28 #include "gimple.h"
29 #include "ggc.h"
31 /* Fill array order with all nodes with output flag set in the reverse
32 topological order. */
34 int
35 cgraph_postorder (struct cgraph_node **order)
37 struct cgraph_node *node, *node2;
38 int stack_size = 0;
39 int order_pos = 0;
40 struct cgraph_edge *edge, last;
41 int pass;
43 struct cgraph_node **stack =
44 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
46 /* We have to deal with cycles nicely, so use a depth first traversal
47 output algorithm. Ignore the fact that some functions won't need
48 to be output and put them into order as well, so we get dependencies
49 right through inline functions. */
50 for (node = cgraph_nodes; node; node = node->next)
51 node->aux = NULL;
52 for (pass = 0; pass < 2; pass++)
53 for (node = cgraph_nodes; node; node = node->next)
54 if (!node->aux
55 && (pass
56 || (!cgraph_only_called_directly_p (node)
57 && !node->address_taken)))
59 node2 = node;
60 if (!node->callers)
61 node->aux = &last;
62 else
63 node->aux = node->callers;
64 while (node2)
66 while (node2->aux != &last)
68 edge = (struct cgraph_edge *) node2->aux;
69 if (edge->next_caller)
70 node2->aux = edge->next_caller;
71 else
72 node2->aux = &last;
73 if (!edge->caller->aux)
75 if (!edge->caller->callers)
76 edge->caller->aux = &last;
77 else
78 edge->caller->aux = edge->caller->callers;
79 stack[stack_size++] = node2;
80 node2 = edge->caller;
81 break;
84 if (node2->aux == &last)
86 order[order_pos++] = node2;
87 if (stack_size)
88 node2 = stack[--stack_size];
89 else
90 node2 = NULL;
94 free (stack);
95 for (node = cgraph_nodes; node; node = node->next)
96 node->aux = NULL;
97 return order_pos;
100 /* Look for all functions inlined to NODE and update their inlined_to pointers
101 to INLINED_TO. */
103 static void
104 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
106 struct cgraph_edge *e;
107 for (e = node->callees; e; e = e->next_callee)
108 if (e->callee->global.inlined_to)
110 e->callee->global.inlined_to = inlined_to;
111 update_inlined_to_pointer (e->callee, inlined_to);
115 /* Perform reachability analysis and reclaim all unreachable nodes.
116 If BEFORE_INLINING_P is true this function is called before inlining
117 decisions has been made. If BEFORE_INLINING_P is false this function also
118 removes unneeded bodies of extern inline functions. */
120 bool
121 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
123 struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
124 struct cgraph_node *node, *next;
125 bool changed = false;
127 #ifdef ENABLE_CHECKING
128 verify_cgraph ();
129 #endif
130 if (file)
131 fprintf (file, "\nReclaiming functions:");
132 #ifdef ENABLE_CHECKING
133 for (node = cgraph_nodes; node; node = node->next)
134 gcc_assert (!node->aux);
135 #endif
136 for (node = cgraph_nodes; node; node = node->next)
137 if (!cgraph_can_remove_if_no_direct_calls_p (node)
138 && ((!DECL_EXTERNAL (node->decl))
139 || !node->analyzed
140 || before_inlining_p))
142 gcc_assert (!node->global.inlined_to);
143 node->aux = first;
144 first = node;
146 else
147 gcc_assert (!node->aux);
149 /* Perform reachability analysis. As a special case do not consider
150 extern inline functions not inlined as live because we won't output
151 them at all. */
152 while (first != (void *) 1)
154 struct cgraph_edge *e;
155 node = first;
156 first = (struct cgraph_node *) first->aux;
158 for (e = node->callees; e; e = e->next_callee)
159 if (!e->callee->aux
160 && node->analyzed
161 && (!e->inline_failed || !e->callee->analyzed
162 || (!DECL_EXTERNAL (e->callee->decl))
163 || before_inlining_p))
165 e->callee->aux = first;
166 first = e->callee;
168 while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
170 node = node->clone_of;
171 node->aux = first;
172 first = node;
176 /* Remove unreachable nodes. Extern inline functions need special care;
177 Unreachable extern inline functions shall be removed.
178 Reachable extern inline functions we never inlined shall get their bodies
179 eliminated.
180 Reachable extern inline functions we sometimes inlined will be turned into
181 unanalyzed nodes so they look like for true extern functions to the rest
182 of code. Body of such functions is released via remove_node once the
183 inline clones are eliminated. */
184 for (node = cgraph_nodes; node; node = next)
186 next = node->next;
187 if (!node->aux)
189 node->global.inlined_to = NULL;
190 if (file)
191 fprintf (file, " %s", cgraph_node_name (node));
192 if (!node->analyzed || !DECL_EXTERNAL (node->decl)
193 || before_inlining_p)
194 cgraph_remove_node (node);
195 else
197 struct cgraph_edge *e;
199 /* See if there is reachable caller. */
200 for (e = node->callers; e; e = e->next_caller)
201 if (e->caller->aux)
202 break;
204 /* If so, we need to keep node in the callgraph. */
205 if (e || node->needed)
207 struct cgraph_node *clone;
209 /* If there are still clones, we must keep body around.
210 Otherwise we can just remove the body but keep the clone. */
211 for (clone = node->clones; clone;
212 clone = clone->next_sibling_clone)
213 if (clone->aux)
214 break;
215 if (!clone)
217 cgraph_release_function_body (node);
218 cgraph_node_remove_callees (node);
219 node->analyzed = false;
220 node->local.inlinable = false;
223 else
224 cgraph_remove_node (node);
226 changed = true;
229 for (node = cgraph_nodes; node; node = node->next)
231 /* Inline clones might be kept around so their materializing allows further
232 cloning. If the function the clone is inlined into is removed, we need
233 to turn it into normal cone. */
234 if (node->global.inlined_to
235 && !node->callers)
237 gcc_assert (node->clones);
238 node->global.inlined_to = NULL;
239 update_inlined_to_pointer (node, node);
241 node->aux = NULL;
243 #ifdef ENABLE_CHECKING
244 verify_cgraph ();
245 #endif
247 /* Reclaim alias pairs for functions that have disappeared from the
248 call graph. */
249 remove_unreachable_alias_pairs ();
251 return changed;
254 static bool
255 cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
257 if (!node->local.finalized)
258 return false;
259 if (!DECL_COMDAT (node->decl)
260 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
261 return false;
262 if (!whole_program)
263 return true;
264 /* COMDAT functions must be shared only if they have address taken,
265 otherwise we can produce our own private implementation with
266 -fwhole-program. */
267 if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed))
268 return true;
269 if (MAIN_NAME_P (DECL_NAME (node->decl)))
270 return true;
271 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
272 return true;
273 return false;
276 /* Mark visibility of all functions.
278 A local function is one whose calls can occur only in the current
279 compilation unit and all its calls are explicit, so we can change
280 its calling convention. We simply mark all static functions whose
281 address is not taken as local.
283 We also change the TREE_PUBLIC flag of all declarations that are public
284 in language point of view but we want to overwrite this default
285 via visibilities for the backend point of view. */
287 static unsigned int
288 function_and_variable_visibility (bool whole_program)
290 struct cgraph_node *node;
291 struct varpool_node *vnode;
293 for (node = cgraph_nodes; node; node = node->next)
295 if (cgraph_externally_visible_p (node, whole_program))
297 gcc_assert (!node->global.inlined_to);
298 node->local.externally_visible = true;
300 else
301 node->local.externally_visible = false;
302 if (!node->local.externally_visible && node->analyzed
303 && !DECL_EXTERNAL (node->decl))
305 gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
306 TREE_PUBLIC (node->decl) = 0;
307 DECL_COMDAT (node->decl) = 0;
308 DECL_WEAK (node->decl) = 0;
310 node->local.local = (cgraph_only_called_directly_p (node)
311 && node->analyzed
312 && !DECL_EXTERNAL (node->decl)
313 && !node->local.externally_visible);
315 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
317 if (!vnode->finalized)
318 continue;
319 if (vnode->needed
320 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
321 && (!whole_program
322 || lookup_attribute ("externally_visible",
323 DECL_ATTRIBUTES (vnode->decl))))
324 vnode->externally_visible = true;
325 else
326 vnode->externally_visible = false;
327 if (!vnode->externally_visible)
329 gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
330 TREE_PUBLIC (vnode->decl) = 0;
332 gcc_assert (TREE_STATIC (vnode->decl));
335 if (dump_file)
337 fprintf (dump_file, "\nMarking local functions:");
338 for (node = cgraph_nodes; node; node = node->next)
339 if (node->local.local)
340 fprintf (dump_file, " %s", cgraph_node_name (node));
341 fprintf (dump_file, "\n\n");
342 fprintf (dump_file, "\nMarking externally visible functions:");
343 for (node = cgraph_nodes; node; node = node->next)
344 if (node->local.externally_visible)
345 fprintf (dump_file, " %s", cgraph_node_name (node));
346 fprintf (dump_file, "\n\n");
348 cgraph_function_flags_ready = true;
349 return 0;
352 /* Local function pass handling visibilities. This happens before LTO streaming
353 so in particular -fwhole-program should be ignored at this level. */
355 static unsigned int
356 local_function_and_variable_visibility (void)
358 return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
361 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
364 SIMPLE_IPA_PASS,
365 "visibility", /* name */
366 NULL, /* gate */
367 local_function_and_variable_visibility,/* execute */
368 NULL, /* sub */
369 NULL, /* next */
370 0, /* static_pass_number */
371 TV_CGRAPHOPT, /* tv_id */
372 0, /* properties_required */
373 0, /* properties_provided */
374 0, /* properties_destroyed */
375 0, /* todo_flags_start */
376 TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
380 /* Do not re-run on ltrans stage. */
382 static bool
383 gate_whole_program_function_and_variable_visibility (void)
385 return !flag_ltrans;
388 /* Bring functionss local at LTO time whith -fwhole-program. */
390 static unsigned int
391 whole_program_function_and_variable_visibility (void)
393 struct cgraph_node *node;
394 struct varpool_node *vnode;
396 function_and_variable_visibility (flag_whole_program);
398 for (node = cgraph_nodes; node; node = node->next)
399 if (node->local.externally_visible && node->local.finalized)
400 cgraph_mark_needed_node (node);
401 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
402 if (vnode->externally_visible)
403 varpool_mark_needed_node (vnode);
404 return 0;
407 struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
410 IPA_PASS,
411 "whole-program", /* name */
412 gate_whole_program_function_and_variable_visibility,/* gate */
413 whole_program_function_and_variable_visibility,/* execute */
414 NULL, /* sub */
415 NULL, /* next */
416 0, /* static_pass_number */
417 TV_CGRAPHOPT, /* tv_id */
418 0, /* properties_required */
419 0, /* properties_provided */
420 0, /* properties_destroyed */
421 0, /* todo_flags_start */
422 TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
424 NULL, /* generate_summary */
425 NULL, /* write_summary */
426 NULL, /* read_summary */
427 NULL, /* function_read_summary */
428 0, /* TODOs */
429 NULL, /* function_transform */
430 NULL, /* variable_transform */
433 /* Hash a cgraph node set element. */
435 static hashval_t
436 hash_cgraph_node_set_element (const void *p)
438 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
439 return htab_hash_pointer (element->node);
442 /* Compare two cgraph node set elements. */
444 static int
445 eq_cgraph_node_set_element (const void *p1, const void *p2)
447 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
448 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
450 return e1->node == e2->node;
453 /* Create a new cgraph node set. */
455 cgraph_node_set
456 cgraph_node_set_new (void)
458 cgraph_node_set new_node_set;
460 new_node_set = GGC_NEW (struct cgraph_node_set_def);
461 new_node_set->hashtab = htab_create_ggc (10,
462 hash_cgraph_node_set_element,
463 eq_cgraph_node_set_element,
464 NULL);
465 new_node_set->nodes = NULL;
466 return new_node_set;
469 /* Add cgraph_node NODE to cgraph_node_set SET. */
471 void
472 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
474 void **slot;
475 cgraph_node_set_element element;
476 struct cgraph_node_set_element_def dummy;
478 dummy.node = node;
479 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
481 if (*slot != HTAB_EMPTY_ENTRY)
483 element = (cgraph_node_set_element) *slot;
484 gcc_assert (node == element->node
485 && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
486 == node));
487 return;
490 /* Insert node into hash table. */
491 element =
492 (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
493 element->node = node;
494 element->index = VEC_length (cgraph_node_ptr, set->nodes);
495 *slot = element;
497 /* Insert into node vector. */
498 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
501 /* Remove cgraph_node NODE from cgraph_node_set SET. */
503 void
504 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
506 void **slot, **last_slot;
507 cgraph_node_set_element element, last_element;
508 struct cgraph_node *last_node;
509 struct cgraph_node_set_element_def dummy;
511 dummy.node = node;
512 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
513 if (slot == NULL)
514 return;
516 element = (cgraph_node_set_element) *slot;
517 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
518 == node);
520 /* Remove from vector. We do this by swapping node with the last element
521 of the vector. */
522 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
523 if (last_node != node)
525 dummy.node = last_node;
526 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
527 last_element = (cgraph_node_set_element) *last_slot;
528 gcc_assert (last_element);
530 /* Move the last element to the original spot of NODE. */
531 last_element->index = element->index;
532 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
533 last_node);
536 /* Remove element from hash table. */
537 htab_clear_slot (set->hashtab, slot);
538 ggc_free (element);
541 /* Find NODE in SET and return an iterator to it if found. A null iterator
542 is returned if NODE is not in SET. */
544 cgraph_node_set_iterator
545 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
547 void **slot;
548 struct cgraph_node_set_element_def dummy;
549 cgraph_node_set_element element;
550 cgraph_node_set_iterator csi;
552 dummy.node = node;
553 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
554 if (slot == NULL)
555 csi.index = (unsigned) ~0;
556 else
558 element = (cgraph_node_set_element) *slot;
559 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
560 == node);
561 csi.index = element->index;
563 csi.set = set;
565 return csi;
568 /* Dump content of SET to file F. */
570 void
571 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
573 cgraph_node_set_iterator iter;
575 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
577 struct cgraph_node *node = csi_node (iter);
578 dump_cgraph_node (f, node);
582 /* Dump content of SET to stderr. */
584 void
585 debug_cgraph_node_set (cgraph_node_set set)
587 dump_cgraph_node_set (stderr, set);