]>
Commit | Line | Data |
---|---|---|
7aeffc5f | 1 | /* IPA visibility pass |
f1717362 | 2 | Copyright (C) 2003-2016 Free Software Foundation, Inc. |
7aeffc5f | 3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it under | |
7 | the terms of the GNU General Public License as published by the Free | |
8 | Software Foundation; either version 3, or (at your option) any later | |
9 | version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GCC; see the file COPYING3. If not see | |
18 | <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | /* This file implements two related passes: | |
21 | ||
22 | - pass_data_ipa_function_and_variable_visibility run just after | |
23 | symbol table, references and callgraph are built | |
24 | ||
25 | - pass_data_ipa_function_and_variable_visibility run as first | |
26 | proper IPA pass (that is after early optimization, or, (with LTO) | |
27 | as a first pass done at link-time. | |
28 | ||
29 | Purpose of both passes is to set correctly visibility properties | |
30 | of all symbols. This includes: | |
31 | ||
32 | - Symbol privatization: | |
33 | ||
34 | Some symbols that are declared public by frontend may be | |
35 | turned local (either by -fwhole-program flag, by linker plugin feedback | |
36 | or by other reasons) | |
37 | ||
38 | - Discovery of local functions: | |
39 | ||
40 | A local function is one whose calls can occur only in the current | |
41 | compilation unit and all its calls are explicit, so we can change | |
42 | its calling convention. We simply mark all static functions whose | |
43 | address is not taken as local. | |
44 | ||
45 | externally_visible flag is set for symbols that can not be privatized. | |
46 | For privatized symbols we clear TREE_PUBLIC flag and dismantle comdat | |
47 | group. | |
48 | ||
49 | - Dismantling of comdat groups: | |
50 | ||
51 | Comdat group represent a section that may be replaced by linker by | |
52 | a different copy of the same section from other unit. | |
53 | If we have resolution information (from linker plugin) and we know that | |
54 | a given comdat gorup is prevailing, we can dismantle it and turn symbols | |
55 | into normal symbols. If the resolution information says that the | |
56 | section was previaled by copy from non-LTO code, we can also dismantle | |
57 | it and turn all symbols into external. | |
58 | ||
59 | - Local aliases: | |
60 | ||
61 | Some symbols can be interposed by dynamic linker. Refering to these | |
62 | symbols is expensive, since it needs to be overwritable by the dynamic | |
63 | linker. In some cases we know that the interposition does not change | |
64 | semantic and we can always refer to a local copy (as in the case of | |
65 | inline function). In this case we produce a local alias and redirect | |
66 | calls to it. | |
67 | ||
68 | TODO: This should be done for references, too. | |
69 | ||
70 | - Removal of static ocnstructors and destructors that have no side effects. | |
71 | ||
72 | - Regularization of several oddities introduced by frontends that may | |
73 | be impractical later in the optimization queue. */ | |
74 | ||
75 | #include "config.h" | |
76 | #include "system.h" | |
77 | #include "coretypes.h" | |
78 | #include "tm.h" | |
1140c305 | 79 | #include "function.h" |
7c29e30e | 80 | #include "tree.h" |
81 | #include "gimple-expr.h" | |
7aeffc5f | 82 | #include "tree-pass.h" |
7c29e30e | 83 | #include "cgraph.h" |
7aeffc5f | 84 | #include "calls.h" |
825463d4 | 85 | #include "varasm.h" |
7aeffc5f | 86 | |
87 | /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ | |
88 | ||
c5e076fc | 89 | static bool |
90 | non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
7aeffc5f | 91 | { |
a09576fe | 92 | return !(node->only_called_directly_or_aliased_p () |
93 | /* i386 would need update to output thunk with locak calling | |
94 | ocnvetions. */ | |
95 | && !node->thunk.thunk_p | |
96 | && node->definition | |
97 | && !DECL_EXTERNAL (node->decl) | |
98 | && !node->externally_visible | |
99 | && !node->used_from_other_partition | |
100 | && !node->in_other_partition); | |
7aeffc5f | 101 | } |
102 | ||
103 | /* Return true when function can be marked local. */ | |
104 | ||
105 | bool | |
415d1b9a | 106 | cgraph_node::local_p (void) |
7aeffc5f | 107 | { |
415d1b9a | 108 | cgraph_node *n = ultimate_alias_target (); |
7aeffc5f | 109 | |
7aeffc5f | 110 | if (n->thunk.thunk_p) |
a09576fe | 111 | return n->callees->callee->local_p (); |
c5e076fc | 112 | return !n->call_for_symbol_thunks_and_aliases (non_local_p, |
a09576fe | 113 | NULL, true); |
7aeffc5f | 114 | |
115 | } | |
116 | ||
7aeffc5f | 117 | /* A helper for comdat_can_be_unshared_p. */ |
118 | ||
119 | static bool | |
120 | comdat_can_be_unshared_p_1 (symtab_node *node) | |
121 | { | |
122 | if (!node->externally_visible) | |
123 | return true; | |
ce7711df | 124 | if (node->address_can_be_compared_p ()) |
125 | { | |
126 | struct ipa_ref *ref; | |
127 | ||
128 | for (unsigned int i = 0; node->iterate_referring (i, ref); i++) | |
129 | if (ref->address_matters_p ()) | |
130 | return false; | |
131 | } | |
7aeffc5f | 132 | |
133 | /* If the symbol is used in some weird way, better to not touch it. */ | |
134 | if (node->force_output) | |
135 | return false; | |
136 | ||
137 | /* Explicit instantiations needs to be output when possibly | |
138 | used externally. */ | |
139 | if (node->forced_by_abi | |
140 | && TREE_PUBLIC (node->decl) | |
141 | && (node->resolution != LDPR_PREVAILING_DEF_IRONLY | |
142 | && !flag_whole_program)) | |
143 | return false; | |
144 | ||
145 | /* Non-readonly and volatile variables can not be duplicated. */ | |
146 | if (is_a <varpool_node *> (node) | |
147 | && (!TREE_READONLY (node->decl) | |
148 | || TREE_THIS_VOLATILE (node->decl))) | |
149 | return false; | |
150 | return true; | |
151 | } | |
152 | ||
153 | /* COMDAT functions must be shared only if they have address taken, | |
154 | otherwise we can produce our own private implementation with | |
155 | -fwhole-program. | |
156 | Return true when turning COMDAT functoin static can not lead to wrong | |
157 | code when the resulting object links with a library defining same COMDAT. | |
158 | ||
159 | Virtual functions do have their addresses taken from the vtables, | |
160 | but in C++ there is no way to compare their addresses for equality. */ | |
161 | ||
162 | static bool | |
163 | comdat_can_be_unshared_p (symtab_node *node) | |
164 | { | |
165 | if (!comdat_can_be_unshared_p_1 (node)) | |
166 | return false; | |
167 | if (node->same_comdat_group) | |
168 | { | |
169 | symtab_node *next; | |
170 | ||
171 | /* If more than one function is in the same COMDAT group, it must | |
172 | be shared even if just one function in the comdat group has | |
173 | address taken. */ | |
174 | for (next = node->same_comdat_group; | |
175 | next != node; next = next->same_comdat_group) | |
176 | if (!comdat_can_be_unshared_p_1 (next)) | |
177 | return false; | |
178 | } | |
179 | return true; | |
180 | } | |
181 | ||
182 | /* Return true when function NODE should be considered externally visible. */ | |
183 | ||
184 | static bool | |
185 | cgraph_externally_visible_p (struct cgraph_node *node, | |
186 | bool whole_program) | |
187 | { | |
e0dec29d | 188 | while (node->transparent_alias && node->definition) |
189 | node = node->get_alias_target (); | |
7aeffc5f | 190 | if (!node->definition) |
191 | return false; | |
192 | if (!TREE_PUBLIC (node->decl) | |
193 | || DECL_EXTERNAL (node->decl)) | |
194 | return false; | |
195 | ||
196 | /* Do not try to localize built-in functions yet. One of problems is that we | |
197 | end up mangling their asm for WHOPR that makes it impossible to call them | |
198 | using the implicit built-in declarations anymore. Similarly this enables | |
199 | us to remove them as unreachable before actual calls may appear during | |
200 | expansion or folding. */ | |
201 | if (DECL_BUILT_IN (node->decl)) | |
202 | return true; | |
203 | ||
204 | /* If linker counts on us, we must preserve the function. */ | |
415d1b9a | 205 | if (node->used_from_object_file_p ()) |
7aeffc5f | 206 | return true; |
207 | if (DECL_PRESERVE_P (node->decl)) | |
208 | return true; | |
209 | if (lookup_attribute ("externally_visible", | |
210 | DECL_ATTRIBUTES (node->decl))) | |
211 | return true; | |
212 | if (TARGET_DLLIMPORT_DECL_ATTRIBUTES | |
213 | && lookup_attribute ("dllexport", | |
214 | DECL_ATTRIBUTES (node->decl))) | |
215 | return true; | |
216 | if (node->resolution == LDPR_PREVAILING_DEF_IRONLY) | |
217 | return false; | |
aca3df3b | 218 | /* When doing LTO or whole program, we can bring COMDAT functoins static. |
7aeffc5f | 219 | This improves code quality and we know we will duplicate them at most twice |
220 | (in the case that we are not using plugin and link with object file | |
221 | implementing same COMDAT) */ | |
4c4a180d | 222 | if (((in_lto_p || whole_program) && !flag_incremental_link) |
7aeffc5f | 223 | && DECL_COMDAT (node->decl) |
224 | && comdat_can_be_unshared_p (node)) | |
225 | return false; | |
226 | ||
227 | /* When doing link time optimizations, hidden symbols become local. */ | |
4c4a180d | 228 | if ((in_lto_p && !flag_incremental_link) |
7aeffc5f | 229 | && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN |
230 | || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL) | |
231 | /* Be sure that node is defined in IR file, not in other object | |
232 | file. In that case we don't set used_from_other_object_file. */ | |
233 | && node->definition) | |
234 | ; | |
235 | else if (!whole_program) | |
236 | return true; | |
237 | ||
238 | if (MAIN_NAME_P (DECL_NAME (node->decl))) | |
239 | return true; | |
240 | ||
058a1b7a | 241 | if (node->instrumentation_clone |
242 | && MAIN_NAME_P (DECL_NAME (node->orig_decl))) | |
243 | return true; | |
244 | ||
7aeffc5f | 245 | return false; |
246 | } | |
247 | ||
97221fd7 | 248 | /* Return true when variable should be considered externally visible. */ |
7aeffc5f | 249 | |
250 | bool | |
97221fd7 | 251 | varpool_node::externally_visible_p (void) |
7aeffc5f | 252 | { |
e0dec29d | 253 | while (transparent_alias && definition) |
254 | return get_alias_target ()->externally_visible_p (); | |
97221fd7 | 255 | if (DECL_EXTERNAL (decl)) |
7aeffc5f | 256 | return true; |
257 | ||
97221fd7 | 258 | if (!TREE_PUBLIC (decl)) |
7aeffc5f | 259 | return false; |
260 | ||
261 | /* If linker counts on us, we must preserve the function. */ | |
97221fd7 | 262 | if (used_from_object_file_p ()) |
7aeffc5f | 263 | return true; |
264 | ||
78eb5b70 | 265 | /* Bringing TLS variables local may cause dynamic linker failures |
266 | on limits of static TLS vars. */ | |
267 | if (DECL_THREAD_LOCAL_P (decl) | |
268 | && (DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED | |
269 | && DECL_TLS_MODEL (decl) != TLS_MODEL_INITIAL_EXEC)) | |
270 | return true; | |
271 | ||
97221fd7 | 272 | if (DECL_HARD_REGISTER (decl)) |
7aeffc5f | 273 | return true; |
97221fd7 | 274 | if (DECL_PRESERVE_P (decl)) |
7aeffc5f | 275 | return true; |
276 | if (lookup_attribute ("externally_visible", | |
97221fd7 | 277 | DECL_ATTRIBUTES (decl))) |
7aeffc5f | 278 | return true; |
279 | if (TARGET_DLLIMPORT_DECL_ATTRIBUTES | |
280 | && lookup_attribute ("dllexport", | |
97221fd7 | 281 | DECL_ATTRIBUTES (decl))) |
7aeffc5f | 282 | return true; |
283 | ||
284 | /* See if we have linker information about symbol not being used or | |
285 | if we need to make guess based on the declaration. | |
286 | ||
287 | Even if the linker clams the symbol is unused, never bring internal | |
288 | symbols that are declared by user as used or externally visible. | |
289 | This is needed for i.e. references from asm statements. */ | |
97221fd7 | 290 | if (used_from_object_file_p ()) |
aca3df3b | 291 | return true; |
97221fd7 | 292 | if (resolution == LDPR_PREVAILING_DEF_IRONLY) |
7aeffc5f | 293 | return false; |
294 | ||
295 | /* As a special case, the COMDAT virtual tables can be unshared. | |
296 | In LTO mode turn vtables into static variables. The variable is readonly, | |
297 | so this does not enable more optimization, but referring static var | |
298 | is faster for dynamic linking. Also this match logic hidding vtables | |
299 | from LTO symbol tables. */ | |
4c4a180d | 300 | if (((in_lto_p || flag_whole_program) && !flag_incremental_link) |
97221fd7 | 301 | && DECL_COMDAT (decl) |
302 | && comdat_can_be_unshared_p (this)) | |
7aeffc5f | 303 | return false; |
304 | ||
305 | /* When doing link time optimizations, hidden symbols become local. */ | |
4c4a180d | 306 | if (in_lto_p && !flag_incremental_link |
97221fd7 | 307 | && (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN |
308 | || DECL_VISIBILITY (decl) == VISIBILITY_INTERNAL) | |
7aeffc5f | 309 | /* Be sure that node is defined in IR file, not in other object |
310 | file. In that case we don't set used_from_other_object_file. */ | |
97221fd7 | 311 | && definition) |
7aeffc5f | 312 | ; |
313 | else if (!flag_whole_program) | |
314 | return true; | |
315 | ||
316 | /* Do not attempt to privatize COMDATS by default. | |
317 | This would break linking with C++ libraries sharing | |
318 | inline definitions. | |
319 | ||
320 | FIXME: We can do so for readonly vars with no address taken and | |
321 | possibly also for vtables since no direct pointer comparsion is done. | |
322 | It might be interesting to do so to reduce linking overhead. */ | |
97221fd7 | 323 | if (DECL_COMDAT (decl) || DECL_WEAK (decl)) |
7aeffc5f | 324 | return true; |
325 | return false; | |
326 | } | |
327 | ||
328 | /* Return true if reference to NODE can be replaced by a local alias. | |
329 | Local aliases save dynamic linking overhead and enable more optimizations. | |
330 | */ | |
331 | ||
a865a0f2 | 332 | static bool |
7aeffc5f | 333 | can_replace_by_local_alias (symtab_node *node) |
334 | { | |
a865a0f2 | 335 | #ifndef ASM_OUTPUT_DEF |
336 | /* If aliases aren't supported, we can't do replacement. */ | |
337 | return false; | |
338 | #endif | |
0325f3fd | 339 | /* Weakrefs have a reason to be non-local. Be sure we do not replace |
340 | them. */ | |
341 | while (node->transparent_alias && node->definition && !node->weakref) | |
342 | node = node->get_alias_target (); | |
343 | if (node->weakref) | |
344 | return false; | |
345 | ||
415d1b9a | 346 | return (node->get_availability () > AVAIL_INTERPOSABLE |
825463d4 | 347 | && !decl_binds_to_current_def_p (node->decl) |
415d1b9a | 348 | && !node->can_be_discarded_p ()); |
7aeffc5f | 349 | } |
350 | ||
a865a0f2 | 351 | /* Return true if we can replace reference to NODE by local alias |
b7cebaf8 | 352 | within a virtual table. Generally we can replace function pointers |
353 | and virtual table pointers. */ | |
354 | ||
a865a0f2 | 355 | static bool |
b7cebaf8 | 356 | can_replace_by_local_alias_in_vtable (symtab_node *node) |
357 | { | |
358 | if (is_a <varpool_node *> (node) | |
359 | && !DECL_VIRTUAL_P (node->decl)) | |
360 | return false; | |
361 | return can_replace_by_local_alias (node); | |
362 | } | |
363 | ||
364 | /* walk_tree callback that rewrites initializer references. */ | |
365 | ||
366 | static tree | |
ce7711df | 367 | update_vtable_references (tree *tp, int *walk_subtrees, |
368 | void *data ATTRIBUTE_UNUSED) | |
b7cebaf8 | 369 | { |
370 | if (TREE_CODE (*tp) == VAR_DECL | |
371 | || TREE_CODE (*tp) == FUNCTION_DECL) | |
372 | { | |
415d1b9a | 373 | if (can_replace_by_local_alias_in_vtable (symtab_node::get (*tp))) |
374 | *tp = symtab_node::get (*tp)->noninterposable_alias ()->decl; | |
b7cebaf8 | 375 | *walk_subtrees = 0; |
376 | } | |
377 | else if (IS_TYPE_OR_DECL_P (*tp)) | |
378 | *walk_subtrees = 0; | |
379 | return NULL; | |
380 | } | |
381 | ||
7aeffc5f | 382 | /* In LTO we can remove COMDAT groups and weak symbols. |
383 | Either turn them into normal symbols or external symbol depending on | |
384 | resolution info. */ | |
385 | ||
386 | static void | |
387 | update_visibility_by_resolution_info (symtab_node * node) | |
388 | { | |
389 | bool define; | |
390 | ||
391 | if (!node->externally_visible | |
392 | || (!DECL_WEAK (node->decl) && !DECL_ONE_ONLY (node->decl)) | |
aca3df3b | 393 | || node->resolution == LDPR_UNKNOWN) |
7aeffc5f | 394 | return; |
395 | ||
396 | define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY | |
397 | || node->resolution == LDPR_PREVAILING_DEF | |
9b71510e | 398 | || node->resolution == LDPR_UNDEF |
7aeffc5f | 399 | || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP); |
400 | ||
401 | /* The linker decisions ought to agree in the whole group. */ | |
402 | if (node->same_comdat_group) | |
403 | for (symtab_node *next = node->same_comdat_group; | |
404 | next != node; next = next->same_comdat_group) | |
a0e59ca8 | 405 | { |
0325f3fd | 406 | if (!next->externally_visible || next->transparent_alias) |
a0e59ca8 | 407 | continue; |
408 | ||
409 | bool same_def | |
410 | = define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY | |
411 | || next->resolution == LDPR_PREVAILING_DEF | |
412 | || next->resolution == LDPR_UNDEF | |
413 | || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP); | |
414 | gcc_assert (in_lto_p || same_def); | |
415 | if (!same_def) | |
416 | return; | |
417 | } | |
7aeffc5f | 418 | |
419 | if (node->same_comdat_group) | |
420 | for (symtab_node *next = node->same_comdat_group; | |
421 | next != node; next = next->same_comdat_group) | |
422 | { | |
4c4a180d | 423 | /* During incremental linking we need to keep symbol weak for future |
424 | linking. We can still drop definition if we know non-LTO world | |
425 | prevails. */ | |
426 | if (!flag_incremental_link) | |
427 | { | |
428 | DECL_WEAK (next->decl) = false; | |
429 | next->set_comdat_group (NULL); | |
430 | } | |
c7549d13 | 431 | if (!define) |
4c4a180d | 432 | { |
c7549d13 | 433 | if (next->externally_visible) |
434 | DECL_EXTERNAL (next->decl) = true; | |
4c4a180d | 435 | next->set_comdat_group (NULL); |
436 | } | |
7aeffc5f | 437 | } |
4c4a180d | 438 | |
439 | /* During incremental linking we need to keep symbol weak for future | |
440 | linking. We can still drop definition if we know non-LTO world prevails. */ | |
441 | if (!flag_incremental_link) | |
442 | { | |
443 | DECL_WEAK (node->decl) = false; | |
444 | node->set_comdat_group (NULL); | |
445 | node->dissolve_same_comdat_group_list (); | |
446 | } | |
7aeffc5f | 447 | if (!define) |
4c4a180d | 448 | { |
449 | DECL_EXTERNAL (node->decl) = true; | |
450 | node->set_comdat_group (NULL); | |
451 | node->dissolve_same_comdat_group_list (); | |
452 | } | |
7aeffc5f | 453 | } |
454 | ||
455 | /* Decide on visibility of all symbols. */ | |
456 | ||
457 | static unsigned int | |
458 | function_and_variable_visibility (bool whole_program) | |
459 | { | |
460 | struct cgraph_node *node; | |
461 | varpool_node *vnode; | |
462 | ||
463 | /* All aliases should be procssed at this point. */ | |
464 | gcc_checking_assert (!alias_pairs || !alias_pairs->length ()); | |
465 | ||
466 | FOR_EACH_FUNCTION (node) | |
467 | { | |
468 | int flags = flags_from_decl_or_type (node->decl); | |
469 | ||
470 | /* Optimize away PURE and CONST constructors and destructors. */ | |
471 | if (optimize | |
472 | && (flags & (ECF_CONST | ECF_PURE)) | |
473 | && !(flags & ECF_LOOPING_CONST_OR_PURE)) | |
474 | { | |
475 | DECL_STATIC_CONSTRUCTOR (node->decl) = 0; | |
476 | DECL_STATIC_DESTRUCTOR (node->decl) = 0; | |
477 | } | |
478 | ||
479 | /* Frontends and alias code marks nodes as needed before parsing is finished. | |
480 | We may end up marking as node external nodes where this flag is meaningless | |
481 | strip it. */ | |
482 | if (DECL_EXTERNAL (node->decl) || !node->definition) | |
483 | { | |
484 | node->force_output = 0; | |
485 | node->forced_by_abi = 0; | |
486 | } | |
487 | ||
488 | /* C++ FE on lack of COMDAT support create local COMDAT functions | |
489 | (that ought to be shared but can not due to object format | |
490 | limitations). It is necessary to keep the flag to make rest of C++ FE | |
491 | happy. Clear the flag here to avoid confusion in middle-end. */ | |
492 | if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl)) | |
493 | DECL_COMDAT (node->decl) = 0; | |
494 | ||
495 | /* For external decls stop tracking same_comdat_group. It doesn't matter | |
7b3390b4 | 496 | what comdat group they are in when they won't be emitted in this TU. |
497 | ||
498 | An exception is LTO where we may end up with both external | |
499 | and non-external declarations in the same comdat group in | |
500 | the case declarations was not merged. */ | |
501 | if (node->same_comdat_group && DECL_EXTERNAL (node->decl) && !in_lto_p) | |
7aeffc5f | 502 | { |
382ecba7 | 503 | if (flag_checking) |
504 | { | |
505 | for (symtab_node *n = node->same_comdat_group; | |
506 | n != node; | |
507 | n = n->same_comdat_group) | |
508 | /* If at least one of same comdat group functions is external, | |
509 | all of them have to be, otherwise it is a front-end bug. */ | |
510 | gcc_assert (DECL_EXTERNAL (n->decl)); | |
511 | } | |
415d1b9a | 512 | node->dissolve_same_comdat_group_list (); |
7aeffc5f | 513 | } |
514 | gcc_assert ((!DECL_WEAK (node->decl) | |
aca3df3b | 515 | && !DECL_COMDAT (node->decl)) |
7aeffc5f | 516 | || TREE_PUBLIC (node->decl) |
517 | || node->weakref | |
518 | || DECL_EXTERNAL (node->decl)); | |
519 | if (cgraph_externally_visible_p (node, whole_program)) | |
520 | { | |
521 | gcc_assert (!node->global.inlined_to); | |
522 | node->externally_visible = true; | |
523 | } | |
524 | else | |
525 | { | |
526 | node->externally_visible = false; | |
527 | node->forced_by_abi = false; | |
528 | } | |
529 | if (!node->externally_visible | |
530 | && node->definition && !node->weakref | |
531 | && !DECL_EXTERNAL (node->decl)) | |
532 | { | |
533 | gcc_assert (whole_program || in_lto_p | |
534 | || !TREE_PUBLIC (node->decl)); | |
c7549d13 | 535 | node->unique_name |= ((node->resolution == LDPR_PREVAILING_DEF_IRONLY |
536 | || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) | |
537 | && TREE_PUBLIC (node->decl) | |
538 | && !flag_incremental_link); | |
7aeffc5f | 539 | node->resolution = LDPR_PREVAILING_DEF_IRONLY; |
540 | if (node->same_comdat_group && TREE_PUBLIC (node->decl)) | |
541 | { | |
542 | symtab_node *next = node; | |
543 | ||
544 | /* Set all members of comdat group local. */ | |
545 | if (node->same_comdat_group) | |
546 | for (next = node->same_comdat_group; | |
547 | next != node; | |
548 | next = next->same_comdat_group) | |
549 | { | |
550 | next->set_comdat_group (NULL); | |
aca3df3b | 551 | if (!next->alias) |
552 | next->set_section (NULL); | |
e0dec29d | 553 | if (!next->transparent_alias) |
554 | next->make_decl_local (); | |
c7549d13 | 555 | next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY |
556 | || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) | |
557 | && TREE_PUBLIC (next->decl) | |
558 | && !flag_incremental_link); | |
7aeffc5f | 559 | } |
560 | /* cgraph_externally_visible_p has already checked all other nodes | |
561 | in the group and they will all be made local. We need to | |
562 | dissolve the group at once so that the predicate does not | |
563 | segfault though. */ | |
415d1b9a | 564 | node->dissolve_same_comdat_group_list (); |
7aeffc5f | 565 | } |
566 | if (TREE_PUBLIC (node->decl)) | |
567 | node->set_comdat_group (NULL); | |
aca3df3b | 568 | if (DECL_COMDAT (node->decl) && !node->alias) |
569 | node->set_section (NULL); | |
e0dec29d | 570 | if (!node->transparent_alias) |
571 | node->make_decl_local (); | |
7aeffc5f | 572 | } |
573 | ||
574 | if (node->thunk.thunk_p | |
058a1b7a | 575 | && !node->thunk.add_pointer_bounds_args |
7aeffc5f | 576 | && TREE_PUBLIC (node->decl)) |
577 | { | |
578 | struct cgraph_node *decl_node = node; | |
579 | ||
415d1b9a | 580 | decl_node = decl_node->callees->callee->function_symbol (); |
7aeffc5f | 581 | |
582 | /* Thunks have the same visibility as function they are attached to. | |
583 | Make sure the C++ front end set this up properly. */ | |
584 | if (DECL_ONE_ONLY (decl_node->decl)) | |
585 | { | |
586 | gcc_checking_assert (DECL_COMDAT (node->decl) | |
587 | == DECL_COMDAT (decl_node->decl)); | |
415d1b9a | 588 | gcc_checking_assert (node->in_same_comdat_group_p (decl_node)); |
7aeffc5f | 589 | gcc_checking_assert (node->same_comdat_group); |
590 | } | |
591 | node->forced_by_abi = decl_node->forced_by_abi; | |
592 | if (DECL_EXTERNAL (decl_node->decl)) | |
593 | DECL_EXTERNAL (node->decl) = 1; | |
594 | } | |
595 | ||
596 | update_visibility_by_resolution_info (node); | |
597 | } | |
598 | FOR_EACH_DEFINED_FUNCTION (node) | |
599 | { | |
e3f2be84 | 600 | if (!node->local.local) |
601 | node->local.local |= node->local_p (); | |
7aeffc5f | 602 | |
a865a0f2 | 603 | /* If we know that function can not be overwritten by a |
604 | different semantics and moreover its section can not be | |
605 | discarded, replace all direct calls by calls to an | |
606 | noninterposable alias. This make dynamic linking cheaper and | |
607 | enable more optimization. | |
7aeffc5f | 608 | |
609 | TODO: We can also update virtual tables. */ | |
4696e459 | 610 | if (node->callers |
4696e459 | 611 | && can_replace_by_local_alias (node)) |
7aeffc5f | 612 | { |
415d1b9a | 613 | cgraph_node *alias = dyn_cast<cgraph_node *> |
614 | (node->noninterposable_alias ()); | |
7aeffc5f | 615 | |
616 | if (alias && alias != node) | |
617 | { | |
618 | while (node->callers) | |
619 | { | |
620 | struct cgraph_edge *e = node->callers; | |
621 | ||
35ee1c66 | 622 | e->redirect_callee (alias); |
7aeffc5f | 623 | if (gimple_has_body_p (e->caller->decl)) |
624 | { | |
625 | push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); | |
35ee1c66 | 626 | e->redirect_call_stmt_to_callee (); |
7aeffc5f | 627 | pop_cfun (); |
628 | } | |
629 | } | |
630 | } | |
631 | } | |
632 | } | |
633 | FOR_EACH_VARIABLE (vnode) | |
634 | { | |
635 | /* weak flag makes no sense on local variables. */ | |
636 | gcc_assert (!DECL_WEAK (vnode->decl) | |
637 | || vnode->weakref | |
638 | || TREE_PUBLIC (vnode->decl) | |
639 | || DECL_EXTERNAL (vnode->decl)); | |
640 | /* In several cases declarations can not be common: | |
641 | ||
642 | - when declaration has initializer | |
643 | - when it is in weak | |
644 | - when it has specific section | |
645 | - when it resides in non-generic address space. | |
646 | - if declaration is local, it will get into .local common section | |
647 | so common flag is not needed. Frontends still produce these in | |
648 | certain cases, such as for: | |
649 | ||
650 | static int a __attribute__ ((common)) | |
651 | ||
652 | Canonicalize things here and clear the redundant flag. */ | |
653 | if (DECL_COMMON (vnode->decl) | |
654 | && (!(TREE_PUBLIC (vnode->decl) | |
655 | || DECL_EXTERNAL (vnode->decl)) | |
656 | || (DECL_INITIAL (vnode->decl) | |
657 | && DECL_INITIAL (vnode->decl) != error_mark_node) | |
658 | || DECL_WEAK (vnode->decl) | |
659 | || DECL_SECTION_NAME (vnode->decl) != NULL | |
660 | || ! (ADDR_SPACE_GENERIC_P | |
661 | (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) | |
662 | DECL_COMMON (vnode->decl) = 0; | |
663 | } | |
664 | FOR_EACH_DEFINED_VARIABLE (vnode) | |
665 | { | |
666 | if (!vnode->definition) | |
667 | continue; | |
97221fd7 | 668 | if (vnode->externally_visible_p ()) |
7aeffc5f | 669 | vnode->externally_visible = true; |
670 | else | |
671 | { | |
672 | vnode->externally_visible = false; | |
673 | vnode->forced_by_abi = false; | |
674 | } | |
6b722052 | 675 | if (lookup_attribute ("no_reorder", |
676 | DECL_ATTRIBUTES (vnode->decl))) | |
677 | vnode->no_reorder = 1; | |
7aeffc5f | 678 | if (!vnode->externally_visible |
e0dec29d | 679 | && !vnode->transparent_alias) |
7aeffc5f | 680 | { |
681 | gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); | |
c7549d13 | 682 | vnode->unique_name |= ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY |
683 | || vnode->resolution | |
4c4a180d | 684 | == LDPR_PREVAILING_DEF_IRONLY_EXP) |
c7549d13 | 685 | && TREE_PUBLIC (vnode->decl) |
686 | && !flag_incremental_link); | |
7aeffc5f | 687 | if (vnode->same_comdat_group && TREE_PUBLIC (vnode->decl)) |
688 | { | |
689 | symtab_node *next = vnode; | |
690 | ||
691 | /* Set all members of comdat group local. */ | |
692 | if (vnode->same_comdat_group) | |
693 | for (next = vnode->same_comdat_group; | |
694 | next != vnode; | |
695 | next = next->same_comdat_group) | |
696 | { | |
697 | next->set_comdat_group (NULL); | |
922f76a8 | 698 | if (!next->alias) |
aca3df3b | 699 | next->set_section (NULL); |
e0dec29d | 700 | if (!next->transparent_alias) |
701 | { | |
702 | next->make_decl_local (); | |
703 | next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY | |
704 | || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) | |
705 | && TREE_PUBLIC (next->decl) | |
706 | && !flag_incremental_link); | |
707 | } | |
7aeffc5f | 708 | } |
415d1b9a | 709 | vnode->dissolve_same_comdat_group_list (); |
7aeffc5f | 710 | } |
711 | if (TREE_PUBLIC (vnode->decl)) | |
712 | vnode->set_comdat_group (NULL); | |
aca3df3b | 713 | if (DECL_COMDAT (vnode->decl) && !vnode->alias) |
714 | vnode->set_section (NULL); | |
e0dec29d | 715 | if (!vnode->transparent_alias) |
716 | { | |
717 | vnode->make_decl_local (); | |
718 | vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; | |
719 | } | |
7aeffc5f | 720 | } |
721 | update_visibility_by_resolution_info (vnode); | |
b7cebaf8 | 722 | |
6f24ab3b | 723 | /* Update virtual tables to point to local aliases where possible. */ |
b7cebaf8 | 724 | if (DECL_VIRTUAL_P (vnode->decl) |
24833914 | 725 | && !DECL_EXTERNAL (vnode->decl)) |
b7cebaf8 | 726 | { |
727 | int i; | |
728 | struct ipa_ref *ref; | |
729 | bool found = false; | |
730 | ||
731 | /* See if there is something to update. */ | |
58da8146 | 732 | for (i = 0; vnode->iterate_reference (i, ref); i++) |
b7cebaf8 | 733 | if (ref->use == IPA_REF_ADDR |
734 | && can_replace_by_local_alias_in_vtable (ref->referred)) | |
735 | { | |
736 | found = true; | |
737 | break; | |
738 | } | |
739 | if (found) | |
740 | { | |
431205b7 | 741 | hash_set<tree> visited_nodes; |
afb0d513 | 742 | |
97221fd7 | 743 | vnode->get_constructor (); |
b7cebaf8 | 744 | walk_tree (&DECL_INITIAL (vnode->decl), |
431205b7 | 745 | update_vtable_references, NULL, &visited_nodes); |
51ce5652 | 746 | vnode->remove_all_references (); |
b7cebaf8 | 747 | record_references_in_initializer (vnode->decl, false); |
748 | } | |
749 | } | |
7aeffc5f | 750 | } |
751 | ||
752 | if (dump_file) | |
753 | { | |
754 | fprintf (dump_file, "\nMarking local functions:"); | |
755 | FOR_EACH_DEFINED_FUNCTION (node) | |
756 | if (node->local.local) | |
757 | fprintf (dump_file, " %s", node->name ()); | |
758 | fprintf (dump_file, "\n\n"); | |
759 | fprintf (dump_file, "\nMarking externally visible functions:"); | |
760 | FOR_EACH_DEFINED_FUNCTION (node) | |
761 | if (node->externally_visible) | |
762 | fprintf (dump_file, " %s", node->name ()); | |
763 | fprintf (dump_file, "\n\n"); | |
764 | fprintf (dump_file, "\nMarking externally visible variables:"); | |
765 | FOR_EACH_DEFINED_VARIABLE (vnode) | |
766 | if (vnode->externally_visible) | |
767 | fprintf (dump_file, " %s", vnode->name ()); | |
768 | fprintf (dump_file, "\n\n"); | |
769 | } | |
35ee1c66 | 770 | symtab->function_flags_ready = true; |
7aeffc5f | 771 | return 0; |
772 | } | |
773 | ||
774 | /* Local function pass handling visibilities. This happens before LTO streaming | |
775 | so in particular -fwhole-program should be ignored at this level. */ | |
776 | ||
7620bc82 | 777 | namespace { |
778 | ||
779 | const pass_data pass_data_ipa_function_and_variable_visibility = | |
7aeffc5f | 780 | { |
781 | SIMPLE_IPA_PASS, /* type */ | |
782 | "visibility", /* name */ | |
783 | OPTGROUP_NONE, /* optinfo_flags */ | |
7aeffc5f | 784 | TV_CGRAPHOPT, /* tv_id */ |
785 | 0, /* properties_required */ | |
786 | 0, /* properties_provided */ | |
787 | 0, /* properties_destroyed */ | |
788 | 0, /* todo_flags_start */ | |
789 | ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ | |
790 | }; | |
791 | ||
792 | /* Bring functions local at LTO time with -fwhole-program. */ | |
793 | ||
794 | static unsigned int | |
795 | whole_program_function_and_variable_visibility (void) | |
796 | { | |
797 | function_and_variable_visibility (flag_whole_program); | |
798 | if (optimize) | |
799 | ipa_discover_readonly_nonaddressable_vars (); | |
800 | return 0; | |
801 | } | |
802 | ||
7620bc82 | 803 | } // anon namespace |
804 | ||
805 | namespace { | |
806 | ||
807 | const pass_data pass_data_ipa_whole_program_visibility = | |
7aeffc5f | 808 | { |
809 | IPA_PASS, /* type */ | |
810 | "whole-program", /* name */ | |
811 | OPTGROUP_NONE, /* optinfo_flags */ | |
7aeffc5f | 812 | TV_CGRAPHOPT, /* tv_id */ |
813 | 0, /* properties_required */ | |
814 | 0, /* properties_provided */ | |
815 | 0, /* properties_destroyed */ | |
816 | 0, /* todo_flags_start */ | |
817 | ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ | |
818 | }; | |
819 | ||
7620bc82 | 820 | class pass_ipa_whole_program_visibility : public ipa_opt_pass_d |
7aeffc5f | 821 | { |
822 | public: | |
823 | pass_ipa_whole_program_visibility (gcc::context *ctxt) | |
824 | : ipa_opt_pass_d (pass_data_ipa_whole_program_visibility, ctxt, | |
825 | NULL, /* generate_summary */ | |
826 | NULL, /* write_summary */ | |
827 | NULL, /* read_summary */ | |
828 | NULL, /* write_optimization_summary */ | |
829 | NULL, /* read_optimization_summary */ | |
830 | NULL, /* stmt_fixup */ | |
831 | 0, /* function_transform_todo_flags_start */ | |
832 | NULL, /* function_transform */ | |
833 | NULL) /* variable_transform */ | |
834 | {} | |
835 | ||
836 | /* opt_pass methods: */ | |
837 | ||
838 | virtual bool gate (function *) | |
839 | { | |
840 | /* Do not re-run on ltrans stage. */ | |
841 | return !flag_ltrans; | |
842 | } | |
843 | virtual unsigned int execute (function *) | |
844 | { | |
845 | return whole_program_function_and_variable_visibility (); | |
846 | } | |
847 | ||
848 | }; // class pass_ipa_whole_program_visibility | |
849 | ||
7620bc82 | 850 | } // anon namespace |
851 | ||
7aeffc5f | 852 | ipa_opt_pass_d * |
853 | make_pass_ipa_whole_program_visibility (gcc::context *ctxt) | |
854 | { | |
855 | return new pass_ipa_whole_program_visibility (ctxt); | |
856 | } | |
857 | ||
858 | class pass_ipa_function_and_variable_visibility : public simple_ipa_opt_pass | |
859 | { | |
860 | public: | |
861 | pass_ipa_function_and_variable_visibility (gcc::context *ctxt) | |
862 | : simple_ipa_opt_pass (pass_data_ipa_function_and_variable_visibility, | |
863 | ctxt) | |
864 | {} | |
865 | ||
866 | /* opt_pass methods: */ | |
867 | virtual unsigned int execute (function *) | |
868 | { | |
869 | return function_and_variable_visibility (flag_whole_program && !flag_lto); | |
870 | } | |
871 | ||
872 | }; // class pass_ipa_function_and_variable_visibility | |
873 | ||
874 | simple_ipa_opt_pass * | |
875 | make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt) | |
876 | { | |
877 | return new pass_ipa_function_and_variable_visibility (ctxt); | |
878 | } |