comparison gcc/ipa.c @ 55:77e2b8dfacca gcc-4.4.5

update it from 4.4.3 to 4.5.0
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Fri, 12 Feb 2010 23:39:51 +0900
parents a06113de4d67
children b7f97abdc517
comparison
equal deleted inserted replaced
52:c156f1bd5cd9 55:77e2b8dfacca
1 /* Basic IPA optimizations and utilities. 1 /* Basic IPA optimizations and utilities.
2 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, 2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
3 Inc. 3 Inc.
4 4
5 This file is part of GCC. 5 This file is part of GCC.
6 6
7 GCC is free software; you can redistribute it and/or modify it under 7 GCC is free software; you can redistribute it and/or modify it under
23 #include "coretypes.h" 23 #include "coretypes.h"
24 #include "tm.h" 24 #include "tm.h"
25 #include "cgraph.h" 25 #include "cgraph.h"
26 #include "tree-pass.h" 26 #include "tree-pass.h"
27 #include "timevar.h" 27 #include "timevar.h"
28 #include "gimple.h"
29 #include "ggc.h"
28 30
29 /* Fill array order with all nodes with output flag set in the reverse 31 /* Fill array order with all nodes with output flag set in the reverse
30 topological order. */ 32 topological order. */
31 33
32 int 34 int
34 { 36 {
35 struct cgraph_node *node, *node2; 37 struct cgraph_node *node, *node2;
36 int stack_size = 0; 38 int stack_size = 0;
37 int order_pos = 0; 39 int order_pos = 0;
38 struct cgraph_edge *edge, last; 40 struct cgraph_edge *edge, last;
41 int pass;
39 42
40 struct cgraph_node **stack = 43 struct cgraph_node **stack =
41 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); 44 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
42 45
43 /* We have to deal with cycles nicely, so use a depth first traversal 46 /* We have to deal with cycles nicely, so use a depth first traversal
44 output algorithm. Ignore the fact that some functions won't need 47 output algorithm. Ignore the fact that some functions won't need
45 to be output and put them into order as well, so we get dependencies 48 to be output and put them into order as well, so we get dependencies
46 right through inline functions. */ 49 right through inline functions. */
47 for (node = cgraph_nodes; node; node = node->next) 50 for (node = cgraph_nodes; node; node = node->next)
48 node->aux = NULL; 51 node->aux = NULL;
49 for (node = cgraph_nodes; node; node = node->next) 52 for (pass = 0; pass < 2; pass++)
50 if (!node->aux) 53 for (node = cgraph_nodes; node; node = node->next)
51 { 54 if (!node->aux
52 node2 = node; 55 && (pass
53 if (!node->callers) 56 || (!cgraph_only_called_directly_p (node)
54 node->aux = &last; 57 && !node->address_taken)))
55 else 58 {
56 node->aux = node->callers; 59 node2 = node;
57 while (node2) 60 if (!node->callers)
58 { 61 node->aux = &last;
59 while (node2->aux != &last) 62 else
60 { 63 node->aux = node->callers;
61 edge = (struct cgraph_edge *) node2->aux; 64 while (node2)
62 if (edge->next_caller) 65 {
63 node2->aux = edge->next_caller; 66 while (node2->aux != &last)
64 else 67 {
65 node2->aux = &last; 68 edge = (struct cgraph_edge *) node2->aux;
66 if (!edge->caller->aux) 69 if (edge->next_caller)
67 { 70 node2->aux = edge->next_caller;
68 if (!edge->caller->callers) 71 else
69 edge->caller->aux = &last; 72 node2->aux = &last;
70 else 73 if (!edge->caller->aux)
71 edge->caller->aux = edge->caller->callers; 74 {
72 stack[stack_size++] = node2; 75 if (!edge->caller->callers)
73 node2 = edge->caller; 76 edge->caller->aux = &last;
74 break; 77 else
75 } 78 edge->caller->aux = edge->caller->callers;
76 } 79 stack[stack_size++] = node2;
77 if (node2->aux == &last) 80 node2 = edge->caller;
78 { 81 break;
79 order[order_pos++] = node2; 82 }
80 if (stack_size) 83 }
81 node2 = stack[--stack_size]; 84 if (node2->aux == &last)
82 else 85 {
83 node2 = NULL; 86 order[order_pos++] = node2;
84 } 87 if (stack_size)
85 } 88 node2 = stack[--stack_size];
86 } 89 else
90 node2 = NULL;
91 }
92 }
93 }
87 free (stack); 94 free (stack);
88 for (node = cgraph_nodes; node; node = node->next) 95 for (node = cgraph_nodes; node; node = node->next)
89 node->aux = NULL; 96 node->aux = NULL;
90 return order_pos; 97 return order_pos;
91 } 98 }
92 99
100 /* Look for all functions inlined to NODE and update their inlined_to pointers
101 to INLINED_TO. */
102
103 static void
104 update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
105 {
106 struct cgraph_edge *e;
107 for (e = node->callees; e; e = e->next_callee)
108 if (e->callee->global.inlined_to)
109 {
110 e->callee->global.inlined_to = inlined_to;
111 update_inlined_to_pointer (e->callee, inlined_to);
112 }
113 }
114
93 /* Perform reachability analysis and reclaim all unreachable nodes. 115 /* Perform reachability analysis and reclaim all unreachable nodes.
94 If BEFORE_INLINING_P is true this function is called before inlining 116 If BEFORE_INLINING_P is true this function is called before inlining
95 decisions has been made. If BEFORE_INLINING_P is false this function also 117 decisions has been made. If BEFORE_INLINING_P is false this function also
96 removes unneeded bodies of extern inline functions. */ 118 removes unneeded bodies of extern inline functions. */
97 119
98 bool 120 bool
99 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) 121 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
100 { 122 {
101 struct cgraph_node *first = (struct cgraph_node *) (void *) 1; 123 struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
124 struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
102 struct cgraph_node *node, *next; 125 struct cgraph_node *node, *next;
103 bool changed = false; 126 bool changed = false;
104 127
105 #ifdef ENABLE_CHECKING 128 #ifdef ENABLE_CHECKING
106 verify_cgraph (); 129 verify_cgraph ();
110 #ifdef ENABLE_CHECKING 133 #ifdef ENABLE_CHECKING
111 for (node = cgraph_nodes; node; node = node->next) 134 for (node = cgraph_nodes; node; node = node->next)
112 gcc_assert (!node->aux); 135 gcc_assert (!node->aux);
113 #endif 136 #endif
114 for (node = cgraph_nodes; node; node = node->next) 137 for (node = cgraph_nodes; node; node = node->next)
115 if (node->needed && !node->global.inlined_to 138 if (!cgraph_can_remove_if_no_direct_calls_p (node)
116 && ((!DECL_EXTERNAL (node->decl)) 139 && ((!DECL_EXTERNAL (node->decl))
117 || !node->analyzed 140 || !node->analyzed
118 || before_inlining_p)) 141 || before_inlining_p))
119 { 142 {
143 gcc_assert (!node->global.inlined_to);
120 node->aux = first; 144 node->aux = first;
121 first = node; 145 first = node;
146 node->reachable = true;
122 } 147 }
123 else 148 else
124 gcc_assert (!node->aux); 149 {
150 gcc_assert (!node->aux);
151 node->reachable = false;
152 }
125 153
126 /* Perform reachability analysis. As a special case do not consider 154 /* Perform reachability analysis. As a special case do not consider
127 extern inline functions not inlined as live because we won't output 155 extern inline functions not inlined as live because we won't output
128 them at all. */ 156 them at all. */
129 while (first != (void *) 1) 157 while (first != (void *) 1)
130 { 158 {
131 struct cgraph_edge *e; 159 struct cgraph_edge *e;
132 node = first; 160 node = first;
133 first = (struct cgraph_node *) first->aux; 161 first = (struct cgraph_node *) first->aux;
134 162 node->aux = processed;
135 for (e = node->callees; e; e = e->next_callee) 163
136 if (!e->callee->aux 164 if (node->reachable)
137 && node->analyzed 165 for (e = node->callees; e; e = e->next_callee)
138 && (!e->inline_failed || !e->callee->analyzed 166 if (!e->callee->reachable
139 || (!DECL_EXTERNAL (e->callee->decl)) 167 && node->analyzed
140 || before_inlining_p)) 168 && (!e->inline_failed || !e->callee->analyzed
141 { 169 || (!DECL_EXTERNAL (e->callee->decl))
142 e->callee->aux = first; 170 || before_inlining_p))
143 first = e->callee; 171 {
144 } 172 bool prev_reachable = e->callee->reachable;
173 e->callee->reachable |= node->reachable;
174 if (!e->callee->aux
175 || (e->callee->aux == processed
176 && prev_reachable != e->callee->reachable))
177 {
178 e->callee->aux = first;
179 first = e->callee;
180 }
181 }
182
183 /* If any function in a comdat group is reachable, force
184 all other functions in the same comdat group to be
185 also reachable. */
186 if (node->same_comdat_group
187 && node->reachable
188 && !node->global.inlined_to)
189 {
190 for (next = node->same_comdat_group;
191 next != node;
192 next = next->same_comdat_group)
193 if (!next->reachable)
194 {
195 next->aux = first;
196 first = next;
197 next->reachable = true;
198 }
199 }
200
201 /* We can freely remove inline clones even if they are cloned, however if
202 function is clone of real clone, we must keep it around in order to
203 make materialize_clones produce function body with the changes
204 applied. */
205 while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
206 {
207 bool noninline = node->clone_of->decl != node->decl;
208 node = node->clone_of;
209 if (noninline)
210 {
211 node->aux = first;
212 first = node;
213 break;
214 }
215 }
145 } 216 }
146 217
147 /* Remove unreachable nodes. Extern inline functions need special care; 218 /* Remove unreachable nodes. Extern inline functions need special care;
148 Unreachable extern inline functions shall be removed. 219 Unreachable extern inline functions shall be removed.
149 Reachable extern inline functions we never inlined shall get their bodies 220 Reachable extern inline functions we never inlined shall get their bodies
153 of code. Body of such functions is released via remove_node once the 224 of code. Body of such functions is released via remove_node once the
154 inline clones are eliminated. */ 225 inline clones are eliminated. */
155 for (node = cgraph_nodes; node; node = next) 226 for (node = cgraph_nodes; node; node = next)
156 { 227 {
157 next = node->next; 228 next = node->next;
229 if (node->aux && !node->reachable)
230 {
231 cgraph_node_remove_callees (node);
232 node->analyzed = false;
233 node->local.inlinable = false;
234 }
158 if (!node->aux) 235 if (!node->aux)
159 { 236 {
160 node->global.inlined_to = NULL; 237 node->global.inlined_to = NULL;
161 if (file) 238 if (file)
162 fprintf (file, " %s", cgraph_node_name (node)); 239 fprintf (file, " %s", cgraph_node_name (node));
163 if (!node->analyzed || !DECL_EXTERNAL (node->decl) 240 if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
164 || before_inlining_p)
165 cgraph_remove_node (node); 241 cgraph_remove_node (node);
166 else 242 else
167 { 243 {
168 struct cgraph_edge *e; 244 struct cgraph_edge *e;
169 245
246 /* See if there is reachable caller. */
170 for (e = node->callers; e; e = e->next_caller) 247 for (e = node->callers; e; e = e->next_caller)
171 if (e->caller->aux) 248 if (e->caller->aux)
172 break; 249 break;
250
251 /* If so, we need to keep node in the callgraph. */
173 if (e || node->needed) 252 if (e || node->needed)
174 { 253 {
175 struct cgraph_node *clone; 254 struct cgraph_node *clone;
176 255
177 for (clone = node->next_clone; clone; 256 /* If there are still clones, we must keep body around.
178 clone = clone->next_clone) 257 Otherwise we can just remove the body but keep the clone. */
258 for (clone = node->clones; clone;
259 clone = clone->next_sibling_clone)
179 if (clone->aux) 260 if (clone->aux)
180 break; 261 break;
181 if (!clone) 262 if (!clone)
182 { 263 {
183 cgraph_release_function_body (node); 264 cgraph_release_function_body (node);
265 cgraph_node_remove_callees (node);
184 node->analyzed = false; 266 node->analyzed = false;
267 node->local.inlinable = false;
185 } 268 }
186 cgraph_node_remove_callees (node); 269 if (node->prev_sibling_clone)
187 node->analyzed = false; 270 node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
188 node->local.inlinable = false; 271 else if (node->clone_of)
272 node->clone_of->clones = node->next_sibling_clone;
273 if (node->next_sibling_clone)
274 node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
275 node->clone_of = NULL;
276 node->next_sibling_clone = NULL;
277 node->prev_sibling_clone = NULL;
189 } 278 }
190 else 279 else
191 cgraph_remove_node (node); 280 cgraph_remove_node (node);
192 } 281 }
193 changed = true; 282 changed = true;
194 } 283 }
195 } 284 }
196 for (node = cgraph_nodes; node; node = node->next) 285 for (node = cgraph_nodes; node; node = node->next)
197 node->aux = NULL; 286 {
287 /* Inline clones might be kept around so their materializing allows further
288 cloning. If the function the clone is inlined into is removed, we need
289 to turn it into normal cone. */
290 if (node->global.inlined_to
291 && !node->callers)
292 {
293 gcc_assert (node->clones);
294 node->global.inlined_to = NULL;
295 update_inlined_to_pointer (node, node);
296 }
297 node->aux = NULL;
298 }
198 #ifdef ENABLE_CHECKING 299 #ifdef ENABLE_CHECKING
199 verify_cgraph (); 300 verify_cgraph ();
200 #endif 301 #endif
302
303 /* Reclaim alias pairs for functions that have disappeared from the
304 call graph. */
305 remove_unreachable_alias_pairs ();
306
201 return changed; 307 return changed;
308 }
309
310 static bool
311 cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
312 {
313 if (!node->local.finalized)
314 return false;
315 if (!DECL_COMDAT (node->decl)
316 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
317 return false;
318 if (!whole_program)
319 return true;
320 /* COMDAT functions must be shared only if they have address taken,
321 otherwise we can produce our own private implementation with
322 -fwhole-program. */
323 if (DECL_COMDAT (node->decl))
324 {
325 if (node->address_taken || !node->analyzed)
326 return true;
327 if (node->same_comdat_group)
328 {
329 struct cgraph_node *next;
330
331 /* If more than one function is in the same COMDAT group, it must
332 be shared even if just one function in the comdat group has
333 address taken. */
334 for (next = node->same_comdat_group;
335 next != node;
336 next = next->same_comdat_group)
337 if (next->address_taken || !next->analyzed)
338 return true;
339 }
340 }
341 if (MAIN_NAME_P (DECL_NAME (node->decl)))
342 return true;
343 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
344 return true;
345 return false;
202 } 346 }
203 347
204 /* Mark visibility of all functions. 348 /* Mark visibility of all functions.
205 349
206 A local function is one whose calls can occur only in the current 350 A local function is one whose calls can occur only in the current
211 We also change the TREE_PUBLIC flag of all declarations that are public 355 We also change the TREE_PUBLIC flag of all declarations that are public
212 in language point of view but we want to overwrite this default 356 in language point of view but we want to overwrite this default
213 via visibilities for the backend point of view. */ 357 via visibilities for the backend point of view. */
214 358
215 static unsigned int 359 static unsigned int
216 function_and_variable_visibility (void) 360 function_and_variable_visibility (bool whole_program)
217 { 361 {
218 struct cgraph_node *node; 362 struct cgraph_node *node;
219 struct varpool_node *vnode; 363 struct varpool_node *vnode;
220 364
221 for (node = cgraph_nodes; node; node = node->next) 365 for (node = cgraph_nodes; node; node = node->next)
222 { 366 {
223 if (node->reachable 367 /* C++ FE on lack of COMDAT support create local COMDAT functions
224 && (DECL_COMDAT (node->decl) 368 (that ought to be shared but can not due to object format
225 || (!flag_whole_program 369 limitations). It is neccesary to keep the flag to make rest of C++ FE
226 && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl)))) 370 happy. Clear the flag here to avoid confusion in middle-end. */
227 node->local.externally_visible = true; 371 if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
372 DECL_COMDAT (node->decl) = 0;
373 /* For external decls stop tracking same_comdat_group, it doesn't matter
374 what comdat group they are in when they won't be emitted in this TU,
375 and simplifies later passes. */
376 if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
377 {
378 struct cgraph_node *n = node, *next;
379 do
380 {
381 /* If at least one of same comdat group functions is external,
382 all of them have to be, otherwise it is a front-end bug. */
383 gcc_assert (DECL_EXTERNAL (n->decl));
384 next = n->same_comdat_group;
385 n->same_comdat_group = NULL;
386 n = next;
387 }
388 while (n != node);
389 }
390 gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
391 || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
392 if (cgraph_externally_visible_p (node, whole_program))
393 {
394 gcc_assert (!node->global.inlined_to);
395 node->local.externally_visible = true;
396 }
397 else
398 node->local.externally_visible = false;
228 if (!node->local.externally_visible && node->analyzed 399 if (!node->local.externally_visible && node->analyzed
229 && !DECL_EXTERNAL (node->decl)) 400 && !DECL_EXTERNAL (node->decl))
230 { 401 {
231 gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl)); 402 gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
232 TREE_PUBLIC (node->decl) = 0; 403 TREE_PUBLIC (node->decl) = 0;
233 } 404 DECL_COMDAT (node->decl) = 0;
234 node->local.local = (!node->needed 405 DECL_WEAK (node->decl) = 0;
406 }
407 node->local.local = (cgraph_only_called_directly_p (node)
235 && node->analyzed 408 && node->analyzed
236 && !DECL_EXTERNAL (node->decl) 409 && !DECL_EXTERNAL (node->decl)
237 && !node->local.externally_visible); 410 && !node->local.externally_visible);
238 } 411 }
239 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) 412 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
240 { 413 {
414 if (!vnode->finalized)
415 continue;
416 gcc_assert ((!DECL_WEAK (vnode->decl) && !DECL_COMMON (vnode->decl))
417 || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
241 if (vnode->needed 418 if (vnode->needed
242 && !flag_whole_program 419 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
243 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))) 420 && (!whole_program
244 vnode->externally_visible = 1; 421 /* We can privatize comdat readonly variables whose address is not taken,
422 but doing so is not going to bring us optimization oppurtunities until
423 we start reordering datastructures. */
424 || DECL_COMDAT (vnode->decl)
425 || DECL_WEAK (vnode->decl)
426 || lookup_attribute ("externally_visible",
427 DECL_ATTRIBUTES (vnode->decl))))
428 vnode->externally_visible = true;
429 else
430 vnode->externally_visible = false;
245 if (!vnode->externally_visible) 431 if (!vnode->externally_visible)
246 { 432 {
247 gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl)); 433 gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
248 TREE_PUBLIC (vnode->decl) = 0; 434 TREE_PUBLIC (vnode->decl) = 0;
435 DECL_COMMON (vnode->decl) = 0;
249 } 436 }
250 gcc_assert (TREE_STATIC (vnode->decl)); 437 gcc_assert (TREE_STATIC (vnode->decl));
251 } 438 }
252 439
253 if (dump_file) 440 if (dump_file)
260 fprintf (dump_file, "\nMarking externally visible functions:"); 447 fprintf (dump_file, "\nMarking externally visible functions:");
261 for (node = cgraph_nodes; node; node = node->next) 448 for (node = cgraph_nodes; node; node = node->next)
262 if (node->local.externally_visible) 449 if (node->local.externally_visible)
263 fprintf (dump_file, " %s", cgraph_node_name (node)); 450 fprintf (dump_file, " %s", cgraph_node_name (node));
264 fprintf (dump_file, "\n\n"); 451 fprintf (dump_file, "\n\n");
452 fprintf (dump_file, "\nMarking externally visible variables:");
453 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
454 if (vnode->externally_visible)
455 fprintf (dump_file, " %s", varpool_node_name (vnode));
456 fprintf (dump_file, "\n\n");
265 } 457 }
266 cgraph_function_flags_ready = true; 458 cgraph_function_flags_ready = true;
267 return 0; 459 return 0;
268 } 460 }
269 461
270 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = 462 /* Local function pass handling visibilities. This happens before LTO streaming
463 so in particular -fwhole-program should be ignored at this level. */
464
465 static unsigned int
466 local_function_and_variable_visibility (void)
467 {
468 return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
469 }
470
471 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
271 { 472 {
272 { 473 {
273 SIMPLE_IPA_PASS, 474 SIMPLE_IPA_PASS,
274 "visibility", /* name */ 475 "visibility", /* name */
275 NULL, /* gate */ 476 NULL, /* gate */
276 function_and_variable_visibility, /* execute */ 477 local_function_and_variable_visibility,/* execute */
277 NULL, /* sub */ 478 NULL, /* sub */
278 NULL, /* next */ 479 NULL, /* next */
279 0, /* static_pass_number */ 480 0, /* static_pass_number */
280 TV_CGRAPHOPT, /* tv_id */ 481 TV_CGRAPHOPT, /* tv_id */
281 0, /* properties_required */ 482 0, /* properties_required */
283 0, /* properties_destroyed */ 484 0, /* properties_destroyed */
284 0, /* todo_flags_start */ 485 0, /* todo_flags_start */
285 TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */ 486 TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
286 } 487 }
287 }; 488 };
489
490 /* Do not re-run on ltrans stage. */
491
492 static bool
493 gate_whole_program_function_and_variable_visibility (void)
494 {
495 return !flag_ltrans;
496 }
497
498 /* Bring functionss local at LTO time whith -fwhole-program. */
499
500 static unsigned int
501 whole_program_function_and_variable_visibility (void)
502 {
503 struct cgraph_node *node;
504 struct varpool_node *vnode;
505
506 function_and_variable_visibility (flag_whole_program);
507
508 for (node = cgraph_nodes; node; node = node->next)
509 if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
510 && node->local.finalized)
511 cgraph_mark_needed_node (node);
512 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
513 if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
514 varpool_mark_needed_node (vnode);
515 if (dump_file)
516 {
517 fprintf (dump_file, "\nNeeded variables:");
518 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
519 if (vnode->needed)
520 fprintf (dump_file, " %s", varpool_node_name (vnode));
521 fprintf (dump_file, "\n\n");
522 }
523 return 0;
524 }
525
526 struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
527 {
528 {
529 IPA_PASS,
530 "whole-program", /* name */
531 gate_whole_program_function_and_variable_visibility,/* gate */
532 whole_program_function_and_variable_visibility,/* execute */
533 NULL, /* sub */
534 NULL, /* next */
535 0, /* static_pass_number */
536 TV_CGRAPHOPT, /* tv_id */
537 0, /* properties_required */
538 0, /* properties_provided */
539 0, /* properties_destroyed */
540 0, /* todo_flags_start */
541 TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
542 },
543 NULL, /* generate_summary */
544 NULL, /* write_summary */
545 NULL, /* read_summary */
546 NULL, /* function_read_summary */
547 NULL, /* stmt_fixup */
548 0, /* TODOs */
549 NULL, /* function_transform */
550 NULL, /* variable_transform */
551 };
552
553 /* Hash a cgraph node set element. */
554
555 static hashval_t
556 hash_cgraph_node_set_element (const void *p)
557 {
558 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
559 return htab_hash_pointer (element->node);
560 }
561
562 /* Compare two cgraph node set elements. */
563
564 static int
565 eq_cgraph_node_set_element (const void *p1, const void *p2)
566 {
567 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
568 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
569
570 return e1->node == e2->node;
571 }
572
573 /* Create a new cgraph node set. */
574
575 cgraph_node_set
576 cgraph_node_set_new (void)
577 {
578 cgraph_node_set new_node_set;
579
580 new_node_set = GGC_NEW (struct cgraph_node_set_def);
581 new_node_set->hashtab = htab_create_ggc (10,
582 hash_cgraph_node_set_element,
583 eq_cgraph_node_set_element,
584 NULL);
585 new_node_set->nodes = NULL;
586 return new_node_set;
587 }
588
589 /* Add cgraph_node NODE to cgraph_node_set SET. */
590
591 void
592 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
593 {
594 void **slot;
595 cgraph_node_set_element element;
596 struct cgraph_node_set_element_def dummy;
597
598 dummy.node = node;
599 slot = htab_find_slot (set->hashtab, &dummy, INSERT);
600
601 if (*slot != HTAB_EMPTY_ENTRY)
602 {
603 element = (cgraph_node_set_element) *slot;
604 gcc_assert (node == element->node
605 && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
606 == node));
607 return;
608 }
609
610 /* Insert node into hash table. */
611 element =
612 (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
613 element->node = node;
614 element->index = VEC_length (cgraph_node_ptr, set->nodes);
615 *slot = element;
616
617 /* Insert into node vector. */
618 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
619 }
620
621 /* Remove cgraph_node NODE from cgraph_node_set SET. */
622
623 void
624 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
625 {
626 void **slot, **last_slot;
627 cgraph_node_set_element element, last_element;
628 struct cgraph_node *last_node;
629 struct cgraph_node_set_element_def dummy;
630
631 dummy.node = node;
632 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
633 if (slot == NULL)
634 return;
635
636 element = (cgraph_node_set_element) *slot;
637 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
638 == node);
639
640 /* Remove from vector. We do this by swapping node with the last element
641 of the vector. */
642 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
643 if (last_node != node)
644 {
645 dummy.node = last_node;
646 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
647 last_element = (cgraph_node_set_element) *last_slot;
648 gcc_assert (last_element);
649
650 /* Move the last element to the original spot of NODE. */
651 last_element->index = element->index;
652 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
653 last_node);
654 }
655
656 /* Remove element from hash table. */
657 htab_clear_slot (set->hashtab, slot);
658 ggc_free (element);
659 }
660
661 /* Find NODE in SET and return an iterator to it if found. A null iterator
662 is returned if NODE is not in SET. */
663
664 cgraph_node_set_iterator
665 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
666 {
667 void **slot;
668 struct cgraph_node_set_element_def dummy;
669 cgraph_node_set_element element;
670 cgraph_node_set_iterator csi;
671
672 dummy.node = node;
673 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
674 if (slot == NULL)
675 csi.index = (unsigned) ~0;
676 else
677 {
678 element = (cgraph_node_set_element) *slot;
679 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
680 == node);
681 csi.index = element->index;
682 }
683 csi.set = set;
684
685 return csi;
686 }
687
688 /* Dump content of SET to file F. */
689
690 void
691 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
692 {
693 cgraph_node_set_iterator iter;
694
695 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
696 {
697 struct cgraph_node *node = csi_node (iter);
698 dump_cgraph_node (f, node);
699 }
700 }
701
702 /* Dump content of SET to stderr. */
703
704 void
705 debug_cgraph_node_set (cgraph_node_set set)
706 {
707 dump_cgraph_node_set (stderr, set);
708 }
709