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