annotate gcc/ipa-visibility.c @ 158:494b0b89df80 default tip

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