xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/ipa.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /* Basic IPA optimizations and utilities.
2    Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
3    Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
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.
11 
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.
16 
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/>.  */
20 
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"
30 
31 /* Fill array order with all nodes with output flag set in the reverse
32    topological order.  */
33 
34 int
35 cgraph_postorder (struct cgraph_node **order)
36 {
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;
42 
43   struct cgraph_node **stack =
44     XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
45 
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)))
58 	{
59 	  node2 = node;
60 	  if (!node->callers)
61 	    node->aux = &last;
62 	  else
63 	    node->aux = node->callers;
64 	  while (node2)
65 	    {
66 	      while (node2->aux != &last)
67 		{
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)
74 		    {
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;
82 		    }
83 		}
84 	      if (node2->aux == &last)
85 		{
86 		  order[order_pos++] = node2;
87 		  if (stack_size)
88 		    node2 = stack[--stack_size];
89 		  else
90 		    node2 = NULL;
91 		}
92 	    }
93 	}
94   free (stack);
95   for (node = cgraph_nodes; node; node = node->next)
96     node->aux = NULL;
97   return order_pos;
98 }
99 
100 /* Look for all functions inlined to NODE and update their inlined_to pointers
101    to INLINED_TO.  */
102 
103 static void
104 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
105 {
106   struct cgraph_edge *e;
107   for (e = node->callees; e; e = e->next_callee)
108     if (e->callee->global.inlined_to)
109       {
110         e->callee->global.inlined_to = inlined_to;
111 	update_inlined_to_pointer (e->callee, inlined_to);
112       }
113 }
114 
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.  */
119 
120 bool
121 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
122 {
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;
127 
128 #ifdef ENABLE_CHECKING
129   verify_cgraph ();
130 #endif
131   if (file)
132     fprintf (file, "\nReclaiming functions:");
133 #ifdef ENABLE_CHECKING
134   for (node = cgraph_nodes; node; node = node->next)
135     gcc_assert (!node->aux);
136 #endif
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))
140             || !node->analyzed
141             || before_inlining_p))
142       {
143         gcc_assert (!node->global.inlined_to);
144 	node->aux = first;
145 	first = node;
146 	node->reachable = true;
147       }
148     else
149       {
150         gcc_assert (!node->aux);
151 	node->reachable = false;
152       }
153 
154   /* Perform reachability analysis.  As a special case do not consider
155      extern inline functions not inlined as live because we won't output
156      them at all.  */
157   while (first != (void *) 1)
158     {
159       struct cgraph_edge *e;
160       node = first;
161       first = (struct cgraph_node *) first->aux;
162       node->aux = processed;
163 
164       if (node->reachable)
165         for (e = node->callees; e; e = e->next_callee)
166 	  if (!e->callee->reachable
167 	      && node->analyzed
168 	      && (!e->inline_failed || !e->callee->analyzed
169 		  || (!DECL_EXTERNAL (e->callee->decl))
170                   || before_inlining_p))
171 	    {
172 	      bool prev_reachable = e->callee->reachable;
173 	      e->callee->reachable |= node->reachable;
174 	      if (!e->callee->aux
175 	          || (e->callee->aux == processed
176 		      && prev_reachable != e->callee->reachable))
177 	        {
178 	          e->callee->aux = first;
179 	          first = e->callee;
180 	        }
181 	    }
182 
183       /* If any function in a comdat group is reachable, force
184 	 all other functions in the same comdat group to be
185 	 also reachable.  */
186       if (node->same_comdat_group
187 	  && node->reachable
188 	  && !node->global.inlined_to)
189 	{
190 	  for (next = node->same_comdat_group;
191 	       next != node;
192 	       next = next->same_comdat_group)
193 	    if (!next->reachable)
194 	      {
195 		next->aux = first;
196 		first = next;
197 		next->reachable = true;
198 	      }
199 	}
200 
201       /* We can freely remove inline clones even if they are cloned, however if
202 	 function is clone of real clone, we must keep it around in order to
203 	 make materialize_clones produce function body with the changes
204 	 applied.  */
205       while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
206         {
207 	  bool noninline = node->clone_of->decl != node->decl;
208 	  node = node->clone_of;
209 	  if (noninline)
210 	    {
211 	      node->aux = first;
212 	      first = node;
213 	      break;
214 	    }
215 	}
216     }
217 
218   /* Remove unreachable nodes.  Extern inline functions need special care;
219      Unreachable extern inline functions shall be removed.
220      Reachable extern inline functions we never inlined shall get their bodies
221      eliminated.
222      Reachable extern inline functions we sometimes inlined will be turned into
223      unanalyzed nodes so they look like for true extern functions to the rest
224      of code.  Body of such functions is released via remove_node once the
225      inline clones are eliminated.  */
226   for (node = cgraph_nodes; node; node = next)
227     {
228       next = node->next;
229       if (node->aux && !node->reachable)
230         {
231 	  cgraph_node_remove_callees (node);
232 	  node->analyzed = false;
233 	  node->local.inlinable = false;
234 	}
235       if (!node->aux)
236 	{
237           node->global.inlined_to = NULL;
238 	  if (file)
239 	    fprintf (file, " %s", cgraph_node_name (node));
240 	  if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
241 	    cgraph_remove_node (node);
242 	  else
243 	    {
244 	      struct cgraph_edge *e;
245 
246 	      /* See if there is reachable caller.  */
247 	      for (e = node->callers; e; e = e->next_caller)
248 		if (e->caller->aux)
249 		  break;
250 
251 	      /* If so, we need to keep node in the callgraph.  */
252 	      if (e || node->needed)
253 		{
254 		  struct cgraph_node *clone;
255 
256 		  /* If there are still clones, we must keep body around.
257 		     Otherwise we can just remove the body but keep the clone.  */
258 		  for (clone = node->clones; clone;
259 		       clone = clone->next_sibling_clone)
260 		    if (clone->aux)
261 		      break;
262 		  if (!clone)
263 		    {
264 		      cgraph_release_function_body (node);
265 		      node->analyzed = false;
266 		      node->local.inlinable = false;
267 		    }
268 		  cgraph_node_remove_callees (node);
269 		  if (node->prev_sibling_clone)
270 		    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
271 		  else if (node->clone_of)
272 		    node->clone_of->clones = node->next_sibling_clone;
273 		  if (node->next_sibling_clone)
274 		    node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
275 		  node->clone_of = NULL;
276 		  node->next_sibling_clone = NULL;
277 		  node->prev_sibling_clone = NULL;
278 		}
279 	      else
280 		cgraph_remove_node (node);
281 	    }
282 	  changed = true;
283 	}
284     }
285   for (node = cgraph_nodes; node; node = node->next)
286     {
287       /* Inline clones might be kept around so their materializing allows further
288          cloning.  If the function the clone is inlined into is removed, we need
289          to turn it into normal cone.  */
290       if (node->global.inlined_to
291 	  && !node->callers)
292 	{
293 	  gcc_assert (node->clones);
294 	  node->global.inlined_to = NULL;
295 	  update_inlined_to_pointer (node, node);
296 	}
297       node->aux = NULL;
298     }
299 #ifdef ENABLE_CHECKING
300   verify_cgraph ();
301 #endif
302 
303   /* Reclaim alias pairs for functions that have disappeared from the
304      call graph.  */
305   remove_unreachable_alias_pairs ();
306 
307   return changed;
308 }
309 
310 static bool
311 cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
312 {
313   if (!node->local.finalized)
314     return false;
315   if (!DECL_COMDAT (node->decl)
316       && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
317     return false;
318   if (!whole_program)
319     return true;
320   if (DECL_PRESERVE_P (node->decl))
321     return true;
322   /* COMDAT functions must be shared only if they have address taken,
323      otherwise we can produce our own private implementation with
324      -fwhole-program.  */
325   if (DECL_COMDAT (node->decl))
326     {
327       if (node->address_taken || !node->analyzed)
328 	return true;
329       if (node->same_comdat_group)
330 	{
331 	  struct cgraph_node *next;
332 
333 	  /* If more than one function is in the same COMDAT group, it must
334 	     be shared even if just one function in the comdat group has
335 	     address taken.  */
336 	  for (next = node->same_comdat_group;
337 	       next != node;
338 	       next = next->same_comdat_group)
339 	    if (next->address_taken || !next->analyzed)
340 	      return true;
341 	}
342     }
343   if (MAIN_NAME_P (DECL_NAME (node->decl)))
344     return true;
345   if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
346     return true;
347   return false;
348 }
349 
350 /* Dissolve the same_comdat_group list in which NODE resides.  */
351 
352 static void
353 dissolve_same_comdat_group_list (struct cgraph_node *node)
354 {
355   struct cgraph_node *n = node, *next;
356   do
357     {
358       next = n->same_comdat_group;
359       n->same_comdat_group = NULL;
360       n = next;
361     }
362   while (n != node);
363 }
364 
365 /* Mark visibility of all functions.
366 
367    A local function is one whose calls can occur only in the current
368    compilation unit and all its calls are explicit, so we can change
369    its calling convention.  We simply mark all static functions whose
370    address is not taken as local.
371 
372    We also change the TREE_PUBLIC flag of all declarations that are public
373    in language point of view but we want to overwrite this default
374    via visibilities for the backend point of view.  */
375 
376 static unsigned int
377 function_and_variable_visibility (bool whole_program)
378 {
379   struct cgraph_node *node;
380   struct varpool_node *vnode;
381 
382   for (node = cgraph_nodes; node; node = node->next)
383     {
384       /* C++ FE on lack of COMDAT support create local COMDAT functions
385 	 (that ought to be shared but can not due to object format
386 	 limitations).  It is neccesary to keep the flag to make rest of C++ FE
387 	 happy.  Clear the flag here to avoid confusion in middle-end.  */
388       if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
389         DECL_COMDAT (node->decl) = 0;
390       /* For external decls stop tracking same_comdat_group, it doesn't matter
391 	 what comdat group they are in when they won't be emitted in this TU,
392 	 and simplifies later passes.  */
393       if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
394 	{
395 #ifdef ENABLE_CHECKING
396 	  struct cgraph_node *n;
397 
398 	  for (n = node->same_comdat_group;
399 	       n != node;
400 	       n = n->same_comdat_group)
401 	      /* If at least one of same comdat group functions is external,
402 		 all of them have to be, otherwise it is a front-end bug.  */
403 	      gcc_assert (DECL_EXTERNAL (n->decl));
404 #endif
405 	  dissolve_same_comdat_group_list (node);
406 	}
407       gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
408       	          || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
409       if (cgraph_externally_visible_p (node, whole_program))
410         {
411 	  gcc_assert (!node->global.inlined_to);
412 	  node->local.externally_visible = true;
413 	}
414       else
415 	node->local.externally_visible = false;
416       if (!node->local.externally_visible && node->analyzed
417 	  && !DECL_EXTERNAL (node->decl))
418 	{
419 	  gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
420 	  cgraph_make_decl_local (node->decl);
421 	  if (node->same_comdat_group)
422 	    /* cgraph_externally_visible_p has already checked all other nodes
423 	       in the group and they will all be made local.  We need to
424 	       dissolve the group at once so that the predicate does not
425 	       segfault though. */
426 	    dissolve_same_comdat_group_list (node);
427 	}
428       node->local.local = (cgraph_only_called_directly_p (node)
429 			   && node->analyzed
430 			   && !DECL_EXTERNAL (node->decl)
431 			   && !node->local.externally_visible);
432     }
433   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
434     {
435       /* weak flag makes no sense on local variables.  */
436       gcc_assert (!DECL_WEAK (vnode->decl)
437       		  || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
438       /* In several cases declarations can not be common:
439 
440 	 - when declaration has initializer
441 	 - when it is in weak
442 	 - when it has specific section
443 	 - when it resides in non-generic address space.
444 	 - if declaration is local, it will get into .local common section
445 	   so common flag is not needed.  Frontends still produce these in
446 	   certain cases, such as for:
447 
448 	     static int a __attribute__ ((common))
449 
450 	 Canonicalize things here and clear the redundant flag.  */
451       if (DECL_COMMON (vnode->decl)
452 	  && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
453 	      || (DECL_INITIAL (vnode->decl)
454 		  && DECL_INITIAL (vnode->decl) != error_mark_node)
455 	      || DECL_WEAK (vnode->decl)
456 	      || DECL_SECTION_NAME (vnode->decl) != NULL
457 	      || ! (ADDR_SPACE_GENERIC_P
458 		    (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
459 	DECL_COMMON (vnode->decl) = 0;
460     }
461   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
462     {
463       if (!vnode->finalized)
464         continue;
465       if (vnode->needed
466 	  && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
467 	  && (!whole_program
468 	      /* We can privatize comdat readonly variables whose address is not taken,
469 	         but doing so is not going to bring us optimization oppurtunities until
470 	         we start reordering datastructures.  */
471 	      || DECL_COMDAT (vnode->decl)
472 	      || DECL_WEAK (vnode->decl)
473 	      || lookup_attribute ("externally_visible",
474 				   DECL_ATTRIBUTES (vnode->decl))))
475 	vnode->externally_visible = true;
476       else
477         vnode->externally_visible = false;
478       if (!vnode->externally_visible)
479 	{
480 	  gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
481 	  cgraph_make_decl_local (vnode->decl);
482 	}
483      gcc_assert (TREE_STATIC (vnode->decl));
484     }
485 
486   if (dump_file)
487     {
488       fprintf (dump_file, "\nMarking local functions:");
489       for (node = cgraph_nodes; node; node = node->next)
490 	if (node->local.local)
491 	  fprintf (dump_file, " %s", cgraph_node_name (node));
492       fprintf (dump_file, "\n\n");
493       fprintf (dump_file, "\nMarking externally visible functions:");
494       for (node = cgraph_nodes; node; node = node->next)
495 	if (node->local.externally_visible)
496 	  fprintf (dump_file, " %s", cgraph_node_name (node));
497       fprintf (dump_file, "\n\n");
498       fprintf (dump_file, "\nMarking externally visible variables:");
499       for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
500 	if (vnode->externally_visible)
501 	  fprintf (dump_file, " %s", varpool_node_name (vnode));
502       fprintf (dump_file, "\n\n");
503     }
504   cgraph_function_flags_ready = true;
505   return 0;
506 }
507 
508 /* Local function pass handling visibilities.  This happens before LTO streaming
509    so in particular -fwhole-program should be ignored at this level.  */
510 
511 static unsigned int
512 local_function_and_variable_visibility (void)
513 {
514   return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
515 }
516 
517 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
518 {
519  {
520   SIMPLE_IPA_PASS,
521   "visibility",				/* name */
522   NULL,					/* gate */
523   local_function_and_variable_visibility,/* execute */
524   NULL,					/* sub */
525   NULL,					/* next */
526   0,					/* static_pass_number */
527   TV_CGRAPHOPT,				/* tv_id */
528   0,	                                /* properties_required */
529   0,					/* properties_provided */
530   0,					/* properties_destroyed */
531   0,					/* todo_flags_start */
532   TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
533  }
534 };
535 
536 /* Do not re-run on ltrans stage.  */
537 
538 static bool
539 gate_whole_program_function_and_variable_visibility (void)
540 {
541   return !flag_ltrans;
542 }
543 
544 /* Bring functionss local at LTO time whith -fwhole-program.  */
545 
546 static unsigned int
547 whole_program_function_and_variable_visibility (void)
548 {
549   struct cgraph_node *node;
550   struct varpool_node *vnode;
551 
552   function_and_variable_visibility (flag_whole_program);
553 
554   for (node = cgraph_nodes; node; node = node->next)
555     if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
556         && node->local.finalized)
557       cgraph_mark_needed_node (node);
558   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
559     if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
560       varpool_mark_needed_node (vnode);
561   if (dump_file)
562     {
563       fprintf (dump_file, "\nNeeded variables:");
564       for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
565 	if (vnode->needed)
566 	  fprintf (dump_file, " %s", varpool_node_name (vnode));
567       fprintf (dump_file, "\n\n");
568     }
569   return 0;
570 }
571 
572 struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
573 {
574  {
575   IPA_PASS,
576   "whole-program",			/* name */
577   gate_whole_program_function_and_variable_visibility,/* gate */
578   whole_program_function_and_variable_visibility,/* execute */
579   NULL,					/* sub */
580   NULL,					/* next */
581   0,					/* static_pass_number */
582   TV_CGRAPHOPT,				/* tv_id */
583   0,	                                /* properties_required */
584   0,					/* properties_provided */
585   0,					/* properties_destroyed */
586   0,					/* todo_flags_start */
587   TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
588  },
589  NULL,					/* generate_summary */
590  NULL,					/* write_summary */
591  NULL,					/* read_summary */
592  NULL,					/* function_read_summary */
593  NULL,					/* stmt_fixup */
594  0,					/* TODOs */
595  NULL,					/* function_transform */
596  NULL,					/* variable_transform */
597 };
598 
599 /* Hash a cgraph node set element.  */
600 
601 static hashval_t
602 hash_cgraph_node_set_element (const void *p)
603 {
604   const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
605   return htab_hash_pointer (element->node);
606 }
607 
608 /* Compare two cgraph node set elements.  */
609 
610 static int
611 eq_cgraph_node_set_element (const void *p1, const void *p2)
612 {
613   const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
614   const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
615 
616   return e1->node == e2->node;
617 }
618 
619 /* Create a new cgraph node set.  */
620 
621 cgraph_node_set
622 cgraph_node_set_new (void)
623 {
624   cgraph_node_set new_node_set;
625 
626   new_node_set = GGC_NEW (struct cgraph_node_set_def);
627   new_node_set->hashtab = htab_create_ggc (10,
628 					   hash_cgraph_node_set_element,
629 					   eq_cgraph_node_set_element,
630 					   NULL);
631   new_node_set->nodes = NULL;
632   return new_node_set;
633 }
634 
635 /* Add cgraph_node NODE to cgraph_node_set SET.  */
636 
637 void
638 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
639 {
640   void **slot;
641   cgraph_node_set_element element;
642   struct cgraph_node_set_element_def dummy;
643 
644   dummy.node = node;
645   slot = htab_find_slot (set->hashtab, &dummy, INSERT);
646 
647   if (*slot != HTAB_EMPTY_ENTRY)
648     {
649       element = (cgraph_node_set_element) *slot;
650       gcc_assert (node == element->node
651 		  && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
652 		      == node));
653       return;
654     }
655 
656   /* Insert node into hash table.  */
657   element =
658     (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
659   element->node = node;
660   element->index = VEC_length (cgraph_node_ptr, set->nodes);
661   *slot = element;
662 
663   /* Insert into node vector.  */
664   VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
665 }
666 
667 /* Remove cgraph_node NODE from cgraph_node_set SET.  */
668 
669 void
670 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
671 {
672   void **slot, **last_slot;
673   cgraph_node_set_element element, last_element;
674   struct cgraph_node *last_node;
675   struct cgraph_node_set_element_def dummy;
676 
677   dummy.node = node;
678   slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
679   if (slot == NULL)
680     return;
681 
682   element = (cgraph_node_set_element) *slot;
683   gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
684 	      == node);
685 
686   /* Remove from vector. We do this by swapping node with the last element
687      of the vector.  */
688   last_node = VEC_pop (cgraph_node_ptr, set->nodes);
689   if (last_node != node)
690     {
691       dummy.node = last_node;
692       last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
693       last_element = (cgraph_node_set_element) *last_slot;
694       gcc_assert (last_element);
695 
696       /* Move the last element to the original spot of NODE.  */
697       last_element->index = element->index;
698       VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
699 		   last_node);
700     }
701 
702   /* Remove element from hash table.  */
703   htab_clear_slot (set->hashtab, slot);
704   ggc_free (element);
705 }
706 
707 /* Find NODE in SET and return an iterator to it if found.  A null iterator
708    is returned if NODE is not in SET.  */
709 
710 cgraph_node_set_iterator
711 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
712 {
713   void **slot;
714   struct cgraph_node_set_element_def dummy;
715   cgraph_node_set_element element;
716   cgraph_node_set_iterator csi;
717 
718   dummy.node = node;
719   slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
720   if (slot == NULL)
721     csi.index = (unsigned) ~0;
722   else
723     {
724       element = (cgraph_node_set_element) *slot;
725       gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
726 		  == node);
727       csi.index = element->index;
728     }
729   csi.set = set;
730 
731   return csi;
732 }
733 
734 /* Dump content of SET to file F.  */
735 
736 void
737 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
738 {
739   cgraph_node_set_iterator iter;
740 
741   for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
742     {
743       struct cgraph_node *node = csi_node (iter);
744       dump_cgraph_node (f, node);
745     }
746 }
747 
748 /* Dump content of SET to stderr.  */
749 
750 void
751 debug_cgraph_node_set (cgraph_node_set set)
752 {
753   dump_cgraph_node_set (stderr, set);
754 }
755 
756