]>
Commit | Line | Data |
---|---|---|
cf8b23bb | 1 | /* Localize comdats. |
fbd26352 | 2 | Copyright (C) 2014-2019 Free Software Foundation, Inc. |
cf8b23bb | 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 | exlusively 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" | |
7c29e30e | 55 | #include "tree.h" |
cf8b23bb | 56 | #include "tree-pass.h" |
7c29e30e | 57 | #include "cgraph.h" |
cf8b23bb | 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 | propagate_comdat_group (struct symtab_node *symbol, | |
d62dd039 | 66 | tree newgroup, hash_map<symtab_node *, tree> &map) |
cf8b23bb | 67 | { |
68 | int i; | |
69 | struct ipa_ref *ref; | |
70 | ||
71 | /* Walk all references to SYMBOL, recursively dive into aliases. */ | |
72 | ||
73 | for (i = 0; | |
51ce5652 | 74 | symbol->iterate_referring (i, ref) |
cf8b23bb | 75 | && newgroup != error_mark_node; i++) |
76 | { | |
77 | struct symtab_node *symbol2 = ref->referring; | |
78 | ||
79 | if (ref->use == IPA_REF_ALIAS) | |
80 | { | |
81 | newgroup = propagate_comdat_group (symbol2, newgroup, map); | |
82 | continue; | |
83 | } | |
84 | ||
f4d3c071 | 85 | /* One COMDAT group cannot hold both variables and functions at |
cf8b23bb | 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 | if (symbol->type != symbol2->type) | |
90 | { | |
91 | newgroup = error_mark_node; | |
92 | 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 | if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2)) | |
100 | { | |
101 | if (cn->global.inlined_to) | |
102 | symbol2 = cn->global.inlined_to; | |
103 | } | |
104 | ||
105 | /* The actual merge operation. */ | |
106 | ||
d62dd039 | 107 | tree *val2 = map.get (symbol2); |
cf8b23bb | 108 | |
109 | if (val2 && *val2 != newgroup) | |
110 | { | |
111 | if (!newgroup) | |
112 | newgroup = *val2; | |
113 | else | |
114 | newgroup = error_mark_node; | |
115 | } | |
116 | } | |
117 | ||
118 | /* If we analyze function, walk also callers. */ | |
119 | ||
120 | cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol); | |
121 | ||
122 | if (cnode) | |
123 | for (struct cgraph_edge * edge = cnode->callers; | |
124 | edge && newgroup != error_mark_node; edge = edge->next_caller) | |
125 | { | |
126 | struct symtab_node *symbol2 = edge->caller; | |
127 | ||
cf8b23bb | 128 | if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2)) |
129 | { | |
f4d3c071 | 130 | /* Thunks cannot call across section boundary. */ |
6f59b325 | 131 | if (cn->thunk.thunk_p) |
132 | 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. */ | |
cf8b23bb | 136 | if (cn->global.inlined_to) |
137 | symbol2 = cn->global.inlined_to; | |
138 | } | |
139 | ||
140 | /* The actual merge operation. */ | |
141 | ||
d62dd039 | 142 | tree *val2 = map.get (symbol2); |
cf8b23bb | 143 | |
144 | if (val2 && *val2 != newgroup) | |
145 | { | |
146 | if (!newgroup) | |
147 | newgroup = *val2; | |
148 | else | |
149 | newgroup = error_mark_node; | |
150 | } | |
151 | } | |
152 | 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 | enqueue_references (symtab_node **first, | |
162 | symtab_node *symbol) | |
163 | { | |
164 | int i; | |
51ce5652 | 165 | struct ipa_ref *ref = NULL; |
cf8b23bb | 166 | |
51ce5652 | 167 | for (i = 0; symbol->iterate_reference (i, ref); i++) |
cf8b23bb | 168 | { |
415d1b9a | 169 | symtab_node *node = ref->referred->ultimate_alias_target (); |
f300163e | 170 | |
171 | /* Always keep thunks in same sections as target function. */ | |
172 | if (is_a <cgraph_node *>(node)) | |
173 | node = dyn_cast <cgraph_node *> (node)->function_symbol (); | |
cf8b23bb | 174 | if (!node->aux && node->definition) |
175 | { | |
176 | node->aux = *first; | |
177 | *first = node; | |
178 | } | |
179 | } | |
180 | ||
181 | if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol)) | |
182 | { | |
183 | struct cgraph_edge *edge; | |
184 | ||
185 | for (edge = cnode->callees; edge; edge = edge->next_callee) | |
186 | if (!edge->inline_failed) | |
187 | enqueue_references (first, edge->callee); | |
188 | else | |
189 | { | |
415d1b9a | 190 | symtab_node *node = edge->callee->ultimate_alias_target (); |
f300163e | 191 | |
192 | /* Always keep thunks in same sections as target function. */ | |
193 | if (is_a <cgraph_node *>(node)) | |
194 | node = dyn_cast <cgraph_node *> (node)->function_symbol (); | |
cf8b23bb | 195 | if (!node->aux && node->definition) |
196 | { | |
197 | node->aux = *first; | |
198 | *first = node; | |
199 | } | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | /* Set comdat group of SYMBOL to GROUP. | |
f300163e | 205 | Callback for for_node_and_aliases. */ |
cf8b23bb | 206 | |
207 | bool | |
208 | set_comdat_group (symtab_node *symbol, | |
209 | void *head_p) | |
210 | { | |
211 | symtab_node *head = (symtab_node *)head_p; | |
212 | ||
8c016392 | 213 | gcc_assert (!symbol->get_comdat_group ()); |
87943954 | 214 | if (symbol->real_symbol_p ()) |
215 | { | |
216 | symbol->set_comdat_group (head->get_comdat_group ()); | |
217 | symbol->add_to_same_comdat_group (head); | |
218 | } | |
cf8b23bb | 219 | return false; |
220 | } | |
221 | ||
f300163e | 222 | /* Set comdat group of SYMBOL to GROUP. |
223 | Callback for for_node_thunks_and_aliases. */ | |
224 | ||
225 | bool | |
226 | set_comdat_group_1 (cgraph_node *symbol, | |
227 | void *head_p) | |
228 | { | |
229 | return set_comdat_group (symbol, head_p); | |
230 | } | |
231 | ||
cf8b23bb | 232 | /* The actual pass with the main dataflow loop. */ |
233 | ||
234 | static unsigned int | |
235 | ipa_comdats (void) | |
236 | { | |
d62dd039 | 237 | hash_map<symtab_node *, tree> map (251); |
238 | hash_map<tree, symtab_node *> comdat_head_map (251); | |
cf8b23bb | 239 | symtab_node *symbol; |
240 | bool comdat_group_seen = false; | |
241 | symtab_node *first = (symtab_node *) (void *) 1; | |
8c016392 | 242 | tree group; |
cf8b23bb | 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 | FOR_EACH_DEFINED_SYMBOL (symbol) | |
415d1b9a | 249 | if (!symbol->real_symbol_p ()) |
cf8b23bb | 250 | ; |
8c016392 | 251 | else if ((group = symbol->get_comdat_group ()) != NULL) |
cf8b23bb | 252 | { |
d62dd039 | 253 | map.put (symbol, group); |
254 | comdat_head_map.put (group, symbol); | |
cf8b23bb | 255 | comdat_group_seen = true; |
256 | ||
257 | /* Mark the symbol so we won't waste time visiting it for dataflow. */ | |
258 | symbol->aux = (symtab_node *) (void *) 1; | |
259 | } | |
f4d3c071 | 260 | /* See symbols that cannot be privatized to comdats; that is externally |
cf8b23bb | 261 | visible symbols or otherwise used ones. We also do not want to mangle |
262 | user section names. */ | |
263 | else if (symbol->externally_visible | |
264 | || symbol->force_output | |
265 | || symbol->used_from_other_partition | |
266 | || TREE_THIS_VOLATILE (symbol->decl) | |
71e19e54 | 267 | || symbol->get_section () |
cf8b23bb | 268 | || (TREE_CODE (symbol->decl) == FUNCTION_DECL |
269 | && (DECL_STATIC_CONSTRUCTOR (symbol->decl) | |
270 | || DECL_STATIC_DESTRUCTOR (symbol->decl)))) | |
271 | { | |
f300163e | 272 | symtab_node *target = symbol->ultimate_alias_target (); |
273 | ||
274 | /* Always keep thunks in same sections as target function. */ | |
275 | if (is_a <cgraph_node *>(target)) | |
276 | target = dyn_cast <cgraph_node *> (target)->function_symbol (); | |
277 | map.put (target, error_mark_node); | |
cf8b23bb | 278 | |
279 | /* Mark the symbol so we won't waste time visiting it for dataflow. */ | |
280 | symbol->aux = (symtab_node *) (void *) 1; | |
281 | } | |
282 | else | |
283 | { | |
284 | /* Enqueue symbol for dataflow. */ | |
285 | symbol->aux = first; | |
286 | first = symbol; | |
287 | } | |
288 | ||
289 | if (!comdat_group_seen) | |
290 | { | |
291 | FOR_EACH_DEFINED_SYMBOL (symbol) | |
292 | symbol->aux = NULL; | |
293 | return 0; | |
294 | } | |
295 | ||
296 | /* The actual dataflow. */ | |
297 | ||
298 | while (first != (void *) 1) | |
299 | { | |
300 | tree group = NULL; | |
301 | tree newgroup, *val; | |
302 | ||
303 | symbol = first; | |
304 | first = (symtab_node *)first->aux; | |
305 | ||
306 | /* Get current lattice value of SYMBOL. */ | |
d62dd039 | 307 | val = map.get (symbol); |
cf8b23bb | 308 | if (val) |
309 | group = *val; | |
310 | ||
311 | /* If it is bottom, there is nothing to do; do not clear AUX | |
312 | so we won't re-queue the symbol. */ | |
313 | if (group == error_mark_node) | |
314 | continue; | |
315 | ||
316 | newgroup = propagate_comdat_group (symbol, group, map); | |
317 | ||
318 | /* If nothing changed, proceed to next symbol. */ | |
319 | if (newgroup == group) | |
320 | { | |
321 | symbol->aux = NULL; | |
322 | continue; | |
323 | } | |
324 | ||
325 | /* Update lattice value and enqueue all references for re-visiting. */ | |
326 | gcc_assert (newgroup); | |
327 | if (val) | |
328 | *val = newgroup; | |
329 | else | |
d62dd039 | 330 | map.put (symbol, newgroup); |
cf8b23bb | 331 | enqueue_references (&first, symbol); |
332 | ||
333 | /* We may need to revisit the symbol unless it is BOTTOM. */ | |
334 | if (newgroup != error_mark_node) | |
335 | symbol->aux = NULL; | |
336 | } | |
337 | ||
338 | /* Finally assign symbols to the sections. */ | |
339 | ||
340 | FOR_EACH_DEFINED_SYMBOL (symbol) | |
341 | { | |
c61d51af | 342 | struct cgraph_node *fun; |
cf8b23bb | 343 | symbol->aux = NULL; |
8c016392 | 344 | if (!symbol->get_comdat_group () |
cf8b23bb | 345 | && !symbol->alias |
c61d51af | 346 | && (!(fun = dyn_cast <cgraph_node *> (symbol)) |
f300163e | 347 | || !fun->thunk.thunk_p) |
415d1b9a | 348 | && symbol->real_symbol_p ()) |
cf8b23bb | 349 | { |
366970c6 | 350 | tree *val = map.get (symbol); |
351 | ||
352 | /* A NULL here means that SYMBOL is unreachable in the definition | |
353 | of ipa-comdats. Either ipa-comdats is wrong about this or someone | |
354 | forgot to cleanup and remove unreachable functions earlier. */ | |
355 | gcc_assert (val); | |
356 | ||
357 | tree group = *val; | |
cf8b23bb | 358 | |
359 | if (group == error_mark_node) | |
360 | continue; | |
361 | if (dump_file) | |
362 | { | |
363 | fprintf (dump_file, "Localizing symbol\n"); | |
415d1b9a | 364 | symbol->dump (dump_file); |
cf8b23bb | 365 | fprintf (dump_file, "To group: %s\n", IDENTIFIER_POINTER (group)); |
366 | } | |
f300163e | 367 | if (is_a <cgraph_node *> (symbol)) |
8bfefdea | 368 | dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases |
f300163e | 369 | (set_comdat_group_1, |
370 | *comdat_head_map.get (group), | |
371 | true); | |
372 | else | |
373 | symbol->call_for_symbol_and_aliases | |
374 | (set_comdat_group, | |
375 | *comdat_head_map.get (group), | |
376 | true); | |
cf8b23bb | 377 | } |
378 | } | |
379 | return 0; | |
380 | } | |
381 | ||
382 | namespace { | |
383 | ||
384 | const pass_data pass_data_ipa_comdats = | |
385 | { | |
386 | IPA_PASS, /* type */ | |
387 | "comdats", /* name */ | |
388 | OPTGROUP_NONE, /* optinfo_flags */ | |
cf8b23bb | 389 | TV_IPA_COMDATS, /* tv_id */ |
390 | 0, /* properties_required */ | |
391 | 0, /* properties_provided */ | |
392 | 0, /* properties_destroyed */ | |
393 | 0, /* todo_flags_start */ | |
394 | 0, /* todo_flags_finish */ | |
395 | }; | |
396 | ||
397 | class pass_ipa_comdats : public ipa_opt_pass_d | |
398 | { | |
399 | public: | |
400 | pass_ipa_comdats (gcc::context *ctxt) | |
401 | : ipa_opt_pass_d (pass_data_ipa_comdats, ctxt, | |
402 | NULL, /* generate_summary */ | |
403 | NULL, /* write_summary */ | |
404 | NULL, /* read_summary */ | |
405 | NULL, /* write_optimization_summary */ | |
406 | NULL, /* read_optimization_summary */ | |
407 | NULL, /* stmt_fixup */ | |
408 | 0, /* function_transform_todo_flags_start */ | |
409 | NULL, /* function_transform */ | |
410 | NULL) /* variable_transform */ | |
411 | {} | |
412 | ||
413 | /* opt_pass methods: */ | |
414 | virtual bool gate (function *); | |
415 | virtual unsigned int execute (function *) { return ipa_comdats (); } | |
416 | ||
417 | }; // class pass_ipa_comdats | |
418 | ||
419 | bool | |
420 | pass_ipa_comdats::gate (function *) | |
421 | { | |
5f4e4f36 | 422 | return HAVE_COMDAT_GROUP; |
cf8b23bb | 423 | } |
424 | ||
425 | } // anon namespace | |
426 | ||
427 | ipa_opt_pass_d * | |
428 | make_pass_ipa_comdats (gcc::context *ctxt) | |
429 | { | |
430 | return new pass_ipa_comdats (ctxt); | |
431 | } |