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
;
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
)
52 for (pass
= 0; pass
< 2; pass
++)
53 for (node
= cgraph_nodes
; node
; node
= node
->next
)
56 || (!cgraph_only_called_directly_p (node
)
57 && !node
->address_taken
)))
63 node
->aux
= node
->callers
;
66 while (node2
->aux
!= &last
)
68 edge
= (struct cgraph_edge
*) node2
->aux
;
69 if (edge
->next_caller
)
70 node2
->aux
= edge
->next_caller
;
73 if (!edge
->caller
->aux
)
75 if (!edge
->caller
->callers
)
76 edge
->caller
->aux
= &last
;
78 edge
->caller
->aux
= edge
->caller
->callers
;
79 stack
[stack_size
++] = node2
;
84 if (node2
->aux
== &last
)
86 order
[order_pos
++] = node2
;
88 node2
= stack
[--stack_size
];
95 for (node
= cgraph_nodes
; node
; node
= node
->next
)
100 /* Look for all functions inlined to NODE and update their inlined_to pointers
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. */
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
*processed
= (struct cgraph_node
*) (void *) 2;
125 struct cgraph_node
*node
, *next
;
126 bool changed
= false;
128 #ifdef ENABLE_CHECKING
132 fprintf (file
, "\nReclaiming functions:");
133 #ifdef ENABLE_CHECKING
134 for (node
= cgraph_nodes
; node
; node
= node
->next
)
135 gcc_assert (!node
->aux
);
137 for (node
= cgraph_nodes
; node
; node
= node
->next
)
138 if (!cgraph_can_remove_if_no_direct_calls_p (node
)
139 && ((!DECL_EXTERNAL (node
->decl
))
141 || before_inlining_p
))
143 gcc_assert (!node
->global
.inlined_to
);
146 node
->reachable
= true;
150 gcc_assert (!node
->aux
);
151 node
->reachable
= false;
154 /* Perform reachability analysis. As a special case do not consider
155 extern inline functions not inlined as live because we won't output
157 while (first
!= (void *) 1)
159 struct cgraph_edge
*e
;
161 first
= (struct cgraph_node
*) first
->aux
;
162 node
->aux
= processed
;
165 for (e
= node
->callees
; e
; e
= e
->next_callee
)
166 if (!e
->callee
->reachable
168 && (!e
->inline_failed
|| !e
->callee
->analyzed
169 || (!DECL_EXTERNAL (e
->callee
->decl
))
170 || before_inlining_p
))
172 bool prev_reachable
= e
->callee
->reachable
;
173 e
->callee
->reachable
|= node
->reachable
;
175 || (e
->callee
->aux
== processed
176 && prev_reachable
!= e
->callee
->reachable
))
178 e
->callee
->aux
= first
;
183 /* We can freely remove inline clones even if they are cloned, however if
184 function is clone of real clone, we must keep it around in order to
185 make materialize_clones produce function body with the changes
187 while (node
->clone_of
&& !node
->clone_of
->aux
&& !gimple_has_body_p (node
->decl
))
189 bool noninline
= node
->clone_of
->decl
!= node
->decl
;
190 node
= node
->clone_of
;
200 /* Remove unreachable nodes. Extern inline functions need special care;
201 Unreachable extern inline functions shall be removed.
202 Reachable extern inline functions we never inlined shall get their bodies
204 Reachable extern inline functions we sometimes inlined will be turned into
205 unanalyzed nodes so they look like for true extern functions to the rest
206 of code. Body of such functions is released via remove_node once the
207 inline clones are eliminated. */
208 for (node
= cgraph_nodes
; node
; node
= next
)
211 if (node
->aux
&& !node
->reachable
)
213 cgraph_node_remove_callees (node
);
214 node
->analyzed
= false;
215 node
->local
.inlinable
= false;
219 node
->global
.inlined_to
= NULL
;
221 fprintf (file
, " %s", cgraph_node_name (node
));
222 if (!node
->analyzed
|| !DECL_EXTERNAL (node
->decl
) || before_inlining_p
)
223 cgraph_remove_node (node
);
226 struct cgraph_edge
*e
;
228 /* See if there is reachable caller. */
229 for (e
= node
->callers
; e
; e
= e
->next_caller
)
233 /* If so, we need to keep node in the callgraph. */
234 if (e
|| node
->needed
)
236 struct cgraph_node
*clone
;
238 /* If there are still clones, we must keep body around.
239 Otherwise we can just remove the body but keep the clone. */
240 for (clone
= node
->clones
; clone
;
241 clone
= clone
->next_sibling_clone
)
246 cgraph_release_function_body (node
);
247 cgraph_node_remove_callees (node
);
248 node
->analyzed
= false;
249 node
->local
.inlinable
= false;
251 if (node
->prev_sibling_clone
)
252 node
->prev_sibling_clone
->next_sibling_clone
= node
->next_sibling_clone
;
253 else if (node
->clone_of
)
254 node
->clone_of
->clones
= node
->next_sibling_clone
;
255 if (node
->next_sibling_clone
)
256 node
->next_sibling_clone
->prev_sibling_clone
= node
->prev_sibling_clone
;
257 node
->clone_of
= NULL
;
258 node
->next_sibling_clone
= NULL
;
259 node
->prev_sibling_clone
= NULL
;
262 cgraph_remove_node (node
);
267 for (node
= cgraph_nodes
; node
; node
= node
->next
)
269 /* Inline clones might be kept around so their materializing allows further
270 cloning. If the function the clone is inlined into is removed, we need
271 to turn it into normal cone. */
272 if (node
->global
.inlined_to
275 gcc_assert (node
->clones
);
276 node
->global
.inlined_to
= NULL
;
277 update_inlined_to_pointer (node
, node
);
281 #ifdef ENABLE_CHECKING
285 /* Reclaim alias pairs for functions that have disappeared from the
287 remove_unreachable_alias_pairs ();
293 cgraph_externally_visible_p (struct cgraph_node
*node
, bool whole_program
)
295 if (!node
->local
.finalized
)
297 if (!DECL_COMDAT (node
->decl
)
298 && (!TREE_PUBLIC (node
->decl
) || DECL_EXTERNAL (node
->decl
)))
302 /* COMDAT functions must be shared only if they have address taken,
303 otherwise we can produce our own private implementation with
305 if (DECL_COMDAT (node
->decl
) && (node
->address_taken
|| !node
->analyzed
))
307 if (MAIN_NAME_P (DECL_NAME (node
->decl
)))
309 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node
->decl
)))
314 /* Mark visibility of all functions.
316 A local function is one whose calls can occur only in the current
317 compilation unit and all its calls are explicit, so we can change
318 its calling convention. We simply mark all static functions whose
319 address is not taken as local.
321 We also change the TREE_PUBLIC flag of all declarations that are public
322 in language point of view but we want to overwrite this default
323 via visibilities for the backend point of view. */
326 function_and_variable_visibility (bool whole_program
)
328 struct cgraph_node
*node
;
329 struct varpool_node
*vnode
;
331 for (node
= cgraph_nodes
; node
; node
= node
->next
)
333 /* C++ FE on lack of COMDAT support create local COMDAT functions
334 (that ought to be shared but can not due to object format
335 limitations). It is neccesary to keep the flag to make rest of C++ FE
336 happy. Clear the flag here to avoid confusion in middle-end. */
337 if (DECL_COMDAT (node
->decl
) && !TREE_PUBLIC (node
->decl
))
338 DECL_COMDAT (node
->decl
) = 0;
339 gcc_assert ((!DECL_WEAK (node
->decl
) && !DECL_COMDAT (node
->decl
))
340 || TREE_PUBLIC (node
->decl
) || DECL_EXTERNAL (node
->decl
));
341 if (cgraph_externally_visible_p (node
, whole_program
))
343 gcc_assert (!node
->global
.inlined_to
);
344 node
->local
.externally_visible
= true;
347 node
->local
.externally_visible
= false;
348 if (!node
->local
.externally_visible
&& node
->analyzed
349 && !DECL_EXTERNAL (node
->decl
))
351 gcc_assert (whole_program
|| !TREE_PUBLIC (node
->decl
));
352 TREE_PUBLIC (node
->decl
) = 0;
353 DECL_COMDAT (node
->decl
) = 0;
354 DECL_WEAK (node
->decl
) = 0;
356 node
->local
.local
= (cgraph_only_called_directly_p (node
)
358 && !DECL_EXTERNAL (node
->decl
)
359 && !node
->local
.externally_visible
);
361 for (vnode
= varpool_nodes_queue
; vnode
; vnode
= vnode
->next_needed
)
363 if (!vnode
->finalized
)
365 gcc_assert ((!DECL_WEAK (vnode
->decl
) && !DECL_COMMON (vnode
->decl
))
366 || TREE_PUBLIC (vnode
->decl
) || DECL_EXTERNAL (vnode
->decl
));
368 && (DECL_COMDAT (vnode
->decl
) || TREE_PUBLIC (vnode
->decl
))
370 /* We can privatize comdat readonly variables whose address is not taken,
371 but doing so is not going to bring us optimization oppurtunities until
372 we start reordering datastructures. */
373 || DECL_COMDAT (vnode
->decl
)
374 || DECL_WEAK (vnode
->decl
)
375 || lookup_attribute ("externally_visible",
376 DECL_ATTRIBUTES (vnode
->decl
))))
377 vnode
->externally_visible
= true;
379 vnode
->externally_visible
= false;
380 if (!vnode
->externally_visible
)
382 gcc_assert (whole_program
|| !TREE_PUBLIC (vnode
->decl
));
383 TREE_PUBLIC (vnode
->decl
) = 0;
384 DECL_COMMON (vnode
->decl
) = 0;
386 gcc_assert (TREE_STATIC (vnode
->decl
));
391 fprintf (dump_file
, "\nMarking local functions:");
392 for (node
= cgraph_nodes
; node
; node
= node
->next
)
393 if (node
->local
.local
)
394 fprintf (dump_file
, " %s", cgraph_node_name (node
));
395 fprintf (dump_file
, "\n\n");
396 fprintf (dump_file
, "\nMarking externally visible functions:");
397 for (node
= cgraph_nodes
; node
; node
= node
->next
)
398 if (node
->local
.externally_visible
)
399 fprintf (dump_file
, " %s", cgraph_node_name (node
));
400 fprintf (dump_file
, "\n\n");
401 fprintf (dump_file
, "\nMarking externally visible variables:");
402 for (vnode
= varpool_nodes_queue
; vnode
; vnode
= vnode
->next_needed
)
403 if (vnode
->externally_visible
)
404 fprintf (dump_file
, " %s", varpool_node_name (vnode
));
405 fprintf (dump_file
, "\n\n");
407 cgraph_function_flags_ready
= true;
411 /* Local function pass handling visibilities. This happens before LTO streaming
412 so in particular -fwhole-program should be ignored at this level. */
415 local_function_and_variable_visibility (void)
417 return function_and_variable_visibility (flag_whole_program
&& !flag_lto
&& !flag_whopr
);
420 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility
=
424 "visibility", /* name */
426 local_function_and_variable_visibility
,/* execute */
429 0, /* static_pass_number */
430 TV_CGRAPHOPT
, /* tv_id */
431 0, /* properties_required */
432 0, /* properties_provided */
433 0, /* properties_destroyed */
434 0, /* todo_flags_start */
435 TODO_remove_functions
| TODO_dump_cgraph
/* todo_flags_finish */
439 /* Do not re-run on ltrans stage. */
442 gate_whole_program_function_and_variable_visibility (void)
447 /* Bring functionss local at LTO time whith -fwhole-program. */
450 whole_program_function_and_variable_visibility (void)
452 struct cgraph_node
*node
;
453 struct varpool_node
*vnode
;
455 function_and_variable_visibility (flag_whole_program
);
457 for (node
= cgraph_nodes
; node
; node
= node
->next
)
458 if ((node
->local
.externally_visible
&& !DECL_COMDAT (node
->decl
))
459 && node
->local
.finalized
)
460 cgraph_mark_needed_node (node
);
461 for (vnode
= varpool_nodes_queue
; vnode
; vnode
= vnode
->next_needed
)
462 if (vnode
->externally_visible
&& !DECL_COMDAT (vnode
->decl
))
463 varpool_mark_needed_node (vnode
);
466 fprintf (dump_file
, "\nNeeded variables:");
467 for (vnode
= varpool_nodes_queue
; vnode
; vnode
= vnode
->next_needed
)
469 fprintf (dump_file
, " %s", varpool_node_name (vnode
));
470 fprintf (dump_file
, "\n\n");
475 struct ipa_opt_pass_d pass_ipa_whole_program_visibility
=
479 "whole-program", /* name */
480 gate_whole_program_function_and_variable_visibility
,/* gate */
481 whole_program_function_and_variable_visibility
,/* execute */
484 0, /* static_pass_number */
485 TV_CGRAPHOPT
, /* tv_id */
486 0, /* properties_required */
487 0, /* properties_provided */
488 0, /* properties_destroyed */
489 0, /* todo_flags_start */
490 TODO_dump_cgraph
| TODO_remove_functions
/* todo_flags_finish */
492 NULL
, /* generate_summary */
493 NULL
, /* write_summary */
494 NULL
, /* read_summary */
495 NULL
, /* function_read_summary */
496 NULL
, /* stmt_fixup */
498 NULL
, /* function_transform */
499 NULL
, /* variable_transform */
502 /* Hash a cgraph node set element. */
505 hash_cgraph_node_set_element (const void *p
)
507 const_cgraph_node_set_element element
= (const_cgraph_node_set_element
) p
;
508 return htab_hash_pointer (element
->node
);
511 /* Compare two cgraph node set elements. */
514 eq_cgraph_node_set_element (const void *p1
, const void *p2
)
516 const_cgraph_node_set_element e1
= (const_cgraph_node_set_element
) p1
;
517 const_cgraph_node_set_element e2
= (const_cgraph_node_set_element
) p2
;
519 return e1
->node
== e2
->node
;
522 /* Create a new cgraph node set. */
525 cgraph_node_set_new (void)
527 cgraph_node_set new_node_set
;
529 new_node_set
= GGC_NEW (struct cgraph_node_set_def
);
530 new_node_set
->hashtab
= htab_create_ggc (10,
531 hash_cgraph_node_set_element
,
532 eq_cgraph_node_set_element
,
534 new_node_set
->nodes
= NULL
;
538 /* Add cgraph_node NODE to cgraph_node_set SET. */
541 cgraph_node_set_add (cgraph_node_set set
, struct cgraph_node
*node
)
544 cgraph_node_set_element element
;
545 struct cgraph_node_set_element_def dummy
;
548 slot
= htab_find_slot (set
->hashtab
, &dummy
, INSERT
);
550 if (*slot
!= HTAB_EMPTY_ENTRY
)
552 element
= (cgraph_node_set_element
) *slot
;
553 gcc_assert (node
== element
->node
554 && (VEC_index (cgraph_node_ptr
, set
->nodes
, element
->index
)
559 /* Insert node into hash table. */
561 (cgraph_node_set_element
) GGC_NEW (struct cgraph_node_set_element_def
);
562 element
->node
= node
;
563 element
->index
= VEC_length (cgraph_node_ptr
, set
->nodes
);
566 /* Insert into node vector. */
567 VEC_safe_push (cgraph_node_ptr
, gc
, set
->nodes
, node
);
570 /* Remove cgraph_node NODE from cgraph_node_set SET. */
573 cgraph_node_set_remove (cgraph_node_set set
, struct cgraph_node
*node
)
575 void **slot
, **last_slot
;
576 cgraph_node_set_element element
, last_element
;
577 struct cgraph_node
*last_node
;
578 struct cgraph_node_set_element_def dummy
;
581 slot
= htab_find_slot (set
->hashtab
, &dummy
, NO_INSERT
);
585 element
= (cgraph_node_set_element
) *slot
;
586 gcc_assert (VEC_index (cgraph_node_ptr
, set
->nodes
, element
->index
)
589 /* Remove from vector. We do this by swapping node with the last element
591 last_node
= VEC_pop (cgraph_node_ptr
, set
->nodes
);
592 if (last_node
!= node
)
594 dummy
.node
= last_node
;
595 last_slot
= htab_find_slot (set
->hashtab
, &dummy
, NO_INSERT
);
596 last_element
= (cgraph_node_set_element
) *last_slot
;
597 gcc_assert (last_element
);
599 /* Move the last element to the original spot of NODE. */
600 last_element
->index
= element
->index
;
601 VEC_replace (cgraph_node_ptr
, set
->nodes
, last_element
->index
,
605 /* Remove element from hash table. */
606 htab_clear_slot (set
->hashtab
, slot
);
610 /* Find NODE in SET and return an iterator to it if found. A null iterator
611 is returned if NODE is not in SET. */
613 cgraph_node_set_iterator
614 cgraph_node_set_find (cgraph_node_set set
, struct cgraph_node
*node
)
617 struct cgraph_node_set_element_def dummy
;
618 cgraph_node_set_element element
;
619 cgraph_node_set_iterator csi
;
622 slot
= htab_find_slot (set
->hashtab
, &dummy
, NO_INSERT
);
624 csi
.index
= (unsigned) ~0;
627 element
= (cgraph_node_set_element
) *slot
;
628 gcc_assert (VEC_index (cgraph_node_ptr
, set
->nodes
, element
->index
)
630 csi
.index
= element
->index
;
637 /* Dump content of SET to file F. */
640 dump_cgraph_node_set (FILE *f
, cgraph_node_set set
)
642 cgraph_node_set_iterator iter
;
644 for (iter
= csi_start (set
); !csi_end_p (iter
); csi_next (&iter
))
646 struct cgraph_node
*node
= csi_node (iter
);
647 dump_cgraph_node (f
, node
);
651 /* Dump content of SET to stderr. */
654 debug_cgraph_node_set (cgraph_node_set set
)
656 dump_cgraph_node_set (stderr
, set
);