]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/lto/lto-partition.c
* tree-pass.h (write_summary, write_optimization_summary): Remove
[thirdparty/gcc.git] / gcc / lto / lto-partition.c
1 /* LTO partitioning logic routines.
2 Copyright 2009, 2010, 2011, 2012 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 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "toplev.h"
24 #include "tree.h"
25 #include "tm.h"
26 #include "cgraph.h"
27 #include "lto-streamer.h"
28 #include "timevar.h"
29 #include "params.h"
30 #include "ipa-inline.h"
31 #include "ipa-utils.h"
32 #include "lto-partition.h"
33
34 VEC(ltrans_partition, heap) *ltrans_partitions;
35
36 static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node);
37 static void add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode);
38
39 /* Create new partition with name NAME. */
40 static ltrans_partition
41 new_partition (const char *name)
42 {
43 ltrans_partition part = XCNEW (struct ltrans_partition_def);
44 part->cgraph_set = cgraph_node_set_new ();
45 part->varpool_set = varpool_node_set_new ();
46 part->name = name;
47 part->insns = 0;
48 VEC_safe_push (ltrans_partition, heap, ltrans_partitions, part);
49 return part;
50 }
51
52 /* Free memory used by ltrans datastructures. */
53 void
54 free_ltrans_partitions (void)
55 {
56 unsigned int idx;
57 ltrans_partition part;
58 for (idx = 0; VEC_iterate (ltrans_partition, ltrans_partitions, idx, part); idx++)
59 {
60 free_cgraph_node_set (part->cgraph_set);
61 free (part);
62 }
63 VEC_free (ltrans_partition, heap, ltrans_partitions);
64 }
65
66 /* See all references that go to comdat objects and bring them into partition too.
67 Also see all aliases of the newly added entry and bring them, too. */
68 static void
69 add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
70 {
71 int i;
72 struct ipa_ref *ref;
73 for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
74 {
75 if (symtab_function_p (ref->referred)
76 && (DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref),
77 NULL)->symbol.decl)
78 || (ref->use == IPA_REF_ALIAS
79 && lookup_attribute
80 ("weakref", DECL_ATTRIBUTES (ipa_ref_node (ref)->symbol.decl))))
81 && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
82 add_cgraph_node_to_partition (part, ipa_ref_node (ref));
83 else
84 if (symtab_variable_p (ref->referred)
85 && (DECL_COMDAT (ipa_ref_varpool_node (ref)->symbol.decl)
86 || DECL_EXTERNAL (ipa_ref_varpool_node (ref)->symbol.decl)
87 || (ref->use == IPA_REF_ALIAS
88 && lookup_attribute
89 ("weakref",
90 DECL_ATTRIBUTES (ipa_ref_varpool_node (ref)->symbol.decl))))
91 && !varpool_node_in_set_p (ipa_ref_varpool_node (ref),
92 part->varpool_set))
93 add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref));
94 }
95 for (i = 0; ipa_ref_list_referring_iterate (refs, i, ref); i++)
96 {
97 if (symtab_function_p (ref->referring)
98 && ref->use == IPA_REF_ALIAS
99 && !cgraph_node_in_set_p (ipa_ref_referring_node (ref),
100 part->cgraph_set)
101 && !lookup_attribute ("weakref",
102 DECL_ATTRIBUTES
103 (ipa_ref_referring_node (ref)->symbol.decl)))
104 add_cgraph_node_to_partition (part, ipa_ref_referring_node (ref));
105 else
106 if (symtab_variable_p (ref->referring)
107 && ref->use == IPA_REF_ALIAS
108 && !varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref),
109 part->varpool_set)
110 && !lookup_attribute ("weakref",
111 DECL_ATTRIBUTES
112 (ipa_ref_referring_varpool_node (ref)->symbol.decl)))
113 add_varpool_node_to_partition (part,
114 ipa_ref_referring_varpool_node (ref));
115 }
116 }
117
118 /* Worker for add_cgraph_node_to_partition. */
119
120 static bool
121 add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
122 {
123 ltrans_partition part = (ltrans_partition) data;
124
125 /* non-COMDAT aliases of COMDAT functions needs to be output just once. */
126 if (!DECL_COMDAT (node->symbol.decl)
127 && !node->global.inlined_to
128 && node->symbol.aux)
129 {
130 gcc_assert (node->thunk.thunk_p || node->alias);
131 return false;
132 }
133
134 if (node->symbol.aux)
135 {
136 node->symbol.in_other_partition = 1;
137 if (cgraph_dump_file)
138 fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
139 cgraph_node_name (node), node->uid);
140 }
141 node->symbol.aux = (void *)((size_t)node->symbol.aux + 1);
142 cgraph_node_set_add (part->cgraph_set, node);
143 return false;
144 }
145
146 /* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
147
148 static void
149 add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
150 {
151 struct cgraph_edge *e;
152 cgraph_node_set_iterator csi;
153 struct cgraph_node *n;
154
155 /* If NODE is already there, we have nothing to do. */
156 csi = cgraph_node_set_find (part->cgraph_set, node);
157 if (!csi_end_p (csi))
158 return;
159
160 cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
161
162 part->insns += inline_summary (node)->self_size;
163
164
165 cgraph_node_set_add (part->cgraph_set, node);
166
167 for (e = node->callees; e; e = e->next_callee)
168 if ((!e->inline_failed
169 || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->symbol.decl))
170 && !cgraph_node_in_set_p (e->callee, part->cgraph_set))
171 add_cgraph_node_to_partition (part, e->callee);
172
173 /* The only way to assemble non-weakref alias is to add the aliased object into
174 the unit. */
175 add_references_to_partition (part, &node->symbol.ref_list);
176 n = cgraph_function_node (node, NULL);
177 if (n != node
178 && !lookup_attribute ("weakref",
179 DECL_ATTRIBUTES (node->symbol.decl)))
180 add_cgraph_node_to_partition (part, n);
181
182 if (node->symbol.same_comdat_group)
183 for (n = cgraph (node->symbol.same_comdat_group);
184 n != node; n = cgraph (n->symbol.same_comdat_group))
185 add_cgraph_node_to_partition (part, n);
186 }
187
188 /* Add VNODE to partition as well as comdat references partition PART. */
189
190 static void
191 add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode)
192 {
193 varpool_node_set_iterator vsi;
194 struct varpool_node *v;
195
196 /* If NODE is already there, we have nothing to do. */
197 vsi = varpool_node_set_find (part->varpool_set, vnode);
198 if (!vsi_end_p (vsi))
199 return;
200
201 varpool_node_set_add (part->varpool_set, vnode);
202
203 if (vnode->symbol.aux)
204 {
205 vnode->symbol.in_other_partition = 1;
206 if (cgraph_dump_file)
207 fprintf (cgraph_dump_file, "Varpool node %s now used in multiple partitions\n",
208 varpool_node_name (vnode));
209 }
210 vnode->symbol.aux = (void *)((size_t)vnode->symbol.aux + 1);
211
212 /* The only way to assemble non-weakref alias is to add the aliased object into
213 the unit. */
214 v = varpool_variable_node (vnode, NULL);
215 if (v != vnode
216 && !lookup_attribute ("weakref",
217 DECL_ATTRIBUTES (vnode->symbol.decl)))
218 add_varpool_node_to_partition (part, v);
219
220 add_references_to_partition (part, &vnode->symbol.ref_list);
221
222 if (vnode->symbol.same_comdat_group
223 && !varpool_node_in_set_p (varpool (vnode->symbol.same_comdat_group),
224 part->varpool_set))
225 add_varpool_node_to_partition (part, varpool (vnode->symbol.same_comdat_group));
226 }
227
228 /* Undo all additions until number of cgraph nodes in PARITION is N_CGRAPH_NODES
229 and number of varpool nodes is N_VARPOOL_NODES. */
230
231 static void
232 undo_partition (ltrans_partition partition, unsigned int n_cgraph_nodes,
233 unsigned int n_varpool_nodes)
234 {
235 while (VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes) >
236 n_cgraph_nodes)
237 {
238 struct cgraph_node *node = VEC_index (cgraph_node_ptr,
239 partition->cgraph_set->nodes,
240 n_cgraph_nodes);
241 partition->insns -= inline_summary (node)->self_size;
242 cgraph_node_set_remove (partition->cgraph_set, node);
243 node->symbol.aux = (void *)((size_t)node->symbol.aux - 1);
244 }
245 while (VEC_length (varpool_node_ptr, partition->varpool_set->nodes) >
246 n_varpool_nodes)
247 {
248 struct varpool_node *node = VEC_index (varpool_node_ptr,
249 partition->varpool_set->nodes,
250 n_varpool_nodes);
251 varpool_node_set_remove (partition->varpool_set, node);
252 node->symbol.aux = (void *)((size_t)node->symbol.aux - 1);
253 }
254 }
255
256 /* Return true if NODE should be partitioned.
257 This means that partitioning algorithm should put NODE into one of partitions.
258 This apply to most functions with bodies. Functions that are not partitions
259 are put into every unit needing them. This is the case of i.e. COMDATs. */
260
261 static bool
262 partition_cgraph_node_p (struct cgraph_node *node)
263 {
264 /* We will get proper partition based on function they are inlined to. */
265 if (node->global.inlined_to)
266 return false;
267 /* Nodes without a body do not need partitioning. */
268 if (!node->analyzed)
269 return false;
270 /* Extern inlines and comdat are always only in partitions they are needed. */
271 if (DECL_EXTERNAL (node->symbol.decl)
272 || (DECL_COMDAT (node->symbol.decl)
273 && !node->symbol.force_output
274 && !symtab_used_from_object_file_p ((symtab_node) node)))
275 return false;
276 if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
277 return false;
278 return true;
279 }
280
281 /* Return true if VNODE should be partitioned.
282 This means that partitioning algorithm should put VNODE into one of partitions. */
283
284 static bool
285 partition_varpool_node_p (struct varpool_node *vnode)
286 {
287 if (vnode->alias || !vnode->analyzed)
288 return false;
289 /* Constant pool and comdat are always only in partitions they are needed. */
290 if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
291 || DECL_EXTERNAL (vnode->symbol.decl)
292 || (DECL_COMDAT (vnode->symbol.decl)
293 && !vnode->symbol.force_output
294 && !symtab_used_from_object_file_p ((symtab_node) vnode)))
295 return false;
296 if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
297 return false;
298 return true;
299 }
300
301 /* Group cgrah nodes by input files. This is used mainly for testing
302 right now. */
303
304 void
305 lto_1_to_1_map (void)
306 {
307 struct cgraph_node *node;
308 struct varpool_node *vnode;
309 struct lto_file_decl_data *file_data;
310 struct pointer_map_t *pmap;
311 ltrans_partition partition;
312 void **slot;
313 int npartitions = 0;
314
315 timevar_push (TV_WHOPR_WPA);
316
317 pmap = pointer_map_create ();
318
319 FOR_EACH_DEFINED_FUNCTION (node)
320 {
321 if (!partition_cgraph_node_p (node)
322 || node->symbol.aux)
323 continue;
324
325 file_data = node->symbol.lto_file_data;
326
327 if (file_data)
328 {
329 slot = pointer_map_contains (pmap, file_data);
330 if (slot)
331 partition = (ltrans_partition) *slot;
332 else
333 {
334 partition = new_partition (file_data->file_name);
335 slot = pointer_map_insert (pmap, file_data);
336 *slot = partition;
337 npartitions++;
338 }
339 }
340 else if (!file_data
341 && VEC_length (ltrans_partition, ltrans_partitions))
342 partition = VEC_index (ltrans_partition, ltrans_partitions, 0);
343 else
344 {
345 partition = new_partition ("");
346 slot = pointer_map_insert (pmap, NULL);
347 *slot = partition;
348 npartitions++;
349 }
350
351 add_cgraph_node_to_partition (partition, node);
352 }
353
354 FOR_EACH_VARIABLE (vnode)
355 {
356 if (!partition_varpool_node_p (vnode)
357 || vnode->symbol.aux)
358 continue;
359 file_data = vnode->symbol.lto_file_data;
360 slot = pointer_map_contains (pmap, file_data);
361 if (slot)
362 partition = (ltrans_partition) *slot;
363 else
364 {
365 partition = new_partition (file_data->file_name);
366 slot = pointer_map_insert (pmap, file_data);
367 *slot = partition;
368 npartitions++;
369 }
370
371 add_varpool_node_to_partition (partition, vnode);
372 }
373 FOR_EACH_FUNCTION (node)
374 node->symbol.aux = NULL;
375 FOR_EACH_VARIABLE (vnode)
376 vnode->symbol.aux = NULL;
377
378 /* If the cgraph is empty, create one cgraph node set so that there is still
379 an output file for any variables that need to be exported in a DSO. */
380 if (!npartitions)
381 new_partition ("empty");
382
383 pointer_map_destroy (pmap);
384
385 timevar_pop (TV_WHOPR_WPA);
386
387 lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition,
388 ltrans_partitions);
389 }
390
391 /* Helper function for qsort; sort nodes by order. */
392 static int
393 node_cmp (const void *pa, const void *pb)
394 {
395 const struct cgraph_node *a = *(const struct cgraph_node * const *) pa;
396 const struct cgraph_node *b = *(const struct cgraph_node * const *) pb;
397 return b->symbol.order - a->symbol.order;
398 }
399
400 /* Helper function for qsort; sort nodes by order. */
401 static int
402 varpool_node_cmp (const void *pa, const void *pb)
403 {
404 const struct varpool_node *a = *(const struct varpool_node * const *) pa;
405 const struct varpool_node *b = *(const struct varpool_node * const *) pb;
406 return b->symbol.order - a->symbol.order;
407 }
408
409 /* Group cgraph nodes into equally-sized partitions.
410
411 The partitioning algorithm is simple: nodes are taken in predefined order.
412 The order corresponds to the order we want functions to have in the final
413 output. In the future this will be given by function reordering pass, but
414 at the moment we use the topological order, which is a good approximation.
415
416 The goal is to partition this linear order into intervals (partitions) so
417 that all the partitions have approximately the same size and the number of
418 callgraph or IPA reference edges crossing boundaries is minimal.
419
420 This is a lot faster (O(n) in size of callgraph) than algorithms doing
421 priority-based graph clustering that are generally O(n^2) and, since
422 WHOPR is designed to make things go well across partitions, it leads
423 to good results.
424
425 We compute the expected size of a partition as:
426
427 max (total_size / lto_partitions, min_partition_size)
428
429 We use dynamic expected size of partition so small programs are partitioned
430 into enough partitions to allow use of multiple CPUs, while large programs
431 are not partitioned too much. Creating too many partitions significantly
432 increases the streaming overhead.
433
434 In the future, we would like to bound the maximal size of partitions so as
435 to prevent the LTRANS stage from consuming too much memory. At the moment,
436 however, the WPA stage is the most memory intensive for large benchmarks,
437 since too many types and declarations are read into memory.
438
439 The function implements a simple greedy algorithm. Nodes are being added
440 to the current partition until after 3/4 of the expected partition size is
441 reached. Past this threshold, we keep track of boundary size (number of
442 edges going to other partitions) and continue adding functions until after
443 the current partition has grown to twice the expected partition size. Then
444 the process is undone to the point where the minimal ratio of boundary size
445 and in-partition calls was reached. */
446
447 void
448 lto_balanced_map (void)
449 {
450 int n_nodes = 0;
451 int n_varpool_nodes = 0, varpool_pos = 0;
452 struct cgraph_node **postorder =
453 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
454 struct cgraph_node **order = XNEWVEC (struct cgraph_node *, cgraph_max_uid);
455 struct varpool_node **varpool_order = NULL;
456 int i, postorder_len;
457 struct cgraph_node *node;
458 int total_size = 0, best_total_size = 0;
459 int partition_size;
460 ltrans_partition partition;
461 unsigned int last_visited_cgraph_node = 0, last_visited_varpool_node = 0;
462 struct varpool_node *vnode;
463 int cost = 0, internal = 0;
464 int best_n_nodes = 0, best_n_varpool_nodes = 0, best_i = 0, best_cost =
465 INT_MAX, best_internal = 0;
466 int npartitions;
467 int current_order = -1;
468
469 FOR_EACH_VARIABLE (vnode)
470 gcc_assert (!vnode->symbol.aux);
471 /* Until we have better ordering facility, use toplogical order.
472 Include only nodes we will partition and compute estimate of program
473 size. Note that since nodes that are not partitioned might be put into
474 multiple partitions, this is just an estimate of real size. This is why
475 we keep partition_size updated after every partition is finalized. */
476 postorder_len = ipa_reverse_postorder (postorder);
477
478 for (i = 0; i < postorder_len; i++)
479 {
480 node = postorder[i];
481 if (partition_cgraph_node_p (node))
482 {
483 order[n_nodes++] = node;
484 total_size += inline_summary (node)->size;
485 }
486 }
487 free (postorder);
488
489 if (!flag_toplevel_reorder)
490 {
491 qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp);
492
493 FOR_EACH_VARIABLE (vnode)
494 if (partition_varpool_node_p (vnode))
495 n_varpool_nodes++;
496 varpool_order = XNEWVEC (struct varpool_node *, n_varpool_nodes);
497
498 n_varpool_nodes = 0;
499 FOR_EACH_VARIABLE (vnode)
500 if (partition_varpool_node_p (vnode))
501 varpool_order[n_varpool_nodes++] = vnode;
502 qsort (varpool_order, n_varpool_nodes, sizeof (struct varpool_node *),
503 varpool_node_cmp);
504 }
505
506 /* Compute partition size and create the first partition. */
507 partition_size = total_size / PARAM_VALUE (PARAM_LTO_PARTITIONS);
508 if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE))
509 partition_size = PARAM_VALUE (MIN_PARTITION_SIZE);
510 npartitions = 1;
511 partition = new_partition ("");
512 if (cgraph_dump_file)
513 fprintf (cgraph_dump_file, "Total unit size: %i, partition size: %i\n",
514 total_size, partition_size);
515
516 for (i = 0; i < n_nodes; i++)
517 {
518 if (order[i]->symbol.aux)
519 continue;
520
521 current_order = order[i]->symbol.order;
522
523 if (!flag_toplevel_reorder)
524 while (varpool_pos < n_varpool_nodes
525 && varpool_order[varpool_pos]->symbol.order < current_order)
526 {
527 if (!varpool_order[varpool_pos]->symbol.aux)
528 add_varpool_node_to_partition (partition, varpool_order[varpool_pos]);
529 varpool_pos++;
530 }
531
532 add_cgraph_node_to_partition (partition, order[i]);
533 total_size -= inline_summary (order[i])->size;
534
535
536 /* Once we added a new node to the partition, we also want to add
537 all referenced variables unless they was already added into some
538 earlier partition.
539 add_cgraph_node_to_partition adds possibly multiple nodes and
540 variables that are needed to satisfy needs of ORDER[i].
541 We remember last visited cgraph and varpool node from last iteration
542 of outer loop that allows us to process every new addition.
543
544 At the same time we compute size of the boundary into COST. Every
545 callgraph or IPA reference edge leaving the partition contributes into
546 COST. Every edge inside partition was earlier computed as one leaving
547 it and thus we need to subtract it from COST. */
548 while (last_visited_cgraph_node <
549 VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes)
550 || last_visited_varpool_node < VEC_length (varpool_node_ptr,
551 partition->varpool_set->
552 nodes))
553 {
554 struct ipa_ref_list *refs;
555 int j;
556 struct ipa_ref *ref;
557 bool cgraph_p = false;
558
559 if (last_visited_cgraph_node <
560 VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes))
561 {
562 struct cgraph_edge *edge;
563
564 cgraph_p = true;
565 node = VEC_index (cgraph_node_ptr, partition->cgraph_set->nodes,
566 last_visited_cgraph_node);
567 refs = &node->symbol.ref_list;
568
569 last_visited_cgraph_node++;
570
571 gcc_assert (node->analyzed);
572
573 /* Compute boundary cost of callgraph edges. */
574 for (edge = node->callees; edge; edge = edge->next_callee)
575 if (edge->callee->analyzed)
576 {
577 int edge_cost = edge->frequency;
578 cgraph_node_set_iterator csi;
579
580 if (!edge_cost)
581 edge_cost = 1;
582 gcc_assert (edge_cost > 0);
583 csi = cgraph_node_set_find (partition->cgraph_set, edge->callee);
584 if (!csi_end_p (csi)
585 && csi.index < last_visited_cgraph_node - 1)
586 cost -= edge_cost, internal+= edge_cost;
587 else
588 cost += edge_cost;
589 }
590 for (edge = node->callers; edge; edge = edge->next_caller)
591 {
592 int edge_cost = edge->frequency;
593 cgraph_node_set_iterator csi;
594
595 gcc_assert (edge->caller->analyzed);
596 if (!edge_cost)
597 edge_cost = 1;
598 gcc_assert (edge_cost > 0);
599 csi = cgraph_node_set_find (partition->cgraph_set, edge->caller);
600 if (!csi_end_p (csi)
601 && csi.index < last_visited_cgraph_node)
602 cost -= edge_cost;
603 else
604 cost += edge_cost;
605 }
606 }
607 else
608 {
609 refs =
610 &VEC_index (varpool_node_ptr, partition->varpool_set->nodes,
611 last_visited_varpool_node)->symbol.ref_list;
612 last_visited_varpool_node++;
613 }
614
615 /* Compute boundary cost of IPA REF edges and at the same time look into
616 variables referenced from current partition and try to add them. */
617 for (j = 0; ipa_ref_list_reference_iterate (refs, j, ref); j++)
618 if (symtab_variable_p (ref->referred))
619 {
620 varpool_node_set_iterator vsi;
621
622 vnode = ipa_ref_varpool_node (ref);
623 if (!vnode->finalized)
624 continue;
625 if (!vnode->symbol.aux && flag_toplevel_reorder
626 && partition_varpool_node_p (vnode))
627 add_varpool_node_to_partition (partition, vnode);
628 vsi = varpool_node_set_find (partition->varpool_set, vnode);
629 if (!vsi_end_p (vsi)
630 && vsi.index < last_visited_varpool_node - !cgraph_p)
631 cost--, internal++;
632 else
633 cost++;
634 }
635 else
636 {
637 cgraph_node_set_iterator csi;
638
639 node = ipa_ref_node (ref);
640 if (!node->analyzed)
641 continue;
642 csi = cgraph_node_set_find (partition->cgraph_set, node);
643 if (!csi_end_p (csi)
644 && csi.index < last_visited_cgraph_node - cgraph_p)
645 cost--, internal++;
646 else
647 cost++;
648 }
649 for (j = 0; ipa_ref_list_referring_iterate (refs, j, ref); j++)
650 if (symtab_variable_p (ref->referring))
651 {
652 varpool_node_set_iterator vsi;
653
654 vnode = ipa_ref_referring_varpool_node (ref);
655 gcc_assert (vnode->finalized);
656 if (!vnode->symbol.aux && flag_toplevel_reorder
657 && partition_varpool_node_p (vnode))
658 add_varpool_node_to_partition (partition, vnode);
659 vsi = varpool_node_set_find (partition->varpool_set, vnode);
660 if (!vsi_end_p (vsi)
661 && vsi.index < last_visited_varpool_node)
662 cost--;
663 else
664 cost++;
665 }
666 else
667 {
668 cgraph_node_set_iterator csi;
669
670 node = ipa_ref_referring_node (ref);
671 gcc_assert (node->analyzed);
672 csi = cgraph_node_set_find (partition->cgraph_set, node);
673 if (!csi_end_p (csi)
674 && csi.index < last_visited_cgraph_node)
675 cost--;
676 else
677 cost++;
678 }
679 }
680
681 /* If the partition is large enough, start looking for smallest boundary cost. */
682 if (partition->insns < partition_size * 3 / 4
683 || best_cost == INT_MAX
684 || ((!cost
685 || (best_internal * (HOST_WIDE_INT) cost
686 > (internal * (HOST_WIDE_INT)best_cost)))
687 && partition->insns < partition_size * 5 / 4))
688 {
689 best_cost = cost;
690 best_internal = internal;
691 best_i = i;
692 best_n_nodes = VEC_length (cgraph_node_ptr,
693 partition->cgraph_set->nodes);
694 best_n_varpool_nodes = VEC_length (varpool_node_ptr,
695 partition->varpool_set->nodes);
696 best_total_size = total_size;
697 }
698 if (cgraph_dump_file)
699 fprintf (cgraph_dump_file, "Step %i: added %s/%i, size %i, cost %i/%i best %i/%i, step %i\n", i,
700 cgraph_node_name (order[i]), order[i]->uid, partition->insns, cost, internal,
701 best_cost, best_internal, best_i);
702 /* Partition is too large, unwind into step when best cost was reached and
703 start new partition. */
704 if (partition->insns > 2 * partition_size)
705 {
706 if (best_i != i)
707 {
708 if (cgraph_dump_file)
709 fprintf (cgraph_dump_file, "Unwinding %i insertions to step %i\n",
710 i - best_i, best_i);
711 undo_partition (partition, best_n_nodes, best_n_varpool_nodes);
712 }
713 i = best_i;
714 /* When we are finished, avoid creating empty partition. */
715 while (i < n_nodes - 1 && order[i + 1]->symbol.aux)
716 i++;
717 if (i == n_nodes - 1)
718 break;
719 partition = new_partition ("");
720 last_visited_cgraph_node = 0;
721 last_visited_varpool_node = 0;
722 total_size = best_total_size;
723 cost = 0;
724
725 if (cgraph_dump_file)
726 fprintf (cgraph_dump_file, "New partition\n");
727 best_n_nodes = 0;
728 best_n_varpool_nodes = 0;
729 best_cost = INT_MAX;
730
731 /* Since the size of partitions is just approximate, update the size after
732 we finished current one. */
733 if (npartitions < PARAM_VALUE (PARAM_LTO_PARTITIONS))
734 partition_size = total_size
735 / (PARAM_VALUE (PARAM_LTO_PARTITIONS) - npartitions);
736 else
737 partition_size = INT_MAX;
738
739 if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE))
740 partition_size = PARAM_VALUE (MIN_PARTITION_SIZE);
741 npartitions ++;
742 }
743 }
744
745 /* Varables that are not reachable from the code go into last partition. */
746 if (flag_toplevel_reorder)
747 {
748 FOR_EACH_VARIABLE (vnode)
749 if (partition_varpool_node_p (vnode) && !vnode->symbol.aux)
750 add_varpool_node_to_partition (partition, vnode);
751 }
752 else
753 {
754 while (varpool_pos < n_varpool_nodes)
755 {
756 if (!varpool_order[varpool_pos]->symbol.aux)
757 add_varpool_node_to_partition (partition, varpool_order[varpool_pos]);
758 varpool_pos++;
759 }
760 free (varpool_order);
761 }
762 free (order);
763 }
764
765 /* Promote variable VNODE to be static. */
766
767 static bool
768 promote_var (struct varpool_node *vnode)
769 {
770 if (TREE_PUBLIC (vnode->symbol.decl) || DECL_EXTERNAL (vnode->symbol.decl))
771 return false;
772 gcc_assert (flag_wpa);
773 TREE_PUBLIC (vnode->symbol.decl) = 1;
774 DECL_VISIBILITY (vnode->symbol.decl) = VISIBILITY_HIDDEN;
775 DECL_VISIBILITY_SPECIFIED (vnode->symbol.decl) = true;
776 if (cgraph_dump_file)
777 fprintf (cgraph_dump_file,
778 "Promoting var as hidden: %s\n", varpool_node_name (vnode));
779 return true;
780 }
781
782 /* Promote function NODE to be static. */
783
784 static bool
785 promote_fn (struct cgraph_node *node)
786 {
787 gcc_assert (flag_wpa);
788 if (TREE_PUBLIC (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
789 return false;
790 TREE_PUBLIC (node->symbol.decl) = 1;
791 DECL_VISIBILITY (node->symbol.decl) = VISIBILITY_HIDDEN;
792 DECL_VISIBILITY_SPECIFIED (node->symbol.decl) = true;
793 if (cgraph_dump_file)
794 fprintf (cgraph_dump_file,
795 "Promoting function as hidden: %s/%i\n",
796 cgraph_node_name (node), node->uid);
797 return true;
798 }
799
800 /* Return if LIST contain references from other partitions.
801 TODO: remove this once lto partitioning is using encoders. */
802
803 static bool
804 set_referenced_from_other_partition_p (struct ipa_ref_list *list, cgraph_node_set set,
805 varpool_node_set vset)
806 {
807 int i;
808 struct ipa_ref *ref;
809 for (i = 0; ipa_ref_list_referring_iterate (list, i, ref); i++)
810 {
811 if (symtab_function_p (ref->referring))
812 {
813 if (ipa_ref_referring_node (ref)->symbol.in_other_partition
814 || !cgraph_node_in_set_p (ipa_ref_referring_node (ref), set))
815 return true;
816 }
817 else
818 {
819 if (ipa_ref_referring_varpool_node (ref)->symbol.in_other_partition
820 || !varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref),
821 vset))
822 return true;
823 }
824 }
825 return false;
826 }
827
828 /* Return true when node is reachable from other partition.
829 TODO: remove this once lto partitioning is using encoders. */
830
831 static bool
832 set_reachable_from_other_partition_p (struct cgraph_node *node, cgraph_node_set set)
833 {
834 struct cgraph_edge *e;
835 if (!node->analyzed)
836 return false;
837 if (node->global.inlined_to)
838 return false;
839 for (e = node->callers; e; e = e->next_caller)
840 if (e->caller->symbol.in_other_partition
841 || !cgraph_node_in_set_p (e->caller, set))
842 return true;
843 return false;
844 }
845
846
847 /* Return if LIST contain references from other partitions.
848 TODO: remove this once lto partitioning is using encoders. */
849
850 static bool
851 set_referenced_from_this_partition_p (struct ipa_ref_list *list, cgraph_node_set set,
852 varpool_node_set vset)
853 {
854 int i;
855 struct ipa_ref *ref;
856 for (i = 0; ipa_ref_list_referring_iterate (list, i, ref); i++)
857 {
858 if (symtab_function_p (ref->referring))
859 {
860 if (cgraph_node_in_set_p (ipa_ref_referring_node (ref), set))
861 return true;
862 }
863 else
864 {
865 if (varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref),
866 vset))
867 return true;
868 }
869 }
870 return false;
871 }
872
873 /* Find out all static decls that need to be promoted to global because
874 of cross file sharing. This function must be run in the WPA mode after
875 all inlinees are added. */
876
877 void
878 lto_promote_cross_file_statics (void)
879 {
880 struct varpool_node *vnode;
881 unsigned i, n_sets;
882 cgraph_node_set set;
883 varpool_node_set vset;
884 cgraph_node_set_iterator csi;
885 varpool_node_set_iterator vsi;
886 VEC(varpool_node_ptr, heap) *promoted_initializers = NULL;
887 struct pointer_set_t *inserted = pointer_set_create ();
888
889 gcc_assert (flag_wpa);
890
891 n_sets = VEC_length (ltrans_partition, ltrans_partitions);
892 for (i = 0; i < n_sets; i++)
893 {
894 ltrans_partition part
895 = VEC_index (ltrans_partition, ltrans_partitions, i);
896 set = part->cgraph_set;
897 vset = part->varpool_set;
898
899 /* If node called or referred to from other partition, it needs to be
900 globalized. */
901 for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
902 {
903 struct cgraph_node *node = csi_node (csi);
904 if (node->symbol.externally_visible)
905 continue;
906 if (node->global.inlined_to)
907 continue;
908 if ((!DECL_EXTERNAL (node->symbol.decl)
909 && !DECL_COMDAT (node->symbol.decl))
910 && (set_referenced_from_other_partition_p (&node->symbol.ref_list, set, vset)
911 || set_reachable_from_other_partition_p (node, set)))
912 promote_fn (node);
913 }
914 for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
915 {
916 vnode = vsi_node (vsi);
917 /* Constant pool references use internal labels and thus can not
918 be made global. It is sensible to keep those ltrans local to
919 allow better optimization. */
920 if (!DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
921 && !DECL_EXTERNAL (vnode->symbol.decl)
922 && !DECL_COMDAT (vnode->symbol.decl)
923 && !vnode->symbol.externally_visible && vnode->analyzed
924 && set_referenced_from_other_partition_p (&vnode->symbol.ref_list,
925 set, vset))
926 promote_var (vnode);
927 }
928
929 /* We export the initializer of a read-only var into each partition
930 referencing the var. Folding might take declarations from the
931 initializer and use them, so everything referenced from the
932 initializer can be accessed from this partition after folding.
933
934 This means that we need to promote all variables and functions
935 referenced from all initializers of read-only vars referenced
936 from this partition that are not in this partition. This needs
937 to be done recursively. */
938 FOR_EACH_VARIABLE (vnode)
939 if (const_value_known_p (vnode->symbol.decl)
940 && DECL_INITIAL (vnode->symbol.decl)
941 && !varpool_node_in_set_p (vnode, vset)
942 && set_referenced_from_this_partition_p (&vnode->symbol.ref_list, set, vset)
943 && !pointer_set_insert (inserted, vnode))
944 VEC_safe_push (varpool_node_ptr, heap, promoted_initializers, vnode);
945
946 while (!VEC_empty (varpool_node_ptr, promoted_initializers))
947 {
948 int i;
949 struct ipa_ref *ref;
950
951 vnode = VEC_pop (varpool_node_ptr, promoted_initializers);
952 for (i = 0;
953 ipa_ref_list_reference_iterate (&vnode->symbol.ref_list, i, ref);
954 i++)
955 {
956 if (symtab_function_p (ref->referred))
957 {
958 struct cgraph_node *n = ipa_ref_node (ref);
959 gcc_assert (!n->global.inlined_to);
960 if (!n->symbol.externally_visible
961 && !cgraph_node_in_set_p (n, set))
962 promote_fn (n);
963 }
964 else
965 {
966 struct varpool_node *v = ipa_ref_varpool_node (ref);
967 if (varpool_node_in_set_p (v, vset))
968 continue;
969
970 /* Constant pool references use internal labels and thus
971 cannot be made global. It is sensible to keep those
972 ltrans local to allow better optimization.
973 Similarly we ship external vars initializers into
974 every ltrans unit possibly referring to it. */
975 if (DECL_IN_CONSTANT_POOL (v->symbol.decl)
976 || DECL_EXTERNAL (v->symbol.decl))
977 {
978 if (!pointer_set_insert (inserted, vnode))
979 VEC_safe_push (varpool_node_ptr, heap,
980 promoted_initializers, v);
981 }
982 else if (!v->symbol.externally_visible && v->analyzed)
983 {
984 if (promote_var (v)
985 && DECL_INITIAL (v->symbol.decl)
986 && const_value_known_p (v->symbol.decl)
987 && !pointer_set_insert (inserted, vnode))
988 VEC_safe_push (varpool_node_ptr, heap,
989 promoted_initializers, v);
990 }
991 }
992 }
993 }
994 }
995 pointer_set_destroy (inserted);
996 }