OSDN Git Service

* doc/configfiles.texi (Configuration Files): Removed
[pf3gnuchains/gcc-fork.git] / gcc / ipa.c
1 /* Basic IPA optimizations and utilities.
2    Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
3    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   /* COMDAT functions must be shared only if they have address taken,
321      otherwise we can produce our own private implementation with
322      -fwhole-program.  */
323   if (DECL_COMDAT (node->decl))
324     {
325       if (node->address_taken || !node->analyzed)
326         return true;
327       if (node->same_comdat_group)
328         {
329           struct cgraph_node *next;
330
331           /* If more than one function is in the same COMDAT group, it must
332              be shared even if just one function in the comdat group has
333              address taken.  */
334           for (next = node->same_comdat_group;
335                next != node;
336                next = next->same_comdat_group)
337             if (next->address_taken || !next->analyzed)
338               return true;
339         }
340     }
341   if (MAIN_NAME_P (DECL_NAME (node->decl)))
342     return true;
343   if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
344     return true;
345   return false;
346 }
347
348 /* Mark visibility of all functions.
349
350    A local function is one whose calls can occur only in the current
351    compilation unit and all its calls are explicit, so we can change
352    its calling convention.  We simply mark all static functions whose
353    address is not taken as local.
354
355    We also change the TREE_PUBLIC flag of all declarations that are public
356    in language point of view but we want to overwrite this default
357    via visibilities for the backend point of view.  */
358
359 static unsigned int
360 function_and_variable_visibility (bool whole_program)
361 {
362   struct cgraph_node *node;
363   struct varpool_node *vnode;
364
365   for (node = cgraph_nodes; node; node = node->next)
366     {
367       /* C++ FE on lack of COMDAT support create local COMDAT functions
368          (that ought to be shared but can not due to object format
369          limitations).  It is neccesary to keep the flag to make rest of C++ FE
370          happy.  Clear the flag here to avoid confusion in middle-end.  */
371       if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
372         DECL_COMDAT (node->decl) = 0;
373       /* For external decls stop tracking same_comdat_group, it doesn't matter
374          what comdat group they are in when they won't be emitted in this TU,
375          and simplifies later passes.  */
376       if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
377         {
378           struct cgraph_node *n = node, *next;
379           do
380             {
381               /* If at least one of same comdat group functions is external,
382                  all of them have to be, otherwise it is a front-end bug.  */
383               gcc_assert (DECL_EXTERNAL (n->decl));
384               next = n->same_comdat_group;
385               n->same_comdat_group = NULL;
386               n = next;
387             }
388           while (n != node);
389         }
390       gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
391                   || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
392       if (cgraph_externally_visible_p (node, whole_program))
393         {
394           gcc_assert (!node->global.inlined_to);
395           node->local.externally_visible = true;
396         }
397       else
398         node->local.externally_visible = false;
399       if (!node->local.externally_visible && node->analyzed
400           && !DECL_EXTERNAL (node->decl))
401         {
402           gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
403           cgraph_make_decl_local (node->decl);
404         }
405       node->local.local = (cgraph_only_called_directly_p (node)
406                            && node->analyzed
407                            && !DECL_EXTERNAL (node->decl)
408                            && !node->local.externally_visible);
409     }
410   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
411     {
412       /* weak flag makes no sense on local variables.  */
413       gcc_assert (!DECL_WEAK (vnode->decl)
414                   || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
415       /* In several cases declarations can not be common:
416
417          - when declaration has initializer
418          - when it is in weak
419          - when it has specific section
420          - when it resides in non-generic address space.
421          - if declaration is local, it will get into .local common section
422            so common flag is not needed.  Frontends still produce these in
423            certain cases, such as for:
424
425              static int a __attribute__ ((common))
426
427          Canonicalize things here and clear the redundant flag.  */
428       if (DECL_COMMON (vnode->decl)
429           && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
430               || (DECL_INITIAL (vnode->decl)
431                   && DECL_INITIAL (vnode->decl) != error_mark_node)
432               || DECL_WEAK (vnode->decl)
433               || DECL_SECTION_NAME (vnode->decl) != NULL
434               || ! (ADDR_SPACE_GENERIC_P
435                     (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
436         DECL_COMMON (vnode->decl) = 0;
437     }
438   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
439     {
440       if (!vnode->finalized)
441         continue;
442       if (vnode->needed
443           && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
444           && (!whole_program
445               /* We can privatize comdat readonly variables whose address is not taken,
446                  but doing so is not going to bring us optimization oppurtunities until
447                  we start reordering datastructures.  */
448               || DECL_COMDAT (vnode->decl)
449               || DECL_WEAK (vnode->decl)
450               || lookup_attribute ("externally_visible",
451                                    DECL_ATTRIBUTES (vnode->decl))))
452         vnode->externally_visible = true;
453       else
454         vnode->externally_visible = false;
455       if (!vnode->externally_visible)
456         {
457           gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
458           cgraph_make_decl_local (vnode->decl);
459         }
460      gcc_assert (TREE_STATIC (vnode->decl));
461     }
462
463   if (dump_file)
464     {
465       fprintf (dump_file, "\nMarking local functions:");
466       for (node = cgraph_nodes; node; node = node->next)
467         if (node->local.local)
468           fprintf (dump_file, " %s", cgraph_node_name (node));
469       fprintf (dump_file, "\n\n");
470       fprintf (dump_file, "\nMarking externally visible functions:");
471       for (node = cgraph_nodes; node; node = node->next)
472         if (node->local.externally_visible)
473           fprintf (dump_file, " %s", cgraph_node_name (node));
474       fprintf (dump_file, "\n\n");
475       fprintf (dump_file, "\nMarking externally visible variables:");
476       for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
477         if (vnode->externally_visible)
478           fprintf (dump_file, " %s", varpool_node_name (vnode));
479       fprintf (dump_file, "\n\n");
480     }
481   cgraph_function_flags_ready = true;
482   return 0;
483 }
484
485 /* Local function pass handling visibilities.  This happens before LTO streaming
486    so in particular -fwhole-program should be ignored at this level.  */
487
488 static unsigned int
489 local_function_and_variable_visibility (void)
490 {
491   return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
492 }
493
494 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
495 {
496  {
497   SIMPLE_IPA_PASS,
498   "visibility",                         /* name */
499   NULL,                                 /* gate */
500   local_function_and_variable_visibility,/* execute */
501   NULL,                                 /* sub */
502   NULL,                                 /* next */
503   0,                                    /* static_pass_number */
504   TV_CGRAPHOPT,                         /* tv_id */
505   0,                                    /* properties_required */
506   0,                                    /* properties_provided */
507   0,                                    /* properties_destroyed */
508   0,                                    /* todo_flags_start */
509   TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
510  }
511 };
512
513 /* Do not re-run on ltrans stage.  */
514
515 static bool
516 gate_whole_program_function_and_variable_visibility (void)
517 {
518   return !flag_ltrans;
519 }
520
521 /* Bring functionss local at LTO time whith -fwhole-program.  */
522
523 static unsigned int
524 whole_program_function_and_variable_visibility (void)
525 {
526   struct cgraph_node *node;
527   struct varpool_node *vnode;
528
529   function_and_variable_visibility (flag_whole_program);
530
531   for (node = cgraph_nodes; node; node = node->next)
532     if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
533         && node->local.finalized)
534       cgraph_mark_needed_node (node);
535   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
536     if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
537       varpool_mark_needed_node (vnode);
538   if (dump_file)
539     {
540       fprintf (dump_file, "\nNeeded variables:");
541       for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
542         if (vnode->needed)
543           fprintf (dump_file, " %s", varpool_node_name (vnode));
544       fprintf (dump_file, "\n\n");
545     }
546   return 0;
547 }
548
549 struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
550 {
551  {
552   IPA_PASS,
553   "whole-program",                      /* name */
554   gate_whole_program_function_and_variable_visibility,/* gate */
555   whole_program_function_and_variable_visibility,/* execute */
556   NULL,                                 /* sub */
557   NULL,                                 /* next */
558   0,                                    /* static_pass_number */
559   TV_CGRAPHOPT,                         /* tv_id */
560   0,                                    /* properties_required */
561   0,                                    /* properties_provided */
562   0,                                    /* properties_destroyed */
563   0,                                    /* todo_flags_start */
564   TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
565  },
566  NULL,                                  /* generate_summary */
567  NULL,                                  /* write_summary */
568  NULL,                                  /* read_summary */
569  NULL,                                  /* function_read_summary */
570  NULL,                                  /* stmt_fixup */
571  0,                                     /* TODOs */
572  NULL,                                  /* function_transform */
573  NULL,                                  /* variable_transform */
574 };
575
576 /* Hash a cgraph node set element.  */
577
578 static hashval_t
579 hash_cgraph_node_set_element (const void *p)
580 {
581   const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
582   return htab_hash_pointer (element->node);
583 }
584
585 /* Compare two cgraph node set elements.  */
586
587 static int
588 eq_cgraph_node_set_element (const void *p1, const void *p2)
589 {
590   const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
591   const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
592
593   return e1->node == e2->node;
594 }
595
596 /* Create a new cgraph node set.  */
597
598 cgraph_node_set
599 cgraph_node_set_new (void)
600 {
601   cgraph_node_set new_node_set;
602
603   new_node_set = GGC_NEW (struct cgraph_node_set_def);
604   new_node_set->hashtab = htab_create_ggc (10,
605                                            hash_cgraph_node_set_element,
606                                            eq_cgraph_node_set_element,
607                                            NULL);
608   new_node_set->nodes = NULL;
609   return new_node_set;
610 }
611
612 /* Add cgraph_node NODE to cgraph_node_set SET.  */
613
614 void
615 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
616 {
617   void **slot;
618   cgraph_node_set_element element;
619   struct cgraph_node_set_element_def dummy;
620
621   dummy.node = node;
622   slot = htab_find_slot (set->hashtab, &dummy, INSERT);
623
624   if (*slot != HTAB_EMPTY_ENTRY)
625     {
626       element = (cgraph_node_set_element) *slot;
627       gcc_assert (node == element->node
628                   && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
629                       == node));
630       return;
631     }
632
633   /* Insert node into hash table.  */
634   element =
635     (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
636   element->node = node;
637   element->index = VEC_length (cgraph_node_ptr, set->nodes);
638   *slot = element;
639
640   /* Insert into node vector.  */
641   VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
642 }
643
644 /* Remove cgraph_node NODE from cgraph_node_set SET.  */
645
646 void
647 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
648 {
649   void **slot, **last_slot;
650   cgraph_node_set_element element, last_element;
651   struct cgraph_node *last_node;
652   struct cgraph_node_set_element_def dummy;
653
654   dummy.node = node;
655   slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
656   if (slot == NULL)
657     return;
658
659   element = (cgraph_node_set_element) *slot;
660   gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
661               == node);
662
663   /* Remove from vector. We do this by swapping node with the last element
664      of the vector.  */
665   last_node = VEC_pop (cgraph_node_ptr, set->nodes);
666   if (last_node != node)
667     {
668       dummy.node = last_node;
669       last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
670       last_element = (cgraph_node_set_element) *last_slot;
671       gcc_assert (last_element);
672
673       /* Move the last element to the original spot of NODE.  */
674       last_element->index = element->index;
675       VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
676                    last_node);
677     }
678
679   /* Remove element from hash table.  */
680   htab_clear_slot (set->hashtab, slot);
681   ggc_free (element);
682 }
683
684 /* Find NODE in SET and return an iterator to it if found.  A null iterator
685    is returned if NODE is not in SET.  */
686
687 cgraph_node_set_iterator
688 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
689 {
690   void **slot;
691   struct cgraph_node_set_element_def dummy;
692   cgraph_node_set_element element;
693   cgraph_node_set_iterator csi;
694
695   dummy.node = node;
696   slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
697   if (slot == NULL)
698     csi.index = (unsigned) ~0;
699   else
700     {
701       element = (cgraph_node_set_element) *slot;
702       gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
703                   == node);
704       csi.index = element->index;
705     }
706   csi.set = set;
707
708   return csi;
709 }
710
711 /* Dump content of SET to file F.  */
712
713 void
714 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
715 {
716   cgraph_node_set_iterator iter;
717
718   for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
719     {
720       struct cgraph_node *node = csi_node (iter);
721       dump_cgraph_node (f, node);
722     }
723 }
724
725 /* Dump content of SET to stderr.  */
726
727 void
728 debug_cgraph_node_set (cgraph_node_set set)
729 {
730   dump_cgraph_node_set (stderr, set);
731 }
732