]>
Commit | Line | Data |
---|---|---|
cf8b23bb | 1 | /* Localize comdats. |
d353bf18 | 2 | Copyright (C) 2014-2015 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" | |
1140c305 | 55 | #include "function.h" |
7c29e30e | 56 | #include "hard-reg-set.h" |
57 | #include "tree.h" | |
cf8b23bb | 58 | #include "tree-pass.h" |
7c29e30e | 59 | #include "cgraph.h" |
60 | #include "alias.h" | |
cf8b23bb | 61 | |
62 | /* Main dataflow loop propagating comdat groups across | |
63 | the symbol table. All references to SYMBOL are examined | |
64 | and NEWGROUP is updated accordingly. MAP holds current lattice | |
65 | values for individual symbols. */ | |
66 | ||
67 | tree | |
68 | propagate_comdat_group (struct symtab_node *symbol, | |
d62dd039 | 69 | tree newgroup, hash_map<symtab_node *, tree> &map) |
cf8b23bb | 70 | { |
71 | int i; | |
72 | struct ipa_ref *ref; | |
73 | ||
74 | /* Walk all references to SYMBOL, recursively dive into aliases. */ | |
75 | ||
76 | for (i = 0; | |
51ce5652 | 77 | symbol->iterate_referring (i, ref) |
cf8b23bb | 78 | && newgroup != error_mark_node; i++) |
79 | { | |
80 | struct symtab_node *symbol2 = ref->referring; | |
81 | ||
82 | if (ref->use == IPA_REF_ALIAS) | |
83 | { | |
84 | newgroup = propagate_comdat_group (symbol2, newgroup, map); | |
85 | continue; | |
86 | } | |
87 | ||
88 | /* One COMDAT group can not hold both variables and functions at | |
89 | a same time. For now we just go to BOTTOM, in future we may | |
90 | invent special comdat groups for this case. */ | |
91 | ||
92 | if (symbol->type != symbol2->type) | |
93 | { | |
94 | newgroup = error_mark_node; | |
95 | break; | |
96 | } | |
97 | ||
98 | /* If we see inline clone, its comdat group actually | |
99 | corresponds to the comdat group of the function it is inlined | |
100 | to. */ | |
101 | ||
102 | if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2)) | |
103 | { | |
104 | if (cn->global.inlined_to) | |
105 | symbol2 = cn->global.inlined_to; | |
106 | } | |
107 | ||
108 | /* The actual merge operation. */ | |
109 | ||
d62dd039 | 110 | tree *val2 = map.get (symbol2); |
cf8b23bb | 111 | |
112 | if (val2 && *val2 != newgroup) | |
113 | { | |
114 | if (!newgroup) | |
115 | newgroup = *val2; | |
116 | else | |
117 | newgroup = error_mark_node; | |
118 | } | |
119 | } | |
120 | ||
121 | /* If we analyze function, walk also callers. */ | |
122 | ||
123 | cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol); | |
124 | ||
125 | if (cnode) | |
126 | for (struct cgraph_edge * edge = cnode->callers; | |
127 | edge && newgroup != error_mark_node; edge = edge->next_caller) | |
128 | { | |
129 | struct symtab_node *symbol2 = edge->caller; | |
130 | ||
cf8b23bb | 131 | if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2)) |
132 | { | |
6f59b325 | 133 | /* Thunks can not call across section boundary. */ |
134 | if (cn->thunk.thunk_p) | |
135 | newgroup = propagate_comdat_group (symbol2, newgroup, map); | |
136 | /* If we see inline clone, its comdat group actually | |
137 | corresponds to the comdat group of the function it | |
138 | is inlined to. */ | |
cf8b23bb | 139 | if (cn->global.inlined_to) |
140 | symbol2 = cn->global.inlined_to; | |
141 | } | |
142 | ||
143 | /* The actual merge operation. */ | |
144 | ||
d62dd039 | 145 | tree *val2 = map.get (symbol2); |
cf8b23bb | 146 | |
147 | if (val2 && *val2 != newgroup) | |
148 | { | |
149 | if (!newgroup) | |
150 | newgroup = *val2; | |
151 | else | |
152 | newgroup = error_mark_node; | |
153 | } | |
154 | } | |
155 | return newgroup; | |
156 | } | |
157 | ||
158 | ||
159 | /* Add all references of SYMBOL that are defined into queue started by FIRST | |
160 | and linked by AUX pointer (unless they are already enqueued). | |
161 | Walk recursively inlined functions. */ | |
162 | ||
163 | void | |
164 | enqueue_references (symtab_node **first, | |
165 | symtab_node *symbol) | |
166 | { | |
167 | int i; | |
51ce5652 | 168 | struct ipa_ref *ref = NULL; |
cf8b23bb | 169 | |
51ce5652 | 170 | for (i = 0; symbol->iterate_reference (i, ref); i++) |
cf8b23bb | 171 | { |
415d1b9a | 172 | symtab_node *node = ref->referred->ultimate_alias_target (); |
f300163e | 173 | |
174 | /* Always keep thunks in same sections as target function. */ | |
175 | if (is_a <cgraph_node *>(node)) | |
176 | node = dyn_cast <cgraph_node *> (node)->function_symbol (); | |
cf8b23bb | 177 | if (!node->aux && node->definition) |
178 | { | |
179 | node->aux = *first; | |
180 | *first = node; | |
181 | } | |
182 | } | |
183 | ||
184 | if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol)) | |
185 | { | |
186 | struct cgraph_edge *edge; | |
187 | ||
188 | for (edge = cnode->callees; edge; edge = edge->next_callee) | |
189 | if (!edge->inline_failed) | |
190 | enqueue_references (first, edge->callee); | |
191 | else | |
192 | { | |
415d1b9a | 193 | symtab_node *node = edge->callee->ultimate_alias_target (); |
f300163e | 194 | |
195 | /* Always keep thunks in same sections as target function. */ | |
196 | if (is_a <cgraph_node *>(node)) | |
197 | node = dyn_cast <cgraph_node *> (node)->function_symbol (); | |
cf8b23bb | 198 | if (!node->aux && node->definition) |
199 | { | |
200 | node->aux = *first; | |
201 | *first = node; | |
202 | } | |
203 | } | |
204 | } | |
205 | } | |
206 | ||
207 | /* Set comdat group of SYMBOL to GROUP. | |
f300163e | 208 | Callback for for_node_and_aliases. */ |
cf8b23bb | 209 | |
210 | bool | |
211 | set_comdat_group (symtab_node *symbol, | |
212 | void *head_p) | |
213 | { | |
214 | symtab_node *head = (symtab_node *)head_p; | |
215 | ||
8c016392 | 216 | gcc_assert (!symbol->get_comdat_group ()); |
217 | symbol->set_comdat_group (head->get_comdat_group ()); | |
415d1b9a | 218 | symbol->add_to_same_comdat_group (head); |
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 | } | |
260 | /* See symbols that can not 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 | 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 | { | |
422 | return optimize; | |
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 | } |