aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/lto/lto-partition.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/lto/lto-partition.c')
-rw-r--r--gcc-4.9/gcc/lto/lto-partition.c945
1 files changed, 945 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/lto/lto-partition.c b/gcc-4.9/gcc/lto/lto-partition.c
new file mode 100644
index 000000000..1ee5fbb85
--- /dev/null
+++ b/gcc-4.9/gcc/lto/lto-partition.c
@@ -0,0 +1,945 @@
+/* LTO partitioning logic routines.
+ Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "tree.h"
+#include "gcc-symtab.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tm.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
+#include "timevar.h"
+#include "params.h"
+#include "ipa-inline.h"
+#include "ipa-utils.h"
+#include "lto-partition.h"
+
+vec<ltrans_partition> ltrans_partitions;
+
+static void add_symbol_to_partition (ltrans_partition part, symtab_node *node);
+
+
+/* Create new partition with name NAME. */
+
+static ltrans_partition
+new_partition (const char *name)
+{
+ ltrans_partition part = XCNEW (struct ltrans_partition_def);
+ part->encoder = lto_symtab_encoder_new (false);
+ part->name = name;
+ part->insns = 0;
+ ltrans_partitions.safe_push (part);
+ return part;
+}
+
+/* Free memory used by ltrans datastructures. */
+
+void
+free_ltrans_partitions (void)
+{
+ unsigned int idx;
+ ltrans_partition part;
+ for (idx = 0; ltrans_partitions.iterate (idx, &part); idx++)
+ {
+ if (part->initializers_visited)
+ pointer_set_destroy (part->initializers_visited);
+ /* Symtab encoder is freed after streaming. */
+ free (part);
+ }
+ ltrans_partitions.release ();
+}
+
+/* Return true if symbol is already in some partition. */
+
+static inline bool
+symbol_partitioned_p (symtab_node *node)
+{
+ return node->aux;
+}
+
+/* Add references into the partition. */
+static void
+add_references_to_partition (ltrans_partition part, symtab_node *node)
+{
+ int i;
+ struct ipa_ref *ref;
+
+ /* Add all duplicated references to the partition. */
+ for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+ if (symtab_get_symbol_partitioning_class (ref->referred) == SYMBOL_DUPLICATE)
+ add_symbol_to_partition (part, ref->referred);
+ /* References to a readonly variable may be constant foled into its value.
+ Recursively look into the initializers of the constant variable and add
+ references, too. */
+ else if (is_a <varpool_node> (ref->referred)
+ && ctor_for_folding (ref->referred->decl) != error_mark_node
+ && !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
+ {
+ if (!part->initializers_visited)
+ part->initializers_visited = pointer_set_create ();
+ if (!pointer_set_insert (part->initializers_visited, ref->referred))
+ add_references_to_partition (part, ref->referred);
+ }
+}
+
+/* Helper function for add_symbol_to_partition doing the actual dirty work
+ of adding NODE to PART. */
+
+static bool
+add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
+{
+ enum symbol_partitioning_class c = symtab_get_symbol_partitioning_class (node);
+ int i;
+ struct ipa_ref *ref;
+ symtab_node *node1;
+
+ /* If NODE is already there, we have nothing to do. */
+ if (lto_symtab_encoder_in_partition_p (part->encoder, node))
+ return true;
+
+ /* non-duplicated aliases or tunks of a duplicated symbol needs to be output
+ just once.
+
+ Be lax about comdats; they may or may not be duplicated and we may
+ end up in need to duplicate keyed comdat because it has unkeyed alias. */
+ if (c == SYMBOL_PARTITION && !DECL_COMDAT (node->decl)
+ && symbol_partitioned_p (node))
+ return false;
+
+ /* Be sure that we never try to duplicate partitioned symbol
+ or add external symbol. */
+ gcc_assert (c != SYMBOL_EXTERNAL
+ && (c == SYMBOL_DUPLICATE || !symbol_partitioned_p (node)));
+
+ lto_set_symtab_encoder_in_partition (part->encoder, node);
+
+ if (symbol_partitioned_p (node))
+ {
+ node->in_other_partition = 1;
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Symbol node %s now used in multiple partitions\n",
+ node->name ());
+ }
+ node->aux = (void *)((size_t)node->aux + 1);
+
+ if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+ {
+ struct cgraph_edge *e;
+ if (!node->alias)
+ part->insns += inline_summary (cnode)->self_size;
+
+ /* Add all inline clones and callees that are duplicated. */
+ for (e = cnode->callees; e; e = e->next_callee)
+ if (!e->inline_failed)
+ add_symbol_to_partition_1 (part, e->callee);
+ else if (symtab_get_symbol_partitioning_class (e->callee) == SYMBOL_DUPLICATE)
+ add_symbol_to_partition (part, e->callee);
+
+ /* Add all thunks associated with the function. */
+ for (e = cnode->callers; e; e = e->next_caller)
+ if (e->caller->thunk.thunk_p)
+ add_symbol_to_partition_1 (part, e->caller);
+ }
+
+ add_references_to_partition (part, node);
+
+ /* Add all aliases associated with the symbol. */
+ for (i = 0; ipa_ref_list_referring_iterate (&node->ref_list, i, ref); i++)
+ if (ref->use == IPA_REF_ALIAS && !node->weakref)
+ add_symbol_to_partition_1 (part, ref->referring);
+
+ /* Ensure that SAME_COMDAT_GROUP lists all allways added in a group. */
+ if (node->same_comdat_group)
+ for (node1 = node->same_comdat_group;
+ node1 != node; node1 = node1->same_comdat_group)
+ if (!node->alias)
+ {
+ bool added = add_symbol_to_partition_1 (part, node1);
+ gcc_assert (added);
+ }
+ return true;
+}
+
+/* If symbol NODE is really part of other symbol's definition (i.e. it is
+ internal label, thunk, alias or so), return the outer symbol.
+ When add_symbol_to_partition_1 is called on the outer symbol it must
+ eventually add NODE, too. */
+static symtab_node *
+contained_in_symbol (symtab_node *node)
+{
+ /* Weakrefs are never contained in anything. */
+ if (node->weakref)
+ return node;
+ if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+ {
+ cnode = cgraph_function_node (cnode, NULL);
+ if (cnode->global.inlined_to)
+ cnode = cnode->global.inlined_to;
+ return cnode;
+ }
+ else if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+ return varpool_variable_node (vnode, NULL);
+ return node;
+}
+
+/* Add symbol NODE to partition. When definition of NODE is part
+ of other symbol definition, add the other symbol, too. */
+
+static void
+add_symbol_to_partition (ltrans_partition part, symtab_node *node)
+{
+ symtab_node *node1;
+
+ /* Verify that we do not try to duplicate something that can not be. */
+ gcc_checking_assert (symtab_get_symbol_partitioning_class (node) == SYMBOL_DUPLICATE
+ || !symbol_partitioned_p (node));
+
+ while ((node1 = contained_in_symbol (node)) != node)
+ node = node1;
+
+ /* If we have duplicated symbol contained in something we can not duplicate,
+ we are very badly screwed. The other way is possible, so we do not
+ assert this in add_symbol_to_partition_1.
+
+ Be lax about comdats; they may or may not be duplicated and we may
+ end up in need to duplicate keyed comdat because it has unkeyed alias. */
+
+ gcc_assert (symtab_get_symbol_partitioning_class (node) == SYMBOL_DUPLICATE
+ || DECL_COMDAT (node->decl)
+ || !symbol_partitioned_p (node));
+
+ add_symbol_to_partition_1 (part, node);
+}
+
+/* Undo all additions until number of cgraph nodes in PARITION is N_CGRAPH_NODES
+ and number of varpool nodes is N_VARPOOL_NODES. */
+
+static void
+undo_partition (ltrans_partition partition, unsigned int n_nodes)
+{
+ while (lto_symtab_encoder_size (partition->encoder) > (int)n_nodes)
+ {
+ symtab_node *node = lto_symtab_encoder_deref (partition->encoder,
+ n_nodes);
+ cgraph_node *cnode;
+
+ /* After UNDO we no longer know what was visited. */
+ if (partition->initializers_visited)
+ pointer_set_destroy (partition->initializers_visited);
+ partition->initializers_visited = NULL;
+
+ if (!node->alias && (cnode = dyn_cast <cgraph_node> (node)))
+ partition->insns -= inline_summary (cnode)->self_size;
+ lto_symtab_encoder_delete_node (partition->encoder, node);
+ node->aux = (void *)((size_t)node->aux - 1);
+ }
+}
+
+/* Group cgrah nodes by input files. This is used mainly for testing
+ right now. */
+
+void
+lto_1_to_1_map (void)
+{
+ symtab_node *node;
+ struct lto_file_decl_data *file_data;
+ struct pointer_map_t *pmap;
+ ltrans_partition partition;
+ void **slot;
+ int npartitions = 0;
+
+ pmap = pointer_map_create ();
+
+ FOR_EACH_SYMBOL (node)
+ {
+ if (symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION
+ || symbol_partitioned_p (node))
+ continue;
+
+ file_data = node->lto_file_data;
+
+ if (file_data)
+ {
+ slot = pointer_map_contains (pmap, file_data);
+ if (slot)
+ partition = (ltrans_partition) *slot;
+ else
+ {
+ partition = new_partition (file_data->file_name);
+ slot = pointer_map_insert (pmap, file_data);
+ *slot = partition;
+ npartitions++;
+ }
+ }
+ else if (!file_data && ltrans_partitions.length ())
+ partition = ltrans_partitions[0];
+ else
+ {
+ partition = new_partition ("");
+ slot = pointer_map_insert (pmap, NULL);
+ *slot = partition;
+ npartitions++;
+ }
+
+ add_symbol_to_partition (partition, node);
+ }
+
+ /* If the cgraph is empty, create one cgraph node set so that there is still
+ an output file for any variables that need to be exported in a DSO. */
+ if (!npartitions)
+ new_partition ("empty");
+
+ pointer_map_destroy (pmap);
+
+}
+
+/* Maximal partitioning. Put every new symbol into new partition if possible. */
+
+void
+lto_max_map (void)
+{
+ symtab_node *node;
+ ltrans_partition partition;
+ int npartitions = 0;
+
+ FOR_EACH_SYMBOL (node)
+ {
+ if (symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION
+ || symbol_partitioned_p (node))
+ continue;
+ partition = new_partition (node->asm_name ());
+ add_symbol_to_partition (partition, node);
+ npartitions++;
+ }
+ if (!npartitions)
+ new_partition ("empty");
+}
+
+/* Helper function for qsort; sort nodes by order. */
+static int
+node_cmp (const void *pa, const void *pb)
+{
+ const struct cgraph_node *a = *(const struct cgraph_node * const *) pa;
+ const struct cgraph_node *b = *(const struct cgraph_node * const *) pb;
+
+ /* Profile reorder flag enables function reordering based on first execution
+ of a function. All functions with profile are placed in ascending
+ order at the beginning. */
+
+ if (flag_profile_reorder_functions)
+ {
+ /* Functions with time profile are sorted in ascending order. */
+ if (a->tp_first_run && b->tp_first_run)
+ return a->tp_first_run != b->tp_first_run
+ ? a->tp_first_run - b->tp_first_run
+ : a->order - b->order;
+
+ /* Functions with time profile are sorted before the functions
+ that do not have the profile. */
+ if (a->tp_first_run || b->tp_first_run)
+ return b->tp_first_run - a->tp_first_run;
+ }
+
+ return b->order - a->order;
+}
+
+/* Helper function for qsort; sort nodes by order. */
+static int
+varpool_node_cmp (const void *pa, const void *pb)
+{
+ const varpool_node *a = *(const varpool_node * const *) pa;
+ const varpool_node *b = *(const varpool_node * const *) pb;
+ return b->order - a->order;
+}
+
+/* Group cgraph nodes into equally-sized partitions.
+
+ The partitioning algorithm is simple: nodes are taken in predefined order.
+ The order corresponds to the order we want functions to have in the final
+ output. In the future this will be given by function reordering pass, but
+ at the moment we use the topological order, which is a good approximation.
+
+ The goal is to partition this linear order into intervals (partitions) so
+ that all the partitions have approximately the same size and the number of
+ callgraph or IPA reference edges crossing boundaries is minimal.
+
+ This is a lot faster (O(n) in size of callgraph) than algorithms doing
+ priority-based graph clustering that are generally O(n^2) and, since
+ WHOPR is designed to make things go well across partitions, it leads
+ to good results.
+
+ We compute the expected size of a partition as:
+
+ max (total_size / lto_partitions, min_partition_size)
+
+ We use dynamic expected size of partition so small programs are partitioned
+ into enough partitions to allow use of multiple CPUs, while large programs
+ are not partitioned too much. Creating too many partitions significantly
+ increases the streaming overhead.
+
+ In the future, we would like to bound the maximal size of partitions so as
+ to prevent the LTRANS stage from consuming too much memory. At the moment,
+ however, the WPA stage is the most memory intensive for large benchmarks,
+ since too many types and declarations are read into memory.
+
+ The function implements a simple greedy algorithm. Nodes are being added
+ to the current partition until after 3/4 of the expected partition size is
+ reached. Past this threshold, we keep track of boundary size (number of
+ edges going to other partitions) and continue adding functions until after
+ the current partition has grown to twice the expected partition size. Then
+ the process is undone to the point where the minimal ratio of boundary size
+ and in-partition calls was reached. */
+
+void
+lto_balanced_map (void)
+{
+ int n_nodes = 0;
+ int n_varpool_nodes = 0, varpool_pos = 0, best_varpool_pos = 0;
+ struct cgraph_node **order = XNEWVEC (struct cgraph_node *, cgraph_max_uid);
+ varpool_node **varpool_order = NULL;
+ int i;
+ struct cgraph_node *node;
+ int total_size = 0, best_total_size = 0;
+ int partition_size;
+ ltrans_partition partition;
+ int last_visited_node = 0;
+ varpool_node *vnode;
+ int cost = 0, internal = 0;
+ int best_n_nodes = 0, best_i = 0, best_cost =
+ INT_MAX, best_internal = 0;
+ int npartitions;
+ int current_order = -1;
+
+ FOR_EACH_VARIABLE (vnode)
+ gcc_assert (!vnode->aux);
+
+ FOR_EACH_DEFINED_FUNCTION (node)
+ if (symtab_get_symbol_partitioning_class (node) == SYMBOL_PARTITION)
+ {
+ order[n_nodes++] = node;
+ if (!node->alias)
+ total_size += inline_summary (node)->size;
+ }
+
+ /* Streaming works best when the source units do not cross partition
+ boundaries much. This is because importing function from a source
+ unit tends to import a lot of global trees defined there. We should
+ get better about minimizing the function bounday, but until that
+ things works smoother if we order in source order. */
+ qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp);
+
+ if (cgraph_dump_file)
+ for(i = 0; i < n_nodes; i++)
+ fprintf (cgraph_dump_file, "Balanced map symbol order:%s:%u\n", order[i]->name (), order[i]->tp_first_run);
+
+ if (!flag_toplevel_reorder)
+ {
+ FOR_EACH_VARIABLE (vnode)
+ if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION)
+ n_varpool_nodes++;
+ varpool_order = XNEWVEC (varpool_node *, n_varpool_nodes);
+
+ n_varpool_nodes = 0;
+ FOR_EACH_VARIABLE (vnode)
+ if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION)
+ varpool_order[n_varpool_nodes++] = vnode;
+ qsort (varpool_order, n_varpool_nodes, sizeof (varpool_node *),
+ varpool_node_cmp);
+ }
+
+ /* Compute partition size and create the first partition. */
+ partition_size = total_size / PARAM_VALUE (PARAM_LTO_PARTITIONS);
+ if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE))
+ partition_size = PARAM_VALUE (MIN_PARTITION_SIZE);
+ npartitions = 1;
+ partition = new_partition ("");
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Total unit size: %i, partition size: %i\n",
+ total_size, partition_size);
+
+ for (i = 0; i < n_nodes; i++)
+ {
+ if (symbol_partitioned_p (order[i]))
+ continue;
+
+ current_order = order[i]->order;
+
+ if (!flag_toplevel_reorder)
+ while (varpool_pos < n_varpool_nodes
+ && varpool_order[varpool_pos]->order < current_order)
+ {
+ if (!symbol_partitioned_p (varpool_order[varpool_pos]))
+ add_symbol_to_partition (partition, varpool_order[varpool_pos]);
+ varpool_pos++;
+ }
+
+ add_symbol_to_partition (partition, order[i]);
+ if (!order[i]->alias)
+ total_size -= inline_summary (order[i])->size;
+
+
+ /* Once we added a new node to the partition, we also want to add
+ all referenced variables unless they was already added into some
+ earlier partition.
+ add_symbol_to_partition adds possibly multiple nodes and
+ variables that are needed to satisfy needs of ORDER[i].
+ We remember last visited cgraph and varpool node from last iteration
+ of outer loop that allows us to process every new addition.
+
+ At the same time we compute size of the boundary into COST. Every
+ callgraph or IPA reference edge leaving the partition contributes into
+ COST. Every edge inside partition was earlier computed as one leaving
+ it and thus we need to subtract it from COST. */
+ while (last_visited_node < lto_symtab_encoder_size (partition->encoder))
+ {
+ struct ipa_ref_list *refs;
+ int j;
+ struct ipa_ref *ref;
+ symtab_node *snode = lto_symtab_encoder_deref (partition->encoder,
+ last_visited_node);
+
+ if (cgraph_node *node = dyn_cast <cgraph_node> (snode))
+ {
+ struct cgraph_edge *edge;
+
+ refs = &node->ref_list;
+
+ last_visited_node++;
+
+ gcc_assert (node->definition || node->weakref);
+
+ /* Compute boundary cost of callgraph edges. */
+ for (edge = node->callees; edge; edge = edge->next_callee)
+ if (edge->callee->definition)
+ {
+ int edge_cost = edge->frequency;
+ int index;
+
+ if (!edge_cost)
+ edge_cost = 1;
+ gcc_assert (edge_cost > 0);
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ edge->callee);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost -= edge_cost, internal += edge_cost;
+ else
+ cost += edge_cost;
+ }
+ for (edge = node->callers; edge; edge = edge->next_caller)
+ {
+ int edge_cost = edge->frequency;
+ int index;
+
+ gcc_assert (edge->caller->definition);
+ if (!edge_cost)
+ edge_cost = 1;
+ gcc_assert (edge_cost > 0);
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ edge->caller);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost -= edge_cost;
+ else
+ cost += edge_cost;
+ }
+ }
+ else
+ {
+ refs = &snode->ref_list;
+ last_visited_node++;
+ }
+
+ /* Compute boundary cost of IPA REF edges and at the same time look into
+ variables referenced from current partition and try to add them. */
+ for (j = 0; ipa_ref_list_reference_iterate (refs, j, ref); j++)
+ if (is_a <varpool_node> (ref->referred))
+ {
+ int index;
+
+ vnode = ipa_ref_varpool_node (ref);
+ if (!vnode->definition)
+ continue;
+ if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder
+ && symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION)
+ add_symbol_to_partition (partition, vnode);
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ vnode);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost--, internal++;
+ else
+ cost++;
+ }
+ else
+ {
+ int index;
+
+ node = ipa_ref_node (ref);
+ if (!node->definition)
+ continue;
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ node);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost--, internal++;
+ else
+ cost++;
+ }
+ for (j = 0; ipa_ref_list_referring_iterate (refs, j, ref); j++)
+ if (is_a <varpool_node> (ref->referring))
+ {
+ int index;
+
+ vnode = ipa_ref_referring_varpool_node (ref);
+ gcc_assert (vnode->definition);
+ /* It is better to couple variables with their users, because it allows them
+ to be removed. Coupling with objects they refer to only helps to reduce
+ number of symbols promoted to hidden. */
+ if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder
+ && !varpool_can_remove_if_no_refs (vnode)
+ && symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION)
+ add_symbol_to_partition (partition, vnode);
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ vnode);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost--;
+ else
+ cost++;
+ }
+ else
+ {
+ int index;
+
+ node = ipa_ref_referring_node (ref);
+ gcc_assert (node->definition);
+ index = lto_symtab_encoder_lookup (partition->encoder,
+ node);
+ if (index != LCC_NOT_FOUND
+ && index < last_visited_node - 1)
+ cost--;
+ else
+ cost++;
+ }
+ }
+
+ /* If the partition is large enough, start looking for smallest boundary cost. */
+ if (partition->insns < partition_size * 3 / 4
+ || best_cost == INT_MAX
+ || ((!cost
+ || (best_internal * (HOST_WIDE_INT) cost
+ > (internal * (HOST_WIDE_INT)best_cost)))
+ && partition->insns < partition_size * 5 / 4))
+ {
+ best_cost = cost;
+ best_internal = internal;
+ best_i = i;
+ best_n_nodes = lto_symtab_encoder_size (partition->encoder);
+ best_total_size = total_size;
+ best_varpool_pos = varpool_pos;
+ }
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Step %i: added %s/%i, size %i, cost %i/%i "
+ "best %i/%i, step %i\n", i,
+ order[i]->name (), order[i]->order,
+ partition->insns, cost, internal,
+ best_cost, best_internal, best_i);
+ /* Partition is too large, unwind into step when best cost was reached and
+ start new partition. */
+ if (partition->insns > 2 * partition_size)
+ {
+ if (best_i != i)
+ {
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Unwinding %i insertions to step %i\n",
+ i - best_i, best_i);
+ undo_partition (partition, best_n_nodes);
+ varpool_pos = best_varpool_pos;
+ }
+ i = best_i;
+ /* When we are finished, avoid creating empty partition. */
+ while (i < n_nodes - 1 && symbol_partitioned_p (order[i + 1]))
+ i++;
+ if (i == n_nodes - 1)
+ break;
+ partition = new_partition ("");
+ last_visited_node = 0;
+ total_size = best_total_size;
+ cost = 0;
+
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "New partition\n");
+ best_n_nodes = 0;
+ best_cost = INT_MAX;
+
+ /* Since the size of partitions is just approximate, update the size after
+ we finished current one. */
+ if (npartitions < PARAM_VALUE (PARAM_LTO_PARTITIONS))
+ partition_size = total_size
+ / (PARAM_VALUE (PARAM_LTO_PARTITIONS) - npartitions);
+ else
+ partition_size = INT_MAX;
+
+ if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE))
+ partition_size = PARAM_VALUE (MIN_PARTITION_SIZE);
+ npartitions ++;
+ }
+ }
+
+ /* Varables that are not reachable from the code go into last partition. */
+ if (flag_toplevel_reorder)
+ {
+ FOR_EACH_VARIABLE (vnode)
+ if (symtab_get_symbol_partitioning_class (vnode) == SYMBOL_PARTITION
+ && !symbol_partitioned_p (vnode))
+ add_symbol_to_partition (partition, vnode);
+ }
+ else
+ {
+ while (varpool_pos < n_varpool_nodes)
+ {
+ if (!symbol_partitioned_p (varpool_order[varpool_pos]))
+ add_symbol_to_partition (partition, varpool_order[varpool_pos]);
+ varpool_pos++;
+ }
+ free (varpool_order);
+ }
+ free (order);
+}
+
+/* Mangle NODE symbol name into a local name.
+ This is necessary to do
+ 1) if two or more static vars of same assembler name
+ are merged into single ltrans unit.
+ 2) if prevoiusly static var was promoted hidden to avoid possible conflict
+ with symbols defined out of the LTO world.
+*/
+
+static bool
+privatize_symbol_name (symtab_node *node)
+{
+ tree decl = node->decl;
+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+ /* Our renaming machinery do not handle more than one change of assembler name.
+ We should not need more than one anyway. */
+ if (node->lto_file_data
+ && lto_get_decl_name_mapping (node->lto_file_data, name) != name)
+ {
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file,
+ "Not privatizing symbol name: %s. It privatized already.\n",
+ name);
+ return false;
+ }
+ /* Avoid mangling of already mangled clones.
+ ??? should have a flag whether a symbol has a 'private' name already,
+ since we produce some symbols like that i.e. for global constructors
+ that are not really clones. */
+ if (node->unique_name)
+ {
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file,
+ "Not privatizing symbol name: %s. Has unique name.\n",
+ name);
+ return false;
+ }
+ change_decl_assembler_name (decl, clone_function_name (decl, "lto_priv"));
+ if (node->lto_file_data)
+ lto_record_renamed_decl (node->lto_file_data, name,
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (decl)));
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file,
+ "Privatizing symbol name: %s -> %s\n",
+ name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ return true;
+}
+
+/* Promote variable VNODE to be static. */
+
+static void
+promote_symbol (symtab_node *node)
+{
+ /* We already promoted ... */
+ if (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
+ && DECL_VISIBILITY_SPECIFIED (node->decl)
+ && TREE_PUBLIC (node->decl))
+ return;
+
+ gcc_checking_assert (!TREE_PUBLIC (node->decl)
+ && !DECL_EXTERNAL (node->decl));
+ /* Be sure that newly public symbol does not conflict with anything already
+ defined by the non-LTO part. */
+ privatize_symbol_name (node);
+ TREE_PUBLIC (node->decl) = 1;
+ DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (node->decl) = true;
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file,
+ "Promoting as hidden: %s\n", node->name ());
+}
+
+/* Return true if NODE needs named section even if it won't land in the partition
+ symbol table.
+ FIXME: we should really not use named sections for inline clones and master clones. */
+
+static bool
+may_need_named_section_p (lto_symtab_encoder_t encoder, symtab_node *node)
+{
+ struct cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+ if (!cnode)
+ return false;
+ if (symtab_real_symbol_p (node))
+ return false;
+ return (!encoder
+ || (lto_symtab_encoder_lookup (encoder, node) != LCC_NOT_FOUND
+ && lto_symtab_encoder_encode_body_p (encoder,
+ cnode)));
+}
+
+/* If NODE represents a static variable. See if there are other variables
+ of the same name in partition ENCODER (or in whole compilation unit if
+ ENCODER is NULL) and if so, mangle the statics. Always mangle all
+ conflicting statics, so we reduce changes of silently miscompiling
+ asm statements referring to them by symbol name. */
+
+static void
+rename_statics (lto_symtab_encoder_t encoder, symtab_node *node)
+{
+ tree decl = node->decl;
+ symtab_node *s;
+ tree name = DECL_ASSEMBLER_NAME (decl);
+
+ /* See if this is static symbol. */
+ if ((node->externally_visible
+ /* FIXME: externally_visible is somewhat illogically not set for
+ external symbols (i.e. those not defined). Remove this test
+ once this is fixed. */
+ || DECL_EXTERNAL (node->decl)
+ || !symtab_real_symbol_p (node))
+ && !may_need_named_section_p (encoder, node))
+ return;
+
+ /* Now walk symbols sharing the same name and see if there are any conflicts.
+ (all types of symbols counts here, since we can not have static of the
+ same name as external or public symbol.) */
+ for (s = symtab_node_for_asm (name);
+ s; s = s->next_sharing_asm_name)
+ if ((symtab_real_symbol_p (s) || may_need_named_section_p (encoder, s))
+ && s->decl != node->decl
+ && (!encoder
+ || lto_symtab_encoder_lookup (encoder, s) != LCC_NOT_FOUND))
+ break;
+
+ /* OK, no confict, so we have nothing to do. */
+ if (!s)
+ return;
+
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file,
+ "Renaming statics with asm name: %s\n", node->name ());
+
+ /* Assign every symbol in the set that shares the same ASM name an unique
+ mangled name. */
+ for (s = symtab_node_for_asm (name); s;)
+ if (!s->externally_visible
+ && ((symtab_real_symbol_p (s)
+ && !DECL_EXTERNAL (node->decl)
+ && !TREE_PUBLIC (node->decl))
+ || may_need_named_section_p (encoder, s))
+ && (!encoder
+ || lto_symtab_encoder_lookup (encoder, s) != LCC_NOT_FOUND))
+ {
+ if (privatize_symbol_name (s))
+ /* Re-start from beginning since we do not know how many symbols changed a name. */
+ s = symtab_node_for_asm (name);
+ else s = s->next_sharing_asm_name;
+ }
+ else s = s->next_sharing_asm_name;
+}
+
+/* Find out all static decls that need to be promoted to global because
+ of cross file sharing. This function must be run in the WPA mode after
+ all inlinees are added. */
+
+void
+lto_promote_cross_file_statics (void)
+{
+ unsigned i, n_sets;
+
+ gcc_assert (flag_wpa);
+
+ /* First compute boundaries. */
+ n_sets = ltrans_partitions.length ();
+ for (i = 0; i < n_sets; i++)
+ {
+ ltrans_partition part
+ = ltrans_partitions[i];
+ part->encoder = compute_ltrans_boundary (part->encoder);
+ }
+
+ /* Look at boundaries and promote symbols as needed. */
+ for (i = 0; i < n_sets; i++)
+ {
+ lto_symtab_encoder_iterator lsei;
+ lto_symtab_encoder_t encoder = ltrans_partitions[i]->encoder;
+
+ for (lsei = lsei_start (encoder); !lsei_end_p (lsei);
+ lsei_next (&lsei))
+ {
+ symtab_node *node = lsei_node (lsei);
+
+ /* If symbol is static, rename it if its assembler name clash with
+ anything else in this unit. */
+ rename_statics (encoder, node);
+
+ /* No need to promote if symbol already is externally visible ... */
+ if (node->externally_visible
+ /* ... or if it is part of current partition ... */
+ || lto_symtab_encoder_in_partition_p (encoder, node)
+ /* ... or if we do not partition it. This mean that it will
+ appear in every partition refernecing it. */
+ || symtab_get_symbol_partitioning_class (node) != SYMBOL_PARTITION)
+ continue;
+
+ promote_symbol (node);
+ }
+ }
+}
+
+/* Rename statics in the whole unit in the case that
+ we do -flto-partition=none. */
+
+void
+lto_promote_statics_nonwpa (void)
+{
+ symtab_node *node;
+ FOR_EACH_SYMBOL (node)
+ rename_statics (NULL, node);
+}