1 /* Basic IPA optimizations and utilities.
2 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
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
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
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/>. */
23 #include "coretypes.h"
26 #include "tree-pass.h"
31 /* Fill array order with all nodes with output flag set in the reverse
35 cgraph_postorder (struct cgraph_node **order)
37 struct cgraph_node *node, *node2;
40 struct cgraph_edge *edge, last;
42 struct cgraph_node **stack =
43 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
45 /* We have to deal with cycles nicely, so use a depth first traversal
46 output algorithm. Ignore the fact that some functions won't need
47 to be output and put them into order as well, so we get dependencies
48 right through inline functions. */
49 for (node = cgraph_nodes; node; node = node->next)
51 for (node = cgraph_nodes; node; node = node->next)
58 node->aux = node->callers;
61 while (node2->aux != &last)
63 edge = (struct cgraph_edge *) node2->aux;
64 if (edge->next_caller)
65 node2->aux = edge->next_caller;
68 if (!edge->caller->aux)
70 if (!edge->caller->callers)
71 edge->caller->aux = &last;
73 edge->caller->aux = edge->caller->callers;
74 stack[stack_size++] = node2;
79 if (node2->aux == &last)
81 order[order_pos++] = node2;
83 node2 = stack[--stack_size];
90 for (node = cgraph_nodes; node; node = node->next)
95 /* Look for all functions inlined to NODE and update their inlined_to pointers
99 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
101 struct cgraph_edge *e;
102 for (e = node->callees; e; e = e->next_callee)
103 if (e->callee->global.inlined_to)
105 e->callee->global.inlined_to = inlined_to;
106 update_inlined_to_pointer (e->callee, inlined_to);
110 /* Perform reachability analysis and reclaim all unreachable nodes.
111 If BEFORE_INLINING_P is true this function is called before inlining
112 decisions has been made. If BEFORE_INLINING_P is false this function also
113 removes unneeded bodies of extern inline functions. */
116 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
118 struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
119 struct cgraph_node *node, *next;
120 bool changed = false;
122 #ifdef ENABLE_CHECKING
126 fprintf (file, "\nReclaiming functions:");
127 #ifdef ENABLE_CHECKING
128 for (node = cgraph_nodes; node; node = node->next)
129 gcc_assert (!node->aux);
131 for (node = cgraph_nodes; node; node = node->next)
132 if (node->needed && !node->global.inlined_to
133 && ((!DECL_EXTERNAL (node->decl))
135 || before_inlining_p))
141 gcc_assert (!node->aux);
143 /* Perform reachability analysis. As a special case do not consider
144 extern inline functions not inlined as live because we won't output
146 while (first != (void *) 1)
148 struct cgraph_edge *e;
150 first = (struct cgraph_node *) first->aux;
152 for (e = node->callees; e; e = e->next_callee)
155 && (!e->inline_failed || !e->callee->analyzed
156 || (!DECL_EXTERNAL (e->callee->decl))
157 || before_inlining_p))
159 e->callee->aux = first;
162 while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
164 node = node->clone_of;
170 /* Remove unreachable nodes. Extern inline functions need special care;
171 Unreachable extern inline functions shall be removed.
172 Reachable extern inline functions we never inlined shall get their bodies
174 Reachable extern inline functions we sometimes inlined will be turned into
175 unanalyzed nodes so they look like for true extern functions to the rest
176 of code. Body of such functions is released via remove_node once the
177 inline clones are eliminated. */
178 for (node = cgraph_nodes; node; node = next)
183 node->global.inlined_to = NULL;
185 fprintf (file, " %s", cgraph_node_name (node));
186 if (!node->analyzed || !DECL_EXTERNAL (node->decl)
187 || before_inlining_p)
188 cgraph_remove_node (node);
191 struct cgraph_edge *e;
193 /* See if there is reachable caller. */
194 for (e = node->callers; e; e = e->next_caller)
198 /* If so, we need to keep node in the callgraph. */
199 if (e || node->needed)
201 struct cgraph_node *clone;
203 /* If there are still clones, we must keep body around.
204 Otherwise we can just remove the body but keep the clone. */
205 for (clone = node->clones; clone;
206 clone = clone->next_sibling_clone)
211 cgraph_release_function_body (node);
212 cgraph_node_remove_callees (node);
213 node->analyzed = false;
214 node->local.inlinable = false;
218 cgraph_remove_node (node);
223 for (node = cgraph_nodes; node; node = node->next)
225 /* Inline clones might be kept around so their materializing allows further
226 cloning. If the function the clone is inlined into is removed, we need
227 to turn it into normal cone. */
228 if (node->global.inlined_to
231 gcc_assert (node->clones);
232 node->global.inlined_to = NULL;
233 update_inlined_to_pointer (node, node);
237 #ifdef ENABLE_CHECKING
243 /* Mark visibility of all functions.
245 A local function is one whose calls can occur only in the current
246 compilation unit and all its calls are explicit, so we can change
247 its calling convention. We simply mark all static functions whose
248 address is not taken as local.
250 We also change the TREE_PUBLIC flag of all declarations that are public
251 in language point of view but we want to overwrite this default
252 via visibilities for the backend point of view. */
255 function_and_variable_visibility (void)
257 struct cgraph_node *node;
258 struct varpool_node *vnode;
260 for (node = cgraph_nodes; node; node = node->next)
263 && (DECL_COMDAT (node->decl)
264 || (!flag_whole_program
265 && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
266 node->local.externally_visible = true;
267 if (!node->local.externally_visible && node->analyzed
268 && !DECL_EXTERNAL (node->decl))
270 gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
271 TREE_PUBLIC (node->decl) = 0;
273 node->local.local = (!node->needed
275 && !DECL_EXTERNAL (node->decl)
276 && !node->local.externally_visible);
278 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
281 && !flag_whole_program
282 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
283 vnode->externally_visible = 1;
284 if (!vnode->externally_visible)
286 gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
287 TREE_PUBLIC (vnode->decl) = 0;
289 gcc_assert (TREE_STATIC (vnode->decl));
294 fprintf (dump_file, "\nMarking local functions:");
295 for (node = cgraph_nodes; node; node = node->next)
296 if (node->local.local)
297 fprintf (dump_file, " %s", cgraph_node_name (node));
298 fprintf (dump_file, "\n\n");
299 fprintf (dump_file, "\nMarking externally visible functions:");
300 for (node = cgraph_nodes; node; node = node->next)
301 if (node->local.externally_visible)
302 fprintf (dump_file, " %s", cgraph_node_name (node));
303 fprintf (dump_file, "\n\n");
305 cgraph_function_flags_ready = true;
309 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
313 "visibility", /* name */
315 function_and_variable_visibility, /* execute */
318 0, /* static_pass_number */
319 TV_CGRAPHOPT, /* tv_id */
320 0, /* properties_required */
321 0, /* properties_provided */
322 0, /* properties_destroyed */
323 0, /* todo_flags_start */
324 TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
329 /* Hash a cgraph node set element. */
332 hash_cgraph_node_set_element (const void *p)
334 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
335 return htab_hash_pointer (element->node);
338 /* Compare two cgraph node set elements. */
341 eq_cgraph_node_set_element (const void *p1, const void *p2)
343 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
344 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
346 return e1->node == e2->node;
349 /* Create a new cgraph node set. */
352 cgraph_node_set_new (void)
354 cgraph_node_set new_node_set;
356 new_node_set = GGC_NEW (struct cgraph_node_set_def);
357 new_node_set->hashtab = htab_create_ggc (10,
358 hash_cgraph_node_set_element,
359 eq_cgraph_node_set_element,
361 new_node_set->nodes = NULL;
365 /* Add cgraph_node NODE to cgraph_node_set SET. */
368 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
371 cgraph_node_set_element element;
372 struct cgraph_node_set_element_def dummy;
375 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
377 if (*slot != HTAB_EMPTY_ENTRY)
379 element = (cgraph_node_set_element) *slot;
380 gcc_assert (node == element->node
381 && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
386 /* Insert node into hash table. */
388 (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
389 element->node = node;
390 element->index = VEC_length (cgraph_node_ptr, set->nodes);
393 /* Insert into node vector. */
394 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
397 /* Remove cgraph_node NODE from cgraph_node_set SET. */
400 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
402 void **slot, **last_slot;
403 cgraph_node_set_element element, last_element;
404 struct cgraph_node *last_node;
405 struct cgraph_node_set_element_def dummy;
408 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
412 element = (cgraph_node_set_element) *slot;
413 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
416 /* Remove from vector. We do this by swapping node with the last element
418 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
419 if (last_node != node)
421 dummy.node = last_node;
422 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
423 last_element = (cgraph_node_set_element) *last_slot;
424 gcc_assert (last_element);
426 /* Move the last element to the original spot of NODE. */
427 last_element->index = element->index;
428 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
432 /* Remove element from hash table. */
433 htab_clear_slot (set->hashtab, slot);
437 /* Find NODE in SET and return an iterator to it if found. A null iterator
438 is returned if NODE is not in SET. */
440 cgraph_node_set_iterator
441 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
444 struct cgraph_node_set_element_def dummy;
445 cgraph_node_set_element element;
446 cgraph_node_set_iterator csi;
449 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
451 csi.index = (unsigned) ~0;
454 element = (cgraph_node_set_element) *slot;
455 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
457 csi.index = element->index;
464 /* Dump content of SET to file F. */
467 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
469 cgraph_node_set_iterator iter;
471 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
473 struct cgraph_node *node = csi_node (iter);
474 dump_cgraph_node (f, node);
478 /* Dump content of SET to stderr. */
481 debug_cgraph_node_set (cgraph_node_set set)
483 dump_cgraph_node_set (stderr, set);