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 arise 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 78514 : propagate_comdat_group (struct symtab_node *symbol,
66 : tree newgroup, hash_map<symtab_node *, tree> &map)
67 : {
68 78514 : int i;
69 78514 : struct ipa_ref *ref;
70 :
71 : /* Walk all references to SYMBOL, recursively dive into aliases. */
72 :
73 105769 : for (i = 0;
74 211538 : symbol->iterate_referring (i, ref)
75 105769 : && newgroup != error_mark_node; i++)
76 : {
77 51724 : struct symtab_node *symbol2 = ref->referring;
78 :
79 51724 : if (ref->use == IPA_REF_ALIAS)
80 : {
81 1230 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
82 1230 : 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 50494 : if (symbol->type != symbol2->type)
90 : {
91 24469 : newgroup = error_mark_node;
92 24469 : 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 26025 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
100 : {
101 14462 : if (cn->inlined_to)
102 2209 : symbol2 = cn->inlined_to;
103 : }
104 :
105 : /* The actual merge operation. */
106 :
107 26025 : tree *val2 = map.get (symbol2);
108 :
109 26025 : if (val2 && *val2 != newgroup)
110 : {
111 22230 : if (!newgroup)
112 : newgroup = *val2;
113 : else
114 153 : newgroup = error_mark_node;
115 : }
116 : }
117 :
118 : /* If we analyze function, walk also callers. */
119 :
120 78514 : cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
121 :
122 52537 : if (cnode)
123 52537 : for (struct cgraph_edge * edge = cnode->callers;
124 111577 : edge && newgroup != error_mark_node; edge = edge->next_caller)
125 : {
126 59040 : struct symtab_node *symbol2 = edge->caller;
127 :
128 59040 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
129 : {
130 : /* Thunks cannot call across section boundary. */
131 59040 : if (cn->thunk)
132 427 : 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 59040 : if (cn->inlined_to)
137 19838 : symbol2 = cn->inlined_to;
138 : }
139 :
140 : /* The actual merge operation. */
141 :
142 59040 : tree *val2 = map.get (symbol2);
143 :
144 59040 : if (val2 && *val2 != newgroup)
145 : {
146 29911 : if (!newgroup)
147 : newgroup = *val2;
148 : else
149 4623 : newgroup = error_mark_node;
150 : }
151 : }
152 78514 : 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 209071 : enqueue_references (symtab_node **first,
162 : symtab_node *symbol)
163 : {
164 209071 : int i;
165 209071 : struct ipa_ref *ref = NULL;
166 :
167 428768 : for (i = 0; symbol->iterate_reference (i, ref); i++)
168 : {
169 219697 : symtab_node *node = ref->referred->ultimate_alias_target ();
170 :
171 : /* Always keep thunks in same sections as target function. */
172 219697 : if (is_a <cgraph_node *>(node))
173 24725 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
174 219697 : if (!node->aux && node->definition)
175 : {
176 1569 : node->aux = *first;
177 1569 : *first = node;
178 : }
179 : }
180 :
181 209071 : if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
182 : {
183 184482 : struct cgraph_edge *edge;
184 :
185 711280 : for (edge = cnode->callees; edge; edge = edge->next_callee)
186 526798 : if (!edge->inline_failed)
187 136739 : enqueue_references (first, edge->callee);
188 : else
189 : {
190 390059 : symtab_node *node = edge->callee->ultimate_alias_target ();
191 :
192 : /* Always keep thunks in same sections as target function. */
193 390059 : if (is_a <cgraph_node *>(node))
194 390059 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
195 390059 : if (!node->aux && node->definition)
196 : {
197 3236 : node->aux = *first;
198 3236 : *first = node;
199 : }
200 : }
201 : }
202 209071 : }
203 :
204 : /* Set comdat group of SYMBOL to GROUP.
205 : Callback for for_node_and_aliases. */
206 :
207 : bool
208 6908 : set_comdat_group (symtab_node *symbol,
209 : void *head_p)
210 : {
211 6908 : symtab_node *head = (symtab_node *)head_p;
212 :
213 6908 : gcc_assert (!symbol->get_comdat_group ());
214 6908 : if (symbol->real_symbol_p ())
215 : {
216 6908 : symbol->set_comdat_group (head->get_comdat_group ());
217 6908 : symbol->add_to_same_comdat_group (head);
218 : }
219 6908 : return false;
220 : }
221 :
222 : /* Set comdat group of SYMBOL to GROUP.
223 : Callback for for_node_thunks_and_aliases. */
224 :
225 : bool
226 6902 : set_comdat_group_1 (cgraph_node *symbol,
227 : void *head_p)
228 : {
229 6902 : return set_comdat_group (symbol, head_p);
230 : }
231 :
232 : /* The actual pass with the main dataflow loop. */
233 :
234 : static unsigned int
235 238256 : ipa_comdats (void)
236 : {
237 238256 : hash_map<symtab_node *, tree> map (251);
238 238256 : hash_map<tree, symtab_node *> comdat_head_map (251);
239 238256 : symtab_node *symbol;
240 238256 : bool comdat_group_seen = false;
241 238256 : symtab_node *first = (symtab_node *) (void *) 1;
242 238256 : 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 6006728 : FOR_EACH_DEFINED_SYMBOL (symbol)
249 5768472 : if (!symbol->real_symbol_p ())
250 : ;
251 4424232 : else if ((group = symbol->get_comdat_group ()) != NULL)
252 : {
253 528609 : map.put (symbol, group);
254 528609 : comdat_head_map.put (group, symbol);
255 528609 : comdat_group_seen = true;
256 :
257 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
258 528609 : 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 3895623 : else if (symbol->externally_visible
264 1751369 : || symbol->force_output
265 1506367 : || symbol->ref_by_asm
266 1506362 : || symbol->used_from_other_partition
267 1506362 : || TREE_THIS_VOLATILE (symbol->decl)
268 1496988 : || symbol->get_section ()
269 4352162 : || (TREE_CODE (symbol->decl) == FUNCTION_DECL
270 184470 : && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
271 182440 : || DECL_STATIC_DESTRUCTOR (symbol->decl))))
272 : {
273 3441175 : symtab_node *target = symbol->ultimate_alias_target ();
274 :
275 : /* Always keep thunks in same sections as target function. */
276 3441175 : if (is_a <cgraph_node *>(target))
277 1146367 : target = dyn_cast <cgraph_node *> (target)->function_symbol ();
278 3441175 : map.put (target, error_mark_node);
279 :
280 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
281 3441175 : symbol->aux = (symtab_node *) (void *) 1;
282 : }
283 : else
284 : {
285 : /* Enqueue symbol for dataflow. */
286 454448 : symbol->aux = first;
287 454448 : first = symbol;
288 : }
289 :
290 238256 : if (!comdat_group_seen)
291 : {
292 2765600 : FOR_EACH_DEFINED_SYMBOL (symbol)
293 2553139 : symbol->aux = NULL;
294 : return 0;
295 : }
296 :
297 : /* The actual dataflow. */
298 :
299 102659 : while (first != (void *) 1)
300 : {
301 76864 : tree group = NULL;
302 76864 : tree newgroup, *val;
303 :
304 76864 : symbol = first;
305 76864 : first = (symtab_node *)first->aux;
306 :
307 : /* Get current lattice value of SYMBOL. */
308 76864 : val = map.get (symbol);
309 76864 : if (val)
310 593 : 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 76864 : if (group == error_mark_node)
315 4532 : continue;
316 :
317 76857 : newgroup = propagate_comdat_group (symbol, group, map);
318 :
319 : /* If nothing changed, proceed to next symbol. */
320 76857 : if (newgroup == group)
321 : {
322 4525 : symbol->aux = NULL;
323 4525 : continue;
324 : }
325 :
326 : /* Update lattice value and enqueue all references for re-visiting. */
327 72332 : gcc_assert (newgroup);
328 72332 : if (val)
329 498 : *val = newgroup;
330 : else
331 71834 : map.put (symbol, newgroup);
332 72332 : enqueue_references (&first, symbol);
333 :
334 : /* We may need to revisit the symbol unless it is BOTTOM. */
335 72332 : if (newgroup != error_mark_node)
336 7556 : symbol->aux = NULL;
337 : }
338 :
339 : /* Finally assign symbols to the sections. */
340 :
341 3241128 : FOR_EACH_DEFINED_SYMBOL (symbol)
342 : {
343 3215333 : struct cgraph_node *fun;
344 3215333 : symbol->aux = NULL;
345 3215333 : if (!symbol->get_comdat_group ()
346 2595892 : && !symbol->alias
347 2585970 : && (!(fun = dyn_cast <cgraph_node *> (symbol))
348 1336102 : || !fun->thunk)
349 5800677 : && symbol->real_symbol_p ())
350 : {
351 1592107 : 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 1592107 : gcc_assert (val);
357 :
358 1592107 : tree group = *val;
359 :
360 1592107 : if (group == error_mark_node)
361 1585211 : continue;
362 6896 : 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 6896 : if (is_a <cgraph_node *> (symbol))
369 6890 : dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
370 6890 : (set_comdat_group_1,
371 6890 : *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 238256 : }
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 298828 : 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 298828 : NULL) /* variable_transform */
421 298828 : {}
422 :
423 : /* opt_pass methods: */
424 : bool gate (function *) final override;
425 238256 : unsigned int execute (function *) final override { return ipa_comdats (); }
426 :
427 : }; // class pass_ipa_comdats
428 :
429 : bool
430 585252 : pass_ipa_comdats::gate (function *)
431 : {
432 585252 : return HAVE_COMDAT_GROUP;
433 : }
434 :
435 : } // anon namespace
436 :
437 : ipa_opt_pass_d *
438 298828 : make_pass_ipa_comdats (gcc::context *ctxt)
439 : {
440 298828 : return new pass_ipa_comdats (ctxt);
441 : }
|