Line data Source code
1 : /* Localize comdats.
2 : Copyright (C) 2014-2026 Free Software Foundation, Inc.
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 is very simple pass that looks for static symbols that are used
21 : exclusively by symbol within one comdat group. In this case it makes
22 : sense to bring the symbol itself into the group to avoid dead code
23 : that would arrise when the comdat group from current unit is replaced
24 : by a different copy. Consider for example:
25 :
26 : static int q(void)
27 : {
28 : ....
29 : }
30 : inline int t(void)
31 : {
32 : return q();
33 : }
34 :
35 : if Q is used only by T, it makes sense to put Q into T's comdat group.
36 :
37 : The pass solve simple dataflow across the callgraph trying to prove what
38 : symbols are used exclusively from a given comdat group.
39 :
40 : The implementation maintains a queue linked by AUX pointer terminated by
41 : pointer value 1. Lattice values are NULL for TOP, actual comdat group, or
42 : ERROR_MARK_NODE for bottom.
43 :
44 : TODO: When symbol is used only by comdat symbols, but from different groups,
45 : it would make sense to produce a new comdat group for it with anonymous name.
46 :
47 : TODO2: We can't mix variables and functions within one group. Currently
48 : we just give up on references of symbols of different types. We also should
49 : handle this by anonymous comdat group section. */
50 :
51 : #include "config.h"
52 : #include "system.h"
53 : #include "coretypes.h"
54 : #include "tm.h"
55 : #include "tree.h"
56 : #include "tree-pass.h"
57 : #include "cgraph.h"
58 :
59 : /* Main dataflow loop propagating comdat groups across
60 : the symbol table. All references to SYMBOL are examined
61 : and NEWGROUP is updated accordingly. MAP holds current lattice
62 : values for individual symbols. */
63 :
64 : tree
65 76017 : propagate_comdat_group (struct symtab_node *symbol,
66 : tree newgroup, hash_map<symtab_node *, tree> &map)
67 : {
68 76017 : int i;
69 76017 : struct ipa_ref *ref;
70 :
71 : /* Walk all references to SYMBOL, recursively dive into aliases. */
72 :
73 101485 : for (i = 0;
74 202970 : symbol->iterate_referring (i, ref)
75 101485 : && newgroup != error_mark_node; i++)
76 : {
77 47662 : struct symtab_node *symbol2 = ref->referring;
78 :
79 47662 : if (ref->use == IPA_REF_ALIAS)
80 : {
81 1179 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
82 1179 : continue;
83 : }
84 :
85 : /* One COMDAT group cannot hold both variables and functions at
86 : a same time. For now we just go to BOTTOM, in future we may
87 : invent special comdat groups for this case. */
88 :
89 46483 : if (symbol->type != symbol2->type)
90 : {
91 22194 : newgroup = error_mark_node;
92 22194 : break;
93 : }
94 :
95 : /* If we see inline clone, its comdat group actually
96 : corresponds to the comdat group of the function it is inlined
97 : to. */
98 :
99 24289 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
100 : {
101 14612 : if (cn->inlined_to)
102 2562 : symbol2 = cn->inlined_to;
103 : }
104 :
105 : /* The actual merge operation. */
106 :
107 24289 : tree *val2 = map.get (symbol2);
108 :
109 24289 : if (val2 && *val2 != newgroup)
110 : {
111 22153 : if (!newgroup)
112 : newgroup = *val2;
113 : else
114 188 : newgroup = error_mark_node;
115 : }
116 : }
117 :
118 : /* If we analyze function, walk also callers. */
119 :
120 76017 : cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
121 :
122 52547 : if (cnode)
123 52547 : for (struct cgraph_edge * edge = cnode->callers;
124 108077 : edge && newgroup != error_mark_node; edge = edge->next_caller)
125 : {
126 55530 : struct symtab_node *symbol2 = edge->caller;
127 :
128 55530 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
129 : {
130 : /* Thunks cannot call across section boundary. */
131 55530 : if (cn->thunk)
132 424 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
133 : /* If we see inline clone, its comdat group actually
134 : corresponds to the comdat group of the function it
135 : is inlined to. */
136 55530 : if (cn->inlined_to)
137 18373 : symbol2 = cn->inlined_to;
138 : }
139 :
140 : /* The actual merge operation. */
141 :
142 55530 : tree *val2 = map.get (symbol2);
143 :
144 55530 : if (val2 && *val2 != newgroup)
145 : {
146 30248 : if (!newgroup)
147 : newgroup = *val2;
148 : else
149 4719 : newgroup = error_mark_node;
150 : }
151 : }
152 76017 : return newgroup;
153 : }
154 :
155 :
156 : /* Add all references of SYMBOL that are defined into queue started by FIRST
157 : and linked by AUX pointer (unless they are already enqueued).
158 : Walk recursively inlined functions. */
159 :
160 : void
161 194748 : enqueue_references (symtab_node **first,
162 : symtab_node *symbol)
163 : {
164 194748 : int i;
165 194748 : struct ipa_ref *ref = NULL;
166 :
167 404149 : for (i = 0; symbol->iterate_reference (i, ref); i++)
168 : {
169 209401 : symtab_node *node = ref->referred->ultimate_alias_target ();
170 :
171 : /* Always keep thunks in same sections as target function. */
172 209401 : if (is_a <cgraph_node *>(node))
173 25420 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
174 209401 : if (!node->aux && node->definition)
175 : {
176 1440 : node->aux = *first;
177 1440 : *first = node;
178 : }
179 : }
180 :
181 194748 : if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
182 : {
183 172523 : struct cgraph_edge *edge;
184 :
185 669199 : for (edge = cnode->callees; edge; edge = edge->next_callee)
186 496676 : if (!edge->inline_failed)
187 124590 : enqueue_references (first, edge->callee);
188 : else
189 : {
190 372086 : symtab_node *node = edge->callee->ultimate_alias_target ();
191 :
192 : /* Always keep thunks in same sections as target function. */
193 372086 : if (is_a <cgraph_node *>(node))
194 372086 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
195 372086 : if (!node->aux && node->definition)
196 : {
197 3121 : node->aux = *first;
198 3121 : *first = node;
199 : }
200 : }
201 : }
202 194748 : }
203 :
204 : /* Set comdat group of SYMBOL to GROUP.
205 : Callback for for_node_and_aliases. */
206 :
207 : bool
208 6894 : set_comdat_group (symtab_node *symbol,
209 : void *head_p)
210 : {
211 6894 : symtab_node *head = (symtab_node *)head_p;
212 :
213 6894 : gcc_assert (!symbol->get_comdat_group ());
214 6894 : if (symbol->real_symbol_p ())
215 : {
216 6894 : symbol->set_comdat_group (head->get_comdat_group ());
217 6894 : symbol->add_to_same_comdat_group (head);
218 : }
219 6894 : return false;
220 : }
221 :
222 : /* Set comdat group of SYMBOL to GROUP.
223 : Callback for for_node_thunks_and_aliases. */
224 :
225 : bool
226 6888 : set_comdat_group_1 (cgraph_node *symbol,
227 : void *head_p)
228 : {
229 6888 : return set_comdat_group (symbol, head_p);
230 : }
231 :
232 : /* The actual pass with the main dataflow loop. */
233 :
234 : static unsigned int
235 230063 : ipa_comdats (void)
236 : {
237 230063 : hash_map<symtab_node *, tree> map (251);
238 230063 : hash_map<tree, symtab_node *> comdat_head_map (251);
239 230063 : symtab_node *symbol;
240 230063 : bool comdat_group_seen = false;
241 230063 : symtab_node *first = (symtab_node *) (void *) 1;
242 230063 : tree group;
243 :
244 : /* Start the dataflow by assigning comdat group to symbols that are in comdat
245 : groups already. All other externally visible symbols must stay, we use
246 : ERROR_MARK_NODE as bottom for the propagation. */
247 :
248 5946882 : FOR_EACH_DEFINED_SYMBOL (symbol)
249 5716819 : if (!symbol->real_symbol_p ())
250 : ;
251 4391948 : else if ((group = symbol->get_comdat_group ()) != NULL)
252 : {
253 530321 : map.put (symbol, group);
254 530321 : comdat_head_map.put (group, symbol);
255 530321 : comdat_group_seen = true;
256 :
257 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
258 530321 : symbol->aux = (symtab_node *) (void *) 1;
259 : }
260 : /* See symbols that cannot be privatized to comdats; that is externally
261 : visible symbols or otherwise used ones. We also do not want to mangle
262 : user section names. */
263 3861627 : else if (symbol->externally_visible
264 1735857 : || symbol->force_output
265 1495907 : || symbol->ref_by_asm
266 1495902 : || symbol->used_from_other_partition
267 1495902 : || TREE_THIS_VOLATILE (symbol->decl)
268 1486595 : || symbol->get_section ()
269 4311297 : || (TREE_CODE (symbol->decl) == FUNCTION_DECL
270 183209 : && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
271 181204 : || DECL_STATIC_DESTRUCTOR (symbol->decl))))
272 : {
273 3414023 : symtab_node *target = symbol->ultimate_alias_target ();
274 :
275 : /* Always keep thunks in same sections as target function. */
276 3414023 : if (is_a <cgraph_node *>(target))
277 1129106 : target = dyn_cast <cgraph_node *> (target)->function_symbol ();
278 3414023 : map.put (target, error_mark_node);
279 :
280 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
281 3414023 : symbol->aux = (symtab_node *) (void *) 1;
282 : }
283 : else
284 : {
285 : /* Enqueue symbol for dataflow. */
286 447604 : symbol->aux = first;
287 447604 : first = symbol;
288 : }
289 :
290 230063 : if (!comdat_group_seen)
291 : {
292 2700932 : FOR_EACH_DEFINED_SYMBOL (symbol)
293 2496774 : symbol->aux = NULL;
294 : return 0;
295 : }
296 :
297 : /* The actual dataflow. */
298 :
299 100326 : while (first != (void *) 1)
300 : {
301 74421 : tree group = NULL;
302 74421 : tree newgroup, *val;
303 :
304 74421 : symbol = first;
305 74421 : first = (symtab_node *)first->aux;
306 :
307 : /* Get current lattice value of SYMBOL. */
308 74421 : val = map.get (symbol);
309 74421 : if (val)
310 546 : group = *val;
311 :
312 : /* If it is bottom, there is nothing to do; do not clear AUX
313 : so we won't re-queue the symbol. */
314 74421 : if (group == error_mark_node)
315 4263 : continue;
316 :
317 74414 : newgroup = propagate_comdat_group (symbol, group, map);
318 :
319 : /* If nothing changed, proceed to next symbol. */
320 74414 : if (newgroup == group)
321 : {
322 4256 : symbol->aux = NULL;
323 4256 : continue;
324 : }
325 :
326 : /* Update lattice value and enqueue all references for re-visiting. */
327 70158 : gcc_assert (newgroup);
328 70158 : if (val)
329 470 : *val = newgroup;
330 : else
331 69688 : map.put (symbol, newgroup);
332 70158 : enqueue_references (&first, symbol);
333 :
334 : /* We may need to revisit the symbol unless it is BOTTOM. */
335 70158 : if (newgroup != error_mark_node)
336 7486 : symbol->aux = NULL;
337 : }
338 :
339 : /* Finally assign symbols to the sections. */
340 :
341 3245950 : FOR_EACH_DEFINED_SYMBOL (symbol)
342 : {
343 3220045 : struct cgraph_node *fun;
344 3220045 : symbol->aux = NULL;
345 3220045 : if (!symbol->get_comdat_group ()
346 2588503 : && !symbol->alias
347 2578307 : && (!(fun = dyn_cast <cgraph_node *> (symbol))
348 1334575 : || !fun->thunk)
349 5797735 : && symbol->real_symbol_p ())
350 : {
351 1587873 : tree *val = map.get (symbol);
352 :
353 : /* A NULL here means that SYMBOL is unreachable in the definition
354 : of ipa-comdats. Either ipa-comdats is wrong about this or someone
355 : forgot to cleanup and remove unreachable functions earlier. */
356 1587873 : gcc_assert (val);
357 :
358 1587873 : tree group = *val;
359 :
360 1587873 : if (group == error_mark_node)
361 1580991 : continue;
362 6882 : if (dump_file)
363 : {
364 3 : fprintf (dump_file, "Localizing symbol\n");
365 3 : symbol->dump (dump_file);
366 3 : fprintf (dump_file, "To group: %s\n", IDENTIFIER_POINTER (group));
367 : }
368 6882 : if (is_a <cgraph_node *> (symbol))
369 6876 : dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
370 6876 : (set_comdat_group_1,
371 6876 : *comdat_head_map.get (group),
372 : true);
373 : else
374 6 : symbol->call_for_symbol_and_aliases
375 6 : (set_comdat_group,
376 6 : *comdat_head_map.get (group),
377 : true);
378 : }
379 : }
380 :
381 : #if 0
382 : /* Recompute calls comdat local flag. This need to be done after all changes
383 : are made. */
384 : cgraph_node *function;
385 : FOR_EACH_DEFINED_FUNCTION (function)
386 : if (function->get_comdat_group ())
387 : function->calls_comdat_local = function->check_calls_comdat_local_p ();
388 : #endif
389 : return 0;
390 230063 : }
391 :
392 : namespace {
393 :
394 : const pass_data pass_data_ipa_comdats =
395 : {
396 : IPA_PASS, /* type */
397 : "comdats", /* name */
398 : OPTGROUP_NONE, /* optinfo_flags */
399 : TV_IPA_COMDATS, /* tv_id */
400 : 0, /* properties_required */
401 : 0, /* properties_provided */
402 : 0, /* properties_destroyed */
403 : 0, /* todo_flags_start */
404 : 0, /* todo_flags_finish */
405 : };
406 :
407 : class pass_ipa_comdats : public ipa_opt_pass_d
408 : {
409 : public:
410 285722 : pass_ipa_comdats (gcc::context *ctxt)
411 : : ipa_opt_pass_d (pass_data_ipa_comdats, ctxt,
412 : NULL, /* generate_summary */
413 : NULL, /* write_summary */
414 : NULL, /* read_summary */
415 : NULL, /* write_optimization_summary */
416 : NULL, /* read_optimization_summary */
417 : NULL, /* stmt_fixup */
418 : 0, /* function_transform_todo_flags_start */
419 : NULL, /* function_transform */
420 285722 : NULL) /* variable_transform */
421 285722 : {}
422 :
423 : /* opt_pass methods: */
424 : bool gate (function *) final override;
425 230063 : unsigned int execute (function *) final override { return ipa_comdats (); }
426 :
427 : }; // class pass_ipa_comdats
428 :
429 : bool
430 563719 : pass_ipa_comdats::gate (function *)
431 : {
432 563719 : return HAVE_COMDAT_GROUP;
433 : }
434 :
435 : } // anon namespace
436 :
437 : ipa_opt_pass_d *
438 285722 : make_pass_ipa_comdats (gcc::context *ctxt)
439 : {
440 285722 : return new pass_ipa_comdats (ctxt);
441 : }
|