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