From: Jan Hubicka Date: Wed, 12 Sep 2012 17:55:13 +0000 (+0200) Subject: common.opt (flto-partition): Add "max". X-Git-Tag: upstream/12.2.0~74310 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c3c445e1cfe4184c0d3537f87e8e5bd3f9974646;p=platform%2Fupstream%2Fgcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 345ea6a..3fb65fe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2012-09-12 Jan Hubicka + + * common.opt (flto-partition): Add "max". + * invoke.texi (flto-partition): Document "max" + 2012-09-12 Ganesh Gopalasubramanian * config/i386/i386.md : Comments on fma4 instruction diff --git a/gcc/common.opt b/gcc/common.opt index 19ea29f..aa893ac 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1a854b0..0a9226a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 85d59b2..8b2a469 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,27 @@ +2012-09-12 Jan Hubicka + + * 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 PR lto/54312 diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c index 4775ee6..b131033 100644 --- a/gcc/lto/lto-partition.c +++ b/gcc/lto/lto-partition.c @@ -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))); + + lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node) node); - if (node->symbol.aux) + 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; + if (symtab_function_p (node)) + { + 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); + } - 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); + add_references_to_partition (part, node); - /* 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); + /* 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); + /* Ensure that SAME_COMDAT_GROUP lists all allways added in a group. */ 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); + 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; } -/* Add VNODE to partition as well as comdat references partition PART. */ +/* 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_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode) +add_symbol_to_partition (ltrans_partition part, symtab_node node) { - struct varpool_node *v; + symtab_node node1; - /* If NODE is already there, we have nothing to do. */ - if (lto_symtab_encoder_in_partition_p (part->encoder, (symtab_node) vnode)) - return; + /* 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)); - lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node) vnode); + while ((node1 = contained_in_symbol (node)) != node) + node = node1; - if (vnode->symbol.aux) - { - 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)); - } - 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, &vnode->symbol.ref_list); - add_aliases_to_partition (part, &vnode->symbol.ref_list); - - 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)); + /* 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,32 +356,8 @@ lto_1_to_1_map (void) npartitions++; } - add_cgraph_node_to_partition (partition, 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); + add_symbol_to_partition (partition, (symtab_node) node); } - 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. */ @@ -371,10 +366,28 @@ lto_1_to_1_map (void) pointer_map_destroy (pmap); - timevar_pop (TV_WHOPR_WPA); +} + +/* Maximal partitioning. Put every new symbol into new partition if possible. */ - lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition, - ltrans_partitions); +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); diff --git a/gcc/lto/lto-partition.h b/gcc/lto/lto-partition.h index e044934..5bf4055 100644 --- a/gcc/lto/lto-partition.h +++ b/gcc/lto/lto-partition.h @@ -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); diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index c87ad6c..c15f9cff 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -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); diff --git a/gcc/timevar.def b/gcc/timevar.def index 149066e..8f99b50 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -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")