This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

LTO partitioning reorg 4/n


Hi,
this patch unifies the code as promised in the previous patch. It also cleans
up the APIs.  We now have enum symbol_class specifying how the symbol should be
handled and add_symbol_to_partition handling all the magic of what needs to be
dragged into partition and what not.

I also commonized some code that was duplicated across different partitioners
and added "max" partitioner that puts every symbol into new partition if
possible.  

The patch also fixed undefined reference symbol seen with max partitioning on a testcase.
Here we fold through a reference to constant variable into a reference to constant pool.
Since initializer of the constant variable is not seen by the partitioner, we do not
duplicate the constant pool entry into the unit and we end up with undefined reference.
Fixed thus.  I will try to prepare fix for 4.7, too.  I think it is the problem
Andi is seeing with kernel build.

Bootstrapped/regtested x86_64-linux. Will commit it after bit of further testing.

	* 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.
Index: common.opt
===================================================================
--- common.opt	(revision 191215)
+++ common.opt	(working copy)
@@ -1439,12 +1439,16 @@ Link-time optimization with number of pa
 
 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: lto/lto.c
===================================================================
--- lto/lto.c	(revision 191215)
+++ lto/lto.c	(working copy)
@@ -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 +3107,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 +3143,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: lto/lto-partition.c
===================================================================
--- lto/lto-partition.c	(revision 191215)
+++ lto/lto-partition.c	(working copy)
@@ -31,13 +31,70 @@ along with GCC; see the file COPYING3.
 #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 (sych 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);
+  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);
+    }
 
-  part->insns += inline_summary (node)->self_size;
+  add_references_to_partition (part, node);
 
-  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);
+  /* 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;
-
-  lto_set_symtab_encoder_in_partition (part->encoder, (symtab_node) vnode);
-
-  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));
+  /* 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 partiti
     {
       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 partiti
     }
 }
 
-/* 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);
+}
+
+/* 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;
 
-  lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition, 
-						 ltrans_partitions);
+  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: lto/lto-partition.h
===================================================================
--- lto/lto-partition.h	(revision 191215)
+++ lto/lto-partition.h	(working copy)
@@ -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: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 191215)
+++ doc/invoke.texi	(working copy)
@@ -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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]