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 79284 : propagate_comdat_group (struct symtab_node *symbol,
66 : tree newgroup, hash_map<symtab_node *, tree> &map)
67 : {
68 79284 : int i;
69 79284 : struct ipa_ref *ref;
70 :
71 : /* Walk all references to SYMBOL, recursively dive into aliases. */
72 :
73 104948 : for (i = 0;
74 209896 : symbol->iterate_referring (i, ref)
75 104948 : && newgroup != error_mark_node; i++)
76 : {
77 49968 : struct symtab_node *symbol2 = ref->referring;
78 :
79 49968 : if (ref->use == IPA_REF_ALIAS)
80 : {
81 1218 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
82 1218 : 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 48750 : if (symbol->type != symbol2->type)
90 : {
91 24304 : newgroup = error_mark_node;
92 24304 : 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 24446 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
100 : {
101 14714 : if (cn->inlined_to)
102 2653 : symbol2 = cn->inlined_to;
103 : }
104 :
105 : /* The actual merge operation. */
106 :
107 24446 : tree *val2 = map.get (symbol2);
108 :
109 24446 : if (val2 && *val2 != newgroup)
110 : {
111 22275 : if (!newgroup)
112 : newgroup = *val2;
113 : else
114 194 : newgroup = error_mark_node;
115 : }
116 : }
117 :
118 : /* If we analyze function, walk also callers. */
119 :
120 79284 : cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
121 :
122 53660 : if (cnode)
123 53660 : for (struct cgraph_edge * edge = cnode->callers;
124 112386 : edge && newgroup != error_mark_node; edge = edge->next_caller)
125 : {
126 58726 : struct symtab_node *symbol2 = edge->caller;
127 :
128 58726 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
129 : {
130 : /* Thunks cannot call across section boundary. */
131 58726 : 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 58726 : if (cn->inlined_to)
137 19140 : symbol2 = cn->inlined_to;
138 : }
139 :
140 : /* The actual merge operation. */
141 :
142 58726 : tree *val2 = map.get (symbol2);
143 :
144 58726 : if (val2 && *val2 != newgroup)
145 : {
146 31046 : if (!newgroup)
147 : newgroup = *val2;
148 : else
149 4763 : newgroup = error_mark_node;
150 : }
151 : }
152 79284 : 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 201825 : enqueue_references (symtab_node **first,
162 : symtab_node *symbol)
163 : {
164 201825 : int i;
165 201825 : struct ipa_ref *ref = NULL;
166 :
167 417967 : for (i = 0; symbol->iterate_reference (i, ref); i++)
168 : {
169 216142 : symtab_node *node = ref->referred->ultimate_alias_target ();
170 :
171 : /* Always keep thunks in same sections as target function. */
172 216142 : if (is_a <cgraph_node *>(node))
173 25743 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
174 216142 : if (!node->aux && node->definition)
175 : {
176 1458 : node->aux = *first;
177 1458 : *first = node;
178 : }
179 : }
180 :
181 201825 : if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
182 : {
183 177463 : struct cgraph_edge *edge;
184 :
185 694827 : for (edge = cnode->callees; edge; edge = edge->next_callee)
186 517364 : if (!edge->inline_failed)
187 128636 : enqueue_references (first, edge->callee);
188 : else
189 : {
190 388728 : symtab_node *node = edge->callee->ultimate_alias_target ();
191 :
192 : /* Always keep thunks in same sections as target function. */
193 388728 : if (is_a <cgraph_node *>(node))
194 388728 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
195 388728 : if (!node->aux && node->definition)
196 : {
197 3332 : node->aux = *first;
198 3332 : *first = node;
199 : }
200 : }
201 : }
202 201825 : }
203 :
204 : /* Set comdat group of SYMBOL to GROUP.
205 : Callback for for_node_and_aliases. */
206 :
207 : bool
208 7486 : set_comdat_group (symtab_node *symbol,
209 : void *head_p)
210 : {
211 7486 : symtab_node *head = (symtab_node *)head_p;
212 :
213 7486 : gcc_assert (!symbol->get_comdat_group ());
214 7486 : if (symbol->real_symbol_p ())
215 : {
216 7486 : symbol->set_comdat_group (head->get_comdat_group ());
217 7486 : symbol->add_to_same_comdat_group (head);
218 : }
219 7486 : return false;
220 : }
221 :
222 : /* Set comdat group of SYMBOL to GROUP.
223 : Callback for for_node_thunks_and_aliases. */
224 :
225 : bool
226 7480 : set_comdat_group_1 (cgraph_node *symbol,
227 : void *head_p)
228 : {
229 7480 : return set_comdat_group (symbol, head_p);
230 : }
231 :
232 : /* The actual pass with the main dataflow loop. */
233 :
234 : static unsigned int
235 232521 : ipa_comdats (void)
236 : {
237 232521 : hash_map<symtab_node *, tree> map (251);
238 232521 : hash_map<tree, symtab_node *> comdat_head_map (251);
239 232521 : symtab_node *symbol;
240 232521 : bool comdat_group_seen = false;
241 232521 : symtab_node *first = (symtab_node *) (void *) 1;
242 232521 : 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 6015629 : FOR_EACH_DEFINED_SYMBOL (symbol)
249 5783108 : if (!symbol->real_symbol_p ())
250 : ;
251 4407140 : else if ((group = symbol->get_comdat_group ()) != NULL)
252 : {
253 530229 : map.put (symbol, group);
254 530229 : comdat_head_map.put (group, symbol);
255 530229 : comdat_group_seen = true;
256 :
257 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
258 530229 : 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 3876911 : else if (symbol->externally_visible
264 1743514 : || symbol->force_output
265 1501430 : || symbol->ref_by_asm
266 1501425 : || symbol->used_from_other_partition
267 1501425 : || TREE_THIS_VOLATILE (symbol->decl)
268 1492054 : || symbol->get_section ()
269 4331962 : || (TREE_CODE (symbol->decl) == FUNCTION_DECL
270 185032 : && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
271 183008 : || DECL_STATIC_DESTRUCTOR (symbol->decl))))
272 : {
273 3423945 : symtab_node *target = symbol->ultimate_alias_target ();
274 :
275 : /* Always keep thunks in same sections as target function. */
276 3423945 : if (is_a <cgraph_node *>(target))
277 1136972 : target = dyn_cast <cgraph_node *> (target)->function_symbol ();
278 3423945 : map.put (target, error_mark_node);
279 :
280 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
281 3423945 : symbol->aux = (symtab_node *) (void *) 1;
282 : }
283 : else
284 : {
285 : /* Enqueue symbol for dataflow. */
286 452966 : symbol->aux = first;
287 452966 : first = symbol;
288 : }
289 :
290 232521 : if (!comdat_group_seen)
291 : {
292 2743265 : FOR_EACH_DEFINED_SYMBOL (symbol)
293 2536491 : symbol->aux = NULL;
294 : return 0;
295 : }
296 :
297 : /* The actual dataflow. */
298 :
299 103396 : while (first != (void *) 1)
300 : {
301 77649 : tree group = NULL;
302 77649 : tree newgroup, *val;
303 :
304 77649 : symbol = first;
305 77649 : first = (symtab_node *)first->aux;
306 :
307 : /* Get current lattice value of SYMBOL. */
308 77649 : val = map.get (symbol);
309 77649 : if (val)
310 598 : 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 77649 : if (group == error_mark_node)
315 4460 : continue;
316 :
317 77642 : newgroup = propagate_comdat_group (symbol, group, map);
318 :
319 : /* If nothing changed, proceed to next symbol. */
320 77642 : if (newgroup == group)
321 : {
322 4453 : symbol->aux = NULL;
323 4453 : continue;
324 : }
325 :
326 : /* Update lattice value and enqueue all references for re-visiting. */
327 73189 : gcc_assert (newgroup);
328 73189 : if (val)
329 521 : *val = newgroup;
330 : else
331 72668 : map.put (symbol, newgroup);
332 73189 : enqueue_references (&first, symbol);
333 :
334 : /* We may need to revisit the symbol unless it is BOTTOM. */
335 73189 : if (newgroup != error_mark_node)
336 8139 : symbol->aux = NULL;
337 : }
338 :
339 : /* Finally assign symbols to the sections. */
340 :
341 3272364 : FOR_EACH_DEFINED_SYMBOL (symbol)
342 : {
343 3246617 : struct cgraph_node *fun;
344 3246617 : symbol->aux = NULL;
345 3246617 : if (!symbol->get_comdat_group ()
346 2624118 : && !symbol->alias
347 2613853 : && (!(fun = dyn_cast <cgraph_node *> (symbol))
348 1368436 : || !fun->thunk)
349 5859853 : && symbol->real_symbol_p ())
350 : {
351 1589608 : 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 1589608 : gcc_assert (val);
357 :
358 1589608 : tree group = *val;
359 :
360 1589608 : if (group == error_mark_node)
361 1582134 : continue;
362 7474 : 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 7474 : if (is_a <cgraph_node *> (symbol))
369 7468 : dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
370 7468 : (set_comdat_group_1,
371 7468 : *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 232521 : }
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 288775 : 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 288775 : NULL) /* variable_transform */
421 288775 : {}
422 :
423 : /* opt_pass methods: */
424 : bool gate (function *) final override;
425 232521 : unsigned int execute (function *) final override { return ipa_comdats (); }
426 :
427 : }; // class pass_ipa_comdats
428 :
429 : bool
430 569413 : pass_ipa_comdats::gate (function *)
431 : {
432 569413 : return HAVE_COMDAT_GROUP;
433 : }
434 :
435 : } // anon namespace
436 :
437 : ipa_opt_pass_d *
438 288775 : make_pass_ipa_comdats (gcc::context *ctxt)
439 : {
440 288775 : return new pass_ipa_comdats (ctxt);
441 : }
|