1 /* Basic IPA optimizations and utilities. 2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 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 #include "flags.h" 31 #include "pointer-set.h" 32 #include "target.h" 33 #include "tree-iterator.h" 34 #include "ipa-utils.h" 35 36 /* Look for all functions inlined to NODE and update their inlined_to pointers 37 to INLINED_TO. */ 38 39 static void 40 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to) 41 { 42 struct cgraph_edge *e; 43 for (e = node->callees; e; e = e->next_callee) 44 if (e->callee->global.inlined_to) 45 { 46 e->callee->global.inlined_to = inlined_to; 47 update_inlined_to_pointer (e->callee, inlined_to); 48 } 49 } 50 51 /* Add cgraph NODE to queue starting at FIRST. 52 53 The queue is linked via AUX pointers and terminated by pointer to 1. 54 We enqueue nodes at two occasions: when we find them reachable or when we find 55 their bodies needed for further clonning. In the second case we mark them 56 by pointer to 2 after processing so they are re-queue when they become 57 reachable. */ 58 59 static void 60 enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first) 61 { 62 /* Node is still in queue; do nothing. */ 63 if (node->aux && node->aux != (void *) 2) 64 return; 65 /* Node was already processed as unreachable, re-enqueue 66 only if it became reachable now. */ 67 if (node->aux == (void *)2 && !node->reachable) 68 return; 69 node->aux = *first; 70 *first = node; 71 } 72 73 /* Add varpool NODE to queue starting at FIRST. */ 74 75 static void 76 enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first) 77 { 78 node->aux = *first; 79 *first = node; 80 } 81 82 /* Process references. */ 83 84 static void 85 process_references (struct ipa_ref_list *list, 86 struct cgraph_node **first, 87 struct varpool_node **first_varpool, 88 bool before_inlining_p) 89 { 90 int i; 91 struct ipa_ref *ref; 92 for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) 93 { 94 if (ref->refered_type == IPA_REF_CGRAPH) 95 { 96 struct cgraph_node *node = ipa_ref_node (ref); 97 if (!node->reachable 98 && node->analyzed 99 && (!DECL_EXTERNAL (node->decl) 100 || before_inlining_p)) 101 node->reachable = true; 102 enqueue_cgraph_node (node, first); 103 } 104 else 105 { 106 struct varpool_node *node = ipa_ref_varpool_node (ref); 107 if (!node->needed) 108 { 109 varpool_mark_needed_node (node); 110 enqueue_varpool_node (node, first_varpool); 111 } 112 } 113 } 114 } 115 116 117 /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ 118 119 static bool 120 cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) 121 { 122 /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ 123 return !(cgraph_only_called_directly_or_aliased_p (node) 124 && !ipa_ref_has_aliases_p (&node->ref_list) 125 && node->analyzed 126 && !DECL_EXTERNAL (node->decl) 127 && !node->local.externally_visible 128 && !node->reachable_from_other_partition 129 && !node->in_other_partition); 130 } 131 132 /* Return true when function can be marked local. */ 133 134 static bool 135 cgraph_local_node_p (struct cgraph_node *node) 136 { 137 struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL); 138 139 /* FIXME: thunks can be considered local, but we need prevent i386 140 from attempting to change calling convention of them. */ 141 if (n->thunk.thunk_p) 142 return false; 143 return !cgraph_for_node_and_aliases (n, 144 cgraph_non_local_node_p_1, NULL, true); 145 146 } 147 148 /* Return true when NODE has ADDR reference. */ 149 150 static bool 151 has_addr_references_p (struct cgraph_node *node, 152 void *data ATTRIBUTE_UNUSED) 153 { 154 int i; 155 struct ipa_ref *ref; 156 157 for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) 158 if (ref->use == IPA_REF_ADDR) 159 return true; 160 return false; 161 } 162 163 /* Perform reachability analysis and reclaim all unreachable nodes. 164 If BEFORE_INLINING_P is true this function is called before inlining 165 decisions has been made. If BEFORE_INLINING_P is false this function also 166 removes unneeded bodies of extern inline functions. */ 167 168 bool 169 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) 170 { 171 struct cgraph_node *first = (struct cgraph_node *) (void *) 1; 172 struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1; 173 struct cgraph_node *node, *next; 174 struct varpool_node *vnode, *vnext; 175 bool changed = false; 176 177 #ifdef ENABLE_CHECKING 178 verify_cgraph (); 179 #endif 180 if (file) 181 fprintf (file, "\nReclaiming functions:"); 182 #ifdef ENABLE_CHECKING 183 for (node = cgraph_nodes; node; node = node->next) 184 gcc_assert (!node->aux); 185 for (vnode = varpool_nodes; vnode; vnode = vnode->next) 186 gcc_assert (!vnode->aux); 187 #endif 188 varpool_reset_queue (); 189 /* Mark functions whose bodies are obviously needed. 190 This is mostly when they can be referenced externally. Inline clones 191 are special since their declarations are shared with master clone and thus 192 cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ 193 for (node = cgraph_nodes; node; node = node->next) 194 if (node->analyzed && !node->global.inlined_to 195 && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) 196 /* Keep around virtual functions for possible devirtualization. */ 197 || (before_inlining_p 198 && DECL_VIRTUAL_P (node->decl) 199 && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))))) 200 { 201 gcc_assert (!node->global.inlined_to); 202 enqueue_cgraph_node (node, &first); 203 node->reachable = true; 204 } 205 else 206 { 207 gcc_assert (!node->aux); 208 node->reachable = false; 209 } 210 211 /* Mark variables that are obviously needed. */ 212 for (vnode = varpool_nodes; vnode; vnode = vnode->next) 213 { 214 vnode->next_needed = NULL; 215 vnode->prev_needed = NULL; 216 if ((vnode->analyzed || vnode->force_output) 217 && !varpool_can_remove_if_no_refs (vnode)) 218 { 219 vnode->needed = false; 220 varpool_mark_needed_node (vnode); 221 enqueue_varpool_node (vnode, &first_varpool); 222 } 223 else 224 vnode->needed = false; 225 } 226 227 /* Perform reachability analysis. As a special case do not consider 228 extern inline functions not inlined as live because we won't output 229 them at all. 230 231 We maintain two worklist, one for cgraph nodes other for varpools and 232 are finished once both are empty. */ 233 234 while (first != (struct cgraph_node *) (void *) 1 235 || first_varpool != (struct varpool_node *) (void *) 1) 236 { 237 if (first != (struct cgraph_node *) (void *) 1) 238 { 239 struct cgraph_edge *e; 240 node = first; 241 first = (struct cgraph_node *) first->aux; 242 if (!node->reachable) 243 node->aux = (void *)2; 244 245 /* If we found this node reachable, first mark on the callees 246 reachable too, unless they are direct calls to extern inline functions 247 we decided to not inline. */ 248 if (node->reachable) 249 { 250 for (e = node->callees; e; e = e->next_callee) 251 { 252 if (!e->callee->reachable 253 && node->analyzed 254 && (!e->inline_failed 255 || !DECL_EXTERNAL (e->callee->decl) 256 || before_inlining_p)) 257 e->callee->reachable = true; 258 enqueue_cgraph_node (e->callee, &first); 259 } 260 process_references (&node->ref_list, &first, &first_varpool, before_inlining_p); 261 } 262 263 /* If any function in a comdat group is reachable, force 264 all other functions in the same comdat group to be 265 also reachable. */ 266 if (node->same_comdat_group 267 && node->reachable 268 && !node->global.inlined_to) 269 { 270 for (next = node->same_comdat_group; 271 next != node; 272 next = next->same_comdat_group) 273 if (!next->reachable) 274 { 275 next->reachable = true; 276 enqueue_cgraph_node (next, &first); 277 } 278 } 279 280 /* We can freely remove inline clones even if they are cloned, however if 281 function is clone of real clone, we must keep it around in order to 282 make materialize_clones produce function body with the changes 283 applied. */ 284 while (node->clone_of && !node->clone_of->aux 285 && !gimple_has_body_p (node->decl)) 286 { 287 bool noninline = node->clone_of->decl != node->decl; 288 node = node->clone_of; 289 if (noninline && !node->reachable && !node->aux) 290 { 291 enqueue_cgraph_node (node, &first); 292 break; 293 } 294 } 295 } 296 if (first_varpool != (struct varpool_node *) (void *) 1) 297 { 298 vnode = first_varpool; 299 first_varpool = (struct varpool_node *)first_varpool->aux; 300 vnode->aux = NULL; 301 process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p); 302 /* If any function in a comdat group is reachable, force 303 all other functions in the same comdat group to be 304 also reachable. */ 305 if (vnode->same_comdat_group) 306 { 307 struct varpool_node *next; 308 for (next = vnode->same_comdat_group; 309 next != vnode; 310 next = next->same_comdat_group) 311 if (!next->needed) 312 { 313 varpool_mark_needed_node (next); 314 enqueue_varpool_node (next, &first_varpool); 315 } 316 } 317 } 318 } 319 320 /* Remove unreachable nodes. 321 322 Completely unreachable functions can be fully removed from the callgraph. 323 Extern inline functions that we decided to not inline need to become unanalyzed nodes of 324 callgraph (so we still have edges to them). We remove function body then. 325 326 Also we need to care functions that are unreachable but we need to keep them around 327 for later clonning. In this case we also turn them to unanalyzed nodes, but 328 keep the body around. */ 329 for (node = cgraph_nodes; node; node = next) 330 { 331 next = node->next; 332 if (node->aux && !node->reachable) 333 { 334 cgraph_node_remove_callees (node); 335 ipa_remove_all_references (&node->ref_list); 336 node->analyzed = false; 337 } 338 if (!node->aux) 339 { 340 struct cgraph_edge *e; 341 bool found = false; 342 int i; 343 struct ipa_ref *ref; 344 345 node->global.inlined_to = NULL; 346 if (file) 347 fprintf (file, " %s", cgraph_node_name (node)); 348 /* See if there is reachable caller. */ 349 for (e = node->callers; e && !found; e = e->next_caller) 350 if (e->caller->reachable) 351 found = true; 352 for (i = 0; (ipa_ref_list_refering_iterate (&node->ref_list, i, ref) 353 && !found); i++) 354 if (ref->refering_type == IPA_REF_CGRAPH 355 && ipa_ref_refering_node (ref)->reachable) 356 found = true; 357 else if (ref->refering_type == IPA_REF_VARPOOL 358 && ipa_ref_refering_varpool_node (ref)->needed) 359 found = true; 360 361 /* If so, we need to keep node in the callgraph. */ 362 if (found) 363 { 364 if (node->analyzed) 365 { 366 struct cgraph_node *clone; 367 368 /* If there are still clones, we must keep body around. 369 Otherwise we can just remove the body but keep the clone. */ 370 for (clone = node->clones; clone; 371 clone = clone->next_sibling_clone) 372 if (clone->aux) 373 break; 374 if (!clone) 375 { 376 cgraph_release_function_body (node); 377 if (node->prev_sibling_clone) 378 node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; 379 else if (node->clone_of) 380 node->clone_of->clones = node->next_sibling_clone; 381 if (node->next_sibling_clone) 382 node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; 383 if (node->clone_of) 384 node->former_clone_of = node->clone_of->decl; 385 node->clone_of = NULL; 386 node->next_sibling_clone = NULL; 387 node->prev_sibling_clone = NULL; 388 } 389 else 390 gcc_assert (!clone->in_other_partition); 391 node->analyzed = false; 392 changed = true; 393 cgraph_node_remove_callees (node); 394 ipa_remove_all_references (&node->ref_list); 395 } 396 } 397 else 398 { 399 cgraph_remove_node (node); 400 changed = true; 401 } 402 } 403 } 404 for (node = cgraph_nodes; node; node = node->next) 405 { 406 /* Inline clones might be kept around so their materializing allows further 407 cloning. If the function the clone is inlined into is removed, we need 408 to turn it into normal cone. */ 409 if (node->global.inlined_to 410 && !node->callers) 411 { 412 gcc_assert (node->clones); 413 node->global.inlined_to = NULL; 414 update_inlined_to_pointer (node, node); 415 } 416 node->aux = NULL; 417 } 418 419 if (file) 420 fprintf (file, "\n"); 421 422 /* We must release unused extern inlines or sanity checking will fail. Rest of transformations 423 are undesirable at -O0 since we do not want to remove anything. */ 424 if (!optimize) 425 return changed; 426 427 if (file) 428 fprintf (file, "Reclaiming variables:"); 429 for (vnode = varpool_nodes; vnode; vnode = vnext) 430 { 431 vnext = vnode->next; 432 if (!vnode->needed) 433 { 434 if (file) 435 fprintf (file, " %s", varpool_node_name (vnode)); 436 varpool_remove_node (vnode); 437 changed = true; 438 } 439 } 440 441 /* Now update address_taken flags and try to promote functions to be local. */ 442 443 if (file) 444 fprintf (file, "\nClearing address taken flags:"); 445 for (node = cgraph_nodes; node; node = node->next) 446 if (node->address_taken 447 && !node->reachable_from_other_partition) 448 { 449 if (!cgraph_for_node_and_aliases (node, has_addr_references_p, NULL, true)) 450 { 451 if (file) 452 fprintf (file, " %s", cgraph_node_name (node)); 453 node->address_taken = false; 454 changed = true; 455 if (cgraph_local_node_p (node)) 456 { 457 node->local.local = true; 458 if (file) 459 fprintf (file, " (local)"); 460 } 461 } 462 } 463 if (file) 464 fprintf (file, "\n"); 465 466 #ifdef ENABLE_CHECKING 467 verify_cgraph (); 468 #endif 469 470 /* Reclaim alias pairs for functions that have disappeared from the 471 call graph. */ 472 remove_unreachable_alias_pairs (); 473 474 return changed; 475 } 476 477 /* Discover variables that have no longer address taken or that are read only 478 and update their flags. 479 480 FIXME: This can not be done in between gimplify and omp_expand since 481 readonly flag plays role on what is shared and what is not. Currently we do 482 this transformation as part of whole program visibility and re-do at 483 ipa-reference pass (to take into account clonning), but it would 484 make sense to do it before early optimizations. */ 485 486 void 487 ipa_discover_readonly_nonaddressable_vars (void) 488 { 489 struct varpool_node *vnode; 490 if (dump_file) 491 fprintf (dump_file, "Clearing variable flags:"); 492 for (vnode = varpool_nodes; vnode; vnode = vnode->next) 493 if (vnode->finalized && varpool_all_refs_explicit_p (vnode) 494 && (TREE_ADDRESSABLE (vnode->decl) || !TREE_READONLY (vnode->decl))) 495 { 496 bool written = false; 497 bool address_taken = false; 498 int i; 499 struct ipa_ref *ref; 500 for (i = 0; ipa_ref_list_refering_iterate (&vnode->ref_list, i, ref) 501 && (!written || !address_taken); i++) 502 switch (ref->use) 503 { 504 case IPA_REF_ADDR: 505 address_taken = true; 506 break; 507 case IPA_REF_LOAD: 508 break; 509 case IPA_REF_STORE: 510 written = true; 511 break; 512 } 513 if (TREE_ADDRESSABLE (vnode->decl) && !address_taken) 514 { 515 if (dump_file) 516 fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode)); 517 TREE_ADDRESSABLE (vnode->decl) = 0; 518 } 519 if (!TREE_READONLY (vnode->decl) && !address_taken && !written 520 /* Making variable in explicit section readonly can cause section 521 type conflict. 522 See e.g. gcc.c-torture/compile/pr23237.c */ 523 && DECL_SECTION_NAME (vnode->decl) == NULL) 524 { 525 if (dump_file) 526 fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode)); 527 TREE_READONLY (vnode->decl) = 1; 528 } 529 } 530 if (dump_file) 531 fprintf (dump_file, "\n"); 532 } 533 534 /* Return true when there is a reference to node and it is not vtable. */ 535 static bool 536 cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node) 537 { 538 int i; 539 struct ipa_ref *ref; 540 for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) 541 if (ref->use == IPA_REF_ADDR) 542 { 543 struct varpool_node *node; 544 if (ref->refering_type == IPA_REF_CGRAPH) 545 return true; 546 node = ipa_ref_refering_varpool_node (ref); 547 if (!DECL_VIRTUAL_P (node->decl)) 548 return true; 549 } 550 return false; 551 } 552 553 /* COMDAT functions must be shared only if they have address taken, 554 otherwise we can produce our own private implementation with 555 -fwhole-program. 556 Return true when turning COMDAT functoin static can not lead to wrong 557 code when the resulting object links with a library defining same COMDAT. 558 559 Virtual functions do have their addresses taken from the vtables, 560 but in C++ there is no way to compare their addresses for equality. */ 561 562 bool 563 cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) 564 { 565 if ((cgraph_address_taken_from_non_vtable_p (node) 566 && !DECL_VIRTUAL_P (node->decl)) 567 || !node->analyzed) 568 return false; 569 if (node->same_comdat_group) 570 { 571 struct cgraph_node *next; 572 573 /* If more than one function is in the same COMDAT group, it must 574 be shared even if just one function in the comdat group has 575 address taken. */ 576 for (next = node->same_comdat_group; 577 next != node; next = next->same_comdat_group) 578 if (cgraph_address_taken_from_non_vtable_p (next) 579 && !DECL_VIRTUAL_P (next->decl)) 580 return false; 581 } 582 return true; 583 } 584 585 /* Return true when function NODE should be considered externally visible. */ 586 587 static bool 588 cgraph_externally_visible_p (struct cgraph_node *node, 589 bool whole_program, bool aliased) 590 { 591 if (!node->local.finalized) 592 return false; 593 if (!DECL_COMDAT (node->decl) 594 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))) 595 return false; 596 597 /* Do not even try to be smart about aliased nodes. Until we properly 598 represent everything by same body alias, these are just evil. */ 599 if (aliased) 600 return true; 601 602 /* Do not try to localize built-in functions yet. One of problems is that we 603 end up mangling their asm for WHOPR that makes it impossible to call them 604 using the implicit built-in declarations anymore. Similarly this enables 605 us to remove them as unreachable before actual calls may appear during 606 expansion or folding. */ 607 if (DECL_BUILT_IN (node->decl)) 608 return true; 609 610 /* If linker counts on us, we must preserve the function. */ 611 if (cgraph_used_from_object_file_p (node)) 612 return true; 613 if (DECL_PRESERVE_P (node->decl)) 614 return true; 615 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) 616 return true; 617 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES 618 && lookup_attribute ("dllexport", DECL_ATTRIBUTES (node->decl))) 619 return true; 620 if (node->resolution == LDPR_PREVAILING_DEF_IRONLY) 621 return false; 622 /* When doing LTO or whole program, we can bring COMDAT functoins static. 623 This improves code quality and we know we will duplicate them at most twice 624 (in the case that we are not using plugin and link with object file 625 implementing same COMDAT) */ 626 if ((in_lto_p || whole_program) 627 && DECL_COMDAT (node->decl) 628 && cgraph_comdat_can_be_unshared_p (node)) 629 return false; 630 631 /* When doing link time optimizations, hidden symbols become local. */ 632 if (in_lto_p 633 && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN 634 || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL) 635 /* Be sure that node is defined in IR file, not in other object 636 file. In that case we don't set used_from_other_object_file. */ 637 && node->analyzed) 638 ; 639 else if (!whole_program) 640 return true; 641 642 if (MAIN_NAME_P (DECL_NAME (node->decl))) 643 return true; 644 645 return false; 646 } 647 648 /* Return true when variable VNODE should be considered externally visible. */ 649 650 bool 651 varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) 652 { 653 if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl)) 654 return false; 655 656 /* Do not even try to be smart about aliased nodes. Until we properly 657 represent everything by same body alias, these are just evil. */ 658 if (aliased) 659 return true; 660 661 /* If linker counts on us, we must preserve the function. */ 662 if (varpool_used_from_object_file_p (vnode)) 663 return true; 664 665 if (DECL_HARD_REGISTER (vnode->decl)) 666 return true; 667 if (DECL_PRESERVE_P (vnode->decl)) 668 return true; 669 if (lookup_attribute ("externally_visible", 670 DECL_ATTRIBUTES (vnode->decl))) 671 return true; 672 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES 673 && lookup_attribute ("dllexport", 674 DECL_ATTRIBUTES (vnode->decl))) 675 return true; 676 677 /* See if we have linker information about symbol not being used or 678 if we need to make guess based on the declaration. 679 680 Even if the linker clams the symbol is unused, never bring internal 681 symbols that are declared by user as used or externally visible. 682 This is needed for i.e. references from asm statements. */ 683 if (varpool_used_from_object_file_p (vnode)) 684 return true; 685 if (vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) 686 return false; 687 688 /* As a special case, the COMDAT virutal tables can be unshared. 689 In LTO mode turn vtables into static variables. The variable is readonly, 690 so this does not enable more optimization, but referring static var 691 is faster for dynamic linking. Also this match logic hidding vtables 692 from LTO symbol tables. */ 693 if ((in_lto_p || flag_whole_program) 694 && !vnode->force_output 695 && DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl)) 696 return false; 697 698 /* When doing link time optimizations, hidden symbols become local. */ 699 if (in_lto_p 700 && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN 701 || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) 702 /* Be sure that node is defined in IR file, not in other object 703 file. In that case we don't set used_from_other_object_file. */ 704 && vnode->finalized) 705 ; 706 else if (!flag_whole_program) 707 return true; 708 709 /* Do not attempt to privatize COMDATS by default. 710 This would break linking with C++ libraries sharing 711 inline definitions. 712 713 FIXME: We can do so for readonly vars with no address taken and 714 possibly also for vtables since no direct pointer comparsion is done. 715 It might be interesting to do so to reduce linking overhead. */ 716 if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl)) 717 return true; 718 return false; 719 } 720 721 /* Dissolve the same_comdat_group list in which NODE resides. */ 722 723 static void 724 dissolve_same_comdat_group_list (struct cgraph_node *node) 725 { 726 struct cgraph_node *n = node, *next; 727 do 728 { 729 next = n->same_comdat_group; 730 n->same_comdat_group = NULL; 731 n = next; 732 } 733 while (n != node); 734 } 735 736 /* Mark visibility of all functions. 737 738 A local function is one whose calls can occur only in the current 739 compilation unit and all its calls are explicit, so we can change 740 its calling convention. We simply mark all static functions whose 741 address is not taken as local. 742 743 We also change the TREE_PUBLIC flag of all declarations that are public 744 in language point of view but we want to overwrite this default 745 via visibilities for the backend point of view. */ 746 747 static unsigned int 748 function_and_variable_visibility (bool whole_program) 749 { 750 struct cgraph_node *node; 751 struct varpool_node *vnode; 752 struct pointer_set_t *aliased_nodes = pointer_set_create (); 753 struct pointer_set_t *aliased_vnodes = pointer_set_create (); 754 unsigned i; 755 alias_pair *p; 756 757 /* Discover aliased nodes. */ 758 FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p) 759 { 760 if (dump_file) 761 fprintf (dump_file, "Alias %s->%s", 762 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (p->decl)), 763 IDENTIFIER_POINTER (p->target)); 764 765 if ((node = cgraph_node_for_asm (p->target)) != NULL 766 && !DECL_EXTERNAL (node->decl)) 767 { 768 if (!node->analyzed) 769 continue; 770 cgraph_mark_needed_node (node); 771 gcc_assert (node->needed); 772 pointer_set_insert (aliased_nodes, node); 773 if (dump_file) 774 fprintf (dump_file, " node %s/%i", 775 cgraph_node_name (node), node->uid); 776 } 777 else if ((vnode = varpool_node_for_asm (p->target)) != NULL 778 && !DECL_EXTERNAL (vnode->decl)) 779 { 780 varpool_mark_needed_node (vnode); 781 gcc_assert (vnode->needed); 782 pointer_set_insert (aliased_vnodes, vnode); 783 if (dump_file) 784 fprintf (dump_file, " varpool node %s", 785 varpool_node_name (vnode)); 786 } 787 if (dump_file) 788 fprintf (dump_file, "\n"); 789 } 790 791 for (node = cgraph_nodes; node; node = node->next) 792 { 793 int flags = flags_from_decl_or_type (node->decl); 794 795 /* Optimize away PURE and CONST constructors and destructors. */ 796 if (optimize 797 && (flags & (ECF_CONST | ECF_PURE)) 798 && !(flags & ECF_LOOPING_CONST_OR_PURE)) 799 { 800 DECL_STATIC_CONSTRUCTOR (node->decl) = 0; 801 DECL_STATIC_DESTRUCTOR (node->decl) = 0; 802 } 803 804 /* Frontends and alias code marks nodes as needed before parsing is finished. 805 We may end up marking as node external nodes where this flag is meaningless 806 strip it. */ 807 if (node->needed 808 && (DECL_EXTERNAL (node->decl) || !node->analyzed)) 809 node->needed = 0; 810 811 /* C++ FE on lack of COMDAT support create local COMDAT functions 812 (that ought to be shared but can not due to object format 813 limitations). It is neccesary to keep the flag to make rest of C++ FE 814 happy. Clear the flag here to avoid confusion in middle-end. */ 815 if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl)) 816 DECL_COMDAT (node->decl) = 0; 817 /* For external decls stop tracking same_comdat_group, it doesn't matter 818 what comdat group they are in when they won't be emitted in this TU, 819 and simplifies later passes. */ 820 if (node->same_comdat_group && DECL_EXTERNAL (node->decl)) 821 { 822 #ifdef ENABLE_CHECKING 823 struct cgraph_node *n; 824 825 for (n = node->same_comdat_group; 826 n != node; 827 n = n->same_comdat_group) 828 /* If at least one of same comdat group functions is external, 829 all of them have to be, otherwise it is a front-end bug. */ 830 gcc_assert (DECL_EXTERNAL (n->decl)); 831 #endif 832 dissolve_same_comdat_group_list (node); 833 } 834 gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl)) 835 || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)); 836 if (cgraph_externally_visible_p (node, whole_program, 837 pointer_set_contains (aliased_nodes, 838 node))) 839 { 840 gcc_assert (!node->global.inlined_to); 841 node->local.externally_visible = true; 842 } 843 else 844 node->local.externally_visible = false; 845 if (!node->local.externally_visible && node->analyzed 846 && !DECL_EXTERNAL (node->decl)) 847 { 848 gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl)); 849 cgraph_make_decl_local (node->decl); 850 node->resolution = LDPR_PREVAILING_DEF_IRONLY; 851 if (node->same_comdat_group) 852 /* cgraph_externally_visible_p has already checked all other nodes 853 in the group and they will all be made local. We need to 854 dissolve the group at once so that the predicate does not 855 segfault though. */ 856 dissolve_same_comdat_group_list (node); 857 } 858 859 if (node->thunk.thunk_p 860 && TREE_PUBLIC (node->decl)) 861 { 862 struct cgraph_node *decl_node = node; 863 864 decl_node = cgraph_function_node (decl_node->callees->callee, NULL); 865 866 /* Thunks have the same visibility as function they are attached to. 867 Make sure the C++ front end set this up properly. */ 868 if (DECL_ONE_ONLY (decl_node->decl)) 869 { 870 gcc_checking_assert (DECL_COMDAT (node->decl) 871 == DECL_COMDAT (decl_node->decl)); 872 gcc_checking_assert (DECL_COMDAT_GROUP (node->decl) 873 == DECL_COMDAT_GROUP (decl_node->decl)); 874 gcc_checking_assert (node->same_comdat_group); 875 } 876 if (DECL_EXTERNAL (decl_node->decl)) 877 DECL_EXTERNAL (node->decl) = 1; 878 } 879 } 880 for (node = cgraph_nodes; node; node = node->next) 881 node->local.local = cgraph_local_node_p (node); 882 for (vnode = varpool_nodes; vnode; vnode = vnode->next) 883 { 884 /* weak flag makes no sense on local variables. */ 885 gcc_assert (!DECL_WEAK (vnode->decl) 886 || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)); 887 /* In several cases declarations can not be common: 888 889 - when declaration has initializer 890 - when it is in weak 891 - when it has specific section 892 - when it resides in non-generic address space. 893 - if declaration is local, it will get into .local common section 894 so common flag is not needed. Frontends still produce these in 895 certain cases, such as for: 896 897 static int a __attribute__ ((common)) 898 899 Canonicalize things here and clear the redundant flag. */ 900 if (DECL_COMMON (vnode->decl) 901 && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)) 902 || (DECL_INITIAL (vnode->decl) 903 && DECL_INITIAL (vnode->decl) != error_mark_node) 904 || DECL_WEAK (vnode->decl) 905 || DECL_SECTION_NAME (vnode->decl) != NULL 906 || ! (ADDR_SPACE_GENERIC_P 907 (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) 908 DECL_COMMON (vnode->decl) = 0; 909 } 910 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) 911 { 912 if (!vnode->finalized) 913 continue; 914 if (vnode->needed 915 && varpool_externally_visible_p 916 (vnode, 917 pointer_set_contains (aliased_vnodes, vnode))) 918 vnode->externally_visible = true; 919 else 920 vnode->externally_visible = false; 921 if (!vnode->externally_visible) 922 { 923 gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); 924 cgraph_make_decl_local (vnode->decl); 925 vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; 926 } 927 gcc_assert (TREE_STATIC (vnode->decl)); 928 } 929 pointer_set_destroy (aliased_nodes); 930 pointer_set_destroy (aliased_vnodes); 931 932 if (dump_file) 933 { 934 fprintf (dump_file, "\nMarking local functions:"); 935 for (node = cgraph_nodes; node; node = node->next) 936 if (node->local.local) 937 fprintf (dump_file, " %s", cgraph_node_name (node)); 938 fprintf (dump_file, "\n\n"); 939 fprintf (dump_file, "\nMarking externally visible functions:"); 940 for (node = cgraph_nodes; node; node = node->next) 941 if (node->local.externally_visible) 942 fprintf (dump_file, " %s", cgraph_node_name (node)); 943 fprintf (dump_file, "\n\n"); 944 fprintf (dump_file, "\nMarking externally visible variables:"); 945 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) 946 if (vnode->externally_visible) 947 fprintf (dump_file, " %s", varpool_node_name (vnode)); 948 fprintf (dump_file, "\n\n"); 949 } 950 cgraph_function_flags_ready = true; 951 return 0; 952 } 953 954 /* Local function pass handling visibilities. This happens before LTO streaming 955 so in particular -fwhole-program should be ignored at this level. */ 956 957 static unsigned int 958 local_function_and_variable_visibility (void) 959 { 960 return function_and_variable_visibility (flag_whole_program && !flag_lto); 961 } 962 963 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = 964 { 965 { 966 SIMPLE_IPA_PASS, 967 "visibility", /* name */ 968 NULL, /* gate */ 969 local_function_and_variable_visibility,/* execute */ 970 NULL, /* sub */ 971 NULL, /* next */ 972 0, /* static_pass_number */ 973 TV_CGRAPHOPT, /* tv_id */ 974 0, /* properties_required */ 975 0, /* properties_provided */ 976 0, /* properties_destroyed */ 977 0, /* todo_flags_start */ 978 TODO_remove_functions | TODO_dump_cgraph 979 | TODO_ggc_collect /* todo_flags_finish */ 980 } 981 }; 982 983 /* Do not re-run on ltrans stage. */ 984 985 static bool 986 gate_whole_program_function_and_variable_visibility (void) 987 { 988 return !flag_ltrans; 989 } 990 991 /* Bring functionss local at LTO time whith -fwhole-program. */ 992 993 static unsigned int 994 whole_program_function_and_variable_visibility (void) 995 { 996 struct cgraph_node *node; 997 struct varpool_node *vnode; 998 999 function_and_variable_visibility (flag_whole_program); 1000 1001 for (node = cgraph_nodes; node; node = node->next) 1002 if ((node->local.externally_visible && !DECL_COMDAT (node->decl)) 1003 && node->local.finalized) 1004 cgraph_mark_needed_node (node); 1005 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) 1006 if (vnode->externally_visible && !DECL_COMDAT (vnode->decl)) 1007 varpool_mark_needed_node (vnode); 1008 if (dump_file) 1009 { 1010 fprintf (dump_file, "\nNeeded variables:"); 1011 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) 1012 if (vnode->needed) 1013 fprintf (dump_file, " %s", varpool_node_name (vnode)); 1014 fprintf (dump_file, "\n\n"); 1015 } 1016 if (optimize) 1017 ipa_discover_readonly_nonaddressable_vars (); 1018 return 0; 1019 } 1020 1021 struct ipa_opt_pass_d pass_ipa_whole_program_visibility = 1022 { 1023 { 1024 IPA_PASS, 1025 "whole-program", /* name */ 1026 gate_whole_program_function_and_variable_visibility,/* gate */ 1027 whole_program_function_and_variable_visibility,/* execute */ 1028 NULL, /* sub */ 1029 NULL, /* next */ 1030 0, /* static_pass_number */ 1031 TV_CGRAPHOPT, /* tv_id */ 1032 0, /* properties_required */ 1033 0, /* properties_provided */ 1034 0, /* properties_destroyed */ 1035 0, /* todo_flags_start */ 1036 TODO_remove_functions | TODO_dump_cgraph 1037 | TODO_ggc_collect /* todo_flags_finish */ 1038 }, 1039 NULL, /* generate_summary */ 1040 NULL, /* write_summary */ 1041 NULL, /* read_summary */ 1042 NULL, /* write_optimization_summary */ 1043 NULL, /* read_optimization_summary */ 1044 NULL, /* stmt_fixup */ 1045 0, /* TODOs */ 1046 NULL, /* function_transform */ 1047 NULL, /* variable_transform */ 1048 }; 1049 1050 1051 /* Simple ipa profile pass propagating frequencies across the callgraph. */ 1052 1053 static unsigned int 1054 ipa_profile (void) 1055 { 1056 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); 1057 struct cgraph_edge *e; 1058 int order_pos; 1059 bool something_changed = false; 1060 int i; 1061 1062 order_pos = ipa_reverse_postorder (order); 1063 for (i = order_pos - 1; i >= 0; i--) 1064 { 1065 if (order[i]->local.local && cgraph_propagate_frequency (order[i])) 1066 { 1067 for (e = order[i]->callees; e; e = e->next_callee) 1068 if (e->callee->local.local && !e->callee->aux) 1069 { 1070 something_changed = true; 1071 e->callee->aux = (void *)1; 1072 } 1073 } 1074 order[i]->aux = NULL; 1075 } 1076 1077 while (something_changed) 1078 { 1079 something_changed = false; 1080 for (i = order_pos - 1; i >= 0; i--) 1081 { 1082 if (order[i]->aux && cgraph_propagate_frequency (order[i])) 1083 { 1084 for (e = order[i]->callees; e; e = e->next_callee) 1085 if (e->callee->local.local && !e->callee->aux) 1086 { 1087 something_changed = true; 1088 e->callee->aux = (void *)1; 1089 } 1090 } 1091 order[i]->aux = NULL; 1092 } 1093 } 1094 free (order); 1095 return 0; 1096 } 1097 1098 static bool 1099 gate_ipa_profile (void) 1100 { 1101 return flag_ipa_profile; 1102 } 1103 1104 struct ipa_opt_pass_d pass_ipa_profile = 1105 { 1106 { 1107 IPA_PASS, 1108 "profile_estimate", /* name */ 1109 gate_ipa_profile, /* gate */ 1110 ipa_profile, /* execute */ 1111 NULL, /* sub */ 1112 NULL, /* next */ 1113 0, /* static_pass_number */ 1114 TV_IPA_PROFILE, /* tv_id */ 1115 0, /* properties_required */ 1116 0, /* properties_provided */ 1117 0, /* properties_destroyed */ 1118 0, /* todo_flags_start */ 1119 0 /* todo_flags_finish */ 1120 }, 1121 NULL, /* generate_summary */ 1122 NULL, /* write_summary */ 1123 NULL, /* read_summary */ 1124 NULL, /* write_optimization_summary */ 1125 NULL, /* read_optimization_summary */ 1126 NULL, /* stmt_fixup */ 1127 0, /* TODOs */ 1128 NULL, /* function_transform */ 1129 NULL /* variable_transform */ 1130 }; 1131 1132 /* Generate and emit a static constructor or destructor. WHICH must 1133 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY 1134 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the 1135 initialization priority for this constructor or destructor. 1136 1137 FINAL specify whether the externally visible name for collect2 should 1138 be produced. */ 1139 1140 static void 1141 cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final) 1142 { 1143 static int counter = 0; 1144 char which_buf[16]; 1145 tree decl, name, resdecl; 1146 1147 /* The priority is encoded in the constructor or destructor name. 1148 collect2 will sort the names and arrange that they are called at 1149 program startup. */ 1150 if (final) 1151 sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++); 1152 else 1153 /* Proudce sane name but one not recognizable by collect2, just for the 1154 case we fail to inline the function. */ 1155 sprintf (which_buf, "sub_%c_%.5d_%d", which, priority, counter++); 1156 name = get_file_function_name (which_buf); 1157 1158 decl = build_decl (input_location, FUNCTION_DECL, name, 1159 build_function_type_list (void_type_node, NULL_TREE)); 1160 current_function_decl = decl; 1161 1162 resdecl = build_decl (input_location, 1163 RESULT_DECL, NULL_TREE, void_type_node); 1164 DECL_ARTIFICIAL (resdecl) = 1; 1165 DECL_RESULT (decl) = resdecl; 1166 DECL_CONTEXT (resdecl) = decl; 1167 1168 allocate_struct_function (decl, false); 1169 1170 TREE_STATIC (decl) = 1; 1171 TREE_USED (decl) = 1; 1172 DECL_ARTIFICIAL (decl) = 1; 1173 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; 1174 DECL_SAVED_TREE (decl) = body; 1175 if (!targetm.have_ctors_dtors && final) 1176 { 1177 TREE_PUBLIC (decl) = 1; 1178 DECL_PRESERVE_P (decl) = 1; 1179 } 1180 DECL_UNINLINABLE (decl) = 1; 1181 1182 DECL_INITIAL (decl) = make_node (BLOCK); 1183 TREE_USED (DECL_INITIAL (decl)) = 1; 1184 1185 DECL_SOURCE_LOCATION (decl) = input_location; 1186 cfun->function_end_locus = input_location; 1187 1188 switch (which) 1189 { 1190 case 'I': 1191 DECL_STATIC_CONSTRUCTOR (decl) = 1; 1192 decl_init_priority_insert (decl, priority); 1193 break; 1194 case 'D': 1195 DECL_STATIC_DESTRUCTOR (decl) = 1; 1196 decl_fini_priority_insert (decl, priority); 1197 break; 1198 default: 1199 gcc_unreachable (); 1200 } 1201 1202 gimplify_function_tree (decl); 1203 1204 cgraph_add_new_function (decl, false); 1205 1206 set_cfun (NULL); 1207 current_function_decl = NULL; 1208 } 1209 1210 /* Generate and emit a static constructor or destructor. WHICH must 1211 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY 1212 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the 1213 initialization priority for this constructor or destructor. */ 1214 1215 void 1216 cgraph_build_static_cdtor (char which, tree body, int priority) 1217 { 1218 cgraph_build_static_cdtor_1 (which, body, priority, false); 1219 } 1220 1221 /* A vector of FUNCTION_DECLs declared as static constructors. */ 1222 static VEC(tree, heap) *static_ctors; 1223 /* A vector of FUNCTION_DECLs declared as static destructors. */ 1224 static VEC(tree, heap) *static_dtors; 1225 1226 /* When target does not have ctors and dtors, we call all constructor 1227 and destructor by special initialization/destruction function 1228 recognized by collect2. 1229 1230 When we are going to build this function, collect all constructors and 1231 destructors and turn them into normal functions. */ 1232 1233 static void 1234 record_cdtor_fn (struct cgraph_node *node) 1235 { 1236 if (DECL_STATIC_CONSTRUCTOR (node->decl)) 1237 VEC_safe_push (tree, heap, static_ctors, node->decl); 1238 if (DECL_STATIC_DESTRUCTOR (node->decl)) 1239 VEC_safe_push (tree, heap, static_dtors, node->decl); 1240 node = cgraph_get_node (node->decl); 1241 DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1; 1242 } 1243 1244 /* Define global constructors/destructor functions for the CDTORS, of 1245 which they are LEN. The CDTORS are sorted by initialization 1246 priority. If CTOR_P is true, these are constructors; otherwise, 1247 they are destructors. */ 1248 1249 static void 1250 build_cdtor (bool ctor_p, VEC (tree, heap) *cdtors) 1251 { 1252 size_t i,j; 1253 size_t len = VEC_length (tree, cdtors); 1254 1255 i = 0; 1256 while (i < len) 1257 { 1258 tree body; 1259 tree fn; 1260 priority_type priority; 1261 1262 priority = 0; 1263 body = NULL_TREE; 1264 j = i; 1265 do 1266 { 1267 priority_type p; 1268 fn = VEC_index (tree, cdtors, j); 1269 p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn); 1270 if (j == i) 1271 priority = p; 1272 else if (p != priority) 1273 break; 1274 j++; 1275 } 1276 while (j < len); 1277 1278 /* When there is only one cdtor and target supports them, do nothing. */ 1279 if (j == i + 1 1280 && targetm.have_ctors_dtors) 1281 { 1282 i++; 1283 continue; 1284 } 1285 /* Find the next batch of constructors/destructors with the same 1286 initialization priority. */ 1287 for (;i < j; i++) 1288 { 1289 tree call; 1290 fn = VEC_index (tree, cdtors, i); 1291 call = build_call_expr (fn, 0); 1292 if (ctor_p) 1293 DECL_STATIC_CONSTRUCTOR (fn) = 0; 1294 else 1295 DECL_STATIC_DESTRUCTOR (fn) = 0; 1296 /* We do not want to optimize away pure/const calls here. 1297 When optimizing, these should be already removed, when not 1298 optimizing, we want user to be able to breakpoint in them. */ 1299 TREE_SIDE_EFFECTS (call) = 1; 1300 append_to_statement_list (call, &body); 1301 } 1302 gcc_assert (body != NULL_TREE); 1303 /* Generate a function to call all the function of like 1304 priority. */ 1305 cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true); 1306 } 1307 } 1308 1309 /* Comparison function for qsort. P1 and P2 are actually of type 1310 "tree *" and point to static constructors. DECL_INIT_PRIORITY is 1311 used to determine the sort order. */ 1312 1313 static int 1314 compare_ctor (const void *p1, const void *p2) 1315 { 1316 tree f1; 1317 tree f2; 1318 int priority1; 1319 int priority2; 1320 1321 f1 = *(const tree *)p1; 1322 f2 = *(const tree *)p2; 1323 priority1 = DECL_INIT_PRIORITY (f1); 1324 priority2 = DECL_INIT_PRIORITY (f2); 1325 1326 if (priority1 < priority2) 1327 return -1; 1328 else if (priority1 > priority2) 1329 return 1; 1330 else 1331 /* Ensure a stable sort. Constructors are executed in backwarding 1332 order to make LTO initialize braries first. */ 1333 return DECL_UID (f2) - DECL_UID (f1); 1334 } 1335 1336 /* Comparison function for qsort. P1 and P2 are actually of type 1337 "tree *" and point to static destructors. DECL_FINI_PRIORITY is 1338 used to determine the sort order. */ 1339 1340 static int 1341 compare_dtor (const void *p1, const void *p2) 1342 { 1343 tree f1; 1344 tree f2; 1345 int priority1; 1346 int priority2; 1347 1348 f1 = *(const tree *)p1; 1349 f2 = *(const tree *)p2; 1350 priority1 = DECL_FINI_PRIORITY (f1); 1351 priority2 = DECL_FINI_PRIORITY (f2); 1352 1353 if (priority1 < priority2) 1354 return -1; 1355 else if (priority1 > priority2) 1356 return 1; 1357 else 1358 /* Ensure a stable sort. */ 1359 return DECL_UID (f1) - DECL_UID (f2); 1360 } 1361 1362 /* Generate functions to call static constructors and destructors 1363 for targets that do not support .ctors/.dtors sections. These 1364 functions have magic names which are detected by collect2. */ 1365 1366 static void 1367 build_cdtor_fns (void) 1368 { 1369 if (!VEC_empty (tree, static_ctors)) 1370 { 1371 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); 1372 VEC_qsort (tree, static_ctors, compare_ctor); 1373 build_cdtor (/*ctor_p=*/true, static_ctors); 1374 } 1375 1376 if (!VEC_empty (tree, static_dtors)) 1377 { 1378 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); 1379 VEC_qsort (tree, static_dtors, compare_dtor); 1380 build_cdtor (/*ctor_p=*/false, static_dtors); 1381 } 1382 } 1383 1384 /* Look for constructors and destructors and produce function calling them. 1385 This is needed for targets not supporting ctors or dtors, but we perform the 1386 transformation also at linktime to merge possibly numberous 1387 constructors/destructors into single function to improve code locality and 1388 reduce size. */ 1389 1390 static unsigned int 1391 ipa_cdtor_merge (void) 1392 { 1393 struct cgraph_node *node; 1394 for (node = cgraph_nodes; node; node = node->next) 1395 if (node->analyzed 1396 && (DECL_STATIC_CONSTRUCTOR (node->decl) 1397 || DECL_STATIC_DESTRUCTOR (node->decl))) 1398 record_cdtor_fn (node); 1399 build_cdtor_fns (); 1400 VEC_free (tree, heap, static_ctors); 1401 VEC_free (tree, heap, static_dtors); 1402 return 0; 1403 } 1404 1405 /* Perform the pass when we have no ctors/dtors support 1406 or at LTO time to merge multiple constructors into single 1407 function. */ 1408 1409 static bool 1410 gate_ipa_cdtor_merge (void) 1411 { 1412 return !targetm.have_ctors_dtors || (optimize && in_lto_p); 1413 } 1414 1415 struct ipa_opt_pass_d pass_ipa_cdtor_merge = 1416 { 1417 { 1418 IPA_PASS, 1419 "cdtor", /* name */ 1420 gate_ipa_cdtor_merge, /* gate */ 1421 ipa_cdtor_merge, /* execute */ 1422 NULL, /* sub */ 1423 NULL, /* next */ 1424 0, /* static_pass_number */ 1425 TV_CGRAPHOPT, /* tv_id */ 1426 0, /* properties_required */ 1427 0, /* properties_provided */ 1428 0, /* properties_destroyed */ 1429 0, /* todo_flags_start */ 1430 0 /* todo_flags_finish */ 1431 }, 1432 NULL, /* generate_summary */ 1433 NULL, /* write_summary */ 1434 NULL, /* read_summary */ 1435 NULL, /* write_optimization_summary */ 1436 NULL, /* read_optimization_summary */ 1437 NULL, /* stmt_fixup */ 1438 0, /* TODOs */ 1439 NULL, /* function_transform */ 1440 NULL /* variable_transform */ 1441 }; 1442