Mercurial > hg > CbC > CbC_gcc
comparison gcc/ipa.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Basic IPA optimizations and utilities. | 1 /* Basic IPA optimizations and utilities. |
2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 | 2 Copyright (C) 2003-2017 Free Software Foundation, Inc. |
3 Free Software Foundation, Inc. | |
4 | 3 |
5 This file is part of GCC. | 4 This file is part of GCC. |
6 | 5 |
7 GCC is free software; you can redistribute it and/or modify it under | 6 GCC is free software; you can redistribute it and/or modify it under |
8 the terms of the GNU General Public License as published by the Free | 7 the terms of the GNU General Public License as published by the Free |
19 <http://www.gnu.org/licenses/>. */ | 18 <http://www.gnu.org/licenses/>. */ |
20 | 19 |
21 #include "config.h" | 20 #include "config.h" |
22 #include "system.h" | 21 #include "system.h" |
23 #include "coretypes.h" | 22 #include "coretypes.h" |
24 #include "tm.h" | 23 #include "backend.h" |
24 #include "target.h" | |
25 #include "tree.h" | |
26 #include "gimple.h" | |
27 #include "alloc-pool.h" | |
28 #include "tree-pass.h" | |
29 #include "stringpool.h" | |
25 #include "cgraph.h" | 30 #include "cgraph.h" |
26 #include "tree-pass.h" | 31 #include "gimplify.h" |
27 #include "timevar.h" | |
28 #include "gimple.h" | |
29 #include "ggc.h" | |
30 #include "flags.h" | |
31 #include "pointer-set.h" | |
32 #include "target.h" | |
33 #include "tree-iterator.h" | 32 #include "tree-iterator.h" |
34 | 33 #include "ipa-utils.h" |
35 /* Fill array order with all nodes with output flag set in the reverse | 34 #include "symbol-summary.h" |
36 topological order. */ | 35 #include "tree-vrp.h" |
37 | 36 #include "ipa-prop.h" |
38 int | 37 #include "ipa-fnsummary.h" |
39 cgraph_postorder (struct cgraph_node **order) | 38 #include "dbgcnt.h" |
40 { | 39 #include "debug.h" |
41 struct cgraph_node *node, *node2; | 40 #include "stringpool.h" |
42 int stack_size = 0; | 41 #include "attribs.h" |
43 int order_pos = 0; | 42 |
44 struct cgraph_edge *edge, last; | 43 /* Return true when NODE has ADDR reference. */ |
45 int pass; | 44 |
46 | 45 static bool |
47 struct cgraph_node **stack = | 46 has_addr_references_p (struct cgraph_node *node, |
48 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | 47 void *) |
49 | 48 { |
50 /* We have to deal with cycles nicely, so use a depth first traversal | 49 int i; |
51 output algorithm. Ignore the fact that some functions won't need | 50 struct ipa_ref *ref = NULL; |
52 to be output and put them into order as well, so we get dependencies | 51 |
53 right through inline functions. */ | 52 for (i = 0; node->iterate_referring (i, ref); i++) |
54 for (node = cgraph_nodes; node; node = node->next) | 53 if (ref->use == IPA_REF_ADDR) |
55 node->aux = NULL; | 54 return true; |
56 for (pass = 0; pass < 2; pass++) | 55 return false; |
57 for (node = cgraph_nodes; node; node = node->next) | 56 } |
58 if (!node->aux | 57 |
59 && (pass | 58 /* Return true when NODE can be target of an indirect call. */ |
60 || (!node->address_taken | 59 |
61 && !node->global.inlined_to | 60 static bool |
62 && !cgraph_only_called_directly_p (node)))) | 61 is_indirect_call_target_p (struct cgraph_node *node, void *) |
63 { | 62 { |
64 node2 = node; | 63 return node->indirect_call_target; |
65 if (!node->callers) | |
66 node->aux = &last; | |
67 else | |
68 node->aux = node->callers; | |
69 while (node2) | |
70 { | |
71 while (node2->aux != &last) | |
72 { | |
73 edge = (struct cgraph_edge *) node2->aux; | |
74 if (edge->next_caller) | |
75 node2->aux = edge->next_caller; | |
76 else | |
77 node2->aux = &last; | |
78 /* Break possible cycles involving always-inline | |
79 functions by ignoring edges from always-inline | |
80 functions to non-always-inline functions. */ | |
81 if (edge->caller->local.disregard_inline_limits | |
82 && !edge->callee->local.disregard_inline_limits) | |
83 continue; | |
84 if (!edge->caller->aux) | |
85 { | |
86 if (!edge->caller->callers) | |
87 edge->caller->aux = &last; | |
88 else | |
89 edge->caller->aux = edge->caller->callers; | |
90 stack[stack_size++] = node2; | |
91 node2 = edge->caller; | |
92 break; | |
93 } | |
94 } | |
95 if (node2->aux == &last) | |
96 { | |
97 order[order_pos++] = node2; | |
98 if (stack_size) | |
99 node2 = stack[--stack_size]; | |
100 else | |
101 node2 = NULL; | |
102 } | |
103 } | |
104 } | |
105 free (stack); | |
106 for (node = cgraph_nodes; node; node = node->next) | |
107 node->aux = NULL; | |
108 return order_pos; | |
109 } | 64 } |
110 | 65 |
111 /* Look for all functions inlined to NODE and update their inlined_to pointers | 66 /* Look for all functions inlined to NODE and update their inlined_to pointers |
112 to INLINED_TO. */ | 67 to INLINED_TO. */ |
113 | 68 |
121 e->callee->global.inlined_to = inlined_to; | 76 e->callee->global.inlined_to = inlined_to; |
122 update_inlined_to_pointer (e->callee, inlined_to); | 77 update_inlined_to_pointer (e->callee, inlined_to); |
123 } | 78 } |
124 } | 79 } |
125 | 80 |
126 /* Add cgraph NODE to queue starting at FIRST. | 81 /* Add symtab NODE to queue starting at FIRST. |
127 | 82 |
128 The queue is linked via AUX pointers and terminated by pointer to 1. | 83 The queue is linked via AUX pointers and terminated by pointer to 1. |
129 We enqueue nodes at two occasions: when we find them reachable or when we find | 84 We enqueue nodes at two occasions: when we find them reachable or when we find |
130 their bodies needed for further clonning. In the second case we mark them | 85 their bodies needed for further clonning. In the second case we mark them |
131 by pointer to 2 after processing so they are re-queue when they become | 86 by pointer to 2 after processing so they are re-queue when they become |
132 reachable. */ | 87 reachable. */ |
133 | 88 |
134 static void | 89 static void |
135 enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first) | 90 enqueue_node (symtab_node *node, symtab_node **first, |
91 hash_set<symtab_node *> *reachable) | |
136 { | 92 { |
137 /* Node is still in queue; do nothing. */ | 93 /* Node is still in queue; do nothing. */ |
138 if (node->aux && node->aux != (void *) 2) | 94 if (node->aux && node->aux != (void *) 2) |
139 return; | 95 return; |
140 /* Node was already processed as unreachable, re-enqueue | 96 /* Node was already processed as unreachable, re-enqueue |
141 only if it became reachable now. */ | 97 only if it became reachable now. */ |
142 if (node->aux == (void *)2 && !node->reachable) | 98 if (node->aux == (void *)2 && !reachable->contains (node)) |
143 return; | 99 return; |
144 node->aux = *first; | 100 node->aux = *first; |
145 *first = node; | 101 *first = node; |
146 } | 102 } |
147 | 103 |
148 /* Add varpool NODE to queue starting at FIRST. */ | 104 /* Process references. */ |
149 | 105 |
150 static void | 106 static void |
151 enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first) | 107 process_references (symtab_node *snode, |
152 { | 108 symtab_node **first, |
153 node->aux = *first; | 109 bool before_inlining_p, |
154 *first = node; | 110 hash_set<symtab_node *> *reachable) |
155 } | 111 { |
156 | 112 int i; |
157 /* Process references. */ | 113 struct ipa_ref *ref = NULL; |
114 for (i = 0; snode->iterate_reference (i, ref); i++) | |
115 { | |
116 symtab_node *node = ref->referred; | |
117 symtab_node *body = node->ultimate_alias_target (); | |
118 | |
119 if (node->definition && !node->in_other_partition | |
120 && ((!DECL_EXTERNAL (node->decl) || node->alias) | |
121 || (((before_inlining_p | |
122 && (TREE_CODE (node->decl) != FUNCTION_DECL | |
123 || (TREE_CODE (node->decl) == FUNCTION_DECL | |
124 && opt_for_fn (body->decl, optimize)) | |
125 || (symtab->state < IPA_SSA | |
126 && lookup_attribute | |
127 ("always_inline", | |
128 DECL_ATTRIBUTES (body->decl)))))) | |
129 /* We use variable constructors during late compilation for | |
130 constant folding. Keep references alive so partitioning | |
131 knows about potential references. */ | |
132 || (VAR_P (node->decl) | |
133 && flag_wpa | |
134 && ctor_for_folding (node->decl) | |
135 != error_mark_node)))) | |
136 { | |
137 /* Be sure that we will not optimize out alias target | |
138 body. */ | |
139 if (DECL_EXTERNAL (node->decl) | |
140 && node->alias | |
141 && before_inlining_p) | |
142 reachable->add (body); | |
143 reachable->add (node); | |
144 } | |
145 enqueue_node (node, first, reachable); | |
146 } | |
147 } | |
148 | |
149 /* EDGE is an polymorphic call. If BEFORE_INLINING_P is set, mark | |
150 all its potential targets as reachable to permit later inlining if | |
151 devirtualization happens. After inlining still keep their declarations | |
152 around, so we can devirtualize to a direct call. | |
153 | |
154 Also try to make trivial devirutalization when no or only one target is | |
155 possible. */ | |
158 | 156 |
159 static void | 157 static void |
160 process_references (struct ipa_ref_list *list, | 158 walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets, |
161 struct cgraph_node **first, | 159 struct cgraph_edge *edge, |
162 struct varpool_node **first_varpool, | 160 symtab_node **first, |
163 bool before_inlining_p) | 161 hash_set<symtab_node *> *reachable, |
164 { | 162 bool before_inlining_p) |
165 int i; | 163 { |
166 struct ipa_ref *ref; | 164 unsigned int i; |
167 for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) | 165 void *cache_token; |
168 { | 166 bool final; |
169 if (ref->refered_type == IPA_REF_CGRAPH) | 167 vec <cgraph_node *>targets |
170 { | 168 = possible_polymorphic_call_targets |
171 struct cgraph_node *node = ipa_ref_node (ref); | 169 (edge, &final, &cache_token); |
172 if (!node->reachable | 170 |
173 && node->analyzed | 171 if (!reachable_call_targets->add (cache_token)) |
174 && (!DECL_EXTERNAL (node->decl) | 172 { |
175 || before_inlining_p)) | 173 for (i = 0; i < targets.length (); i++) |
176 node->reachable = true; | 174 { |
177 enqueue_cgraph_node (node, first); | 175 struct cgraph_node *n = targets[i]; |
178 } | 176 |
179 else | 177 /* Do not bother to mark virtual methods in anonymous namespace; |
180 { | 178 either we will find use of virtual table defining it, or it is |
181 struct varpool_node *node = ipa_ref_varpool_node (ref); | 179 unused. */ |
182 if (!node->needed) | 180 if (TREE_CODE (TREE_TYPE (n->decl)) == METHOD_TYPE |
181 && type_in_anonymous_namespace_p | |
182 (TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl)))) | |
183 continue; | |
184 | |
185 n->indirect_call_target = true; | |
186 symtab_node *body = n->function_symbol (); | |
187 | |
188 /* Prior inlining, keep alive bodies of possible targets for | |
189 devirtualization. */ | |
190 if (n->definition | |
191 && (before_inlining_p | |
192 && opt_for_fn (body->decl, optimize) | |
193 && opt_for_fn (body->decl, flag_devirtualize))) | |
194 { | |
195 /* Be sure that we will not optimize out alias target | |
196 body. */ | |
197 if (DECL_EXTERNAL (n->decl) | |
198 && n->alias | |
199 && before_inlining_p) | |
200 reachable->add (body); | |
201 reachable->add (n); | |
202 } | |
203 /* Even after inlining we want to keep the possible targets in the | |
204 boundary, so late passes can still produce direct call even if | |
205 the chance for inlining is lost. */ | |
206 enqueue_node (n, first, reachable); | |
207 } | |
208 } | |
209 | |
210 /* Very trivial devirtualization; when the type is | |
211 final or anonymous (so we know all its derivation) | |
212 and there is only one possible virtual call target, | |
213 make the edge direct. */ | |
214 if (final) | |
215 { | |
216 if (targets.length () <= 1 && dbg_cnt (devirt)) | |
217 { | |
218 cgraph_node *target, *node = edge->caller; | |
219 if (targets.length () == 1) | |
220 target = targets[0]; | |
221 else | |
222 target = cgraph_node::get_create | |
223 (builtin_decl_implicit (BUILT_IN_UNREACHABLE)); | |
224 | |
225 if (dump_enabled_p ()) | |
226 { | |
227 location_t locus; | |
228 if (edge->call_stmt) | |
229 locus = gimple_location (edge->call_stmt); | |
230 else | |
231 locus = UNKNOWN_LOCATION; | |
232 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, locus, | |
233 "devirtualizing call in %s to %s\n", | |
234 edge->caller->dump_name (), | |
235 target->dump_name ()); | |
236 } | |
237 edge = edge->make_direct (target); | |
238 if (ipa_fn_summaries) | |
239 ipa_update_overall_fn_summary (node); | |
240 else if (edge->call_stmt) | |
183 { | 241 { |
184 varpool_mark_needed_node (node); | 242 edge->redirect_call_stmt_to_callee (); |
185 enqueue_varpool_node (node, first_varpool); | 243 |
244 /* Call to __builtin_unreachable shouldn't be instrumented. */ | |
245 if (!targets.length ()) | |
246 gimple_call_set_with_bounds (edge->call_stmt, false); | |
186 } | 247 } |
187 } | 248 } |
188 } | 249 } |
189 } | 250 } |
190 | 251 |
191 /* Return true when function can be marked local. */ | |
192 | |
193 static bool | |
194 cgraph_local_node_p (struct cgraph_node *node) | |
195 { | |
196 return (cgraph_only_called_directly_p (node) | |
197 && node->analyzed | |
198 && !DECL_EXTERNAL (node->decl) | |
199 && !node->local.externally_visible | |
200 && !node->reachable_from_other_partition | |
201 && !node->in_other_partition); | |
202 } | |
203 | |
204 /* Perform reachability analysis and reclaim all unreachable nodes. | 252 /* Perform reachability analysis and reclaim all unreachable nodes. |
205 If BEFORE_INLINING_P is true this function is called before inlining | 253 |
206 decisions has been made. If BEFORE_INLINING_P is false this function also | 254 The algorithm is basically mark&sweep but with some extra refinements: |
207 removes unneeded bodies of extern inline functions. */ | 255 |
256 - reachable extern inline functions needs special handling; the bodies needs | |
257 to stay in memory until inlining in hope that they will be inlined. | |
258 After inlining we release their bodies and turn them into unanalyzed | |
259 nodes even when they are reachable. | |
260 | |
261 - virtual functions are kept in callgraph even if they seem unreachable in | |
262 hope calls to them will be devirtualized. | |
263 | |
264 Again we remove them after inlining. In late optimization some | |
265 devirtualization may happen, but it is not important since we won't inline | |
266 the call. In theory early opts and IPA should work out all important cases. | |
267 | |
268 - virtual clones needs bodies of their origins for later materialization; | |
269 this means that we want to keep the body even if the origin is unreachable | |
270 otherwise. To avoid origin from sitting in the callgraph and being | |
271 walked by IPA passes, we turn them into unanalyzed nodes with body | |
272 defined. | |
273 | |
274 We maintain set of function declaration where body needs to stay in | |
275 body_needed_for_clonning | |
276 | |
277 Inline clones represent special case: their declaration match the | |
278 declaration of origin and cgraph_remove_node already knows how to | |
279 reshape callgraph and preserve body when offline copy of function or | |
280 inline clone is being removed. | |
281 | |
282 - C++ virtual tables keyed to other unit are represented as DECL_EXTERNAL | |
283 variables with DECL_INITIAL set. We finalize these and keep reachable | |
284 ones around for constant folding purposes. After inlining we however | |
285 stop walking their references to let everything static referneced by them | |
286 to be removed when it is otherwise unreachable. | |
287 | |
288 We maintain queue of both reachable symbols (i.e. defined symbols that needs | |
289 to stay) and symbols that are in boundary (i.e. external symbols referenced | |
290 by reachable symbols or origins of clones). The queue is represented | |
291 as linked list by AUX pointer terminated by 1. | |
292 | |
293 At the end we keep all reachable symbols. For symbols in boundary we always | |
294 turn definition into a declaration, but we may keep function body around | |
295 based on body_needed_for_clonning | |
296 | |
297 All symbols that enter the queue have AUX pointer non-zero and are in the | |
298 boundary. Pointer set REACHABLE is used to track reachable symbols. | |
299 | |
300 Every symbol can be visited twice - once as part of boundary and once | |
301 as real reachable symbol. enqueue_node needs to decide whether the | |
302 node needs to be re-queued for second processing. For this purpose | |
303 we set AUX pointer of processed symbols in the boundary to constant 2. */ | |
208 | 304 |
209 bool | 305 bool |
210 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) | 306 symbol_table::remove_unreachable_nodes (FILE *file) |
211 { | 307 { |
212 struct cgraph_node *first = (struct cgraph_node *) (void *) 1; | 308 symtab_node *first = (symtab_node *) (void *) 1; |
213 struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1; | |
214 struct cgraph_node *node, *next; | 309 struct cgraph_node *node, *next; |
215 struct varpool_node *vnode, *vnext; | 310 varpool_node *vnode, *vnext; |
216 bool changed = false; | 311 bool changed = false; |
217 | 312 hash_set<symtab_node *> reachable; |
218 #ifdef ENABLE_CHECKING | 313 hash_set<tree> body_needed_for_clonning; |
219 verify_cgraph (); | 314 hash_set<void *> reachable_call_targets; |
220 #endif | 315 bool before_inlining_p = symtab->state < (!optimize && !in_lto_p ? IPA_SSA |
316 : IPA_SSA_AFTER_INLINING); | |
317 | |
318 timevar_push (TV_IPA_UNREACHABLE); | |
319 build_type_inheritance_graph (); | |
221 if (file) | 320 if (file) |
222 fprintf (file, "\nReclaiming functions:"); | 321 fprintf (file, "\nReclaiming functions:"); |
223 #ifdef ENABLE_CHECKING | 322 if (flag_checking) |
224 for (node = cgraph_nodes; node; node = node->next) | 323 { |
225 gcc_assert (!node->aux); | 324 FOR_EACH_FUNCTION (node) |
226 for (vnode = varpool_nodes; vnode; vnode = vnode->next) | 325 gcc_assert (!node->aux); |
227 gcc_assert (!vnode->aux); | 326 FOR_EACH_VARIABLE (vnode) |
228 #endif | 327 gcc_assert (!vnode->aux); |
229 varpool_reset_queue (); | 328 } |
230 /* Mark functions whose bodies are obviously needed. | 329 /* Mark functions whose bodies are obviously needed. |
231 This is mostly when they can be referenced externally. Inline clones | 330 This is mostly when they can be referenced externally. Inline clones |
232 are special since their declarations are shared with master clone and thus | 331 are special since their declarations are shared with master clone and thus |
233 cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ | 332 cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ |
234 for (node = cgraph_nodes; node; node = node->next) | 333 FOR_EACH_FUNCTION (node) |
235 if (node->analyzed && !node->global.inlined_to | 334 { |
236 && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) | 335 node->used_as_abstract_origin = false; |
237 /* Keep around virtual functions for possible devirtualization. */ | 336 node->indirect_call_target = false; |
238 || (before_inlining_p | 337 if (node->definition |
239 && DECL_VIRTUAL_P (node->decl) | 338 && !node->global.inlined_to |
240 && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))) | 339 && !node->in_other_partition |
241 /* Also external functions with address taken are better to stay | 340 && !node->can_remove_if_no_direct_calls_and_refs_p ()) |
242 for indirect inlining. */ | 341 { |
243 || (before_inlining_p | 342 gcc_assert (!node->global.inlined_to); |
244 && DECL_EXTERNAL (node->decl) | 343 reachable.add (node); |
245 && node->address_taken))) | 344 enqueue_node (node, &first, &reachable); |
345 } | |
346 else | |
347 gcc_assert (!node->aux); | |
348 } | |
349 | |
350 /* Mark variables that are obviously needed. */ | |
351 FOR_EACH_DEFINED_VARIABLE (vnode) | |
352 if (!vnode->can_remove_if_no_refs_p() | |
353 && !vnode->in_other_partition) | |
246 { | 354 { |
247 gcc_assert (!node->global.inlined_to); | 355 reachable.add (vnode); |
248 enqueue_cgraph_node (node, &first); | 356 enqueue_node (vnode, &first, &reachable); |
249 node->reachable = true; | |
250 } | 357 } |
251 else | 358 |
252 { | 359 /* Perform reachability analysis. */ |
253 gcc_assert (!node->aux); | 360 while (first != (symtab_node *) (void *) 1) |
254 node->reachable = false; | 361 { |
255 } | 362 bool in_boundary_p = !reachable.contains (first); |
256 | 363 symtab_node *node = first; |
257 /* Mark variables that are obviously needed. */ | 364 |
258 for (vnode = varpool_nodes; vnode; vnode = vnode->next) | 365 first = (symtab_node *)first->aux; |
259 { | 366 |
260 vnode->next_needed = NULL; | 367 /* If we are processing symbol in boundary, mark its AUX pointer for |
261 vnode->prev_needed = NULL; | 368 possible later re-processing in enqueue_node. */ |
262 if ((vnode->analyzed || vnode->force_output) | 369 if (in_boundary_p) |
263 && !varpool_can_remove_if_no_refs (vnode)) | 370 { |
264 { | 371 node->aux = (void *)2; |
265 vnode->needed = false; | 372 if (node->alias && node->analyzed) |
266 varpool_mark_needed_node (vnode); | 373 enqueue_node (node->get_alias_target (), &first, &reachable); |
267 enqueue_varpool_node (vnode, &first_varpool); | |
268 } | 374 } |
269 else | 375 else |
270 vnode->needed = false; | 376 { |
271 } | 377 if (TREE_CODE (node->decl) == FUNCTION_DECL |
272 | 378 && DECL_ABSTRACT_ORIGIN (node->decl)) |
273 /* Perform reachability analysis. As a special case do not consider | |
274 extern inline functions not inlined as live because we won't output | |
275 them at all. | |
276 | |
277 We maintain two worklist, one for cgraph nodes other for varpools and | |
278 are finished once both are empty. */ | |
279 | |
280 while (first != (struct cgraph_node *) (void *) 1 | |
281 || first_varpool != (struct varpool_node *) (void *) 1) | |
282 { | |
283 if (first != (struct cgraph_node *) (void *) 1) | |
284 { | |
285 struct cgraph_edge *e; | |
286 node = first; | |
287 first = (struct cgraph_node *) first->aux; | |
288 if (!node->reachable) | |
289 node->aux = (void *)2; | |
290 | |
291 /* If we found this node reachable, first mark on the callees | |
292 reachable too, unless they are direct calls to extern inline functions | |
293 we decided to not inline. */ | |
294 if (node->reachable) | |
295 { | 379 { |
296 for (e = node->callees; e; e = e->next_callee) | 380 struct cgraph_node *origin_node |
381 = cgraph_node::get (DECL_ABSTRACT_ORIGIN (node->decl)); | |
382 if (origin_node && !origin_node->used_as_abstract_origin) | |
297 { | 383 { |
298 if (!e->callee->reachable | 384 origin_node->used_as_abstract_origin = true; |
299 && node->analyzed | 385 gcc_assert (!origin_node->prev_sibling_clone); |
300 && (!e->inline_failed | 386 gcc_assert (!origin_node->next_sibling_clone); |
301 || !DECL_EXTERNAL (e->callee->decl) | 387 for (cgraph_node *n = origin_node->clones; n; |
302 || before_inlining_p)) | 388 n = n->next_sibling_clone) |
303 e->callee->reachable = true; | 389 if (n->decl == DECL_ABSTRACT_ORIGIN (node->decl)) |
304 enqueue_cgraph_node (e->callee, &first); | 390 n->used_as_abstract_origin = true; |
305 } | 391 } |
306 process_references (&node->ref_list, &first, &first_varpool, before_inlining_p); | |
307 } | 392 } |
308 | 393 /* If any symbol in a comdat group is reachable, force |
309 /* If any function in a comdat group is reachable, force | 394 all externally visible symbols in the same comdat |
310 all other functions in the same comdat group to be | 395 group to be reachable as well. Comdat-local symbols |
311 also reachable. */ | 396 can be discarded if all uses were inlined. */ |
312 if (node->same_comdat_group | 397 if (node->same_comdat_group) |
313 && node->reachable | |
314 && !node->global.inlined_to) | |
315 { | 398 { |
399 symtab_node *next; | |
316 for (next = node->same_comdat_group; | 400 for (next = node->same_comdat_group; |
317 next != node; | 401 next != node; |
318 next = next->same_comdat_group) | 402 next = next->same_comdat_group) |
319 if (!next->reachable) | 403 if (!next->comdat_local_p () |
320 { | 404 && !reachable.add (next)) |
321 next->reachable = true; | 405 enqueue_node (next, &first, &reachable); |
322 enqueue_cgraph_node (next, &first); | |
323 } | |
324 } | 406 } |
325 | 407 /* Mark references as reachable. */ |
326 /* We can freely remove inline clones even if they are cloned, however if | 408 process_references (node, &first, before_inlining_p, &reachable); |
327 function is clone of real clone, we must keep it around in order to | 409 } |
328 make materialize_clones produce function body with the changes | 410 |
329 applied. */ | 411 if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) |
330 while (node->clone_of && !node->clone_of->aux | 412 { |
331 && !gimple_has_body_p (node->decl)) | 413 /* Mark the callees reachable unless they are direct calls to extern |
414 inline functions we decided to not inline. */ | |
415 if (!in_boundary_p) | |
332 { | 416 { |
333 bool noninline = node->clone_of->decl != node->decl; | 417 struct cgraph_edge *e; |
334 node = node->clone_of; | 418 /* Keep alive possible targets for devirtualization. */ |
335 if (noninline && !node->reachable && !node->aux) | 419 if (opt_for_fn (cnode->decl, optimize) |
336 { | 420 && opt_for_fn (cnode->decl, flag_devirtualize)) |
337 enqueue_cgraph_node (node, &first); | 421 { |
338 break; | 422 struct cgraph_edge *next; |
423 for (e = cnode->indirect_calls; e; e = next) | |
424 { | |
425 next = e->next_callee; | |
426 if (e->indirect_info->polymorphic) | |
427 walk_polymorphic_call_targets (&reachable_call_targets, | |
428 e, &first, &reachable, | |
429 before_inlining_p); | |
430 } | |
431 } | |
432 for (e = cnode->callees; e; e = e->next_callee) | |
433 { | |
434 symtab_node *body = e->callee->function_symbol (); | |
435 if (e->callee->definition | |
436 && !e->callee->in_other_partition | |
437 && (!e->inline_failed | |
438 || !DECL_EXTERNAL (e->callee->decl) | |
439 || e->callee->alias | |
440 || (before_inlining_p | |
441 && (opt_for_fn (body->decl, optimize) | |
442 || (symtab->state < IPA_SSA | |
443 && lookup_attribute | |
444 ("always_inline", | |
445 DECL_ATTRIBUTES (body->decl))))))) | |
446 { | |
447 /* Be sure that we will not optimize out alias target | |
448 body. */ | |
449 if (DECL_EXTERNAL (e->callee->decl) | |
450 && e->callee->alias | |
451 && before_inlining_p) | |
452 reachable.add (body); | |
453 reachable.add (e->callee); | |
454 } | |
455 enqueue_node (e->callee, &first, &reachable); | |
456 } | |
457 | |
458 /* When inline clone exists, mark body to be preserved so when removing | |
459 offline copy of the function we don't kill it. */ | |
460 if (cnode->global.inlined_to) | |
461 body_needed_for_clonning.add (cnode->decl); | |
462 | |
463 /* For instrumentation clones we always need original | |
464 function node for proper LTO privatization. */ | |
465 if (cnode->instrumentation_clone | |
466 && cnode->definition) | |
467 { | |
468 gcc_assert (cnode->instrumented_version || in_lto_p); | |
469 if (cnode->instrumented_version) | |
470 { | |
471 enqueue_node (cnode->instrumented_version, &first, | |
472 &reachable); | |
473 reachable.add (cnode->instrumented_version); | |
474 } | |
475 } | |
476 | |
477 /* For non-inline clones, force their origins to the boundary and ensure | |
478 that body is not removed. */ | |
479 while (cnode->clone_of) | |
480 { | |
481 bool noninline = cnode->clone_of->decl != cnode->decl; | |
482 cnode = cnode->clone_of; | |
483 if (noninline) | |
484 { | |
485 body_needed_for_clonning.add (cnode->decl); | |
486 enqueue_node (cnode, &first, &reachable); | |
487 } | |
488 } | |
489 | |
490 } | |
491 else if (cnode->thunk.thunk_p) | |
492 enqueue_node (cnode->callees->callee, &first, &reachable); | |
493 | |
494 /* If any reachable function has simd clones, mark them as | |
495 reachable as well. */ | |
496 if (cnode->simd_clones) | |
497 { | |
498 cgraph_node *next; | |
499 for (next = cnode->simd_clones; | |
500 next; | |
501 next = next->simdclone->next_clone) | |
502 if (in_boundary_p | |
503 || !reachable.add (next)) | |
504 enqueue_node (next, &first, &reachable); | |
505 } | |
506 } | |
507 /* When we see constructor of external variable, keep referred nodes in the | |
508 boundary. This will also hold initializers of the external vars NODE | |
509 refers to. */ | |
510 varpool_node *vnode = dyn_cast <varpool_node *> (node); | |
511 if (vnode | |
512 && DECL_EXTERNAL (node->decl) | |
513 && !vnode->alias | |
514 && in_boundary_p) | |
515 { | |
516 struct ipa_ref *ref = NULL; | |
517 for (int i = 0; node->iterate_reference (i, ref); i++) | |
518 enqueue_node (ref->referred, &first, &reachable); | |
519 } | |
520 } | |
521 | |
522 /* Remove unreachable functions. */ | |
523 for (node = first_function (); node; node = next) | |
524 { | |
525 next = next_function (node); | |
526 | |
527 /* If node is not needed at all, remove it. */ | |
528 if (!node->aux) | |
529 { | |
530 if (file) | |
531 fprintf (file, " %s", node->dump_name ()); | |
532 node->remove (); | |
533 changed = true; | |
534 } | |
535 /* If node is unreachable, remove its body. */ | |
536 else if (!reachable.contains (node)) | |
537 { | |
538 /* We keep definitions of thunks and aliases in the boundary so | |
539 we can walk to the ultimate alias targets and function symbols | |
540 reliably. */ | |
541 if (node->alias || node->thunk.thunk_p) | |
542 ; | |
543 else if (!body_needed_for_clonning.contains (node->decl) | |
544 && !node->alias && !node->thunk.thunk_p) | |
545 node->release_body (); | |
546 else if (!node->clone_of) | |
547 gcc_assert (in_lto_p || DECL_RESULT (node->decl)); | |
548 if (node->definition && !node->alias && !node->thunk.thunk_p) | |
549 { | |
550 if (file) | |
551 fprintf (file, " %s", node->dump_name ()); | |
552 node->body_removed = true; | |
553 node->analyzed = false; | |
554 node->definition = false; | |
555 node->cpp_implicit_alias = false; | |
556 node->alias = false; | |
557 node->transparent_alias = false; | |
558 node->thunk.thunk_p = false; | |
559 node->weakref = false; | |
560 /* After early inlining we drop always_inline attributes on | |
561 bodies of functions that are still referenced (have their | |
562 address taken). */ | |
563 DECL_ATTRIBUTES (node->decl) | |
564 = remove_attribute ("always_inline", | |
565 DECL_ATTRIBUTES (node->decl)); | |
566 if (!node->in_other_partition) | |
567 node->local.local = false; | |
568 node->remove_callees (); | |
569 node->remove_all_references (); | |
570 changed = true; | |
571 if (node->thunk.thunk_p | |
572 && node->thunk.add_pointer_bounds_args) | |
573 { | |
574 node->thunk.thunk_p = false; | |
575 node->thunk.add_pointer_bounds_args = false; | |
339 } | 576 } |
340 } | 577 } |
341 } | 578 } |
342 if (first_varpool != (struct varpool_node *) (void *) 1) | 579 else |
343 { | 580 gcc_assert (node->clone_of || !node->has_gimple_body_p () |
344 vnode = first_varpool; | 581 || in_lto_p || DECL_RESULT (node->decl)); |
345 first_varpool = (struct varpool_node *)first_varpool->aux; | 582 } |
346 vnode->aux = NULL; | 583 |
347 process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p); | 584 /* Inline clones might be kept around so their materializing allows further |
348 /* If any function in a comdat group is reachable, force | 585 cloning. If the function the clone is inlined into is removed, we need |
349 all other functions in the same comdat group to be | 586 to turn it into normal cone. */ |
350 also reachable. */ | 587 FOR_EACH_FUNCTION (node) |
351 if (vnode->same_comdat_group) | 588 { |
352 { | |
353 struct varpool_node *next; | |
354 for (next = vnode->same_comdat_group; | |
355 next != vnode; | |
356 next = next->same_comdat_group) | |
357 if (!next->needed) | |
358 { | |
359 varpool_mark_needed_node (next); | |
360 enqueue_varpool_node (next, &first_varpool); | |
361 } | |
362 } | |
363 } | |
364 } | |
365 | |
366 /* Remove unreachable nodes. | |
367 | |
368 Completely unreachable functions can be fully removed from the callgraph. | |
369 Extern inline functions that we decided to not inline need to become unanalyzed nodes of | |
370 callgraph (so we still have edges to them). We remove function body then. | |
371 | |
372 Also we need to care functions that are unreachable but we need to keep them around | |
373 for later clonning. In this case we also turn them to unanalyzed nodes, but | |
374 keep the body around. */ | |
375 for (node = cgraph_nodes; node; node = next) | |
376 { | |
377 next = node->next; | |
378 if (node->aux && !node->reachable) | |
379 { | |
380 cgraph_node_remove_callees (node); | |
381 ipa_remove_all_references (&node->ref_list); | |
382 node->analyzed = false; | |
383 node->local.inlinable = false; | |
384 } | |
385 if (!node->aux) | |
386 { | |
387 struct cgraph_edge *e; | |
388 bool found = false; | |
389 int i; | |
390 struct ipa_ref *ref; | |
391 | |
392 node->global.inlined_to = NULL; | |
393 if (file) | |
394 fprintf (file, " %s", cgraph_node_name (node)); | |
395 /* See if there is reachable caller. */ | |
396 for (e = node->callers; e && !found; e = e->next_caller) | |
397 if (e->caller->reachable) | |
398 found = true; | |
399 for (i = 0; (ipa_ref_list_refering_iterate (&node->ref_list, i, ref) | |
400 && !found); i++) | |
401 if (ref->refering_type == IPA_REF_CGRAPH | |
402 && ipa_ref_refering_node (ref)->reachable) | |
403 found = true; | |
404 else if (ref->refering_type == IPA_REF_VARPOOL | |
405 && ipa_ref_refering_varpool_node (ref)->needed) | |
406 found = true; | |
407 | |
408 /* If so, we need to keep node in the callgraph. */ | |
409 if (found) | |
410 { | |
411 if (node->analyzed) | |
412 { | |
413 struct cgraph_node *clone; | |
414 | |
415 /* If there are still clones, we must keep body around. | |
416 Otherwise we can just remove the body but keep the clone. */ | |
417 for (clone = node->clones; clone; | |
418 clone = clone->next_sibling_clone) | |
419 if (clone->aux) | |
420 break; | |
421 if (!clone) | |
422 { | |
423 cgraph_release_function_body (node); | |
424 node->local.inlinable = false; | |
425 if (node->prev_sibling_clone) | |
426 node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; | |
427 else if (node->clone_of) | |
428 node->clone_of->clones = node->next_sibling_clone; | |
429 if (node->next_sibling_clone) | |
430 node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; | |
431 if (node->clone_of) | |
432 node->former_clone_of = node->clone_of->decl; | |
433 node->clone_of = NULL; | |
434 node->next_sibling_clone = NULL; | |
435 node->prev_sibling_clone = NULL; | |
436 } | |
437 else | |
438 gcc_assert (!clone->in_other_partition); | |
439 node->analyzed = false; | |
440 changed = true; | |
441 cgraph_node_remove_callees (node); | |
442 ipa_remove_all_references (&node->ref_list); | |
443 } | |
444 } | |
445 else | |
446 { | |
447 cgraph_remove_node (node); | |
448 changed = true; | |
449 } | |
450 } | |
451 } | |
452 for (node = cgraph_nodes; node; node = node->next) | |
453 { | |
454 /* Inline clones might be kept around so their materializing allows further | |
455 cloning. If the function the clone is inlined into is removed, we need | |
456 to turn it into normal cone. */ | |
457 if (node->global.inlined_to | 589 if (node->global.inlined_to |
458 && !node->callers) | 590 && !node->callers) |
459 { | 591 { |
460 gcc_assert (node->clones); | 592 gcc_assert (node->clones); |
461 node->global.inlined_to = NULL; | 593 node->global.inlined_to = NULL; |
462 update_inlined_to_pointer (node, node); | 594 update_inlined_to_pointer (node, node); |
463 } | 595 } |
464 node->aux = NULL; | 596 node->aux = NULL; |
465 } | 597 } |
466 | 598 |
599 /* Remove unreachable variables. */ | |
467 if (file) | 600 if (file) |
468 fprintf (file, "\n"); | 601 fprintf (file, "\nReclaiming variables:"); |
469 | 602 for (vnode = first_variable (); vnode; vnode = vnext) |
470 /* We must release unused extern inlines or sanity checking will fail. Rest of transformations | 603 { |
471 are undesirable at -O0 since we do not want to remove anything. */ | 604 vnext = next_variable (vnode); |
472 if (!optimize) | 605 if (!vnode->aux |
473 return changed; | 606 /* For can_refer_decl_in_current_unit_p we want to track for |
474 | 607 all external variables if they are defined in other partition |
475 if (file) | 608 or not. */ |
476 fprintf (file, "Reclaiming variables:"); | 609 && (!flag_ltrans || !DECL_EXTERNAL (vnode->decl))) |
477 for (vnode = varpool_nodes; vnode; vnode = vnext) | 610 { |
478 { | 611 struct ipa_ref *ref = NULL; |
479 vnext = vnode->next; | 612 |
480 if (!vnode->needed) | 613 /* First remove the aliases, so varpool::remove can possibly lookup |
614 the constructor and save it for future use. */ | |
615 while (vnode->iterate_direct_aliases (0, ref)) | |
616 { | |
617 if (file) | |
618 fprintf (file, " %s", ref->referred->dump_name ()); | |
619 ref->referring->remove (); | |
620 } | |
621 if (file) | |
622 fprintf (file, " %s", vnode->dump_name ()); | |
623 vnext = next_variable (vnode); | |
624 /* Signal removal to the debug machinery. */ | |
625 if (! flag_wpa) | |
626 { | |
627 vnode->definition = false; | |
628 (*debug_hooks->late_global_decl) (vnode->decl); | |
629 } | |
630 vnode->remove (); | |
631 changed = true; | |
632 } | |
633 else if (!reachable.contains (vnode) && !vnode->alias) | |
481 { | 634 { |
482 if (file) | 635 tree init; |
483 fprintf (file, " %s", varpool_node_name (vnode)); | 636 if (vnode->definition) |
484 varpool_remove_node (vnode); | 637 { |
485 changed = true; | 638 if (file) |
486 } | 639 fprintf (file, " %s", vnode->name ()); |
640 changed = true; | |
641 } | |
642 /* Keep body if it may be useful for constant folding. */ | |
643 if ((init = ctor_for_folding (vnode->decl)) == error_mark_node | |
644 && !POINTER_BOUNDS_P (vnode->decl)) | |
645 vnode->remove_initializer (); | |
646 else | |
647 DECL_INITIAL (vnode->decl) = init; | |
648 vnode->body_removed = true; | |
649 vnode->definition = false; | |
650 vnode->analyzed = false; | |
651 vnode->aux = NULL; | |
652 | |
653 vnode->remove_from_same_comdat_group (); | |
654 | |
655 vnode->remove_all_references (); | |
656 } | |
657 else | |
658 vnode->aux = NULL; | |
487 } | 659 } |
488 | 660 |
489 /* Now update address_taken flags and try to promote functions to be local. */ | 661 /* Now update address_taken flags and try to promote functions to be local. */ |
490 | |
491 if (file) | 662 if (file) |
492 fprintf (file, "\nClearing address taken flags:"); | 663 fprintf (file, "\nClearing address taken flags:"); |
493 for (node = cgraph_nodes; node; node = node->next) | 664 FOR_EACH_DEFINED_FUNCTION (node) |
494 if (node->address_taken | 665 if (node->address_taken |
495 && !node->reachable_from_other_partition) | 666 && !node->used_from_other_partition) |
496 { | 667 { |
497 int i; | 668 if (!node->call_for_symbol_and_aliases |
498 struct ipa_ref *ref; | 669 (has_addr_references_p, NULL, true) |
499 bool found = false; | 670 && (!node->instrumentation_clone |
500 for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref) | 671 || !node->instrumented_version |
501 && !found; i++) | 672 || !node->instrumented_version->address_taken)) |
502 { | |
503 gcc_assert (ref->use == IPA_REF_ADDR); | |
504 found = true; | |
505 } | |
506 if (!found) | |
507 { | 673 { |
508 if (file) | 674 if (file) |
509 fprintf (file, " %s", cgraph_node_name (node)); | 675 fprintf (file, " %s", node->name ()); |
510 node->address_taken = false; | 676 node->address_taken = false; |
511 changed = true; | 677 changed = true; |
512 if (cgraph_local_node_p (node)) | 678 if (node->local_p () |
679 /* Virtual functions may be kept in cgraph just because | |
680 of possible later devirtualization. Do not mark them as | |
681 local too early so we won't optimize them out before | |
682 we are done with polymorphic call analysis. */ | |
683 && (!before_inlining_p | |
684 || !node->call_for_symbol_and_aliases | |
685 (is_indirect_call_target_p, NULL, true))) | |
513 { | 686 { |
514 node->local.local = true; | 687 node->local.local = true; |
515 if (file) | 688 if (file) |
516 fprintf (file, " (local)"); | 689 fprintf (file, " (local)"); |
517 } | 690 } |
518 } | 691 } |
519 } | 692 } |
520 | 693 if (file) |
521 #ifdef ENABLE_CHECKING | 694 fprintf (file, "\n"); |
522 verify_cgraph (); | 695 |
523 #endif | 696 symtab_node::checking_verify_symtab_nodes (); |
524 | 697 |
525 /* Reclaim alias pairs for functions that have disappeared from the | 698 /* If we removed something, perhaps profile could be improved. */ |
526 call graph. */ | 699 if (changed && (optimize || in_lto_p) && ipa_call_summaries) |
527 remove_unreachable_alias_pairs (); | 700 FOR_EACH_DEFINED_FUNCTION (node) |
528 | 701 ipa_propagate_frequency (node); |
702 | |
703 timevar_pop (TV_IPA_UNREACHABLE); | |
529 return changed; | 704 return changed; |
705 } | |
706 | |
707 /* Process references to VNODE and set flags WRITTEN, ADDRESS_TAKEN, READ | |
708 as needed, also clear EXPLICIT_REFS if the references to given variable | |
709 do not need to be explicit. */ | |
710 | |
711 void | |
712 process_references (varpool_node *vnode, | |
713 bool *written, bool *address_taken, | |
714 bool *read, bool *explicit_refs) | |
715 { | |
716 int i; | |
717 struct ipa_ref *ref; | |
718 | |
719 if (!vnode->all_refs_explicit_p () | |
720 || TREE_THIS_VOLATILE (vnode->decl)) | |
721 *explicit_refs = false; | |
722 | |
723 for (i = 0; vnode->iterate_referring (i, ref) | |
724 && *explicit_refs && (!*written || !*address_taken || !*read); i++) | |
725 switch (ref->use) | |
726 { | |
727 case IPA_REF_ADDR: | |
728 *address_taken = true; | |
729 break; | |
730 case IPA_REF_LOAD: | |
731 *read = true; | |
732 break; | |
733 case IPA_REF_STORE: | |
734 *written = true; | |
735 break; | |
736 case IPA_REF_ALIAS: | |
737 process_references (dyn_cast<varpool_node *> (ref->referring), written, | |
738 address_taken, read, explicit_refs); | |
739 break; | |
740 case IPA_REF_CHKP: | |
741 gcc_unreachable (); | |
742 } | |
743 } | |
744 | |
745 /* Set TREE_READONLY bit. */ | |
746 | |
747 bool | |
748 set_readonly_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED) | |
749 { | |
750 TREE_READONLY (vnode->decl) = true; | |
751 return false; | |
752 } | |
753 | |
754 /* Set writeonly bit and clear the initalizer, since it will not be needed. */ | |
755 | |
756 bool | |
757 set_writeonly_bit (varpool_node *vnode, void *data) | |
758 { | |
759 vnode->writeonly = true; | |
760 if (optimize || in_lto_p) | |
761 { | |
762 DECL_INITIAL (vnode->decl) = NULL; | |
763 if (!vnode->alias) | |
764 { | |
765 if (vnode->num_references ()) | |
766 *(bool *)data = true; | |
767 vnode->remove_all_references (); | |
768 } | |
769 } | |
770 return false; | |
771 } | |
772 | |
773 /* Clear addressale bit of VNODE. */ | |
774 | |
775 bool | |
776 clear_addressable_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED) | |
777 { | |
778 vnode->address_taken = false; | |
779 TREE_ADDRESSABLE (vnode->decl) = 0; | |
780 return false; | |
530 } | 781 } |
531 | 782 |
532 /* Discover variables that have no longer address taken or that are read only | 783 /* Discover variables that have no longer address taken or that are read only |
533 and update their flags. | 784 and update their flags. |
785 | |
786 Return true when unreachable symbol removan should be done. | |
534 | 787 |
535 FIXME: This can not be done in between gimplify and omp_expand since | 788 FIXME: This can not be done in between gimplify and omp_expand since |
536 readonly flag plays role on what is shared and what is not. Currently we do | 789 readonly flag plays role on what is shared and what is not. Currently we do |
537 this transformation as part of whole program visibility and re-do at | 790 this transformation as part of whole program visibility and re-do at |
538 ipa-reference pass (to take into account clonning), but it would | 791 ipa-reference pass (to take into account clonning), but it would |
539 make sense to do it before early optimizations. */ | 792 make sense to do it before early optimizations. */ |
540 | 793 |
541 void | 794 bool |
542 ipa_discover_readonly_nonaddressable_vars (void) | 795 ipa_discover_readonly_nonaddressable_vars (void) |
543 { | 796 { |
544 struct varpool_node *vnode; | 797 bool remove_p = false; |
798 varpool_node *vnode; | |
545 if (dump_file) | 799 if (dump_file) |
546 fprintf (dump_file, "Clearing variable flags:"); | 800 fprintf (dump_file, "Clearing variable flags:"); |
547 for (vnode = varpool_nodes; vnode; vnode = vnode->next) | 801 FOR_EACH_VARIABLE (vnode) |
548 if (vnode->finalized && varpool_all_refs_explicit_p (vnode) | 802 if (!vnode->alias |
549 && (TREE_ADDRESSABLE (vnode->decl) || !TREE_READONLY (vnode->decl))) | 803 && (TREE_ADDRESSABLE (vnode->decl) |
804 || !vnode->writeonly | |
805 || !TREE_READONLY (vnode->decl))) | |
550 { | 806 { |
551 bool written = false; | 807 bool written = false; |
552 bool address_taken = false; | 808 bool address_taken = false; |
553 int i; | 809 bool read = false; |
554 struct ipa_ref *ref; | 810 bool explicit_refs = true; |
555 for (i = 0; ipa_ref_list_refering_iterate (&vnode->ref_list, i, ref) | 811 |
556 && (!written || !address_taken); i++) | 812 process_references (vnode, &written, &address_taken, &read, |
557 switch (ref->use) | 813 &explicit_refs); |
558 { | 814 if (!explicit_refs) |
559 case IPA_REF_ADDR: | 815 continue; |
560 address_taken = true; | 816 if (!address_taken) |
561 break; | |
562 case IPA_REF_LOAD: | |
563 break; | |
564 case IPA_REF_STORE: | |
565 written = true; | |
566 break; | |
567 } | |
568 if (TREE_ADDRESSABLE (vnode->decl) && !address_taken) | |
569 { | 817 { |
570 if (dump_file) | 818 if (TREE_ADDRESSABLE (vnode->decl) && dump_file) |
571 fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode)); | 819 fprintf (dump_file, " %s (non-addressable)", vnode->name ()); |
572 TREE_ADDRESSABLE (vnode->decl) = 0; | 820 vnode->call_for_symbol_and_aliases (clear_addressable_bit, NULL, |
821 true); | |
573 } | 822 } |
574 if (!TREE_READONLY (vnode->decl) && !address_taken && !written | 823 if (!address_taken && !written |
575 /* Making variable in explicit section readonly can cause section | 824 /* Making variable in explicit section readonly can cause section |
576 type conflict. | 825 type conflict. |
577 See e.g. gcc.c-torture/compile/pr23237.c */ | 826 See e.g. gcc.c-torture/compile/pr23237.c */ |
578 && DECL_SECTION_NAME (vnode->decl) == NULL) | 827 && vnode->get_section () == NULL) |
828 { | |
829 if (!TREE_READONLY (vnode->decl) && dump_file) | |
830 fprintf (dump_file, " %s (read-only)", vnode->name ()); | |
831 vnode->call_for_symbol_and_aliases (set_readonly_bit, NULL, true); | |
832 } | |
833 if (!vnode->writeonly && !read && !address_taken && written) | |
579 { | 834 { |
580 if (dump_file) | 835 if (dump_file) |
581 fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode)); | 836 fprintf (dump_file, " %s (write-only)", vnode->name ()); |
582 TREE_READONLY (vnode->decl) = 1; | 837 vnode->call_for_symbol_and_aliases (set_writeonly_bit, &remove_p, |
838 true); | |
583 } | 839 } |
584 } | 840 } |
585 if (dump_file) | 841 if (dump_file) |
586 fprintf (dump_file, "\n"); | 842 fprintf (dump_file, "\n"); |
587 } | 843 return remove_p; |
588 | 844 } |
589 /* Return true when there is a reference to node and it is not vtable. */ | |
590 static bool | |
591 cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node) | |
592 { | |
593 int i; | |
594 struct ipa_ref *ref; | |
595 for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) | |
596 { | |
597 struct varpool_node *node; | |
598 if (ref->refered_type == IPA_REF_CGRAPH) | |
599 return true; | |
600 node = ipa_ref_varpool_node (ref); | |
601 if (!DECL_VIRTUAL_P (node->decl)) | |
602 return true; | |
603 } | |
604 return false; | |
605 } | |
606 | |
607 /* COMDAT functions must be shared only if they have address taken, | |
608 otherwise we can produce our own private implementation with | |
609 -fwhole-program. | |
610 Return true when turning COMDAT functoin static can not lead to wrong | |
611 code when the resulting object links with a library defining same COMDAT. | |
612 | |
613 Virtual functions do have their addresses taken from the vtables, | |
614 but in C++ there is no way to compare their addresses for equality. */ | |
615 | |
616 bool | |
617 cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) | |
618 { | |
619 if ((cgraph_address_taken_from_non_vtable_p (node) | |
620 && !DECL_VIRTUAL_P (node->decl)) | |
621 || !node->analyzed) | |
622 return false; | |
623 if (node->same_comdat_group) | |
624 { | |
625 struct cgraph_node *next; | |
626 | |
627 /* If more than one function is in the same COMDAT group, it must | |
628 be shared even if just one function in the comdat group has | |
629 address taken. */ | |
630 for (next = node->same_comdat_group; | |
631 next != node; next = next->same_comdat_group) | |
632 if (cgraph_address_taken_from_non_vtable_p (node) | |
633 && !DECL_VIRTUAL_P (next->decl)) | |
634 return false; | |
635 } | |
636 return true; | |
637 } | |
638 | |
639 /* Return true when function NODE should be considered externally visible. */ | |
640 | |
641 static bool | |
642 cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased) | |
643 { | |
644 struct cgraph_node *alias; | |
645 if (!node->local.finalized) | |
646 return false; | |
647 if (!DECL_COMDAT (node->decl) | |
648 && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))) | |
649 return false; | |
650 | |
651 /* Do not even try to be smart about aliased nodes. Until we properly | |
652 represent everything by same body alias, these are just evil. */ | |
653 if (aliased) | |
654 return true; | |
655 | |
656 /* Do not try to localize built-in functions yet. One of problems is that we | |
657 end up mangling their asm for WHOPR that makes it impossible to call them | |
658 using the implicit built-in declarations anymore. Similarly this enables | |
659 us to remove them as unreachable before actual calls may appear during | |
660 expansion or folding. */ | |
661 if (DECL_BUILT_IN (node->decl)) | |
662 return true; | |
663 | |
664 /* FIXME: We get wrong symbols with asm aliases in callgraph and LTO. | |
665 This is because very little of code knows that assembler name needs to | |
666 mangled. Avoid touching declarations with user asm name set to mask | |
667 some of the problems. */ | |
668 if (DECL_ASSEMBLER_NAME_SET_P (node->decl) | |
669 && IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))[0]=='*') | |
670 return true; | |
671 | |
672 /* If linker counts on us, we must preserve the function. */ | |
673 if (cgraph_used_from_object_file_p (node)) | |
674 return true; | |
675 if (DECL_PRESERVE_P (node->decl)) | |
676 return true; | |
677 if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) | |
678 return true; | |
679 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES | |
680 && lookup_attribute ("dllexport", DECL_ATTRIBUTES (node->decl))) | |
681 return true; | |
682 /* When doing LTO or whole program, we can bring COMDAT functoins static. | |
683 This improves code quality and we know we will duplicate them at most twice | |
684 (in the case that we are not using plugin and link with object file | |
685 implementing same COMDAT) */ | |
686 if ((in_lto_p || whole_program) | |
687 && DECL_COMDAT (node->decl) | |
688 && cgraph_comdat_can_be_unshared_p (node)) | |
689 return false; | |
690 | |
691 /* See if we have linker information about symbol not being used or | |
692 if we need to make guess based on the declaration. | |
693 | |
694 Even if the linker clams the symbol is unused, never bring internal | |
695 symbols that are declared by user as used or externally visible. | |
696 This is needed for i.e. references from asm statements. */ | |
697 for (alias = node->same_body; alias; alias = alias->next) | |
698 if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY) | |
699 break; | |
700 if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY) | |
701 return false; | |
702 | |
703 /* When doing link time optimizations, hidden symbols become local. */ | |
704 if (in_lto_p | |
705 && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN | |
706 || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL) | |
707 /* Be sure that node is defined in IR file, not in other object | |
708 file. In that case we don't set used_from_other_object_file. */ | |
709 && node->analyzed) | |
710 ; | |
711 else if (!whole_program) | |
712 return true; | |
713 | |
714 if (MAIN_NAME_P (DECL_NAME (node->decl))) | |
715 return true; | |
716 | |
717 return false; | |
718 } | |
719 | |
720 /* Return true when variable VNODE should be considered externally visible. */ | |
721 | |
722 static bool | |
723 varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) | |
724 { | |
725 struct varpool_node *alias; | |
726 if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl)) | |
727 return false; | |
728 | |
729 /* Do not even try to be smart about aliased nodes. Until we properly | |
730 represent everything by same body alias, these are just evil. */ | |
731 if (aliased) | |
732 return true; | |
733 | |
734 /* If linker counts on us, we must preserve the function. */ | |
735 if (varpool_used_from_object_file_p (vnode)) | |
736 return true; | |
737 | |
738 /* FIXME: We get wrong symbols with asm aliases in callgraph and LTO. | |
739 This is because very little of code knows that assembler name needs to | |
740 mangled. Avoid touching declarations with user asm name set to mask | |
741 some of the problems. */ | |
742 if (DECL_ASSEMBLER_NAME_SET_P (vnode->decl) | |
743 && IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (vnode->decl))[0]=='*') | |
744 return true; | |
745 | |
746 if (DECL_PRESERVE_P (vnode->decl)) | |
747 return true; | |
748 if (lookup_attribute ("externally_visible", | |
749 DECL_ATTRIBUTES (vnode->decl))) | |
750 return true; | |
751 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES | |
752 && lookup_attribute ("dllexport", | |
753 DECL_ATTRIBUTES (vnode->decl))) | |
754 return true; | |
755 | |
756 /* See if we have linker information about symbol not being used or | |
757 if we need to make guess based on the declaration. | |
758 | |
759 Even if the linker clams the symbol is unused, never bring internal | |
760 symbols that are declared by user as used or externally visible. | |
761 This is needed for i.e. references from asm statements. */ | |
762 if (varpool_used_from_object_file_p (vnode)) | |
763 return true; | |
764 for (alias = vnode->extra_name; alias; alias = alias->next) | |
765 if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY) | |
766 break; | |
767 if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) | |
768 return false; | |
769 | |
770 /* As a special case, the COMDAT virutal tables can be unshared. | |
771 In LTO mode turn vtables into static variables. The variable is readonly, | |
772 so this does not enable more optimization, but referring static var | |
773 is faster for dynamic linking. Also this match logic hidding vtables | |
774 from LTO symbol tables. */ | |
775 if ((in_lto_p || flag_whole_program) | |
776 && !vnode->force_output | |
777 && DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl)) | |
778 return false; | |
779 | |
780 /* When doing link time optimizations, hidden symbols become local. */ | |
781 if (in_lto_p | |
782 && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN | |
783 || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) | |
784 /* Be sure that node is defined in IR file, not in other object | |
785 file. In that case we don't set used_from_other_object_file. */ | |
786 && vnode->finalized) | |
787 ; | |
788 else if (!flag_whole_program) | |
789 return true; | |
790 | |
791 /* Do not attempt to privatize COMDATS by default. | |
792 This would break linking with C++ libraries sharing | |
793 inline definitions. | |
794 | |
795 FIXME: We can do so for readonly vars with no address taken and | |
796 possibly also for vtables since no direct pointer comparsion is done. | |
797 It might be interesting to do so to reduce linking overhead. */ | |
798 if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl)) | |
799 return true; | |
800 return false; | |
801 } | |
802 | |
803 /* Dissolve the same_comdat_group list in which NODE resides. */ | |
804 | |
805 static void | |
806 dissolve_same_comdat_group_list (struct cgraph_node *node) | |
807 { | |
808 struct cgraph_node *n = node, *next; | |
809 do | |
810 { | |
811 next = n->same_comdat_group; | |
812 n->same_comdat_group = NULL; | |
813 n = next; | |
814 } | |
815 while (n != node); | |
816 } | |
817 | |
818 /* Mark visibility of all functions. | |
819 | |
820 A local function is one whose calls can occur only in the current | |
821 compilation unit and all its calls are explicit, so we can change | |
822 its calling convention. We simply mark all static functions whose | |
823 address is not taken as local. | |
824 | |
825 We also change the TREE_PUBLIC flag of all declarations that are public | |
826 in language point of view but we want to overwrite this default | |
827 via visibilities for the backend point of view. */ | |
828 | |
829 static unsigned int | |
830 function_and_variable_visibility (bool whole_program) | |
831 { | |
832 struct cgraph_node *node; | |
833 struct varpool_node *vnode; | |
834 struct pointer_set_t *aliased_nodes = pointer_set_create (); | |
835 struct pointer_set_t *aliased_vnodes = pointer_set_create (); | |
836 unsigned i; | |
837 alias_pair *p; | |
838 | |
839 /* Discover aliased nodes. */ | |
840 FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p) | |
841 { | |
842 if (dump_file) | |
843 fprintf (dump_file, "Alias %s->%s", | |
844 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (p->decl)), | |
845 IDENTIFIER_POINTER (p->target)); | |
846 | |
847 if ((node = cgraph_node_for_asm (p->target)) != NULL | |
848 && !DECL_EXTERNAL (node->decl)) | |
849 { | |
850 if (!node->analyzed) | |
851 continue; | |
852 /* Weakrefs alias symbols from other compilation unit. In the case | |
853 the destination of weakref became available because of LTO, we must | |
854 mark it as needed. */ | |
855 if (in_lto_p | |
856 && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) | |
857 && !node->needed) | |
858 cgraph_mark_needed_node (node); | |
859 gcc_assert (node->needed); | |
860 pointer_set_insert (aliased_nodes, node); | |
861 if (dump_file) | |
862 fprintf (dump_file, " node %s/%i", | |
863 cgraph_node_name (node), node->uid); | |
864 } | |
865 else if ((vnode = varpool_node_for_asm (p->target)) != NULL | |
866 && !DECL_EXTERNAL (vnode->decl)) | |
867 { | |
868 /* Weakrefs alias symbols from other compilation unit. In the case | |
869 the destination of weakref became available because of LTO, we must | |
870 mark it as needed. */ | |
871 if (in_lto_p | |
872 && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) | |
873 && !vnode->needed) | |
874 varpool_mark_needed_node (vnode); | |
875 gcc_assert (vnode->needed); | |
876 pointer_set_insert (aliased_vnodes, vnode); | |
877 if (dump_file) | |
878 fprintf (dump_file, " varpool node %s", | |
879 varpool_node_name (vnode)); | |
880 } | |
881 if (dump_file) | |
882 fprintf (dump_file, "\n"); | |
883 } | |
884 | |
885 for (node = cgraph_nodes; node; node = node->next) | |
886 { | |
887 int flags = flags_from_decl_or_type (node->decl); | |
888 | |
889 /* Optimize away PURE and CONST constructors and destructors. */ | |
890 if (optimize | |
891 && (flags & (ECF_CONST | ECF_PURE)) | |
892 && !(flags & ECF_LOOPING_CONST_OR_PURE)) | |
893 { | |
894 DECL_STATIC_CONSTRUCTOR (node->decl) = 0; | |
895 DECL_STATIC_DESTRUCTOR (node->decl) = 0; | |
896 } | |
897 | |
898 /* Frontends and alias code marks nodes as needed before parsing is finished. | |
899 We may end up marking as node external nodes where this flag is meaningless | |
900 strip it. */ | |
901 if (node->needed | |
902 && (DECL_EXTERNAL (node->decl) || !node->analyzed)) | |
903 node->needed = 0; | |
904 | |
905 /* C++ FE on lack of COMDAT support create local COMDAT functions | |
906 (that ought to be shared but can not due to object format | |
907 limitations). It is neccesary to keep the flag to make rest of C++ FE | |
908 happy. Clear the flag here to avoid confusion in middle-end. */ | |
909 if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl)) | |
910 DECL_COMDAT (node->decl) = 0; | |
911 /* For external decls stop tracking same_comdat_group, it doesn't matter | |
912 what comdat group they are in when they won't be emitted in this TU, | |
913 and simplifies later passes. */ | |
914 if (node->same_comdat_group && DECL_EXTERNAL (node->decl)) | |
915 { | |
916 #ifdef ENABLE_CHECKING | |
917 struct cgraph_node *n; | |
918 | |
919 for (n = node->same_comdat_group; | |
920 n != node; | |
921 n = n->same_comdat_group) | |
922 /* If at least one of same comdat group functions is external, | |
923 all of them have to be, otherwise it is a front-end bug. */ | |
924 gcc_assert (DECL_EXTERNAL (n->decl)); | |
925 #endif | |
926 dissolve_same_comdat_group_list (node); | |
927 } | |
928 gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl)) | |
929 || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)); | |
930 if (cgraph_externally_visible_p (node, whole_program, | |
931 pointer_set_contains (aliased_nodes, | |
932 node))) | |
933 { | |
934 gcc_assert (!node->global.inlined_to); | |
935 node->local.externally_visible = true; | |
936 } | |
937 else | |
938 node->local.externally_visible = false; | |
939 if (!node->local.externally_visible && node->analyzed | |
940 && !DECL_EXTERNAL (node->decl)) | |
941 { | |
942 struct cgraph_node *alias; | |
943 gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl)); | |
944 cgraph_make_decl_local (node->decl); | |
945 node->resolution = LDPR_PREVAILING_DEF_IRONLY; | |
946 for (alias = node->same_body; alias; alias = alias->next) | |
947 cgraph_make_decl_local (alias->decl); | |
948 if (node->same_comdat_group) | |
949 /* cgraph_externally_visible_p has already checked all other nodes | |
950 in the group and they will all be made local. We need to | |
951 dissolve the group at once so that the predicate does not | |
952 segfault though. */ | |
953 dissolve_same_comdat_group_list (node); | |
954 } | |
955 node->local.local = cgraph_local_node_p (node); | |
956 } | |
957 for (vnode = varpool_nodes; vnode; vnode = vnode->next) | |
958 { | |
959 /* weak flag makes no sense on local variables. */ | |
960 gcc_assert (!DECL_WEAK (vnode->decl) | |
961 || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)); | |
962 /* In several cases declarations can not be common: | |
963 | |
964 - when declaration has initializer | |
965 - when it is in weak | |
966 - when it has specific section | |
967 - when it resides in non-generic address space. | |
968 - if declaration is local, it will get into .local common section | |
969 so common flag is not needed. Frontends still produce these in | |
970 certain cases, such as for: | |
971 | |
972 static int a __attribute__ ((common)) | |
973 | |
974 Canonicalize things here and clear the redundant flag. */ | |
975 if (DECL_COMMON (vnode->decl) | |
976 && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)) | |
977 || (DECL_INITIAL (vnode->decl) | |
978 && DECL_INITIAL (vnode->decl) != error_mark_node) | |
979 || DECL_WEAK (vnode->decl) | |
980 || DECL_SECTION_NAME (vnode->decl) != NULL | |
981 || ! (ADDR_SPACE_GENERIC_P | |
982 (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) | |
983 DECL_COMMON (vnode->decl) = 0; | |
984 } | |
985 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) | |
986 { | |
987 if (!vnode->finalized) | |
988 continue; | |
989 if (vnode->needed | |
990 && varpool_externally_visible_p | |
991 (vnode, | |
992 pointer_set_contains (aliased_vnodes, vnode))) | |
993 vnode->externally_visible = true; | |
994 else | |
995 vnode->externally_visible = false; | |
996 if (!vnode->externally_visible) | |
997 { | |
998 gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); | |
999 cgraph_make_decl_local (vnode->decl); | |
1000 vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; | |
1001 } | |
1002 gcc_assert (TREE_STATIC (vnode->decl)); | |
1003 } | |
1004 pointer_set_destroy (aliased_nodes); | |
1005 pointer_set_destroy (aliased_vnodes); | |
1006 | |
1007 if (dump_file) | |
1008 { | |
1009 fprintf (dump_file, "\nMarking local functions:"); | |
1010 for (node = cgraph_nodes; node; node = node->next) | |
1011 if (node->local.local) | |
1012 fprintf (dump_file, " %s", cgraph_node_name (node)); | |
1013 fprintf (dump_file, "\n\n"); | |
1014 fprintf (dump_file, "\nMarking externally visible functions:"); | |
1015 for (node = cgraph_nodes; node; node = node->next) | |
1016 if (node->local.externally_visible) | |
1017 fprintf (dump_file, " %s", cgraph_node_name (node)); | |
1018 fprintf (dump_file, "\n\n"); | |
1019 fprintf (dump_file, "\nMarking externally visible variables:"); | |
1020 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) | |
1021 if (vnode->externally_visible) | |
1022 fprintf (dump_file, " %s", varpool_node_name (vnode)); | |
1023 fprintf (dump_file, "\n\n"); | |
1024 } | |
1025 cgraph_function_flags_ready = true; | |
1026 return 0; | |
1027 } | |
1028 | |
1029 /* Local function pass handling visibilities. This happens before LTO streaming | |
1030 so in particular -fwhole-program should be ignored at this level. */ | |
1031 | |
1032 static unsigned int | |
1033 local_function_and_variable_visibility (void) | |
1034 { | |
1035 return function_and_variable_visibility (flag_whole_program && !flag_lto); | |
1036 } | |
1037 | |
1038 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = | |
1039 { | |
1040 { | |
1041 SIMPLE_IPA_PASS, | |
1042 "visibility", /* name */ | |
1043 NULL, /* gate */ | |
1044 local_function_and_variable_visibility,/* execute */ | |
1045 NULL, /* sub */ | |
1046 NULL, /* next */ | |
1047 0, /* static_pass_number */ | |
1048 TV_CGRAPHOPT, /* tv_id */ | |
1049 0, /* properties_required */ | |
1050 0, /* properties_provided */ | |
1051 0, /* properties_destroyed */ | |
1052 0, /* todo_flags_start */ | |
1053 TODO_remove_functions | TODO_dump_cgraph | |
1054 | TODO_ggc_collect /* todo_flags_finish */ | |
1055 } | |
1056 }; | |
1057 | |
1058 /* Do not re-run on ltrans stage. */ | |
1059 | |
1060 static bool | |
1061 gate_whole_program_function_and_variable_visibility (void) | |
1062 { | |
1063 return !flag_ltrans; | |
1064 } | |
1065 | |
1066 /* Bring functionss local at LTO time whith -fwhole-program. */ | |
1067 | |
1068 static unsigned int | |
1069 whole_program_function_and_variable_visibility (void) | |
1070 { | |
1071 struct cgraph_node *node; | |
1072 struct varpool_node *vnode; | |
1073 | |
1074 function_and_variable_visibility (flag_whole_program); | |
1075 | |
1076 for (node = cgraph_nodes; node; node = node->next) | |
1077 if ((node->local.externally_visible && !DECL_COMDAT (node->decl)) | |
1078 && node->local.finalized) | |
1079 cgraph_mark_needed_node (node); | |
1080 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) | |
1081 if (vnode->externally_visible && !DECL_COMDAT (vnode->decl)) | |
1082 varpool_mark_needed_node (vnode); | |
1083 if (dump_file) | |
1084 { | |
1085 fprintf (dump_file, "\nNeeded variables:"); | |
1086 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) | |
1087 if (vnode->needed) | |
1088 fprintf (dump_file, " %s", varpool_node_name (vnode)); | |
1089 fprintf (dump_file, "\n\n"); | |
1090 } | |
1091 if (optimize) | |
1092 ipa_discover_readonly_nonaddressable_vars (); | |
1093 return 0; | |
1094 } | |
1095 | |
1096 struct ipa_opt_pass_d pass_ipa_whole_program_visibility = | |
1097 { | |
1098 { | |
1099 IPA_PASS, | |
1100 "whole-program", /* name */ | |
1101 gate_whole_program_function_and_variable_visibility,/* gate */ | |
1102 whole_program_function_and_variable_visibility,/* execute */ | |
1103 NULL, /* sub */ | |
1104 NULL, /* next */ | |
1105 0, /* static_pass_number */ | |
1106 TV_CGRAPHOPT, /* tv_id */ | |
1107 0, /* properties_required */ | |
1108 0, /* properties_provided */ | |
1109 0, /* properties_destroyed */ | |
1110 0, /* todo_flags_start */ | |
1111 TODO_remove_functions | TODO_dump_cgraph | |
1112 | TODO_ggc_collect /* todo_flags_finish */ | |
1113 }, | |
1114 NULL, /* generate_summary */ | |
1115 NULL, /* write_summary */ | |
1116 NULL, /* read_summary */ | |
1117 NULL, /* write_optimization_summary */ | |
1118 NULL, /* read_optimization_summary */ | |
1119 NULL, /* stmt_fixup */ | |
1120 0, /* TODOs */ | |
1121 NULL, /* function_transform */ | |
1122 NULL, /* variable_transform */ | |
1123 }; | |
1124 | |
1125 /* Hash a cgraph node set element. */ | |
1126 | |
1127 static hashval_t | |
1128 hash_cgraph_node_set_element (const void *p) | |
1129 { | |
1130 const_cgraph_node_set_element element = (const_cgraph_node_set_element) p; | |
1131 return htab_hash_pointer (element->node); | |
1132 } | |
1133 | |
1134 /* Compare two cgraph node set elements. */ | |
1135 | |
1136 static int | |
1137 eq_cgraph_node_set_element (const void *p1, const void *p2) | |
1138 { | |
1139 const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1; | |
1140 const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2; | |
1141 | |
1142 return e1->node == e2->node; | |
1143 } | |
1144 | |
1145 /* Create a new cgraph node set. */ | |
1146 | |
1147 cgraph_node_set | |
1148 cgraph_node_set_new (void) | |
1149 { | |
1150 cgraph_node_set new_node_set; | |
1151 | |
1152 new_node_set = ggc_alloc_cgraph_node_set_def (); | |
1153 new_node_set->hashtab = htab_create_ggc (10, | |
1154 hash_cgraph_node_set_element, | |
1155 eq_cgraph_node_set_element, | |
1156 NULL); | |
1157 new_node_set->nodes = NULL; | |
1158 return new_node_set; | |
1159 } | |
1160 | |
1161 /* Add cgraph_node NODE to cgraph_node_set SET. */ | |
1162 | |
1163 void | |
1164 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node) | |
1165 { | |
1166 void **slot; | |
1167 cgraph_node_set_element element; | |
1168 struct cgraph_node_set_element_def dummy; | |
1169 | |
1170 dummy.node = node; | |
1171 slot = htab_find_slot (set->hashtab, &dummy, INSERT); | |
1172 | |
1173 if (*slot != HTAB_EMPTY_ENTRY) | |
1174 { | |
1175 element = (cgraph_node_set_element) *slot; | |
1176 gcc_assert (node == element->node | |
1177 && (VEC_index (cgraph_node_ptr, set->nodes, element->index) | |
1178 == node)); | |
1179 return; | |
1180 } | |
1181 | |
1182 /* Insert node into hash table. */ | |
1183 element = ggc_alloc_cgraph_node_set_element_def (); | |
1184 element->node = node; | |
1185 element->index = VEC_length (cgraph_node_ptr, set->nodes); | |
1186 *slot = element; | |
1187 | |
1188 /* Insert into node vector. */ | |
1189 VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node); | |
1190 } | |
1191 | |
1192 /* Remove cgraph_node NODE from cgraph_node_set SET. */ | |
1193 | |
1194 void | |
1195 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node) | |
1196 { | |
1197 void **slot, **last_slot; | |
1198 cgraph_node_set_element element, last_element; | |
1199 struct cgraph_node *last_node; | |
1200 struct cgraph_node_set_element_def dummy; | |
1201 | |
1202 dummy.node = node; | |
1203 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1204 if (slot == NULL) | |
1205 return; | |
1206 | |
1207 element = (cgraph_node_set_element) *slot; | |
1208 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index) | |
1209 == node); | |
1210 | |
1211 /* Remove from vector. We do this by swapping node with the last element | |
1212 of the vector. */ | |
1213 last_node = VEC_pop (cgraph_node_ptr, set->nodes); | |
1214 if (last_node != node) | |
1215 { | |
1216 dummy.node = last_node; | |
1217 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1218 last_element = (cgraph_node_set_element) *last_slot; | |
1219 gcc_assert (last_element); | |
1220 | |
1221 /* Move the last element to the original spot of NODE. */ | |
1222 last_element->index = element->index; | |
1223 VEC_replace (cgraph_node_ptr, set->nodes, last_element->index, | |
1224 last_node); | |
1225 } | |
1226 | |
1227 /* Remove element from hash table. */ | |
1228 htab_clear_slot (set->hashtab, slot); | |
1229 ggc_free (element); | |
1230 } | |
1231 | |
1232 /* Find NODE in SET and return an iterator to it if found. A null iterator | |
1233 is returned if NODE is not in SET. */ | |
1234 | |
1235 cgraph_node_set_iterator | |
1236 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node) | |
1237 { | |
1238 void **slot; | |
1239 struct cgraph_node_set_element_def dummy; | |
1240 cgraph_node_set_element element; | |
1241 cgraph_node_set_iterator csi; | |
1242 | |
1243 dummy.node = node; | |
1244 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1245 if (slot == NULL) | |
1246 csi.index = (unsigned) ~0; | |
1247 else | |
1248 { | |
1249 element = (cgraph_node_set_element) *slot; | |
1250 gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index) | |
1251 == node); | |
1252 csi.index = element->index; | |
1253 } | |
1254 csi.set = set; | |
1255 | |
1256 return csi; | |
1257 } | |
1258 | |
1259 /* Dump content of SET to file F. */ | |
1260 | |
1261 void | |
1262 dump_cgraph_node_set (FILE *f, cgraph_node_set set) | |
1263 { | |
1264 cgraph_node_set_iterator iter; | |
1265 | |
1266 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter)) | |
1267 { | |
1268 struct cgraph_node *node = csi_node (iter); | |
1269 fprintf (f, " %s/%i", cgraph_node_name (node), node->uid); | |
1270 } | |
1271 fprintf (f, "\n"); | |
1272 } | |
1273 | |
1274 /* Dump content of SET to stderr. */ | |
1275 | |
1276 DEBUG_FUNCTION void | |
1277 debug_cgraph_node_set (cgraph_node_set set) | |
1278 { | |
1279 dump_cgraph_node_set (stderr, set); | |
1280 } | |
1281 | |
1282 /* Hash a varpool node set element. */ | |
1283 | |
1284 static hashval_t | |
1285 hash_varpool_node_set_element (const void *p) | |
1286 { | |
1287 const_varpool_node_set_element element = (const_varpool_node_set_element) p; | |
1288 return htab_hash_pointer (element->node); | |
1289 } | |
1290 | |
1291 /* Compare two varpool node set elements. */ | |
1292 | |
1293 static int | |
1294 eq_varpool_node_set_element (const void *p1, const void *p2) | |
1295 { | |
1296 const_varpool_node_set_element e1 = (const_varpool_node_set_element) p1; | |
1297 const_varpool_node_set_element e2 = (const_varpool_node_set_element) p2; | |
1298 | |
1299 return e1->node == e2->node; | |
1300 } | |
1301 | |
1302 /* Create a new varpool node set. */ | |
1303 | |
1304 varpool_node_set | |
1305 varpool_node_set_new (void) | |
1306 { | |
1307 varpool_node_set new_node_set; | |
1308 | |
1309 new_node_set = ggc_alloc_varpool_node_set_def (); | |
1310 new_node_set->hashtab = htab_create_ggc (10, | |
1311 hash_varpool_node_set_element, | |
1312 eq_varpool_node_set_element, | |
1313 NULL); | |
1314 new_node_set->nodes = NULL; | |
1315 return new_node_set; | |
1316 } | |
1317 | |
1318 /* Add varpool_node NODE to varpool_node_set SET. */ | |
1319 | |
1320 void | |
1321 varpool_node_set_add (varpool_node_set set, struct varpool_node *node) | |
1322 { | |
1323 void **slot; | |
1324 varpool_node_set_element element; | |
1325 struct varpool_node_set_element_def dummy; | |
1326 | |
1327 dummy.node = node; | |
1328 slot = htab_find_slot (set->hashtab, &dummy, INSERT); | |
1329 | |
1330 if (*slot != HTAB_EMPTY_ENTRY) | |
1331 { | |
1332 element = (varpool_node_set_element) *slot; | |
1333 gcc_assert (node == element->node | |
1334 && (VEC_index (varpool_node_ptr, set->nodes, element->index) | |
1335 == node)); | |
1336 return; | |
1337 } | |
1338 | |
1339 /* Insert node into hash table. */ | |
1340 element = ggc_alloc_varpool_node_set_element_def (); | |
1341 element->node = node; | |
1342 element->index = VEC_length (varpool_node_ptr, set->nodes); | |
1343 *slot = element; | |
1344 | |
1345 /* Insert into node vector. */ | |
1346 VEC_safe_push (varpool_node_ptr, gc, set->nodes, node); | |
1347 } | |
1348 | |
1349 /* Remove varpool_node NODE from varpool_node_set SET. */ | |
1350 | |
1351 void | |
1352 varpool_node_set_remove (varpool_node_set set, struct varpool_node *node) | |
1353 { | |
1354 void **slot, **last_slot; | |
1355 varpool_node_set_element element, last_element; | |
1356 struct varpool_node *last_node; | |
1357 struct varpool_node_set_element_def dummy; | |
1358 | |
1359 dummy.node = node; | |
1360 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1361 if (slot == NULL) | |
1362 return; | |
1363 | |
1364 element = (varpool_node_set_element) *slot; | |
1365 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index) | |
1366 == node); | |
1367 | |
1368 /* Remove from vector. We do this by swapping node with the last element | |
1369 of the vector. */ | |
1370 last_node = VEC_pop (varpool_node_ptr, set->nodes); | |
1371 if (last_node != node) | |
1372 { | |
1373 dummy.node = last_node; | |
1374 last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1375 last_element = (varpool_node_set_element) *last_slot; | |
1376 gcc_assert (last_element); | |
1377 | |
1378 /* Move the last element to the original spot of NODE. */ | |
1379 last_element->index = element->index; | |
1380 VEC_replace (varpool_node_ptr, set->nodes, last_element->index, | |
1381 last_node); | |
1382 } | |
1383 | |
1384 /* Remove element from hash table. */ | |
1385 htab_clear_slot (set->hashtab, slot); | |
1386 ggc_free (element); | |
1387 } | |
1388 | |
1389 /* Find NODE in SET and return an iterator to it if found. A null iterator | |
1390 is returned if NODE is not in SET. */ | |
1391 | |
1392 varpool_node_set_iterator | |
1393 varpool_node_set_find (varpool_node_set set, struct varpool_node *node) | |
1394 { | |
1395 void **slot; | |
1396 struct varpool_node_set_element_def dummy; | |
1397 varpool_node_set_element element; | |
1398 varpool_node_set_iterator vsi; | |
1399 | |
1400 dummy.node = node; | |
1401 slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT); | |
1402 if (slot == NULL) | |
1403 vsi.index = (unsigned) ~0; | |
1404 else | |
1405 { | |
1406 element = (varpool_node_set_element) *slot; | |
1407 gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index) | |
1408 == node); | |
1409 vsi.index = element->index; | |
1410 } | |
1411 vsi.set = set; | |
1412 | |
1413 return vsi; | |
1414 } | |
1415 | |
1416 /* Dump content of SET to file F. */ | |
1417 | |
1418 void | |
1419 dump_varpool_node_set (FILE *f, varpool_node_set set) | |
1420 { | |
1421 varpool_node_set_iterator iter; | |
1422 | |
1423 for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter)) | |
1424 { | |
1425 struct varpool_node *node = vsi_node (iter); | |
1426 fprintf (f, " %s", varpool_node_name (node)); | |
1427 } | |
1428 fprintf (f, "\n"); | |
1429 } | |
1430 | |
1431 /* Dump content of SET to stderr. */ | |
1432 | |
1433 DEBUG_FUNCTION void | |
1434 debug_varpool_node_set (varpool_node_set set) | |
1435 { | |
1436 dump_varpool_node_set (stderr, set); | |
1437 } | |
1438 | |
1439 | |
1440 /* Simple ipa profile pass propagating frequencies across the callgraph. */ | |
1441 | |
1442 static unsigned int | |
1443 ipa_profile (void) | |
1444 { | |
1445 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
1446 struct cgraph_edge *e; | |
1447 int order_pos; | |
1448 bool something_changed = false; | |
1449 int i; | |
1450 | |
1451 order_pos = cgraph_postorder (order); | |
1452 for (i = order_pos - 1; i >= 0; i--) | |
1453 { | |
1454 if (order[i]->local.local && cgraph_propagate_frequency (order[i])) | |
1455 { | |
1456 for (e = order[i]->callees; e; e = e->next_callee) | |
1457 if (e->callee->local.local && !e->callee->aux) | |
1458 { | |
1459 something_changed = true; | |
1460 e->callee->aux = (void *)1; | |
1461 } | |
1462 } | |
1463 order[i]->aux = NULL; | |
1464 } | |
1465 | |
1466 while (something_changed) | |
1467 { | |
1468 something_changed = false; | |
1469 for (i = order_pos - 1; i >= 0; i--) | |
1470 { | |
1471 if (order[i]->aux && cgraph_propagate_frequency (order[i])) | |
1472 { | |
1473 for (e = order[i]->callees; e; e = e->next_callee) | |
1474 if (e->callee->local.local && !e->callee->aux) | |
1475 { | |
1476 something_changed = true; | |
1477 e->callee->aux = (void *)1; | |
1478 } | |
1479 } | |
1480 order[i]->aux = NULL; | |
1481 } | |
1482 } | |
1483 free (order); | |
1484 return 0; | |
1485 } | |
1486 | |
1487 static bool | |
1488 gate_ipa_profile (void) | |
1489 { | |
1490 return flag_ipa_profile; | |
1491 } | |
1492 | |
1493 struct ipa_opt_pass_d pass_ipa_profile = | |
1494 { | |
1495 { | |
1496 IPA_PASS, | |
1497 "ipa-profile", /* name */ | |
1498 gate_ipa_profile, /* gate */ | |
1499 ipa_profile, /* execute */ | |
1500 NULL, /* sub */ | |
1501 NULL, /* next */ | |
1502 0, /* static_pass_number */ | |
1503 TV_IPA_PROFILE, /* tv_id */ | |
1504 0, /* properties_required */ | |
1505 0, /* properties_provided */ | |
1506 0, /* properties_destroyed */ | |
1507 0, /* todo_flags_start */ | |
1508 0 /* todo_flags_finish */ | |
1509 }, | |
1510 NULL, /* generate_summary */ | |
1511 NULL, /* write_summary */ | |
1512 NULL, /* read_summary */ | |
1513 NULL, /* write_optimization_summary */ | |
1514 NULL, /* read_optimization_summary */ | |
1515 NULL, /* stmt_fixup */ | |
1516 0, /* TODOs */ | |
1517 NULL, /* function_transform */ | |
1518 NULL /* variable_transform */ | |
1519 }; | |
1520 | 845 |
1521 /* Generate and emit a static constructor or destructor. WHICH must | 846 /* Generate and emit a static constructor or destructor. WHICH must |
1522 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY | 847 be one of 'I' (for a constructor), 'D' (for a destructor), 'P' |
1523 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the | 848 (for chp static vars constructor) or 'B' (for chkp static bounds |
1524 initialization priority for this constructor or destructor. | 849 constructor). BODY is a STATEMENT_LIST containing GENERIC |
850 statements. PRIORITY is the initialization priority for this | |
851 constructor or destructor. | |
1525 | 852 |
1526 FINAL specify whether the externally visible name for collect2 should | 853 FINAL specify whether the externally visible name for collect2 should |
1527 be produced. */ | 854 be produced. */ |
1528 | 855 |
1529 static void | 856 static void |
1557 allocate_struct_function (decl, false); | 884 allocate_struct_function (decl, false); |
1558 | 885 |
1559 TREE_STATIC (decl) = 1; | 886 TREE_STATIC (decl) = 1; |
1560 TREE_USED (decl) = 1; | 887 TREE_USED (decl) = 1; |
1561 DECL_ARTIFICIAL (decl) = 1; | 888 DECL_ARTIFICIAL (decl) = 1; |
889 DECL_IGNORED_P (decl) = 1; | |
1562 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; | 890 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; |
1563 DECL_SAVED_TREE (decl) = body; | 891 DECL_SAVED_TREE (decl) = body; |
1564 if (!targetm.have_ctors_dtors && final) | 892 if (!targetm.have_ctors_dtors && final) |
1565 { | 893 { |
1566 TREE_PUBLIC (decl) = 1; | 894 TREE_PUBLIC (decl) = 1; |
1567 DECL_PRESERVE_P (decl) = 1; | 895 DECL_PRESERVE_P (decl) = 1; |
1568 } | 896 } |
1569 DECL_UNINLINABLE (decl) = 1; | 897 DECL_UNINLINABLE (decl) = 1; |
1570 | 898 |
1571 DECL_INITIAL (decl) = make_node (BLOCK); | 899 DECL_INITIAL (decl) = make_node (BLOCK); |
900 BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl; | |
1572 TREE_USED (DECL_INITIAL (decl)) = 1; | 901 TREE_USED (DECL_INITIAL (decl)) = 1; |
1573 | 902 |
1574 DECL_SOURCE_LOCATION (decl) = input_location; | 903 DECL_SOURCE_LOCATION (decl) = input_location; |
1575 cfun->function_end_locus = input_location; | 904 cfun->function_end_locus = input_location; |
1576 | 905 |
1577 switch (which) | 906 switch (which) |
1578 { | 907 { |
1579 case 'I': | 908 case 'I': |
1580 DECL_STATIC_CONSTRUCTOR (decl) = 1; | 909 DECL_STATIC_CONSTRUCTOR (decl) = 1; |
910 decl_init_priority_insert (decl, priority); | |
911 break; | |
912 case 'P': | |
913 DECL_STATIC_CONSTRUCTOR (decl) = 1; | |
914 DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("chkp ctor"), | |
915 NULL, | |
916 NULL_TREE); | |
917 decl_init_priority_insert (decl, priority); | |
918 break; | |
919 case 'B': | |
920 DECL_STATIC_CONSTRUCTOR (decl) = 1; | |
921 DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("bnd_legacy"), | |
922 NULL, | |
923 NULL_TREE); | |
1581 decl_init_priority_insert (decl, priority); | 924 decl_init_priority_insert (decl, priority); |
1582 break; | 925 break; |
1583 case 'D': | 926 case 'D': |
1584 DECL_STATIC_DESTRUCTOR (decl) = 1; | 927 DECL_STATIC_DESTRUCTOR (decl) = 1; |
1585 decl_fini_priority_insert (decl, priority); | 928 decl_fini_priority_insert (decl, priority); |
1588 gcc_unreachable (); | 931 gcc_unreachable (); |
1589 } | 932 } |
1590 | 933 |
1591 gimplify_function_tree (decl); | 934 gimplify_function_tree (decl); |
1592 | 935 |
1593 cgraph_add_new_function (decl, false); | 936 cgraph_node::add_new_function (decl, false); |
1594 | 937 |
1595 set_cfun (NULL); | 938 set_cfun (NULL); |
1596 current_function_decl = NULL; | 939 current_function_decl = NULL; |
1597 } | 940 } |
1598 | 941 |
1599 /* Generate and emit a static constructor or destructor. WHICH must | 942 /* Generate and emit a static constructor or destructor. WHICH must |
1600 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY | 943 be one of 'I' (for a constructor), 'D' (for a destructor), 'P' |
1601 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the | 944 (for chkp static vars constructor) or 'B' (for chkp static bounds |
1602 initialization priority for this constructor or destructor. */ | 945 constructor). BODY is a STATEMENT_LIST containing GENERIC |
946 statements. PRIORITY is the initialization priority for this | |
947 constructor or destructor. */ | |
1603 | 948 |
1604 void | 949 void |
1605 cgraph_build_static_cdtor (char which, tree body, int priority) | 950 cgraph_build_static_cdtor (char which, tree body, int priority) |
1606 { | 951 { |
1607 cgraph_build_static_cdtor_1 (which, body, priority, false); | 952 cgraph_build_static_cdtor_1 (which, body, priority, false); |
1608 } | 953 } |
1609 | |
1610 /* A vector of FUNCTION_DECLs declared as static constructors. */ | |
1611 static VEC(tree, heap) *static_ctors; | |
1612 /* A vector of FUNCTION_DECLs declared as static destructors. */ | |
1613 static VEC(tree, heap) *static_dtors; | |
1614 | 954 |
1615 /* When target does not have ctors and dtors, we call all constructor | 955 /* When target does not have ctors and dtors, we call all constructor |
1616 and destructor by special initialization/destruction function | 956 and destructor by special initialization/destruction function |
1617 recognized by collect2. | 957 recognized by collect2. |
1618 | 958 |
1619 When we are going to build this function, collect all constructors and | 959 When we are going to build this function, collect all constructors and |
1620 destructors and turn them into normal functions. */ | 960 destructors and turn them into normal functions. */ |
1621 | 961 |
1622 static void | 962 static void |
1623 record_cdtor_fn (struct cgraph_node *node) | 963 record_cdtor_fn (struct cgraph_node *node, vec<tree> *ctors, vec<tree> *dtors) |
1624 { | 964 { |
1625 if (DECL_STATIC_CONSTRUCTOR (node->decl)) | 965 if (DECL_STATIC_CONSTRUCTOR (node->decl)) |
1626 VEC_safe_push (tree, heap, static_ctors, node->decl); | 966 ctors->safe_push (node->decl); |
1627 if (DECL_STATIC_DESTRUCTOR (node->decl)) | 967 if (DECL_STATIC_DESTRUCTOR (node->decl)) |
1628 VEC_safe_push (tree, heap, static_dtors, node->decl); | 968 dtors->safe_push (node->decl); |
1629 node = cgraph_node (node->decl); | 969 node = cgraph_node::get (node->decl); |
1630 node->local.disregard_inline_limits = 1; | 970 DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1; |
1631 } | 971 } |
1632 | 972 |
1633 /* Define global constructors/destructor functions for the CDTORS, of | 973 /* Define global constructors/destructor functions for the CDTORS, of |
1634 which they are LEN. The CDTORS are sorted by initialization | 974 which they are LEN. The CDTORS are sorted by initialization |
1635 priority. If CTOR_P is true, these are constructors; otherwise, | 975 priority. If CTOR_P is true, these are constructors; otherwise, |
1636 they are destructors. */ | 976 they are destructors. */ |
1637 | 977 |
1638 static void | 978 static void |
1639 build_cdtor (bool ctor_p, VEC (tree, heap) *cdtors) | 979 build_cdtor (bool ctor_p, const vec<tree> &cdtors) |
1640 { | 980 { |
1641 size_t i,j; | 981 size_t i,j; |
1642 size_t len = VEC_length (tree, cdtors); | 982 size_t len = cdtors.length (); |
1643 | 983 |
1644 i = 0; | 984 i = 0; |
1645 while (i < len) | 985 while (i < len) |
1646 { | 986 { |
1647 tree body; | 987 tree body; |
1652 body = NULL_TREE; | 992 body = NULL_TREE; |
1653 j = i; | 993 j = i; |
1654 do | 994 do |
1655 { | 995 { |
1656 priority_type p; | 996 priority_type p; |
1657 fn = VEC_index (tree, cdtors, j); | 997 fn = cdtors[j]; |
1658 p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn); | 998 p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn); |
1659 if (j == i) | 999 if (j == i) |
1660 priority = p; | 1000 priority = p; |
1661 else if (p != priority) | 1001 else if (p != priority) |
1662 break; | 1002 break; |
1674 /* Find the next batch of constructors/destructors with the same | 1014 /* Find the next batch of constructors/destructors with the same |
1675 initialization priority. */ | 1015 initialization priority. */ |
1676 for (;i < j; i++) | 1016 for (;i < j; i++) |
1677 { | 1017 { |
1678 tree call; | 1018 tree call; |
1679 fn = VEC_index (tree, cdtors, i); | 1019 fn = cdtors[i]; |
1680 call = build_call_expr (fn, 0); | 1020 call = build_call_expr (fn, 0); |
1681 if (ctor_p) | 1021 if (ctor_p) |
1682 DECL_STATIC_CONSTRUCTOR (fn) = 0; | 1022 DECL_STATIC_CONSTRUCTOR (fn) = 0; |
1683 else | 1023 else |
1684 DECL_STATIC_DESTRUCTOR (fn) = 0; | 1024 DECL_STATIC_DESTRUCTOR (fn) = 0; |
1751 /* Generate functions to call static constructors and destructors | 1091 /* Generate functions to call static constructors and destructors |
1752 for targets that do not support .ctors/.dtors sections. These | 1092 for targets that do not support .ctors/.dtors sections. These |
1753 functions have magic names which are detected by collect2. */ | 1093 functions have magic names which are detected by collect2. */ |
1754 | 1094 |
1755 static void | 1095 static void |
1756 build_cdtor_fns (void) | 1096 build_cdtor_fns (vec<tree> *ctors, vec<tree> *dtors) |
1757 { | 1097 { |
1758 if (!VEC_empty (tree, static_ctors)) | 1098 if (!ctors->is_empty ()) |
1759 { | 1099 { |
1760 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); | 1100 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); |
1761 VEC_qsort (tree, static_ctors, compare_ctor); | 1101 ctors->qsort (compare_ctor); |
1762 build_cdtor (/*ctor_p=*/true, static_ctors); | 1102 build_cdtor (/*ctor_p=*/true, *ctors); |
1763 } | 1103 } |
1764 | 1104 |
1765 if (!VEC_empty (tree, static_dtors)) | 1105 if (!dtors->is_empty ()) |
1766 { | 1106 { |
1767 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); | 1107 gcc_assert (!targetm.have_ctors_dtors || in_lto_p); |
1768 VEC_qsort (tree, static_dtors, compare_dtor); | 1108 dtors->qsort (compare_dtor); |
1769 build_cdtor (/*ctor_p=*/false, static_dtors); | 1109 build_cdtor (/*ctor_p=*/false, *dtors); |
1770 } | 1110 } |
1771 } | 1111 } |
1772 | 1112 |
1773 /* Look for constructors and destructors and produce function calling them. | 1113 /* Look for constructors and destructors and produce function calling them. |
1774 This is needed for targets not supporting ctors or dtors, but we perform the | 1114 This is needed for targets not supporting ctors or dtors, but we perform the |
1775 transformation also at linktime to merge possibly numberous | 1115 transformation also at linktime to merge possibly numerous |
1776 constructors/destructors into single function to improve code locality and | 1116 constructors/destructors into single function to improve code locality and |
1777 reduce size. */ | 1117 reduce size. */ |
1778 | 1118 |
1779 static unsigned int | 1119 static unsigned int |
1780 ipa_cdtor_merge (void) | 1120 ipa_cdtor_merge (void) |
1781 { | 1121 { |
1122 /* A vector of FUNCTION_DECLs declared as static constructors. */ | |
1123 auto_vec<tree, 20> ctors; | |
1124 /* A vector of FUNCTION_DECLs declared as static destructors. */ | |
1125 auto_vec<tree, 20> dtors; | |
1782 struct cgraph_node *node; | 1126 struct cgraph_node *node; |
1783 for (node = cgraph_nodes; node; node = node->next) | 1127 FOR_EACH_DEFINED_FUNCTION (node) |
1784 if (node->analyzed | 1128 if (DECL_STATIC_CONSTRUCTOR (node->decl) |
1785 && (DECL_STATIC_CONSTRUCTOR (node->decl) | 1129 || DECL_STATIC_DESTRUCTOR (node->decl)) |
1786 || DECL_STATIC_DESTRUCTOR (node->decl))) | 1130 record_cdtor_fn (node, &ctors, &dtors); |
1787 record_cdtor_fn (node); | 1131 build_cdtor_fns (&ctors, &dtors); |
1788 build_cdtor_fns (); | |
1789 VEC_free (tree, heap, static_ctors); | |
1790 VEC_free (tree, heap, static_dtors); | |
1791 return 0; | 1132 return 0; |
1792 } | 1133 } |
1793 | 1134 |
1794 /* Perform the pass when we have no ctors/dtors support | 1135 namespace { |
1795 or at LTO time to merge multiple constructors into single | 1136 |
1796 function. */ | 1137 const pass_data pass_data_ipa_cdtor_merge = |
1797 | 1138 { |
1798 static bool | 1139 IPA_PASS, /* type */ |
1799 gate_ipa_cdtor_merge (void) | 1140 "cdtor", /* name */ |
1800 { | 1141 OPTGROUP_NONE, /* optinfo_flags */ |
1801 return !targetm.have_ctors_dtors || (optimize && in_lto_p); | 1142 TV_CGRAPHOPT, /* tv_id */ |
1802 } | 1143 0, /* properties_required */ |
1803 | 1144 0, /* properties_provided */ |
1804 struct ipa_opt_pass_d pass_ipa_cdtor_merge = | 1145 0, /* properties_destroyed */ |
1805 { | 1146 0, /* todo_flags_start */ |
1806 { | 1147 0, /* todo_flags_finish */ |
1807 IPA_PASS, | |
1808 "cdtor", /* name */ | |
1809 gate_ipa_cdtor_merge, /* gate */ | |
1810 ipa_cdtor_merge, /* execute */ | |
1811 NULL, /* sub */ | |
1812 NULL, /* next */ | |
1813 0, /* static_pass_number */ | |
1814 TV_CGRAPHOPT, /* tv_id */ | |
1815 0, /* properties_required */ | |
1816 0, /* properties_provided */ | |
1817 0, /* properties_destroyed */ | |
1818 0, /* todo_flags_start */ | |
1819 0 /* todo_flags_finish */ | |
1820 }, | |
1821 NULL, /* generate_summary */ | |
1822 NULL, /* write_summary */ | |
1823 NULL, /* read_summary */ | |
1824 NULL, /* write_optimization_summary */ | |
1825 NULL, /* read_optimization_summary */ | |
1826 NULL, /* stmt_fixup */ | |
1827 0, /* TODOs */ | |
1828 NULL, /* function_transform */ | |
1829 NULL /* variable_transform */ | |
1830 }; | 1148 }; |
1149 | |
1150 class pass_ipa_cdtor_merge : public ipa_opt_pass_d | |
1151 { | |
1152 public: | |
1153 pass_ipa_cdtor_merge (gcc::context *ctxt) | |
1154 : ipa_opt_pass_d (pass_data_ipa_cdtor_merge, ctxt, | |
1155 NULL, /* generate_summary */ | |
1156 NULL, /* write_summary */ | |
1157 NULL, /* read_summary */ | |
1158 NULL, /* write_optimization_summary */ | |
1159 NULL, /* read_optimization_summary */ | |
1160 NULL, /* stmt_fixup */ | |
1161 0, /* function_transform_todo_flags_start */ | |
1162 NULL, /* function_transform */ | |
1163 NULL) /* variable_transform */ | |
1164 {} | |
1165 | |
1166 /* opt_pass methods: */ | |
1167 virtual bool gate (function *); | |
1168 virtual unsigned int execute (function *) { return ipa_cdtor_merge (); } | |
1169 | |
1170 }; // class pass_ipa_cdtor_merge | |
1171 | |
1172 bool | |
1173 pass_ipa_cdtor_merge::gate (function *) | |
1174 { | |
1175 /* Perform the pass when we have no ctors/dtors support | |
1176 or at LTO time to merge multiple constructors into single | |
1177 function. */ | |
1178 return !targetm.have_ctors_dtors || in_lto_p; | |
1179 } | |
1180 | |
1181 } // anon namespace | |
1182 | |
1183 ipa_opt_pass_d * | |
1184 make_pass_ipa_cdtor_merge (gcc::context *ctxt) | |
1185 { | |
1186 return new pass_ipa_cdtor_merge (ctxt); | |
1187 } | |
1188 | |
1189 /* Invalid pointer representing BOTTOM for single user dataflow. */ | |
1190 #define BOTTOM ((cgraph_node *)(size_t) 2) | |
1191 | |
1192 /* Meet operation for single user dataflow. | |
1193 Here we want to associate variables with sigle function that may access it. | |
1194 | |
1195 FUNCTION is current single user of a variable, VAR is variable that uses it. | |
1196 Latttice is stored in SINGLE_USER_MAP. | |
1197 | |
1198 We represent: | |
1199 - TOP by no entry in SIGNLE_USER_MAP | |
1200 - BOTTOM by BOTTOM in AUX pointer (to save lookups) | |
1201 - known single user by cgraph pointer in SINGLE_USER_MAP. */ | |
1202 | |
1203 cgraph_node * | |
1204 meet (cgraph_node *function, varpool_node *var, | |
1205 hash_map<varpool_node *, cgraph_node *> &single_user_map) | |
1206 { | |
1207 struct cgraph_node *user, **f; | |
1208 | |
1209 if (var->aux == BOTTOM) | |
1210 return BOTTOM; | |
1211 | |
1212 f = single_user_map.get (var); | |
1213 if (!f) | |
1214 return function; | |
1215 user = *f; | |
1216 if (!function) | |
1217 return user; | |
1218 else if (function != user) | |
1219 return BOTTOM; | |
1220 else | |
1221 return function; | |
1222 } | |
1223 | |
1224 /* Propagation step of single-use dataflow. | |
1225 | |
1226 Check all uses of VNODE and see if they are used by single function FUNCTION. | |
1227 SINGLE_USER_MAP represents the dataflow lattice. */ | |
1228 | |
1229 cgraph_node * | |
1230 propagate_single_user (varpool_node *vnode, cgraph_node *function, | |
1231 hash_map<varpool_node *, cgraph_node *> &single_user_map) | |
1232 { | |
1233 int i; | |
1234 struct ipa_ref *ref; | |
1235 | |
1236 gcc_assert (!vnode->externally_visible); | |
1237 | |
1238 /* If node is an alias, first meet with its target. */ | |
1239 if (vnode->alias) | |
1240 function = meet (function, vnode->get_alias_target (), single_user_map); | |
1241 | |
1242 /* Check all users and see if they correspond to a single function. */ | |
1243 for (i = 0; vnode->iterate_referring (i, ref) && function != BOTTOM; i++) | |
1244 { | |
1245 struct cgraph_node *cnode = dyn_cast <cgraph_node *> (ref->referring); | |
1246 if (cnode) | |
1247 { | |
1248 if (cnode->global.inlined_to) | |
1249 cnode = cnode->global.inlined_to; | |
1250 if (!function) | |
1251 function = cnode; | |
1252 else if (function != cnode) | |
1253 function = BOTTOM; | |
1254 } | |
1255 else | |
1256 function = meet (function, dyn_cast <varpool_node *> (ref->referring), | |
1257 single_user_map); | |
1258 } | |
1259 return function; | |
1260 } | |
1261 | |
1262 /* Pass setting used_by_single_function flag. | |
1263 This flag is set on variable when there is only one function that may | |
1264 possibly referr to it. */ | |
1265 | |
1266 static unsigned int | |
1267 ipa_single_use (void) | |
1268 { | |
1269 varpool_node *first = (varpool_node *) (void *) 1; | |
1270 varpool_node *var; | |
1271 hash_map<varpool_node *, cgraph_node *> single_user_map; | |
1272 | |
1273 FOR_EACH_DEFINED_VARIABLE (var) | |
1274 if (!var->all_refs_explicit_p ()) | |
1275 var->aux = BOTTOM; | |
1276 else | |
1277 { | |
1278 /* Enqueue symbol for dataflow. */ | |
1279 var->aux = first; | |
1280 first = var; | |
1281 } | |
1282 | |
1283 /* The actual dataflow. */ | |
1284 | |
1285 while (first != (void *) 1) | |
1286 { | |
1287 cgraph_node *user, *orig_user, **f; | |
1288 | |
1289 var = first; | |
1290 first = (varpool_node *)first->aux; | |
1291 | |
1292 f = single_user_map.get (var); | |
1293 if (f) | |
1294 orig_user = *f; | |
1295 else | |
1296 orig_user = NULL; | |
1297 user = propagate_single_user (var, orig_user, single_user_map); | |
1298 | |
1299 gcc_checking_assert (var->aux != BOTTOM); | |
1300 | |
1301 /* If user differs, enqueue all references. */ | |
1302 if (user != orig_user) | |
1303 { | |
1304 unsigned int i; | |
1305 ipa_ref *ref; | |
1306 | |
1307 single_user_map.put (var, user); | |
1308 | |
1309 /* Enqueue all aliases for re-processing. */ | |
1310 for (i = 0; var->iterate_direct_aliases (i, ref); i++) | |
1311 if (!ref->referring->aux) | |
1312 { | |
1313 ref->referring->aux = first; | |
1314 first = dyn_cast <varpool_node *> (ref->referring); | |
1315 } | |
1316 /* Enqueue all users for re-processing. */ | |
1317 for (i = 0; var->iterate_reference (i, ref); i++) | |
1318 if (!ref->referred->aux | |
1319 && ref->referred->definition | |
1320 && is_a <varpool_node *> (ref->referred)) | |
1321 { | |
1322 ref->referred->aux = first; | |
1323 first = dyn_cast <varpool_node *> (ref->referred); | |
1324 } | |
1325 | |
1326 /* If user is BOTTOM, just punt on this var. */ | |
1327 if (user == BOTTOM) | |
1328 var->aux = BOTTOM; | |
1329 else | |
1330 var->aux = NULL; | |
1331 } | |
1332 else | |
1333 var->aux = NULL; | |
1334 } | |
1335 | |
1336 FOR_EACH_DEFINED_VARIABLE (var) | |
1337 { | |
1338 if (var->aux != BOTTOM) | |
1339 { | |
1340 /* Not having the single user known means that the VAR is | |
1341 unreachable. Either someone forgot to remove unreachable | |
1342 variables or the reachability here is wrong. */ | |
1343 | |
1344 gcc_checking_assert (single_user_map.get (var)); | |
1345 | |
1346 if (dump_file) | |
1347 { | |
1348 fprintf (dump_file, "Variable %s is used by single function\n", | |
1349 var->dump_name ()); | |
1350 } | |
1351 var->used_by_single_function = true; | |
1352 } | |
1353 var->aux = NULL; | |
1354 } | |
1355 return 0; | |
1356 } | |
1357 | |
1358 namespace { | |
1359 | |
1360 const pass_data pass_data_ipa_single_use = | |
1361 { | |
1362 IPA_PASS, /* type */ | |
1363 "single-use", /* name */ | |
1364 OPTGROUP_NONE, /* optinfo_flags */ | |
1365 TV_CGRAPHOPT, /* tv_id */ | |
1366 0, /* properties_required */ | |
1367 0, /* properties_provided */ | |
1368 0, /* properties_destroyed */ | |
1369 0, /* todo_flags_start */ | |
1370 0, /* todo_flags_finish */ | |
1371 }; | |
1372 | |
1373 class pass_ipa_single_use : public ipa_opt_pass_d | |
1374 { | |
1375 public: | |
1376 pass_ipa_single_use (gcc::context *ctxt) | |
1377 : ipa_opt_pass_d (pass_data_ipa_single_use, ctxt, | |
1378 NULL, /* generate_summary */ | |
1379 NULL, /* write_summary */ | |
1380 NULL, /* read_summary */ | |
1381 NULL, /* write_optimization_summary */ | |
1382 NULL, /* read_optimization_summary */ | |
1383 NULL, /* stmt_fixup */ | |
1384 0, /* function_transform_todo_flags_start */ | |
1385 NULL, /* function_transform */ | |
1386 NULL) /* variable_transform */ | |
1387 {} | |
1388 | |
1389 /* opt_pass methods: */ | |
1390 virtual unsigned int execute (function *) { return ipa_single_use (); } | |
1391 | |
1392 }; // class pass_ipa_single_use | |
1393 | |
1394 } // anon namespace | |
1395 | |
1396 ipa_opt_pass_d * | |
1397 make_pass_ipa_single_use (gcc::context *ctxt) | |
1398 { | |
1399 return new pass_ipa_single_use (ctxt); | |
1400 } | |
1401 | |
1402 /* Materialize all clones. */ | |
1403 | |
1404 namespace { | |
1405 | |
1406 const pass_data pass_data_materialize_all_clones = | |
1407 { | |
1408 SIMPLE_IPA_PASS, /* type */ | |
1409 "materialize-all-clones", /* name */ | |
1410 OPTGROUP_NONE, /* optinfo_flags */ | |
1411 TV_IPA_OPT, /* tv_id */ | |
1412 0, /* properties_required */ | |
1413 0, /* properties_provided */ | |
1414 0, /* properties_destroyed */ | |
1415 0, /* todo_flags_start */ | |
1416 0, /* todo_flags_finish */ | |
1417 }; | |
1418 | |
1419 class pass_materialize_all_clones : public simple_ipa_opt_pass | |
1420 { | |
1421 public: | |
1422 pass_materialize_all_clones (gcc::context *ctxt) | |
1423 : simple_ipa_opt_pass (pass_data_materialize_all_clones, ctxt) | |
1424 {} | |
1425 | |
1426 /* opt_pass methods: */ | |
1427 virtual unsigned int execute (function *) | |
1428 { | |
1429 symtab->materialize_all_clones (); | |
1430 return 0; | |
1431 } | |
1432 | |
1433 }; // class pass_materialize_all_clones | |
1434 | |
1435 } // anon namespace | |
1436 | |
1437 simple_ipa_opt_pass * | |
1438 make_pass_materialize_all_clones (gcc::context *ctxt) | |
1439 { | |
1440 return new pass_materialize_all_clones (ctxt); | |
1441 } |