]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ipa.c
typeck.c (build_array_ref): Take complain parm.
[thirdparty/gcc.git] / gcc / ipa.c
CommitLineData
ca31b95f 1/* Basic IPA optimizations and utilities.
c75c517d
SB
2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
3 Free Software Foundation, Inc.
ca31b95f
JH
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
9dcd6f09 9Software Foundation; either version 3, or (at your option) any later
ca31b95f
JH
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
9dcd6f09
NC
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
ca31b95f
JH
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "cgraph.h"
f4b3ca72
JH
26#include "tree-pass.h"
27#include "timevar.h"
9187e02d 28#include "gimple.h"
fed5ae11 29#include "ggc.h"
ca31b95f
JH
30
31/* Fill array order with all nodes with output flag set in the reverse
32 topological order. */
33
34int
35cgraph_postorder (struct cgraph_node **order)
36{
37 struct cgraph_node *node, *node2;
38 int stack_size = 0;
39 int order_pos = 0;
40 struct cgraph_edge *edge, last;
39ff5a96 41 int pass;
ca31b95f
JH
42
43 struct cgraph_node **stack =
5ed6ace5 44 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
ca31b95f
JH
45
46 /* We have to deal with cycles nicely, so use a depth first traversal
47 output algorithm. Ignore the fact that some functions won't need
48 to be output and put them into order as well, so we get dependencies
fa10beec 49 right through inline functions. */
ca31b95f
JH
50 for (node = cgraph_nodes; node; node = node->next)
51 node->aux = NULL;
39ff5a96
JH
52 for (pass = 0; pass < 2; pass++)
53 for (node = cgraph_nodes; node; node = node->next)
54 if (!node->aux
b20996ff
JH
55 && (pass
56 || (!cgraph_only_called_directly_p (node)
57 && !node->address_taken)))
39ff5a96
JH
58 {
59 node2 = node;
60 if (!node->callers)
61 node->aux = &last;
62 else
63 node->aux = node->callers;
64 while (node2)
65 {
66 while (node2->aux != &last)
67 {
68 edge = (struct cgraph_edge *) node2->aux;
69 if (edge->next_caller)
70 node2->aux = edge->next_caller;
71 else
72 node2->aux = &last;
af961c7f
RG
73 /* Break possible cycles involving always-inline
74 functions by ignoring edges from always-inline
75 functions to non-always-inline functions. */
76 if (edge->caller->local.disregard_inline_limits
77 && !edge->callee->local.disregard_inline_limits)
78 continue;
39ff5a96
JH
79 if (!edge->caller->aux)
80 {
81 if (!edge->caller->callers)
82 edge->caller->aux = &last;
83 else
84 edge->caller->aux = edge->caller->callers;
85 stack[stack_size++] = node2;
86 node2 = edge->caller;
87 break;
88 }
89 }
90 if (node2->aux == &last)
91 {
92 order[order_pos++] = node2;
93 if (stack_size)
94 node2 = stack[--stack_size];
95 else
96 node2 = NULL;
97 }
98 }
99 }
ca31b95f 100 free (stack);
d63db217
JH
101 for (node = cgraph_nodes; node; node = node->next)
102 node->aux = NULL;
ca31b95f
JH
103 return order_pos;
104}
105
d563610d
JH
106/* Look for all functions inlined to NODE and update their inlined_to pointers
107 to INLINED_TO. */
108
109static void
110update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
111{
112 struct cgraph_edge *e;
113 for (e = node->callees; e; e = e->next_callee)
114 if (e->callee->global.inlined_to)
115 {
116 e->callee->global.inlined_to = inlined_to;
117 update_inlined_to_pointer (e->callee, inlined_to);
118 }
119}
120
b34fd25c
JH
121/* Add cgraph NODE to queue starting at FIRST. */
122
123static void
124enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first)
125{
126 node->aux = *first;
127 *first = node;
128}
129
130/* Add varpool NODE to queue starting at FIRST. */
131
132static void
133enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first)
134{
135 node->aux = *first;
136 *first = node;
137}
138
139/* Process references. */
140
141static void
142process_references (struct ipa_ref_list *list,
143 struct cgraph_node **first,
144 struct varpool_node **first_varpool,
145 bool before_inlining_p)
146{
147 int i;
148 struct ipa_ref *ref;
149 for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
150 {
151 if (ref->refered_type == IPA_REF_CGRAPH)
152 {
153 struct cgraph_node *node = ipa_ref_node (ref);
154 if (!node->reachable
155 && (!DECL_EXTERNAL (node->decl)
156 || before_inlining_p))
157 {
158 node->reachable = true;
159 enqueue_cgraph_node (node, first);
160 }
161 }
162 else
163 {
164 struct varpool_node *node = ipa_ref_varpool_node (ref);
165 if (!node->needed)
166 {
167 varpool_mark_needed_node (node);
168 enqueue_varpool_node (node, first_varpool);
169 }
170 }
171 }
172}
173
174/* Return true when function NODE can be removed from callgraph
175 if all direct calls are eliminated. */
176
177static inline bool
178varpool_can_remove_if_no_refs (struct varpool_node *node)
179{
180 return (!node->force_output && !node->used_from_other_partition
181 && (DECL_COMDAT (node->decl) || !node->externally_visible));
182}
183
ca31b95f
JH
184/* Perform reachability analysis and reclaim all unreachable nodes.
185 If BEFORE_INLINING_P is true this function is called before inlining
b8698a0f 186 decisions has been made. If BEFORE_INLINING_P is false this function also
ca31b95f
JH
187 removes unneeded bodies of extern inline functions. */
188
189bool
10d22567 190cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
ca31b95f 191{
c5274326 192 struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
b34fd25c 193 struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1;
0e3776db 194 struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
96fc428c 195 struct cgraph_node *node, *next;
b34fd25c 196 struct varpool_node *vnode, *vnext;
ca31b95f 197 bool changed = false;
ca31b95f
JH
198
199#ifdef ENABLE_CHECKING
200 verify_cgraph ();
201#endif
10d22567
ZD
202 if (file)
203 fprintf (file, "\nReclaiming functions:");
ca31b95f
JH
204#ifdef ENABLE_CHECKING
205 for (node = cgraph_nodes; node; node = node->next)
206 gcc_assert (!node->aux);
207#endif
b34fd25c 208 varpool_reset_queue ();
ca31b95f 209 for (node = cgraph_nodes; node; node = node->next)
b20996ff 210 if (!cgraph_can_remove_if_no_direct_calls_p (node)
b8698a0f 211 && ((!DECL_EXTERNAL (node->decl))
ca31b95f
JH
212 || before_inlining_p))
213 {
b20996ff 214 gcc_assert (!node->global.inlined_to);
b34fd25c 215 enqueue_cgraph_node (node, &first);
0e3776db 216 node->reachable = true;
ca31b95f
JH
217 }
218 else
0e3776db
JH
219 {
220 gcc_assert (!node->aux);
221 node->reachable = false;
222 }
b34fd25c
JH
223 for (vnode = varpool_nodes; vnode; vnode = vnode->next)
224 {
225 vnode->next_needed = NULL;
226 vnode->prev_needed = NULL;
227 if (!varpool_can_remove_if_no_refs (vnode))
228 {
229 vnode->needed = false;
230 varpool_mark_needed_node (vnode);
231 enqueue_varpool_node (vnode, &first_varpool);
232 }
233 else
234 vnode->needed = false;
235 }
ca31b95f
JH
236
237 /* Perform reachability analysis. As a special case do not consider
238 extern inline functions not inlined as live because we won't output
239 them at all. */
b34fd25c
JH
240 while (first != (struct cgraph_node *) (void *) 1
241 || first_varpool != (struct varpool_node *) (void *) 1)
ca31b95f 242 {
b34fd25c
JH
243 if (first != (struct cgraph_node *) (void *) 1)
244 {
245 struct cgraph_edge *e;
246 node = first;
247 first = (struct cgraph_node *) first->aux;
248 node->aux = processed;
249
250 if (node->reachable)
251 for (e = node->callees; e; e = e->next_callee)
252 if (!e->callee->reachable
253 && node->analyzed
254 && (!e->inline_failed || !e->callee->analyzed
255 || (!DECL_EXTERNAL (e->callee->decl))
256 || before_inlining_p))
257 {
258 bool prev_reachable = e->callee->reachable;
259 e->callee->reachable |= node->reachable;
260 if (!e->callee->aux
261 || (e->callee->aux == processed
262 && prev_reachable != e->callee->reachable))
263 {
264 e->callee->aux = first;
265 first = e->callee;
266 }
267 }
268
269 /* If any function in a comdat group is reachable, force
270 all other functions in the same comdat group to be
271 also reachable. */
272 if (node->same_comdat_group
273 && node->reachable
274 && !node->global.inlined_to)
0e3776db 275 {
b34fd25c
JH
276 for (next = node->same_comdat_group;
277 next != node;
278 next = next->same_comdat_group)
279 if (!next->reachable)
280 {
281 next->aux = first;
282 first = next;
283 next->reachable = true;
284 }
0e3776db 285 }
b66887e4 286
b34fd25c
JH
287 /* We can freely remove inline clones even if they are cloned, however if
288 function is clone of real clone, we must keep it around in order to
289 make materialize_clones produce function body with the changes
290 applied. */
291 while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
47cb0d7d 292 {
b34fd25c
JH
293 bool noninline = node->clone_of->decl != node->decl;
294 node = node->clone_of;
295 if (noninline)
296 {
297 enqueue_cgraph_node (node, &first);
298 break;
299 }
47cb0d7d 300 }
b34fd25c
JH
301 process_references (&node->ref_list, &first, &first_varpool, before_inlining_p);
302 }
303 if (first_varpool != (struct varpool_node *) (void *) 1)
304 {
305 vnode = first_varpool;
306 first_varpool = (struct varpool_node *)first_varpool->aux;
307 vnode->aux = NULL;
308 process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p);
9187e02d 309 }
ca31b95f
JH
310 }
311
312 /* Remove unreachable nodes. Extern inline functions need special care;
313 Unreachable extern inline functions shall be removed.
314 Reachable extern inline functions we never inlined shall get their bodies
315 eliminated.
316 Reachable extern inline functions we sometimes inlined will be turned into
317 unanalyzed nodes so they look like for true extern functions to the rest
318 of code. Body of such functions is released via remove_node once the
319 inline clones are eliminated. */
96fc428c 320 for (node = cgraph_nodes; node; node = next)
ca31b95f 321 {
96fc428c 322 next = node->next;
0e3776db
JH
323 if (node->aux && !node->reachable)
324 {
325 cgraph_node_remove_callees (node);
326 node->analyzed = false;
327 node->local.inlinable = false;
328 }
ca31b95f
JH
329 if (!node->aux)
330 {
ca31b95f 331 node->global.inlined_to = NULL;
10d22567
ZD
332 if (file)
333 fprintf (file, " %s", cgraph_node_name (node));
0e3776db 334 if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
ca31b95f
JH
335 cgraph_remove_node (node);
336 else
337 {
338 struct cgraph_edge *e;
339
9187e02d 340 /* See if there is reachable caller. */
ca31b95f
JH
341 for (e = node->callers; e; e = e->next_caller)
342 if (e->caller->aux)
343 break;
9187e02d
JH
344
345 /* If so, we need to keep node in the callgraph. */
ca31b95f
JH
346 if (e || node->needed)
347 {
348 struct cgraph_node *clone;
349
9187e02d
JH
350 /* If there are still clones, we must keep body around.
351 Otherwise we can just remove the body but keep the clone. */
352 for (clone = node->clones; clone;
353 clone = clone->next_sibling_clone)
ca31b95f
JH
354 if (clone->aux)
355 break;
356 if (!clone)
357 {
3a40c18a 358 cgraph_release_function_body (node);
ca31b95f 359 node->analyzed = false;
9187e02d 360 node->local.inlinable = false;
ca31b95f 361 }
e792884f
JH
362 else
363 gcc_assert (!clone->in_other_partition);
8132a837 364 cgraph_node_remove_callees (node);
b34fd25c 365 ipa_remove_all_references (&node->ref_list);
0e3776db
JH
366 if (node->prev_sibling_clone)
367 node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
368 else if (node->clone_of)
369 node->clone_of->clones = node->next_sibling_clone;
370 if (node->next_sibling_clone)
371 node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
47cb0d7d
JH
372 node->clone_of = NULL;
373 node->next_sibling_clone = NULL;
374 node->prev_sibling_clone = NULL;
ca31b95f
JH
375 }
376 else
377 cgraph_remove_node (node);
378 }
ca31b95f
JH
379 changed = true;
380 }
381 }
382 for (node = cgraph_nodes; node; node = node->next)
9187e02d
JH
383 {
384 /* Inline clones might be kept around so their materializing allows further
385 cloning. If the function the clone is inlined into is removed, we need
386 to turn it into normal cone. */
387 if (node->global.inlined_to
388 && !node->callers)
389 {
390 gcc_assert (node->clones);
d563610d
JH
391 node->global.inlined_to = NULL;
392 update_inlined_to_pointer (node, node);
9187e02d
JH
393 }
394 node->aux = NULL;
395 }
b34fd25c
JH
396 if (file)
397 fprintf (file, "\nReclaiming variables:");
398 for (vnode = varpool_nodes; vnode; vnode = vnext)
399 {
400 vnext = vnode->next;
401 if (!vnode->needed)
402 {
403 if (file)
404 fprintf (file, " %s", varpool_node_name (vnode));
405 varpool_remove_node (vnode);
406 }
407 }
408
873aa8f5
JH
409#ifdef ENABLE_CHECKING
410 verify_cgraph ();
411#endif
4537ec0c
DN
412
413 /* Reclaim alias pairs for functions that have disappeared from the
414 call graph. */
415 remove_unreachable_alias_pairs ();
416
ca31b95f
JH
417 return changed;
418}
f4b3ca72 419
b20996ff
JH
420static bool
421cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
422{
b820a2f9
JH
423 if (!node->local.finalized)
424 return false;
b20996ff
JH
425 if (!DECL_COMDAT (node->decl)
426 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
427 return false;
428 if (!whole_program)
429 return true;
b932b8b1
JDA
430 if (DECL_PRESERVE_P (node->decl))
431 return true;
b20996ff
JH
432 /* COMDAT functions must be shared only if they have address taken,
433 otherwise we can produce our own private implementation with
434 -fwhole-program. */
b66887e4
JJ
435 if (DECL_COMDAT (node->decl))
436 {
437 if (node->address_taken || !node->analyzed)
438 return true;
439 if (node->same_comdat_group)
440 {
441 struct cgraph_node *next;
442
443 /* If more than one function is in the same COMDAT group, it must
444 be shared even if just one function in the comdat group has
445 address taken. */
446 for (next = node->same_comdat_group;
447 next != node;
448 next = next->same_comdat_group)
449 if (next->address_taken || !next->analyzed)
450 return true;
451 }
452 }
b20996ff
JH
453 if (MAIN_NAME_P (DECL_NAME (node->decl)))
454 return true;
455 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
456 return true;
457 return false;
458}
459
78eaf7bf
MJ
460/* Dissolve the same_comdat_group list in which NODE resides. */
461
462static void
463dissolve_same_comdat_group_list (struct cgraph_node *node)
464{
465 struct cgraph_node *n = node, *next;
466 do
467 {
468 next = n->same_comdat_group;
469 n->same_comdat_group = NULL;
470 n = next;
471 }
472 while (n != node);
473}
474
f4b3ca72
JH
475/* Mark visibility of all functions.
476
477 A local function is one whose calls can occur only in the current
478 compilation unit and all its calls are explicit, so we can change
479 its calling convention. We simply mark all static functions whose
480 address is not taken as local.
481
482 We also change the TREE_PUBLIC flag of all declarations that are public
483 in language point of view but we want to overwrite this default
484 via visibilities for the backend point of view. */
485
4e260309 486static unsigned int
b20996ff 487function_and_variable_visibility (bool whole_program)
f4b3ca72
JH
488{
489 struct cgraph_node *node;
490 struct varpool_node *vnode;
491
492 for (node = cgraph_nodes; node; node = node->next)
493 {
589520b6
JH
494 /* C++ FE on lack of COMDAT support create local COMDAT functions
495 (that ought to be shared but can not due to object format
496 limitations). It is neccesary to keep the flag to make rest of C++ FE
497 happy. Clear the flag here to avoid confusion in middle-end. */
498 if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
499 DECL_COMDAT (node->decl) = 0;
3fd54fb0
JJ
500 /* For external decls stop tracking same_comdat_group, it doesn't matter
501 what comdat group they are in when they won't be emitted in this TU,
502 and simplifies later passes. */
503 if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
504 {
78eaf7bf
MJ
505#ifdef ENABLE_CHECKING
506 struct cgraph_node *n;
507
508 for (n = node->same_comdat_group;
509 n != node;
510 n = n->same_comdat_group)
3fd54fb0
JJ
511 /* If at least one of same comdat group functions is external,
512 all of them have to be, otherwise it is a front-end bug. */
513 gcc_assert (DECL_EXTERNAL (n->decl));
78eaf7bf
MJ
514#endif
515 dissolve_same_comdat_group_list (node);
3fd54fb0 516 }
a8289259
JH
517 gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
518 || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
b20996ff
JH
519 if (cgraph_externally_visible_p (node, whole_program))
520 {
521 gcc_assert (!node->global.inlined_to);
522 node->local.externally_visible = true;
523 }
524 else
525 node->local.externally_visible = false;
f4b3ca72
JH
526 if (!node->local.externally_visible && node->analyzed
527 && !DECL_EXTERNAL (node->decl))
528 {
b20996ff 529 gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
715a4e08 530 cgraph_make_decl_local (node->decl);
78eaf7bf
MJ
531 if (node->same_comdat_group)
532 /* cgraph_externally_visible_p has already checked all other nodes
533 in the group and they will all be made local. We need to
534 dissolve the group at once so that the predicate does not
535 segfault though. */
536 dissolve_same_comdat_group_list (node);
f4b3ca72 537 }
b20996ff 538 node->local.local = (cgraph_only_called_directly_p (node)
f4b3ca72
JH
539 && node->analyzed
540 && !DECL_EXTERNAL (node->decl)
541 && !node->local.externally_visible);
542 }
e9fecf0e
JH
543 for (vnode = varpool_nodes; vnode; vnode = vnode->next)
544 {
545 /* weak flag makes no sense on local variables. */
546 gcc_assert (!DECL_WEAK (vnode->decl)
547 || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
548 /* In several cases declarations can not be common:
549
550 - when declaration has initializer
551 - when it is in weak
552 - when it has specific section
553 - when it resides in non-generic address space.
554 - if declaration is local, it will get into .local common section
555 so common flag is not needed. Frontends still produce these in
556 certain cases, such as for:
557
558 static int a __attribute__ ((common))
559
560 Canonicalize things here and clear the redundant flag. */
561 if (DECL_COMMON (vnode->decl)
562 && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
563 || (DECL_INITIAL (vnode->decl)
564 && DECL_INITIAL (vnode->decl) != error_mark_node)
565 || DECL_WEAK (vnode->decl)
566 || DECL_SECTION_NAME (vnode->decl) != NULL
567 || ! (ADDR_SPACE_GENERIC_P
568 (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
569 DECL_COMMON (vnode->decl) = 0;
570 }
f4b3ca72
JH
571 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
572 {
b820a2f9
JH
573 if (!vnode->finalized)
574 continue;
f4b3ca72 575 if (vnode->needed
b20996ff
JH
576 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
577 && (!whole_program
62a0a52e
JH
578 /* We can privatize comdat readonly variables whose address is not taken,
579 but doing so is not going to bring us optimization oppurtunities until
580 we start reordering datastructures. */
581 || DECL_COMDAT (vnode->decl)
582 || DECL_WEAK (vnode->decl)
b20996ff
JH
583 || lookup_attribute ("externally_visible",
584 DECL_ATTRIBUTES (vnode->decl))))
585 vnode->externally_visible = true;
586 else
587 vnode->externally_visible = false;
f4b3ca72
JH
588 if (!vnode->externally_visible)
589 {
b20996ff 590 gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
715a4e08 591 cgraph_make_decl_local (vnode->decl);
f4b3ca72
JH
592 }
593 gcc_assert (TREE_STATIC (vnode->decl));
594 }
595
596 if (dump_file)
597 {
598 fprintf (dump_file, "\nMarking local functions:");
599 for (node = cgraph_nodes; node; node = node->next)
600 if (node->local.local)
601 fprintf (dump_file, " %s", cgraph_node_name (node));
602 fprintf (dump_file, "\n\n");
603 fprintf (dump_file, "\nMarking externally visible functions:");
604 for (node = cgraph_nodes; node; node = node->next)
605 if (node->local.externally_visible)
606 fprintf (dump_file, " %s", cgraph_node_name (node));
607 fprintf (dump_file, "\n\n");
a8289259
JH
608 fprintf (dump_file, "\nMarking externally visible variables:");
609 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
610 if (vnode->externally_visible)
611 fprintf (dump_file, " %s", varpool_node_name (vnode));
612 fprintf (dump_file, "\n\n");
f4b3ca72
JH
613 }
614 cgraph_function_flags_ready = true;
4e260309 615 return 0;
f4b3ca72
JH
616}
617
b20996ff
JH
618/* Local function pass handling visibilities. This happens before LTO streaming
619 so in particular -fwhole-program should be ignored at this level. */
620
621static unsigned int
622local_function_and_variable_visibility (void)
623{
624 return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
625}
626
b8698a0f 627struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
f4b3ca72 628{
8ddbbcae
JH
629 {
630 SIMPLE_IPA_PASS,
f4b3ca72
JH
631 "visibility", /* name */
632 NULL, /* gate */
b20996ff 633 local_function_and_variable_visibility,/* execute */
f4b3ca72
JH
634 NULL, /* sub */
635 NULL, /* next */
636 0, /* static_pass_number */
637 TV_CGRAPHOPT, /* tv_id */
638 0, /* properties_required */
639 0, /* properties_provided */
640 0, /* properties_destroyed */
641 0, /* todo_flags_start */
49ba8180
JH
642 TODO_remove_functions | TODO_dump_cgraph
643 | TODO_ggc_collect /* todo_flags_finish */
8ddbbcae 644 }
f4b3ca72 645};
fed5ae11 646
b20996ff
JH
647/* Do not re-run on ltrans stage. */
648
649static bool
650gate_whole_program_function_and_variable_visibility (void)
651{
652 return !flag_ltrans;
653}
654
655/* Bring functionss local at LTO time whith -fwhole-program. */
656
657static unsigned int
658whole_program_function_and_variable_visibility (void)
659{
660 struct cgraph_node *node;
661 struct varpool_node *vnode;
662
663 function_and_variable_visibility (flag_whole_program);
664
665 for (node = cgraph_nodes; node; node = node->next)
62a0a52e
JH
666 if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
667 && node->local.finalized)
b20996ff
JH
668 cgraph_mark_needed_node (node);
669 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
62a0a52e 670 if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
b20996ff 671 varpool_mark_needed_node (vnode);
a8289259
JH
672 if (dump_file)
673 {
674 fprintf (dump_file, "\nNeeded variables:");
675 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
676 if (vnode->needed)
677 fprintf (dump_file, " %s", varpool_node_name (vnode));
678 fprintf (dump_file, "\n\n");
679 }
b20996ff
JH
680 return 0;
681}
682
683struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
684{
685 {
686 IPA_PASS,
687 "whole-program", /* name */
688 gate_whole_program_function_and_variable_visibility,/* gate */
689 whole_program_function_and_variable_visibility,/* execute */
690 NULL, /* sub */
691 NULL, /* next */
692 0, /* static_pass_number */
693 TV_CGRAPHOPT, /* tv_id */
694 0, /* properties_required */
695 0, /* properties_provided */
696 0, /* properties_destroyed */
697 0, /* todo_flags_start */
49ba8180
JH
698 TODO_remove_functions | TODO_dump_cgraph
699 | TODO_ggc_collect /* todo_flags_finish */
b20996ff
JH
700 },
701 NULL, /* generate_summary */
702 NULL, /* write_summary */
703 NULL, /* read_summary */
e792884f
JH
704 NULL, /* write_optimization_summary */
705 NULL, /* read_optimization_summary */
2c5721d9 706 NULL, /* stmt_fixup */
b20996ff
JH
707 0, /* TODOs */
708 NULL, /* function_transform */
709 NULL, /* variable_transform */
710};
fed5ae11
DK
711
712/* Hash a cgraph node set element. */
713
714static hashval_t
715hash_cgraph_node_set_element (const void *p)
716{
717 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
718 return htab_hash_pointer (element->node);
719}
720
721/* Compare two cgraph node set elements. */
722
723static int
724eq_cgraph_node_set_element (const void *p1, const void *p2)
725{
726 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
727 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
728
729 return e1->node == e2->node;
730}
731
732/* Create a new cgraph node set. */
733
734cgraph_node_set
735cgraph_node_set_new (void)
736{
737 cgraph_node_set new_node_set;
738
739 new_node_set = GGC_NEW (struct cgraph_node_set_def);
740 new_node_set->hashtab = htab_create_ggc (10,
741 hash_cgraph_node_set_element,
742 eq_cgraph_node_set_element,
743 NULL);
744 new_node_set->nodes = NULL;
745 return new_node_set;
746}
747
748/* Add cgraph_node NODE to cgraph_node_set SET. */
749
750void
751cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
752{
753 void **slot;
754 cgraph_node_set_element element;
755 struct cgraph_node_set_element_def dummy;
756
757 dummy.node = node;
758 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
759
760 if (*slot != HTAB_EMPTY_ENTRY)
761 {
762 element = (cgraph_node_set_element) *slot;
763 gcc_assert (node == element->node
764 && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
765 == node));
766 return;
767 }
768
769 /* Insert node into hash table. */
770 element =
771 (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
772 element->node = node;
773 element->index = VEC_length (cgraph_node_ptr, set->nodes);
774 *slot = element;
775
776 /* Insert into node vector. */
777 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
778}
779
780/* Remove cgraph_node NODE from cgraph_node_set SET. */
781
782void
783cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
784{
785 void **slot, **last_slot;
786 cgraph_node_set_element element, last_element;
787 struct cgraph_node *last_node;
788 struct cgraph_node_set_element_def dummy;
789
790 dummy.node = node;
791 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
792 if (slot == NULL)
793 return;
794
795 element = (cgraph_node_set_element) *slot;
796 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
797 == node);
798
799 /* Remove from vector. We do this by swapping node with the last element
800 of the vector. */
801 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
802 if (last_node != node)
803 {
804 dummy.node = last_node;
805 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
806 last_element = (cgraph_node_set_element) *last_slot;
807 gcc_assert (last_element);
808
809 /* Move the last element to the original spot of NODE. */
810 last_element->index = element->index;
811 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
812 last_node);
813 }
b8698a0f 814
fed5ae11
DK
815 /* Remove element from hash table. */
816 htab_clear_slot (set->hashtab, slot);
817 ggc_free (element);
818}
819
820/* Find NODE in SET and return an iterator to it if found. A null iterator
821 is returned if NODE is not in SET. */
822
823cgraph_node_set_iterator
824cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
825{
826 void **slot;
827 struct cgraph_node_set_element_def dummy;
828 cgraph_node_set_element element;
829 cgraph_node_set_iterator csi;
830
831 dummy.node = node;
832 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
833 if (slot == NULL)
834 csi.index = (unsigned) ~0;
835 else
836 {
837 element = (cgraph_node_set_element) *slot;
838 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
839 == node);
840 csi.index = element->index;
841 }
842 csi.set = set;
843
844 return csi;
845}
846
847/* Dump content of SET to file F. */
848
849void
850dump_cgraph_node_set (FILE *f, cgraph_node_set set)
851{
852 cgraph_node_set_iterator iter;
853
854 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
855 {
856 struct cgraph_node *node = csi_node (iter);
857 dump_cgraph_node (f, node);
858 }
859}
860
861/* Dump content of SET to stderr. */
862
863void
864debug_cgraph_node_set (cgraph_node_set set)
865{
866 dump_cgraph_node_set (stderr, set);
867}
868
2942c502
JH
869/* Hash a varpool node set element. */
870
871static hashval_t
872hash_varpool_node_set_element (const void *p)
873{
874 const_varpool_node_set_element element = (const_varpool_node_set_element) p;
875 return htab_hash_pointer (element->node);
876}
877
878/* Compare two varpool node set elements. */
879
880static int
881eq_varpool_node_set_element (const void *p1, const void *p2)
882{
883 const_varpool_node_set_element e1 = (const_varpool_node_set_element) p1;
884 const_varpool_node_set_element e2 = (const_varpool_node_set_element) p2;
885
886 return e1->node == e2->node;
887}
888
889/* Create a new varpool node set. */
890
891varpool_node_set
892varpool_node_set_new (void)
893{
894 varpool_node_set new_node_set;
895
896 new_node_set = GGC_NEW (struct varpool_node_set_def);
897 new_node_set->hashtab = htab_create_ggc (10,
898 hash_varpool_node_set_element,
899 eq_varpool_node_set_element,
900 NULL);
901 new_node_set->nodes = NULL;
902 return new_node_set;
903}
904
905/* Add varpool_node NODE to varpool_node_set SET. */
906
907void
908varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
909{
910 void **slot;
911 varpool_node_set_element element;
912 struct varpool_node_set_element_def dummy;
913
914 dummy.node = node;
915 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
916
917 if (*slot != HTAB_EMPTY_ENTRY)
918 {
919 element = (varpool_node_set_element) *slot;
920 gcc_assert (node == element->node
921 && (VEC_index (varpool_node_ptr, set->nodes, element->index)
922 == node));
923 return;
924 }
925
926 /* Insert node into hash table. */
927 element =
928 (varpool_node_set_element) GGC_NEW (struct varpool_node_set_element_def);
929 element->node = node;
930 element->index = VEC_length (varpool_node_ptr, set->nodes);
931 *slot = element;
932
933 /* Insert into node vector. */
934 VEC_safe_push (varpool_node_ptr, gc, set->nodes, node);
935}
936
937/* Remove varpool_node NODE from varpool_node_set SET. */
938
939void
940varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
941{
942 void **slot, **last_slot;
943 varpool_node_set_element element, last_element;
944 struct varpool_node *last_node;
945 struct varpool_node_set_element_def dummy;
946
947 dummy.node = node;
948 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
949 if (slot == NULL)
950 return;
951
952 element = (varpool_node_set_element) *slot;
953 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
954 == node);
955
956 /* Remove from vector. We do this by swapping node with the last element
957 of the vector. */
958 last_node = VEC_pop (varpool_node_ptr, set->nodes);
959 if (last_node != node)
960 {
961 dummy.node = last_node;
962 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
963 last_element = (varpool_node_set_element) *last_slot;
964 gcc_assert (last_element);
965
966 /* Move the last element to the original spot of NODE. */
967 last_element->index = element->index;
968 VEC_replace (varpool_node_ptr, set->nodes, last_element->index,
969 last_node);
970 }
971
972 /* Remove element from hash table. */
973 htab_clear_slot (set->hashtab, slot);
974 ggc_free (element);
975}
976
977/* Find NODE in SET and return an iterator to it if found. A null iterator
978 is returned if NODE is not in SET. */
979
980varpool_node_set_iterator
981varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
982{
983 void **slot;
984 struct varpool_node_set_element_def dummy;
985 varpool_node_set_element element;
986 varpool_node_set_iterator vsi;
987
988 dummy.node = node;
989 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
990 if (slot == NULL)
991 vsi.index = (unsigned) ~0;
992 else
993 {
994 element = (varpool_node_set_element) *slot;
995 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
996 == node);
997 vsi.index = element->index;
998 }
999 vsi.set = set;
1000
1001 return vsi;
1002}
1003
1004/* Dump content of SET to file F. */
1005
1006void
1007dump_varpool_node_set (FILE *f, varpool_node_set set)
1008{
1009 varpool_node_set_iterator iter;
1010
1011 for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
1012 {
1013 struct varpool_node *node = vsi_node (iter);
1014 dump_varpool_node (f, node);
1015 }
1016}
1017
1018/* Dump content of SET to stderr. */
1019
1020void
1021debug_varpool_node_set (varpool_node_set set)
1022{
1023 dump_varpool_node_set (stderr, set);
1024}
1025
1026
e65bb9be
JH
1027/* Simple ipa profile pass propagating frequencies across the callgraph. */
1028
1029static unsigned int
1030ipa_profile (void)
1031{
1032 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
1033 struct cgraph_edge *e;
1034 int order_pos;
1035 bool something_changed = false;
1036 int i;
1037
1038 order_pos = cgraph_postorder (order);
1039 for (i = order_pos - 1; i >= 0; i--)
1040 {
1041 if (order[i]->local.local && cgraph_propagate_frequency (order[i]))
1042 {
1043 for (e = order[i]->callees; e; e = e->next_callee)
1044 if (e->callee->local.local && !e->callee->aux)
1045 {
1046 something_changed = true;
1047 e->callee->aux = (void *)1;
1048 }
1049 }
1050 order[i]->aux = NULL;
1051 }
1052
1053 while (something_changed)
1054 {
1055 something_changed = false;
1056 for (i = order_pos - 1; i >= 0; i--)
1057 {
1058 if (order[i]->aux && cgraph_propagate_frequency (order[i]))
1059 {
1060 for (e = order[i]->callees; e; e = e->next_callee)
1061 if (e->callee->local.local && !e->callee->aux)
1062 {
1063 something_changed = true;
1064 e->callee->aux = (void *)1;
1065 }
1066 }
1067 order[i]->aux = NULL;
1068 }
1069 }
1070 free (order);
1071 return 0;
1072}
1073
1074static bool
1075gate_ipa_profile (void)
1076{
1077 return flag_ipa_profile;
1078}
1079
1080struct ipa_opt_pass_d pass_ipa_profile =
1081{
1082 {
1083 IPA_PASS,
1084 "ipa-profile", /* name */
1085 gate_ipa_profile, /* gate */
1086 ipa_profile, /* execute */
1087 NULL, /* sub */
1088 NULL, /* next */
1089 0, /* static_pass_number */
1090 TV_IPA_PROFILE, /* tv_id */
1091 0, /* properties_required */
1092 0, /* properties_provided */
1093 0, /* properties_destroyed */
1094 0, /* todo_flags_start */
1095 0 /* todo_flags_finish */
1096 },
1097 NULL, /* generate_summary */
1098 NULL, /* write_summary */
1099 NULL, /* read_summary */
1100 NULL, /* write_optimization_summary */
1101 NULL, /* read_optimization_summary */
1102 NULL, /* stmt_fixup */
1103 0, /* TODOs */
1104 NULL, /* function_transform */
1105 NULL /* variable_transform */
1106};