common.opt (flto-partition): Add "max".
authorJan Hubicka <jh@suse.cz>
Wed, 12 Sep 2012 17:55:13 +0000 (19:55 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 12 Sep 2012 17:55:13 +0000 (17:55 +0000)
* 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

gcc/ChangeLog
gcc/common.opt
gcc/doc/invoke.texi
gcc/lto/ChangeLog
gcc/lto/lto-partition.c
gcc/lto/lto-partition.h
gcc/lto/lto.c
gcc/timevar.def

index 345ea6a..3fb65fe 100644 (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
index 19ea29f..aa893ac 100644 (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
index 1a854b0..0a9226a 100644 (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
index 85d59b2..8b2a469 100644 (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
index 4775ee6..b131033 100644 (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)));
+
+  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);
index e044934..5bf4055 100644 (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);
index c87ad6c..c15f9cf 100644 (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);
 
index 149066e..8f99b50 100644 (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")