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