Mercurial > hg > CbC > CbC_gcc
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 |