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 77521 : propagate_comdat_group (struct symtab_node *symbol,
66 : tree newgroup, hash_map<symtab_node *, tree> &map)
67 : {
68 77521 : int i;
69 77521 : struct ipa_ref *ref;
70 :
71 : /* Walk all references to SYMBOL, recursively dive into aliases. */
72 :
73 102968 : for (i = 0;
74 205936 : symbol->iterate_referring (i, ref)
75 102968 : && newgroup != error_mark_node; i++)
76 : {
77 49937 : struct symtab_node *symbol2 = ref->referring;
78 :
79 49937 : if (ref->use == IPA_REF_ALIAS)
80 : {
81 1182 : newgroup = propagate_comdat_group (symbol2, newgroup, map);
82 1182 : 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 48755 : if (symbol->type != symbol2->type)
90 : {
91 24490 : newgroup = error_mark_node;
92 24490 : 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 24265 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
100 : {
101 14665 : if (cn->inlined_to)
102 2612 : symbol2 = cn->inlined_to;
103 : }
104 :
105 : /* The actual merge operation. */
106 :
107 24265 : tree *val2 = map.get (symbol2);
108 :
109 24265 : if (val2 && *val2 != newgroup)
110 : {
111 22139 : if (!newgroup)
112 : newgroup = *val2;
113 : else
114 192 : newgroup = error_mark_node;
115 : }
116 : }
117 :
118 : /* If we analyze function, walk also callers. */
119 :
120 77521 : cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
121 :
122 51842 : if (cnode)
123 51842 : for (struct cgraph_edge * edge = cnode->callers;
124 107923 : edge && newgroup != error_mark_node; edge = edge->next_caller)
125 : {
126 56081 : struct symtab_node *symbol2 = edge->caller;
127 :
128 56081 : if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
129 : {
130 : /* Thunks cannot call across section boundary. */
131 56081 : 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 56081 : if (cn->inlined_to)
137 19573 : symbol2 = cn->inlined_to;
138 : }
139 :
140 : /* The actual merge operation. */
141 :
142 56081 : tree *val2 = map.get (symbol2);
143 :
144 56081 : if (val2 && *val2 != newgroup)
145 : {
146 29433 : if (!newgroup)
147 : newgroup = *val2;
148 : else
149 4647 : newgroup = error_mark_node;
150 : }
151 : }
152 77521 : 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 200229 : enqueue_references (symtab_node **first,
162 : symtab_node *symbol)
163 : {
164 200229 : int i;
165 200229 : struct ipa_ref *ref = NULL;
166 :
167 416262 : for (i = 0; symbol->iterate_reference (i, ref); i++)
168 : {
169 216033 : symtab_node *node = ref->referred->ultimate_alias_target ();
170 :
171 : /* Always keep thunks in same sections as target function. */
172 216033 : if (is_a <cgraph_node *>(node))
173 25649 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
174 216033 : if (!node->aux && node->definition)
175 : {
176 1414 : node->aux = *first;
177 1414 : *first = node;
178 : }
179 : }
180 :
181 200229 : if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
182 : {
183 175769 : struct cgraph_edge *edge;
184 :
185 693226 : for (edge = cnode->callees; edge; edge = edge->next_callee)
186 517457 : if (!edge->inline_failed)
187 128528 : enqueue_references (first, edge->callee);
188 : else
189 : {
190 388929 : symtab_node *node = edge->callee->ultimate_alias_target ();
191 :
192 : /* Always keep thunks in same sections as target function. */
193 388929 : if (is_a <cgraph_node *>(node))
194 388929 : node = dyn_cast <cgraph_node *> (node)->function_symbol ();
195 388929 : if (!node->aux && node->definition)
196 : {
197 3107 : node->aux = *first;
198 3107 : *first = node;
199 : }
200 : }
201 : }
202 200229 : }
203 :
204 : /* Set comdat group of SYMBOL to GROUP.
205 : Callback for for_node_and_aliases. */
206 :
207 : bool
208 6413 : set_comdat_group (symtab_node *symbol,
209 : void *head_p)
210 : {
211 6413 : symtab_node *head = (symtab_node *)head_p;
212 :
213 6413 : gcc_assert (!symbol->get_comdat_group ());
214 6413 : if (symbol->real_symbol_p ())
215 : {
216 6413 : symbol->set_comdat_group (head->get_comdat_group ());
217 6413 : symbol->add_to_same_comdat_group (head);
218 : }
219 6413 : return false;
220 : }
221 :
222 : /* Set comdat group of SYMBOL to GROUP.
223 : Callback for for_node_thunks_and_aliases. */
224 :
225 : bool
226 6407 : set_comdat_group_1 (cgraph_node *symbol,
227 : void *head_p)
228 : {
229 6407 : return set_comdat_group (symbol, head_p);
230 : }
231 :
232 : /* The actual pass with the main dataflow loop. */
233 :
234 : static unsigned int
235 232280 : ipa_comdats (void)
236 : {
237 232280 : hash_map<symtab_node *, tree> map (251);
238 232280 : hash_map<tree, symtab_node *> comdat_head_map (251);
239 232280 : symtab_node *symbol;
240 232280 : bool comdat_group_seen = false;
241 232280 : symtab_node *first = (symtab_node *) (void *) 1;
242 232280 : 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 5951715 : FOR_EACH_DEFINED_SYMBOL (symbol)
249 5719435 : if (!symbol->real_symbol_p ())
250 : ;
251 4404188 : else if ((group = symbol->get_comdat_group ()) != NULL)
252 : {
253 528261 : map.put (symbol, group);
254 528261 : comdat_head_map.put (group, symbol);
255 528261 : comdat_group_seen = true;
256 :
257 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
258 528261 : 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 3875927 : else if (symbol->externally_visible
264 1742399 : || symbol->force_output
265 1497954 : || symbol->ref_by_asm
266 1497949 : || symbol->used_from_other_partition
267 1497949 : || TREE_THIS_VOLATILE (symbol->decl)
268 1488611 : || symbol->get_section ()
269 4327535 : || (TREE_CODE (symbol->decl) == FUNCTION_DECL
270 182595 : && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
271 180574 : || DECL_STATIC_DESTRUCTOR (symbol->decl))))
272 : {
273 3426401 : symtab_node *target = symbol->ultimate_alias_target ();
274 :
275 : /* Always keep thunks in same sections as target function. */
276 3426401 : if (is_a <cgraph_node *>(target))
277 1140543 : target = dyn_cast <cgraph_node *> (target)->function_symbol ();
278 3426401 : map.put (target, error_mark_node);
279 :
280 : /* Mark the symbol so we won't waste time visiting it for dataflow. */
281 3426401 : symbol->aux = (symtab_node *) (void *) 1;
282 : }
283 : else
284 : {
285 : /* Enqueue symbol for dataflow. */
286 449526 : symbol->aux = first;
287 449526 : first = symbol;
288 : }
289 :
290 232280 : if (!comdat_group_seen)
291 : {
292 2717776 : FOR_EACH_DEFINED_SYMBOL (symbol)
293 2511291 : symbol->aux = NULL;
294 : return 0;
295 : }
296 :
297 : /* The actual dataflow. */
298 :
299 101717 : while (first != (void *) 1)
300 : {
301 75922 : tree group = NULL;
302 75922 : tree newgroup, *val;
303 :
304 75922 : symbol = first;
305 75922 : first = (symtab_node *)first->aux;
306 :
307 : /* Get current lattice value of SYMBOL. */
308 75922 : val = map.get (symbol);
309 75922 : if (val)
310 554 : 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 75922 : if (group == error_mark_node)
315 4221 : continue;
316 :
317 75915 : newgroup = propagate_comdat_group (symbol, group, map);
318 :
319 : /* If nothing changed, proceed to next symbol. */
320 75915 : if (newgroup == group)
321 : {
322 4214 : symbol->aux = NULL;
323 4214 : continue;
324 : }
325 :
326 : /* Update lattice value and enqueue all references for re-visiting. */
327 71701 : gcc_assert (newgroup);
328 71701 : if (val)
329 478 : *val = newgroup;
330 : else
331 71223 : map.put (symbol, newgroup);
332 71701 : enqueue_references (&first, symbol);
333 :
334 : /* We may need to revisit the symbol unless it is BOTTOM. */
335 71701 : if (newgroup != error_mark_node)
336 7014 : symbol->aux = NULL;
337 : }
338 :
339 : /* Finally assign symbols to the sections. */
340 :
341 3233939 : FOR_EACH_DEFINED_SYMBOL (symbol)
342 : {
343 3208144 : struct cgraph_node *fun;
344 3208144 : symbol->aux = NULL;
345 3208144 : if (!symbol->get_comdat_group ()
346 2579076 : && !symbol->alias
347 2569067 : && (!(fun = dyn_cast <cgraph_node *> (symbol))
348 1323404 : || !fun->thunk)
349 5776594 : && symbol->real_symbol_p ())
350 : {
351 1587944 : 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 1587944 : gcc_assert (val);
357 :
358 1587944 : tree group = *val;
359 :
360 1587944 : if (group == error_mark_node)
361 1581543 : continue;
362 6401 : 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 6401 : if (is_a <cgraph_node *> (symbol))
369 6395 : dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
370 6395 : (set_comdat_group_1,
371 6395 : *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 232280 : }
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 287872 : 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 287872 : NULL) /* variable_transform */
421 287872 : {}
422 :
423 : /* opt_pass methods: */
424 : bool gate (function *) final override;
425 232280 : unsigned int execute (function *) final override { return ipa_comdats (); }
426 :
427 : }; // class pass_ipa_comdats
428 :
429 : bool
430 568226 : pass_ipa_comdats::gate (function *)
431 : {
432 568226 : return HAVE_COMDAT_GROUP;
433 : }
434 :
435 : } // anon namespace
436 :
437 : ipa_opt_pass_d *
438 287872 : make_pass_ipa_comdats (gcc::context *ctxt)
439 : {
440 287872 : return new pass_ipa_comdats (ctxt);
441 : }
|