1 /* Basic IPA optimizations and utilities.
2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
3 Free Software Foundation, 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
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 /* Break possible cycles involving always-inline
74 functions by ignoring edges from always-inline
75 functions to non-always-inline functions. */
76 if (edge->caller->local.disregard_inline_limits
77 && !edge->callee->local.disregard_inline_limits)
79 if (!edge->caller->aux)
81 if (!edge->caller->callers)
82 edge->caller->aux = &last;
84 edge->caller->aux = edge->caller->callers;
85 stack[stack_size++] = node2;
90 if (node2->aux == &last)
92 order[order_pos++] = node2;
94 node2 = stack[--stack_size];
101 for (node = cgraph_nodes; node; node = node->next)
106 /* Look for all functions inlined to NODE and update their inlined_to pointers
110 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
112 struct cgraph_edge *e;
113 for (e = node->callees; e; e = e->next_callee)
114 if (e->callee->global.inlined_to)
116 e->callee->global.inlined_to = inlined_to;
117 update_inlined_to_pointer (e->callee, inlined_to);
121 /* Add cgraph NODE to queue starting at FIRST. */
124 enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first)
130 /* Add varpool NODE to queue starting at FIRST. */
133 enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first)
139 /* Process references. */
142 process_references (struct ipa_ref_list *list,
143 struct cgraph_node **first,
144 struct varpool_node **first_varpool,
145 bool before_inlining_p)
149 for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
151 if (ref->refered_type == IPA_REF_CGRAPH)
153 struct cgraph_node *node = ipa_ref_node (ref);
155 && (!DECL_EXTERNAL (node->decl)
156 || before_inlining_p))
158 node->reachable = true;
159 enqueue_cgraph_node (node, first);
164 struct varpool_node *node = ipa_ref_varpool_node (ref);
167 varpool_mark_needed_node (node);
168 enqueue_varpool_node (node, first_varpool);
174 /* Return true when function NODE can be removed from callgraph
175 if all direct calls are eliminated. */
178 varpool_can_remove_if_no_refs (struct varpool_node *node)
180 return (!node->force_output && !node->used_from_other_partition
181 && (DECL_COMDAT (node->decl) || !node->externally_visible));
184 /* Perform reachability analysis and reclaim all unreachable nodes.
185 If BEFORE_INLINING_P is true this function is called before inlining
186 decisions has been made. If BEFORE_INLINING_P is false this function also
187 removes unneeded bodies of extern inline functions. */
190 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
192 struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
193 struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1;
194 struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
195 struct cgraph_node *node, *next;
196 struct varpool_node *vnode, *vnext;
197 bool changed = false;
199 #ifdef ENABLE_CHECKING
203 fprintf (file, "\nReclaiming functions:");
204 #ifdef ENABLE_CHECKING
205 for (node = cgraph_nodes; node; node = node->next)
206 gcc_assert (!node->aux);
208 varpool_reset_queue ();
209 for (node = cgraph_nodes; node; node = node->next)
210 if (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
211 && ((!DECL_EXTERNAL (node->decl))
212 || before_inlining_p))
214 gcc_assert (!node->global.inlined_to);
215 enqueue_cgraph_node (node, &first);
216 node->reachable = true;
220 gcc_assert (!node->aux);
221 node->reachable = false;
223 for (vnode = varpool_nodes; vnode; vnode = vnode->next)
225 vnode->next_needed = NULL;
226 vnode->prev_needed = NULL;
227 if (!varpool_can_remove_if_no_refs (vnode))
229 vnode->needed = false;
230 varpool_mark_needed_node (vnode);
231 enqueue_varpool_node (vnode, &first_varpool);
234 vnode->needed = false;
237 /* Perform reachability analysis. As a special case do not consider
238 extern inline functions not inlined as live because we won't output
240 while (first != (struct cgraph_node *) (void *) 1
241 || first_varpool != (struct varpool_node *) (void *) 1)
243 if (first != (struct cgraph_node *) (void *) 1)
245 struct cgraph_edge *e;
247 first = (struct cgraph_node *) first->aux;
248 node->aux = processed;
251 for (e = node->callees; e; e = e->next_callee)
252 if (!e->callee->reachable
254 && (!e->inline_failed || !e->callee->analyzed
255 || (!DECL_EXTERNAL (e->callee->decl))
256 || before_inlining_p))
258 bool prev_reachable = e->callee->reachable;
259 e->callee->reachable |= node->reachable;
261 || (e->callee->aux == processed
262 && prev_reachable != e->callee->reachable))
264 e->callee->aux = first;
269 /* If any function in a comdat group is reachable, force
270 all other functions in the same comdat group to be
272 if (node->same_comdat_group
274 && !node->global.inlined_to)
276 for (next = node->same_comdat_group;
278 next = next->same_comdat_group)
279 if (!next->reachable)
283 next->reachable = true;
287 /* We can freely remove inline clones even if they are cloned, however if
288 function is clone of real clone, we must keep it around in order to
289 make materialize_clones produce function body with the changes
291 while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
293 bool noninline = node->clone_of->decl != node->decl;
294 node = node->clone_of;
297 enqueue_cgraph_node (node, &first);
301 process_references (&node->ref_list, &first, &first_varpool, before_inlining_p);
303 if (first_varpool != (struct varpool_node *) (void *) 1)
305 vnode = first_varpool;
306 first_varpool = (struct varpool_node *)first_varpool->aux;
308 process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p);
312 /* Remove unreachable nodes. Extern inline functions need special care;
313 Unreachable extern inline functions shall be removed.
314 Reachable extern inline functions we never inlined shall get their bodies
316 Reachable extern inline functions we sometimes inlined will be turned into
317 unanalyzed nodes so they look like for true extern functions to the rest
318 of code. Body of such functions is released via remove_node once the
319 inline clones are eliminated. */
320 for (node = cgraph_nodes; node; node = next)
323 if (node->aux && !node->reachable)
325 cgraph_node_remove_callees (node);
326 node->analyzed = false;
327 node->local.inlinable = false;
331 node->global.inlined_to = NULL;
333 fprintf (file, " %s", cgraph_node_name (node));
334 if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
335 cgraph_remove_node (node);
338 struct cgraph_edge *e;
340 /* See if there is reachable caller. */
341 for (e = node->callers; e; e = e->next_caller)
345 /* If so, we need to keep node in the callgraph. */
346 if (e || node->needed)
348 struct cgraph_node *clone;
350 /* If there are still clones, we must keep body around.
351 Otherwise we can just remove the body but keep the clone. */
352 for (clone = node->clones; clone;
353 clone = clone->next_sibling_clone)
358 cgraph_release_function_body (node);
359 node->analyzed = false;
360 node->local.inlinable = false;
363 gcc_assert (!clone->in_other_partition);
364 cgraph_node_remove_callees (node);
365 ipa_remove_all_references (&node->ref_list);
366 if (node->prev_sibling_clone)
367 node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
368 else if (node->clone_of)
369 node->clone_of->clones = node->next_sibling_clone;
370 if (node->next_sibling_clone)
371 node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
372 node->clone_of = NULL;
373 node->next_sibling_clone = NULL;
374 node->prev_sibling_clone = NULL;
377 cgraph_remove_node (node);
382 for (node = cgraph_nodes; node; node = node->next)
384 /* Inline clones might be kept around so their materializing allows further
385 cloning. If the function the clone is inlined into is removed, we need
386 to turn it into normal cone. */
387 if (node->global.inlined_to
390 gcc_assert (node->clones);
391 node->global.inlined_to = NULL;
392 update_inlined_to_pointer (node, node);
397 fprintf (file, "\nReclaiming variables:");
398 for (vnode = varpool_nodes; vnode; vnode = vnext)
404 fprintf (file, " %s", varpool_node_name (vnode));
405 varpool_remove_node (vnode);
409 fprintf (file, "\nClearing address taken flags:");
410 for (node = cgraph_nodes; node; node = node->next)
411 if (node->address_taken
412 && !node->reachable_from_other_partition)
417 for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref)
423 fprintf (file, " %s", cgraph_node_name (node));
424 node->address_taken = false;
428 #ifdef ENABLE_CHECKING
432 /* Reclaim alias pairs for functions that have disappeared from the
434 remove_unreachable_alias_pairs ();
440 cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
442 if (!node->local.finalized)
444 if (!DECL_COMDAT (node->decl)
445 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
449 if (DECL_PRESERVE_P (node->decl))
451 /* COMDAT functions must be shared only if they have address taken,
452 otherwise we can produce our own private implementation with
454 if (DECL_COMDAT (node->decl))
456 if (node->address_taken || !node->analyzed)
458 if (node->same_comdat_group)
460 struct cgraph_node *next;
462 /* If more than one function is in the same COMDAT group, it must
463 be shared even if just one function in the comdat group has
465 for (next = node->same_comdat_group;
467 next = next->same_comdat_group)
468 if (next->address_taken || !next->analyzed)
472 if (MAIN_NAME_P (DECL_NAME (node->decl)))
474 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
479 /* Dissolve the same_comdat_group list in which NODE resides. */
482 dissolve_same_comdat_group_list (struct cgraph_node *node)
484 struct cgraph_node *n = node, *next;
487 next = n->same_comdat_group;
488 n->same_comdat_group = NULL;
494 /* Mark visibility of all functions.
496 A local function is one whose calls can occur only in the current
497 compilation unit and all its calls are explicit, so we can change
498 its calling convention. We simply mark all static functions whose
499 address is not taken as local.
501 We also change the TREE_PUBLIC flag of all declarations that are public
502 in language point of view but we want to overwrite this default
503 via visibilities for the backend point of view. */
506 function_and_variable_visibility (bool whole_program)
508 struct cgraph_node *node;
509 struct varpool_node *vnode;
511 for (node = cgraph_nodes; node; node = node->next)
513 /* C++ FE on lack of COMDAT support create local COMDAT functions
514 (that ought to be shared but can not due to object format
515 limitations). It is neccesary to keep the flag to make rest of C++ FE
516 happy. Clear the flag here to avoid confusion in middle-end. */
517 if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
518 DECL_COMDAT (node->decl) = 0;
519 /* For external decls stop tracking same_comdat_group, it doesn't matter
520 what comdat group they are in when they won't be emitted in this TU,
521 and simplifies later passes. */
522 if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
524 #ifdef ENABLE_CHECKING
525 struct cgraph_node *n;
527 for (n = node->same_comdat_group;
529 n = n->same_comdat_group)
530 /* If at least one of same comdat group functions is external,
531 all of them have to be, otherwise it is a front-end bug. */
532 gcc_assert (DECL_EXTERNAL (n->decl));
534 dissolve_same_comdat_group_list (node);
536 gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
537 || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
538 if (cgraph_externally_visible_p (node, whole_program))
540 gcc_assert (!node->global.inlined_to);
541 node->local.externally_visible = true;
544 node->local.externally_visible = false;
545 if (!node->local.externally_visible && node->analyzed
546 && !DECL_EXTERNAL (node->decl))
548 gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
549 cgraph_make_decl_local (node->decl);
550 if (node->same_comdat_group)
551 /* cgraph_externally_visible_p has already checked all other nodes
552 in the group and they will all be made local. We need to
553 dissolve the group at once so that the predicate does not
555 dissolve_same_comdat_group_list (node);
557 node->local.local = (cgraph_only_called_directly_p (node)
559 && !DECL_EXTERNAL (node->decl)
560 && !node->local.externally_visible);
562 for (vnode = varpool_nodes; vnode; vnode = vnode->next)
564 /* weak flag makes no sense on local variables. */
565 gcc_assert (!DECL_WEAK (vnode->decl)
566 || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
567 /* In several cases declarations can not be common:
569 - when declaration has initializer
571 - when it has specific section
572 - when it resides in non-generic address space.
573 - if declaration is local, it will get into .local common section
574 so common flag is not needed. Frontends still produce these in
575 certain cases, such as for:
577 static int a __attribute__ ((common))
579 Canonicalize things here and clear the redundant flag. */
580 if (DECL_COMMON (vnode->decl)
581 && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
582 || (DECL_INITIAL (vnode->decl)
583 && DECL_INITIAL (vnode->decl) != error_mark_node)
584 || DECL_WEAK (vnode->decl)
585 || DECL_SECTION_NAME (vnode->decl) != NULL
586 || ! (ADDR_SPACE_GENERIC_P
587 (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
588 DECL_COMMON (vnode->decl) = 0;
590 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
592 if (!vnode->finalized)
595 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
597 /* We can privatize comdat readonly variables whose address is not taken,
598 but doing so is not going to bring us optimization oppurtunities until
599 we start reordering datastructures. */
600 || DECL_COMDAT (vnode->decl)
601 || DECL_WEAK (vnode->decl)
602 || lookup_attribute ("externally_visible",
603 DECL_ATTRIBUTES (vnode->decl))))
604 vnode->externally_visible = true;
606 vnode->externally_visible = false;
607 if (!vnode->externally_visible)
609 gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
610 cgraph_make_decl_local (vnode->decl);
612 gcc_assert (TREE_STATIC (vnode->decl));
617 fprintf (dump_file, "\nMarking local functions:");
618 for (node = cgraph_nodes; node; node = node->next)
619 if (node->local.local)
620 fprintf (dump_file, " %s", cgraph_node_name (node));
621 fprintf (dump_file, "\n\n");
622 fprintf (dump_file, "\nMarking externally visible functions:");
623 for (node = cgraph_nodes; node; node = node->next)
624 if (node->local.externally_visible)
625 fprintf (dump_file, " %s", cgraph_node_name (node));
626 fprintf (dump_file, "\n\n");
627 fprintf (dump_file, "\nMarking externally visible variables:");
628 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
629 if (vnode->externally_visible)
630 fprintf (dump_file, " %s", varpool_node_name (vnode));
631 fprintf (dump_file, "\n\n");
633 cgraph_function_flags_ready = true;
637 /* Local function pass handling visibilities. This happens before LTO streaming
638 so in particular -fwhole-program should be ignored at this level. */
641 local_function_and_variable_visibility (void)
643 return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
646 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
650 "visibility", /* name */
652 local_function_and_variable_visibility,/* execute */
655 0, /* static_pass_number */
656 TV_CGRAPHOPT, /* tv_id */
657 0, /* properties_required */
658 0, /* properties_provided */
659 0, /* properties_destroyed */
660 0, /* todo_flags_start */
661 TODO_remove_functions | TODO_dump_cgraph
662 | TODO_ggc_collect /* todo_flags_finish */
666 /* Do not re-run on ltrans stage. */
669 gate_whole_program_function_and_variable_visibility (void)
674 /* Bring functionss local at LTO time whith -fwhole-program. */
677 whole_program_function_and_variable_visibility (void)
679 struct cgraph_node *node;
680 struct varpool_node *vnode;
682 function_and_variable_visibility (flag_whole_program);
684 for (node = cgraph_nodes; node; node = node->next)
685 if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
686 && node->local.finalized)
687 cgraph_mark_needed_node (node);
688 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
689 if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
690 varpool_mark_needed_node (vnode);
693 fprintf (dump_file, "\nNeeded variables:");
694 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
696 fprintf (dump_file, " %s", varpool_node_name (vnode));
697 fprintf (dump_file, "\n\n");
702 struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
706 "whole-program", /* name */
707 gate_whole_program_function_and_variable_visibility,/* gate */
708 whole_program_function_and_variable_visibility,/* execute */
711 0, /* static_pass_number */
712 TV_CGRAPHOPT, /* tv_id */
713 0, /* properties_required */
714 0, /* properties_provided */
715 0, /* properties_destroyed */
716 0, /* todo_flags_start */
717 TODO_remove_functions | TODO_dump_cgraph
718 | TODO_ggc_collect /* todo_flags_finish */
720 NULL, /* generate_summary */
721 NULL, /* write_summary */
722 NULL, /* read_summary */
723 NULL, /* write_optimization_summary */
724 NULL, /* read_optimization_summary */
725 NULL, /* stmt_fixup */
727 NULL, /* function_transform */
728 NULL, /* variable_transform */
731 /* Hash a cgraph node set element. */
734 hash_cgraph_node_set_element (const void *p)
736 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
737 return htab_hash_pointer (element->node);
740 /* Compare two cgraph node set elements. */
743 eq_cgraph_node_set_element (const void *p1, const void *p2)
745 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
746 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
748 return e1->node == e2->node;
751 /* Create a new cgraph node set. */
754 cgraph_node_set_new (void)
756 cgraph_node_set new_node_set;
758 new_node_set = GGC_NEW (struct cgraph_node_set_def);
759 new_node_set->hashtab = htab_create_ggc (10,
760 hash_cgraph_node_set_element,
761 eq_cgraph_node_set_element,
763 new_node_set->nodes = NULL;
767 /* Add cgraph_node NODE to cgraph_node_set SET. */
770 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
773 cgraph_node_set_element element;
774 struct cgraph_node_set_element_def dummy;
777 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
779 if (*slot != HTAB_EMPTY_ENTRY)
781 element = (cgraph_node_set_element) *slot;
782 gcc_assert (node == element->node
783 && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
788 /* Insert node into hash table. */
790 (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
791 element->node = node;
792 element->index = VEC_length (cgraph_node_ptr, set->nodes);
795 /* Insert into node vector. */
796 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
799 /* Remove cgraph_node NODE from cgraph_node_set SET. */
802 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
804 void **slot, **last_slot;
805 cgraph_node_set_element element, last_element;
806 struct cgraph_node *last_node;
807 struct cgraph_node_set_element_def dummy;
810 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
814 element = (cgraph_node_set_element) *slot;
815 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
818 /* Remove from vector. We do this by swapping node with the last element
820 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
821 if (last_node != node)
823 dummy.node = last_node;
824 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
825 last_element = (cgraph_node_set_element) *last_slot;
826 gcc_assert (last_element);
828 /* Move the last element to the original spot of NODE. */
829 last_element->index = element->index;
830 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
834 /* Remove element from hash table. */
835 htab_clear_slot (set->hashtab, slot);
839 /* Find NODE in SET and return an iterator to it if found. A null iterator
840 is returned if NODE is not in SET. */
842 cgraph_node_set_iterator
843 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
846 struct cgraph_node_set_element_def dummy;
847 cgraph_node_set_element element;
848 cgraph_node_set_iterator csi;
851 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
853 csi.index = (unsigned) ~0;
856 element = (cgraph_node_set_element) *slot;
857 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
859 csi.index = element->index;
866 /* Dump content of SET to file F. */
869 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
871 cgraph_node_set_iterator iter;
873 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
875 struct cgraph_node *node = csi_node (iter);
876 dump_cgraph_node (f, node);
880 /* Dump content of SET to stderr. */
883 debug_cgraph_node_set (cgraph_node_set set)
885 dump_cgraph_node_set (stderr, set);
888 /* Hash a varpool node set element. */
891 hash_varpool_node_set_element (const void *p)
893 const_varpool_node_set_element element = (const_varpool_node_set_element) p;
894 return htab_hash_pointer (element->node);
897 /* Compare two varpool node set elements. */
900 eq_varpool_node_set_element (const void *p1, const void *p2)
902 const_varpool_node_set_element e1 = (const_varpool_node_set_element) p1;
903 const_varpool_node_set_element e2 = (const_varpool_node_set_element) p2;
905 return e1->node == e2->node;
908 /* Create a new varpool node set. */
911 varpool_node_set_new (void)
913 varpool_node_set new_node_set;
915 new_node_set = GGC_NEW (struct varpool_node_set_def);
916 new_node_set->hashtab = htab_create_ggc (10,
917 hash_varpool_node_set_element,
918 eq_varpool_node_set_element,
920 new_node_set->nodes = NULL;
924 /* Add varpool_node NODE to varpool_node_set SET. */
927 varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
930 varpool_node_set_element element;
931 struct varpool_node_set_element_def dummy;
934 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
936 if (*slot != HTAB_EMPTY_ENTRY)
938 element = (varpool_node_set_element) *slot;
939 gcc_assert (node == element->node
940 && (VEC_index (varpool_node_ptr, set->nodes, element->index)
945 /* Insert node into hash table. */
947 (varpool_node_set_element) GGC_NEW (struct varpool_node_set_element_def);
948 element->node = node;
949 element->index = VEC_length (varpool_node_ptr, set->nodes);
952 /* Insert into node vector. */
953 VEC_safe_push (varpool_node_ptr, gc, set->nodes, node);
956 /* Remove varpool_node NODE from varpool_node_set SET. */
959 varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
961 void **slot, **last_slot;
962 varpool_node_set_element element, last_element;
963 struct varpool_node *last_node;
964 struct varpool_node_set_element_def dummy;
967 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
971 element = (varpool_node_set_element) *slot;
972 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
975 /* Remove from vector. We do this by swapping node with the last element
977 last_node = VEC_pop (varpool_node_ptr, set->nodes);
978 if (last_node != node)
980 dummy.node = last_node;
981 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
982 last_element = (varpool_node_set_element) *last_slot;
983 gcc_assert (last_element);
985 /* Move the last element to the original spot of NODE. */
986 last_element->index = element->index;
987 VEC_replace (varpool_node_ptr, set->nodes, last_element->index,
991 /* Remove element from hash table. */
992 htab_clear_slot (set->hashtab, slot);
996 /* Find NODE in SET and return an iterator to it if found. A null iterator
997 is returned if NODE is not in SET. */
999 varpool_node_set_iterator
1000 varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
1003 struct varpool_node_set_element_def dummy;
1004 varpool_node_set_element element;
1005 varpool_node_set_iterator vsi;
1008 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
1010 vsi.index = (unsigned) ~0;
1013 element = (varpool_node_set_element) *slot;
1014 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
1016 vsi.index = element->index;
1023 /* Dump content of SET to file F. */
1026 dump_varpool_node_set (FILE *f, varpool_node_set set)
1028 varpool_node_set_iterator iter;
1030 for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
1032 struct varpool_node *node = vsi_node (iter);
1033 dump_varpool_node (f, node);
1037 /* Dump content of SET to stderr. */
1040 debug_varpool_node_set (varpool_node_set set)
1042 dump_varpool_node_set (stderr, set);
1046 /* Simple ipa profile pass propagating frequencies across the callgraph. */
1051 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
1052 struct cgraph_edge *e;
1054 bool something_changed = false;
1057 order_pos = cgraph_postorder (order);
1058 for (i = order_pos - 1; i >= 0; i--)
1060 if (order[i]->local.local && cgraph_propagate_frequency (order[i]))
1062 for (e = order[i]->callees; e; e = e->next_callee)
1063 if (e->callee->local.local && !e->callee->aux)
1065 something_changed = true;
1066 e->callee->aux = (void *)1;
1069 order[i]->aux = NULL;
1072 while (something_changed)
1074 something_changed = false;
1075 for (i = order_pos - 1; i >= 0; i--)
1077 if (order[i]->aux && cgraph_propagate_frequency (order[i]))
1079 for (e = order[i]->callees; e; e = e->next_callee)
1080 if (e->callee->local.local && !e->callee->aux)
1082 something_changed = true;
1083 e->callee->aux = (void *)1;
1086 order[i]->aux = NULL;
1094 gate_ipa_profile (void)
1096 return flag_ipa_profile;
1099 struct ipa_opt_pass_d pass_ipa_profile =
1103 "ipa-profile", /* name */
1104 gate_ipa_profile, /* gate */
1105 ipa_profile, /* execute */
1108 0, /* static_pass_number */
1109 TV_IPA_PROFILE, /* tv_id */
1110 0, /* properties_required */
1111 0, /* properties_provided */
1112 0, /* properties_destroyed */
1113 0, /* todo_flags_start */
1114 0 /* todo_flags_finish */
1116 NULL, /* generate_summary */
1117 NULL, /* write_summary */
1118 NULL, /* read_summary */
1119 NULL, /* write_optimization_summary */
1120 NULL, /* read_optimization_summary */
1121 NULL, /* stmt_fixup */
1123 NULL, /* function_transform */
1124 NULL /* variable_transform */