common.opt (flto-partition): Add "max".

* common.opt (flto-partition): Add "max".
	* invoke.texi (flto-partition): Document "max"

	* lto.c (do_whole_program_analysis): Care timevars, statistics and
	AUX pointer cleaning. Add max partitioning.
	* lto-partition.c (enum symbol_class): New.
	(get_symbol_class): New function.
	(symbol_partitioned_p): New function.
	(add_references_to_partition): Remove.
	(add_aliases_to_partition): Remove.
	(add_cgraph_node_to_partition_1): Remove.
	(add_cgraph_node_to_partition): Remove.
	(add_symbol_to_partition): New function.
	(add_symbol_to_partition_1): New function.
	(contained_in_symbol): New function.
	(partition_cgraph_node_p): Remove.
	(partition_varpool_node_p): Remove.
	(partition_symbol_p): Remove.
	(lto_1_to_1_map): Cleanup.
	(lto_max_map): New.
	(lto_balanced_map): Update.
	(lto_promote_cross_file_statics): Update.
	* lto-partition.h (lto_max_map): Declare.
	* timevar.def (TV_WHOPR_PARTITIONING): New timevar.

From-SVN: r191229
This commit is contained in:
Jan Hubicka 2012-09-12 19:55:13 +02:00 committed by Jan Hubicka
parent b5c7cdfb0a
commit c3c445e1cf
8 changed files with 323 additions and 237 deletions

View File

@ -1,3 +1,8 @@
2012-09-12 Jan Hubicka <jh@suse.cz>
* common.opt (flto-partition): Add "max".
* invoke.texi (flto-partition): Document "max"
2012-09-12 Ganesh Gopalasubramanian <Ganesh.Gopalasubramanian@amd.com>
* config/i386/i386.md : Comments on fma4 instruction

View File

@ -1439,12 +1439,16 @@ Link-time optimization with number of parallel jobs or jobserver.
flto-partition=1to1
Common Var(flag_lto_partition_1to1)
Partition functions and vars at linktime based on object files they originate from
Partition symbols and vars at linktime based on object files they originate from
flto-partition=balanced
Common Var(flag_lto_partition_balanced)
Partition functions and vars at linktime into approximately same sized buckets
flto-partition=max
Common Var(flag_lto_partition_max)
Put every symbol into separate partition
flto-partition=none
Common Var(flag_lto_partition_none)
Disable partioning and streaming

View File

@ -8093,9 +8093,12 @@ This option is disabled by default.
Specify the partitioning algorithm used by the link-time optimizer.
The value is either @code{1to1} to specify a partitioning mirroring
the original source files or @code{balanced} to specify partitioning
into equally sized chunks (whenever possible). Specifying @code{none}
as an algorithm disables partitioning and streaming completely. The
default value is @code{balanced}.
into equally sized chunks (whenever possible) or @code{max} to create
new partition for every symbol where possible. Specifying @code{none}
as an algorithm disables partitioning and streaming completely.
The default value is @code{balanced}. While @code{1to1} can be used
as an workaround for various code ordering issues, the @code{max}
partitioning is intended for internal testing only.
@item -flto-compression-level=@var{n}
This option specifies the level of compression used for intermediate

View File

@ -1,3 +1,27 @@
2012-09-12 Jan Hubicka <jh@suse.cz>
* lto.c (do_whole_program_analysis): Care timevars, statistics and
AUX pointer cleaning. Add max partitioning.
* lto-partition.c (enum symbol_class): New.
(get_symbol_class): New function.
(symbol_partitioned_p): New function.
(add_references_to_partition): Remove.
(add_aliases_to_partition): Remove.
(add_cgraph_node_to_partition_1): Remove.
(add_cgraph_node_to_partition): Remove.
(add_symbol_to_partition): New function.
(add_symbol_to_partition_1): New function.
(contained_in_symbol): New function.
(partition_cgraph_node_p): Remove.
(partition_varpool_node_p): Remove.
(partition_symbol_p): Remove.
(lto_1_to_1_map): Cleanup.
(lto_max_map): New.
(lto_balanced_map): Update.
(lto_promote_cross_file_statics): Update.
* lto-partition.h (lto_max_map): Declare.
* timevar.def (TV_WHOPR_PARTITIONING): New timevar.
2012-09-11 Jan Hubicka <jh@suse.cz>
PR lto/54312

View File

