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 79666 : propagate_comdat_group (struct symtab_node *symbol,
66 : tree newgroup, hash_map<symtab_node *, tree> &map)
67 : {
68 79666 : int i;
69 79666 : struct ipa_ref *ref;
70 :
71 : /* Walk all references to SYMBOL, recursively dive into aliases. */
72 :
73 105029 : for (i = 0;
74 210058 : symbol->iterate_referring (i, ref)
75 105029 : && newgroup != error_mark_node; i++)
76 : {
77 49732 : struct symtab_node *symbol2 = ref->referring;
78 :
79 49732 : if (ref->use == IPA_REF_ALIAS)
80 : {
81 1234 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
82 1234 : 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 48498 : if (symbol->type != symbol2->type)
90 : {
91 24369 : newgroup = error_mark_node;
92 24369 : 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 24129 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
100 : {
101 14427 : if (cn->inlined_to)
102 2348 : symbol2 = cn->inlined_to;
103 : }
104 :
105 : /* The actual merge operation. */
106 :
107 24129 : tree *val2 = map.get (symbol2);
108 :
109 24129 : if (val2 && *val2 != newgroup)
110 : {
111 22123 : if (!newgroup)
112 : newgroup = *val2;
113 : else
114 148 : newgroup = error_mark_node;
115 : }
116 : }
117 :
118 : /* If we analyze function, walk also callers. */
119 :
120 79666 : cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
121 :
122 53988 : if (cnode)
123 53988 : for (struct cgraph_edge * edge = cnode->callers;
124 114652 : edge && newgroup != error_mark_node; edge = edge->next_caller)
125 : {
126 60664 : struct symtab_node *symbol2 = edge->caller;
127 :
128 60664 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
129 : {
130 : /* Thunks cannot call across section boundary. */
131 60664 : 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 60664 : if (cn->inlined_to)
137 19873 : symbol2 = cn->inlined_to;
138 : }
139 :
140 : /* The actual merge operation. */
141 :
142 60664 : tree *val2 = map.get (symbol2);
143 :
144 60664 : if (val2 && *val2 != newgroup)
145 : {
146 31383 : if (!newgroup)
147 : newgroup = *val2;
148 : else
149 4800 : newgroup = error_mark_node;
150 : }
151 : }
152 79666 : 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 210607 : enqueue_references (symtab_node **first,
162 : symtab_node *symbol)
163 : {
164 210607 : int i;
165 210607 : struct ipa_ref *ref = NULL;
166 :
167 424307 : for (i = 0; symbol->iterate_reference (i, ref); i++)
168 : {
169 213700 : symtab_node *node = ref->referred->ultimate_alias_target ();
170 :
171 : /* Always keep thunks in same sections as target function. */
172 213700 : if (is_a <cgraph_node *>(node))
173 24711 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
174 213700 : if (!node->aux && node->definition)
175 : {
176 1448 : node->aux = *first;
177 1448 : *first = node;
178 : }
179 : }
180 :
181 210607 : if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
182 : {
183 186200 : struct cgraph_edge *edge;
184 :
185 715743 : for (edge = cnode->callees; edge; edge = edge->next_callee)
186 529543 : if (!edge->inline_failed)
187 137146 : enqueue_references (first, edge->callee);
188 : else
189 : {
190 392397 : symtab_node *node = edge->callee->ultimate_alias_target ();
191 :
192 : /* Always keep thunks in same sections as target function. */
193 392397 : if (is_a <cgraph_node *>(node))
194 392397 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
195 392397 : if (!node->aux && node->definition)
196 : {
197 3414 : node->aux = *first;
198 3414 : *first = node;
199 : }
200 : }
201 : }
202 210607 : }
203 :
204 : /* Set comdat group of SYMBOL to GROUP.
205 : Callback for for_node_and_aliases. */
206 :
207 : bool
208 7761 : set_comdat_group (symtab_node *symbol,
209 : void *head_p)
210 : {
211 7761 : symtab_node *head = (symtab_node *)head_p;
212 :
213 7761 : gcc_assert (!symbol->get_comdat_group ());
214 7761 : if (symbol->real_symbol_p ())
215 : {
216 7761 : symbol->set_comdat_group (head->get_comdat_group ());
217 7761 : symbol->add_to_same_comdat_group (head);
218 : }
219 7761 : return false;
220 : }
221 :
222 : /* Set comdat group of SYMBOL to GROUP.
223 : Callback for for_node_thunks_and_aliases. */
224 :
225 : bool
226 7755 : set_comdat_group_1 (cgraph_node *symbol,
227 : void *head_p)
228 : {
229 7755 : return set_comdat_group (symbol, head_p);
230 : }
231 :
232 : /* The actual pass with the main dataflow loop. */
233 :
234 : static unsigned int
235 232558 : ipa_comdats (void)
236 : {
237 232558 : hash_map<symtab_node *, tree> map (251);
238 232558 : hash_map<tree, symtab_node *> comdat_head_map (251);
239 232558 : symtab_node *symbol;
240 232558 : bool comdat_group_seen = false;
241 232558 : symtab_node *first = (symtab_node *) (void *) 1;
242 232558 : 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 6053248 : FOR_EACH_DEFINED_SYMBOL (symbol)
249 5820690 : if (!symbol->real_symbol_p ())
250 : ;
251 4413666 : else if ((group = symbol->get_comdat_group ()) != NULL)
252 : {
253 529541 : map.put (symbol, group);
254 529541 : comdat_head_map.put (group, symbol);
255 529541 : comdat_group_seen = true;
256 :
257 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
258 529541 : 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 3884125 : else if (symbol->externally_visible
264 1748583 : || symbol->force_output
265 1506376 : || symbol->ref_by_asm
266 1506371 : || symbol->used_from_other_partition
267 1506371 : || TREE_THIS_VOLATILE (symbol->decl)
268 1496966 : || symbol->get_section ()
269 4340639 : || (TREE_CODE (symbol->decl) == FUNCTION_DECL
270 185272 : && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
271 183242 : || DECL_STATIC_DESTRUCTOR (symbol->decl))))
272 : {
273 3429702 : symtab_node *target = symbol->ultimate_alias_target ();
274 :
275 : /* Always keep thunks in same sections as target function. */
276 3429702 : if (is_a <cgraph_node *>(target))
277 1138456 : target = dyn_cast <cgraph_node *> (target)->function_symbol ();
278 3429702 : map.put (target, error_mark_node);
279 :
280 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
281 3429702 : symbol->aux = (symtab_node *) (void *) 1;
282 : }
283 : else
284 : {
285 : /* Enqueue symbol for dataflow. */
286 454423 : symbol->aux = first;
287 454423 : first = symbol;
288 : }
289 :
290 232558 : if (!comdat_group_seen)
291 : {
292 2749333 : FOR_EACH_DEFINED_SYMBOL (symbol)
293 2542519 : symbol->aux = NULL;
294 : return 0;
295 : }
296 :
297 : /* The actual dataflow. */
298 :
299 103756 : while (first != (void *) 1)
300 : {
301 78012 : tree group = NULL;
302 78012 : tree newgroup, *val;
303 :
304 78012 : symbol = first;
305 78012 : first = (symtab_node *)first->aux;
306 :
307 : /* Get current lattice value of SYMBOL. */
308 78012 : val = map.get (symbol);
309 78012 : if (val)
310 629 : 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 78012 : if (group == error_mark_node)
315 4551 : continue;
316 :
317 78005 : newgroup = propagate_comdat_group (symbol, group, map);
318 :
319 : /* If nothing changed, proceed to next symbol. */
320 78005 : if (newgroup == group)
321 : {
322 4544 : symbol->aux = NULL;
323 4544 : continue;
324 : }
325 :
326 : /* Update lattice value and enqueue all references for re-visiting. */
327 73461 : gcc_assert (newgroup);
328 73461 : if (val)
329 534 : *val = newgroup;
330 : else
331 72927 : map.put (symbol, newgroup);
332 73461 : enqueue_references (&first, symbol);
333 :
334 : /* We may need to revisit the symbol unless it is BOTTOM. */
335 73461 : if (newgroup != error_mark_node)
336 8440 : symbol->aux = NULL;
337 : }
338 :
339 : /* Finally assign symbols to the sections. */
340 :
341 3303915 : FOR_EACH_DEFINED_SYMBOL (symbol)
342 : {
343 3278171 : struct cgraph_node *fun;
344 3278171 : symbol->aux = NULL;
345 3278171 : if (!symbol->get_comdat_group ()
346 2656052 : && !symbol->alias
347 2645848 : && (!(fun = dyn_cast <cgraph_node *> (symbol))
348 1396800 : || !fun->thunk)
349 5923393 : && symbol->real_symbol_p ())
350 : {
351 1593395 : 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 1593395 : gcc_assert (val);
357 :
358 1593395 : tree group = *val;
359 :
360 1593395 : if (group == error_mark_node)
361 1585646 : continue;
362 7749 : 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 7749 : if (is_a <cgraph_node *> (symbol))
369 7743 : dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
370 7743 : (set_comdat_group_1,
371 7743 : *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 232558 : }
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 288767 : 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 288767 : NULL) /* variable_transform */
421 288767 : {}
422 :
423 : /* opt_pass methods: */
424 : bool gate (function *) final override;
425 232558 : unsigned int execute (function *) final override { return ipa_comdats (); }
426 :
427 : }; // class pass_ipa_comdats
428 :
429 : bool
430 569027 : pass_ipa_comdats::gate (function *)
431 : {
432 569027 : return HAVE_COMDAT_GROUP;
433 : }
434 :
435 : } // anon namespace
436 :
437 : ipa_opt_pass_d *
438 288767 : make_pass_ipa_comdats (gcc::context *ctxt)
439 : {
440 288767 : return new pass_ipa_comdats (ctxt);
441 : }
|