1/* Basic IPA optimizations and utilities.
2   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
3   Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
34int
35cgraph_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
103static void
104update_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
120bool
121cgraph_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
310static bool
311cgraph_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
352static void
353dissolve_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
376static unsigned int
377function_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
511static unsigned int
512local_function_and_variable_visibility (void)
513{
514  return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
515}
516
517struct 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
538static bool
539gate_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
546static unsigned int
547whole_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
572struct 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
601static hashval_t
602hash_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
610static int
611eq_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
621cgraph_node_set
622cgraph_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
637void
638cgraph_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
669void
670cgraph_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
710cgraph_node_set_iterator
711cgraph_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
736void
737dump_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
750void
751debug_cgraph_node_set (cgraph_node_set set)
752{
753  dump_cgraph_node_set (stderr, set);
754}
755
756