@ -31,13 +31,70 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h"
#include "lto-partition.h"
/* Classifcation of symbols into classes WRT partitioning. */
enum symbol_class
{
/* External declarations are ignored by partitioning algorithms and they are
added into the boundary later via compute_ltrans_boundary. */
SYMBOL_EXTERNAL,
/* Partitioned symbols are pur into one of partitions. */
SYMBOL_PARTITION,
/* Duplicated symbols (such as comdat or constant pool references) are
copied into every node needing them via add_symbol_to_partition. */
SYMBOL_DUPLICATE
};
VEC(ltrans_partition, heap) *ltrans_partitions;
static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node);
static void add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode);
static bool partition_symbol_p (symtab_node node);
static void add_symbol_to_partition (ltrans_partition part, symtab_node node);
/* Classify symbol NODE. */
enum symbol_class
get_symbol_class (symtab_node node)
{
/* Inline clones are always duplicated.
This include external delcarations. */
if (symtab_function_p (node)
&& cgraph (node)->global.inlined_to)
return SYMBOL_DUPLICATE;
/* External declarations are external. */
if (DECL_EXTERNAL (node->symbol.decl))
return SYMBOL_EXTERNAL;
if (symtab_variable_p (node))
{
/* Constant pool references use local symbol names that can not
be promoted global. We should never put into a constant pool
objects that can not be duplicated across partitions. */
if (DECL_IN_CONSTANT_POOL (node->symbol.decl))
return SYMBOL_DUPLICATE;
gcc_checking_assert (varpool (node)->analyzed);
}
/* Functions that are cloned may stay in callgraph even if they are unused.
Handle them as external; compute_ltrans_boundary take care to make
proper things to happen (i.e. to make them appear in the boundary but
with body streamed, so clone can me materialized). */
else if (!cgraph (node)->analyzed)
return SYMBOL_EXTERNAL;
/* Weakref aliases are always duplicated. */
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
return SYMBOL_DUPLICATE;
/* Comdats are duplicated to every use unless they are keyed.
Those do not need duplication. */
if (DECL_COMDAT (node->symbol.decl)
&& !node->symbol.force_output
&& !symtab_used_from_object_file_p ((symtab_node) node))
return SYMBOL_DUPLICATE;
return SYMBOL_PARTITION;
}
/* Create new partition with name NAME. */
static ltrans_partition
new_partition (const char *name)
{
@ -50,6 +107,7 @@ new_partition (const char *name)
}
/* Free memory used by ltrans datastructures. */
void
free_ltrans_partitions (void)
{
@ -57,160 +115,175 @@ free_ltrans_partitions (void)
ltrans_partition part;
for (idx = 0; VEC_iterate (ltrans_partition, ltrans_partitions, idx, part); idx++)
{
if (part->initializers_visited)
pointer_set_destroy (part->initializers_visited);
/* Symtab encoder is freed after streaming. */
free (part);
}
VEC_free (ltrans_partition, heap, ltrans_partitions);
}
/* Add all referenced symbols referenced by REFS that are not external and not
partitioned into PART. */
static void
add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
/* Return true if symbol is already in some partition. */
static inline bool
symbol_partitioned_p (symtab_node node)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
{
if (DECL_EXTERNAL (ref->referred->symbol.decl)
|| partition_symbol_p (ref->referred)
|| lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
continue;
if (symtab_function_p (ref->referred))
add_cgraph_node_to_partition (part, ipa_ref_node (ref));
else
add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref));
}
return node->symbol.aux;
}
/* Look for all (nonweakref) aliases in REFS and add them into PART. */
/* Add references into the partition. */
static void
add_aliases_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
add_references_to_partition (ltrans_partition part, symtab_node node)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_referring_iterate (refs, i, ref); i++)
if (ref->use == IPA_REF_ALIAS
&& !lto_symtab_encoder_in_partition_p (part->encoder,
ref->referring)
&& !lookup_attribute ("weakref",
DECL_ATTRIBUTES
(ref->referring->symbol.decl)))
/* Add all duplicated references to the partition. */
for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
if (get_symbol_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 (symtab_variable_p (ref->referred)
&& const_value_known_p (ref->referred->symbol.decl)
&& !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
{
if (symtab_function_p (ref->referring))
add_cgraph_node_to_partition (part, ipa_ref_referring_node (ref));
else
add_varpool_node_to_partition (part,
ipa_ref_referring_varpool_node (ref));
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);
}
}
/* Worker for add_cgraph_node_to_partition. */
/* Helper function for add_symbol_to_partition doing the actual dirty work
of adding NODE to PART. */
static bool
add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
add_symbol_to_partition_1 (ltrans_partition part, symtab_node node)
{
ltrans_partition part = (ltrans_partition) data;
enum symbol_class c = get_symbol_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, (symtab_node) 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->symbol.decl)
&& symbol_partitioned_p (node))
return false;
/* non-COMDAT aliases of COMDAT functions needs to be output just once. */
if (!DECL_COMDAT (node->symbol.decl)
&& !node->global.inlined_to
&& node->symbol.aux)
{
gcc_assert (node->thunk.thunk_p || node->alias);
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)));
if (node->symbol.aux)
lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node) node);
if (symbol_partitioned_p (node))
{
node->symbol.in_other_partition = 1;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
cgraph_node_name (node), node->uid);
fprintf (cgraph_dump_file, "Symbol node %s now used in multiple partitions\n",
symtab_node_name (node));
}
node->symbol.aux = (void *)((size_t)node->symbol.aux + 1);
lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node)node);
return false;
}
/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
static void
add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
{
struct cgraph_edge *e;
struct cgraph_node *n;
/* If NODE is already there, we have nothing to do. */
if (lto_symtab_encoder_in_partition_p (part->encoder, (symtab_node) node))
return;
cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
part->insns += inline_summary (node)->self_size;
for (e = node->callees; e; e = e->next_callee)
if ((!e->inline_failed
|| (!DECL_EXTERNAL (e->callee->symbol.decl)
&& !partition_symbol_p ((symtab_node) e->callee))))
add_cgraph_node_to_partition (part, e->callee);
/* The only way to assemble non-weakref alias is to add the aliased object into
the unit. */
add_references_to_partition (part, &node->symbol.ref_list);
n = cgraph_function_node (node, NULL);
if (n != node
&& !lookup_attribute ("weakref",
DECL_ATTRIBUTES (node->symbol.decl)))
add_cgraph_node_to_partition (part, n);
if (node->symbol.same_comdat_group)
for (n = cgraph (node->symbol.same_comdat_group);
n != node; n = cgraph (n->symbol.same_comdat_group))
add_cgraph_node_to_partition (part, n);
}
/* Add VNODE to partition as well as comdat references partition PART. */
static void
add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode)
{
struct varpool_node *v;
/* If NODE is already there, we have nothing to do. */
if (lto_symtab_encoder_in_partition_p (part->encoder, (symtab_node) vnode))
return;
lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node) vnode);
if (vnode->symbol.aux)
if (symtab_function_p (node))
{
vnode->symbol.in_other_partition = 1;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Varpool node %s now used in multiple partitions\n",
varpool_node_name (vnode));
struct cgraph_node *cnode = cgraph (node);
struct cgraph_edge *e;
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, (symtab_node) e->callee);
else if (get_symbol_class ((symtab_node) e->callee) == SYMBOL_DUPLICATE)
add_symbol_to_partition (part, (symtab_node) 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, (symtab_node) e->caller);
}
vnode->symbol.aux = (void *)((size_t)vnode->symbol.aux + 1);
/* The only way to assemble non-weakref alias is to add the aliased object into
the unit. */
v = varpool_variable_node (vnode, NULL);
if (v != vnode
&& !lookup_attribute ("weakref",
DECL_ATTRIBUTES (vnode->symbol.decl)))
add_varpool_node_to_partition (part, v);
add_references_to_partition (part, node);
add_references_to_partition (part, &vnode->symbol.ref_list);
add_aliases_to_partition (part, &vnode->symbol.ref_list);
/* Add all aliases associated with the symbol. */
for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS
&& !lookup_attribute ("weakref",
DECL_ATTRIBUTES
(ref->referring->symbol.decl)))
add_symbol_to_partition_1 (part, ref->referring);
if (vnode->symbol.same_comdat_group
&& !lto_symtab_encoder_in_partition_p (part->encoder,
vnode->symbol.same_comdat_group))
add_varpool_node_to_partition (part, varpool (vnode->symbol.same_comdat_group));
/* Ensure that SAME_COMDAT_GROUP lists all allways added in a group. */
if (node->symbol.same_comdat_group)
for (node1 = node->symbol.same_comdat_group;
node1 != node; node1 = node1->symbol.same_comdat_group)
{
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 (lookup_attribute ("weakref",
DECL_ATTRIBUTES (node->symbol.decl)))
return node;
if (symtab_function_p (node))
{
struct cgraph_node *cnode = cgraph_function_node (cgraph (node), NULL);
if (cnode->global.inlined_to)
cnode = cnode->global.inlined_to;
return (symtab_node) cnode;
}
else if (symtab_variable_p (node))
return (symtab_node) varpool_variable_node (varpool (node), 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 (get_symbol_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 (get_symbol_class (node) == SYMBOL_DUPLICATE
|| DECL_COMDAT (node->symbol.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
@ -223,6 +296,12 @@ undo_partition (ltrans_partition partition, unsigned int n_nodes)
{
symtab_node node = lto_symtab_encoder_deref (partition->encoder,
n_nodes);
/* After UNDO we no longer know what was visited. */
if (partition->initializers_visited)
pointer_set_destroy (partition->initializers_visited);
partition->initializers_visited = NULL;
if (symtab_function_p (node))
partition->insns -= inline_summary (cgraph (node))->self_size;
lto_symtab_encoder_delete_node (partition->encoder, node);
@ -230,85 +309,25 @@ undo_partition (ltrans_partition partition, unsigned int n_nodes)
}
}
/* Return true if NODE should be partitioned.
This means that partitioning algorithm should put NODE into one of partitions.
This apply to most functions with bodies. Functions that are not partitions
are put into every unit needing them. This is the case of i.e. COMDATs. */
static bool
partition_cgraph_node_p (struct cgraph_node *node)
{
/* We will get proper partition based on function they are inlined to. */
if (node->global.inlined_to)
return false;
/* Nodes without a body do not need partitioning. */
if (!node->analyzed)
return false;
/* Extern inlines and comdat are always only in partitions they are needed. */
if (DECL_EXTERNAL (node->symbol.decl)
|| (DECL_COMDAT (node->symbol.decl)
&& !node->symbol.force_output
&& !symtab_used_from_object_file_p ((symtab_node) node)))
return false;
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
return false;
return true;
}
/* Return true if VNODE should be partitioned.
This means that partitioning algorithm should put VNODE into one of partitions. */
static bool
partition_varpool_node_p (struct varpool_node *vnode)
{
if (!vnode->analyzed)
return false;
/* Constant pool and comdat are always only in partitions they are needed. */
if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
|| DECL_EXTERNAL (vnode->symbol.decl)
|| (DECL_COMDAT (vnode->symbol.decl)
&& !vnode->symbol.force_output
&& !symtab_used_from_object_file_p ((symtab_node) vnode)))
return false;
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
return false;
return true;
}
/* Return true if NODE should be partitioned.
This means that partitioning algorithm should put NODE into one of partitions. */
static bool
partition_symbol_p (symtab_node node)
{
if (symtab_function_p (node))
return partition_cgraph_node_p (cgraph (node));
else
return partition_varpool_node_p (varpool (node));
}
/* Group cgrah nodes by input files. This is used mainly for testing
right now. */
void
lto_1_to_1_map (void)
{
struct cgraph_node *node;
struct varpool_node *vnode;
symtab_node node;
struct lto_file_decl_data *file_data;
struct pointer_map_t *pmap;
ltrans_partition partition;
void **slot;
int npartitions = 0;
timevar_push (TV_WHOPR_WPA);
pmap = pointer_map_create ();
FOR_EACH_DEFINED_FUNCTION (node)
FOR_EACH_SYMBOL (node)
{
if (!partition_cgraph_node_p (node)
|| node->symbol.aux)
if (get_symbol_class (node) != SYMBOL_PARTITION
|| symbol_partitioned_p (node))
continue;
file_data = node->symbol.lto_file_data;
@ -337,33 +356,9 @@ lto_1_to_1_map (void)
npartitions++;
}
add_cgraph_node_to_partition (partition, node);
add_symbol_to_partition (partition, (symtab_node) node);
}
FOR_EACH_VARIABLE (vnode)
{
if (!partition_varpool_node_p (vnode)
|| vnode->symbol.aux)
continue;
file_data = vnode->symbol.lto_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++;
}
add_varpool_node_to_partition (partition, vnode);
}
FOR_EACH_FUNCTION (node)
node->symbol.aux = NULL;
FOR_EACH_VARIABLE (vnode)
vnode->symbol.aux = NULL;
/* 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)
@ -371,10 +366,28 @@ lto_1_to_1_map (void)
pointer_map_destroy (pmap);
timevar_pop (TV_WHOPR_WPA);
}
lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition,
ltrans_partitions);
/* 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 (get_symbol_class (node) != SYMBOL_PARTITION
|| symbol_partitioned_p (node))
continue;
partition = new_partition (symtab_node_asm_name (node));
add_symbol_to_partition (partition, (symtab_node) node);
npartitions++;
}
if (!npartitions)
new_partition ("empty");
}
/* Helper function for qsort; sort nodes by order. */
@ -467,7 +480,7 @@ lto_balanced_map (void)
for (i = 0; i < postorder_len; i++)
{
node = postorder[i];
if (partition_cgraph_node_p (node))
if (get_symbol_class ((symtab_node) node) == SYMBOL_PARTITION)
{
order[n_nodes++] = node;
total_size += inline_summary (node)->size;
@ -480,13 +493,13 @@ lto_balanced_map (void)
qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp);
FOR_EACH_VARIABLE (vnode)
if (partition_varpool_node_p (vnode))
if (get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION)
n_varpool_nodes++;
varpool_order = XNEWVEC (struct varpool_node *, n_varpool_nodes);
n_varpool_nodes = 0;
FOR_EACH_VARIABLE (vnode)
if (partition_varpool_node_p (vnode))
if (get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION)
varpool_order[n_varpool_nodes++] = vnode;
qsort (varpool_order, n_varpool_nodes, sizeof (struct varpool_node *),
varpool_node_cmp);
@ -504,7 +517,7 @@ lto_balanced_map (void)
for (i = 0; i < n_nodes; i++)
{
if (order[i]->symbol.aux)
if (symbol_partitioned_p ((symtab_node) order[i]))
continue;
current_order = order[i]->symbol.order;
@ -513,19 +526,19 @@ lto_balanced_map (void)
while (varpool_pos < n_varpool_nodes
&& varpool_order[varpool_pos]->symbol.order < current_order)
{
if (!varpool_order[varpool_pos]->symbol.aux)
add_varpool_node_to_partition (partition, varpool_order[varpool_pos]);
if (!symbol_partitioned_p ((symtab_node) varpool_order[varpool_pos]))
add_symbol_to_partition (partition, (symtab_node) varpool_order[varpool_pos]);
varpool_pos++;
}
add_cgraph_node_to_partition (partition, order[i]);
add_symbol_to_partition (partition, (symtab_node) order[i]);
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_cgraph_node_to_partition adds possibly multiple nodes and
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.
@ -605,9 +618,9 @@ lto_balanced_map (void)
vnode = ipa_ref_varpool_node (ref);
if (!vnode->finalized)
continue;
if (!vnode->symbol.aux && flag_toplevel_reorder
&& partition_varpool_node_p (vnode))
add_varpool_node_to_partition (partition, vnode);
if (!symbol_partitioned_p ((symtab_node) vnode) && flag_toplevel_reorder
&& get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION)
add_symbol_to_partition (partition, (symtab_node) vnode);
index = lto_symtab_encoder_lookup (partition->encoder,
(symtab_node)vnode);
if (index != LCC_NOT_FOUND
@ -638,9 +651,9 @@ lto_balanced_map (void)
vnode = ipa_ref_referring_varpool_node (ref);
gcc_assert (vnode->finalized);
if (!vnode->symbol.aux && flag_toplevel_reorder
&& partition_varpool_node_p (vnode))
add_varpool_node_to_partition (partition, vnode);
if (!symbol_partitioned_p ((symtab_node) vnode) && flag_toplevel_reorder
&& get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION)
add_symbol_to_partition (partition, (symtab_node) vnode);
index = lto_symtab_encoder_lookup (partition->encoder,
(symtab_node)vnode);
if (index != LCC_NOT_FOUND
@ -696,7 +709,7 @@ lto_balanced_map (void)
}
i = best_i;
/* When we are finished, avoid creating empty partition. */
while (i < n_nodes - 1 && order[i + 1]->symbol.aux)
while (i < n_nodes - 1 && symbol_partitioned_p ((symtab_node) order[i + 1]))
i++;
if (i == n_nodes - 1)
break;
@ -728,15 +741,16 @@ lto_balanced_map (void)
if (flag_toplevel_reorder)
{
FOR_EACH_VARIABLE (vnode)
if (partition_varpool_node_p (vnode) && !vnode->symbol.aux)
add_varpool_node_to_partition (partition, vnode);
if (get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION
&& !symbol_partitioned_p ((symtab_node) vnode))
add_symbol_to_partition (partition, (symtab_node) vnode);
}
else
{
while (varpool_pos < n_varpool_nodes)
{
if (!varpool_order[varpool_pos]->symbol.aux)
add_varpool_node_to_partition (partition, varpool_order[varpool_pos]);
if (!symbol_partitioned_p ((symtab_node) varpool_order[varpool_pos]))
add_symbol_to_partition (partition, (symtab_node) varpool_order[varpool_pos]);
varpool_pos++;
}
free (varpool_order);
@ -806,7 +820,7 @@ lto_promote_cross_file_statics (void)
|| 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. */
|| !partition_symbol_p (node))
|| get_symbol_class ((symtab_node) node) != SYMBOL_PARTITION)
continue;
promote_symbol (node);

View File

@ -25,6 +25,7 @@ struct ltrans_partition_def
lto_symtab_encoder_t encoder;
const char * name;
int insns;
pointer_set_t *initializers_visited;
};
typedef struct ltrans_partition_def *ltrans_partition;
@ -34,6 +35,7 @@ DEF_VEC_ALLOC_P(ltrans_partition,heap);
extern VEC(ltrans_partition, heap) *ltrans_partitions;
void lto_1_to_1_map (void);
void lto_max_map (void);
void lto_balanced_map (void);
void lto_promote_cross_file_statics (void);
void free_ltrans_partitions (void);

View File

@ -2604,11 +2604,28 @@ lto_wpa_write_files (void)
fprintf (cgraph_dump_file, "Writing partition %s to file %s, %i insns\n",
part->name, temp_filename, part->insns);
fprintf (cgraph_dump_file, " Symbols in partition: ");
for (lsei = lsei_start_in_partition (part->encoder); !lsei_end_p (lsei);
lsei_next_in_partition (&lsei))
{
symtab_node node = lsei_node (lsei);
fprintf (cgraph_dump_file, "%s ", symtab_node_name (node));
fprintf (cgraph_dump_file, "%s ", symtab_node_asm_name (node));
}
fprintf (cgraph_dump_file, "\n Symbols in boundary: ");
for (lsei = lsei_start (part->encoder); !lsei_end_p (lsei);
lsei_next (&lsei))
{
symtab_node node = lsei_node (lsei);
if (!lto_symtab_encoder_in_partition_p (part->encoder, node))
{
fprintf (cgraph_dump_file, "%s ", symtab_node_asm_name (node));
if (symtab_function_p (node)
&& lto_symtab_encoder_encode_body_p (part->encoder, cgraph (node)))
fprintf (cgraph_dump_file, "(body included)");
else if (symtab_variable_p (node)
&& lto_symtab_encoder_encode_initializer_p (part->encoder, varpool (node)))
fprintf (cgraph_dump_file, "(initializer included)");
}
}
fprintf (cgraph_dump_file, "\n");
}
@ -3093,6 +3110,8 @@ print_lto_report_1 (void)
static void
do_whole_program_analysis (void)
{
symtab_node node;
timevar_start (TV_PHASE_OPT_GEN);
/* Note that since we are in WPA mode, materialize_cgraph will not
@ -3127,17 +3146,31 @@ do_whole_program_analysis (void)
dump_cgraph (cgraph_dump_file);
dump_varpool (cgraph_dump_file);
}
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif
bitmap_obstack_release (NULL);
/* We are about to launch the final LTRANS phase, stop the WPA timer. */
timevar_pop (TV_WHOPR_WPA);
timevar_push (TV_WHOPR_PARTITIONING);
if (flag_lto_partition_1to1)
lto_1_to_1_map ();
else if (flag_lto_partition_max)
lto_max_map ();
else
lto_balanced_map ();
/* AUX pointers are used by partitioning code to bookkeep number of
partitions symbol is in. This is no longer needed. */
FOR_EACH_SYMBOL (node)
node->symbol.aux = NULL;
lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition,
ltrans_partitions);
timevar_pop (TV_WHOPR_PARTITIONING);
timevar_stop (TV_PHASE_OPT_GEN);
timevar_start (TV_PHASE_STREAM_OUT);

View File

@ -81,6 +81,7 @@ DEFTIMEVAR (TV_IPA_LTO_CGRAPH_MERGE , "ipa lto cgraph merge")
DEFTIMEVAR (TV_LTO , "lto")
DEFTIMEVAR (TV_WHOPR_WPA , "whopr wpa")
DEFTIMEVAR (TV_WHOPR_WPA_IO , "whopr wpa I/O")
DEFTIMEVAR (TV_WHOPR_PARTITIONING , "whopr partitioning")
DEFTIMEVAR (TV_WHOPR_LTRANS , "whopr ltrans")
DEFTIMEVAR (TV_IPA_REFERENCE , "ipa reference")
DEFTIMEVAR (TV_IPA_PROFILE , "ipa profile")