Index: cgraph.h
===================================================================
--- cgraph.h	(revision 161812)
+++ cgraph.h	(working copy)
@@ -286,7 +286,9 @@
   /* Set once the function has been instantiated and its callee
      lists created.  */
   unsigned analyzed : 1;
-  /* Set when function is available in the other LTRANS partition.  */
+  /* Set when function is available in the other LTRANS partition.  
+     During WPA output it is used to mark nodes that are present in
+     multiple partitions.  */
   unsigned in_other_partition : 1;
   /* Set when function is scheduled to be processed by local passes.  */
   unsigned process : 1;
@@ -497,7 +499,9 @@
   unsigned alias : 1;
   /* Set when variable is used from other LTRANS partition.  */
   unsigned used_from_other_partition : 1;
-  /* Set when variable is available in the other LTRANS partition.  */
+  /* Set when variable is available in the other LTRANS partition.
+     During WPA output it is used to mark nodes that are present in
+     multiple partitions.  */
   unsigned in_other_partition : 1;
 };
 
@@ -556,6 +560,7 @@
 struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int,
 						 gcov_type, int, int);
 struct cgraph_node * cgraph_get_node (tree);
+struct cgraph_node * cgraph_get_node_or_alias (tree);
 struct cgraph_node *cgraph_node (tree);
 bool cgraph_same_body_alias (tree, tree);
 void cgraph_add_thunk (tree, tree, bool, HOST_WIDE_INT, HOST_WIDE_INT, tree, tree);
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 161812)
+++ lto-cgraph.c	(working copy)
@@ -319,13 +319,15 @@
     {
       if (ref->refering_type == IPA_REF_CGRAPH)
 	{
-	  if (!cgraph_node_in_set_p (ipa_ref_refering_node (ref), set))
+	  if (ipa_ref_refering_node (ref)->in_other_partition
+	      || !cgraph_node_in_set_p (ipa_ref_refering_node (ref), set))
 	    return true;
 	}
       else
 	{
-	  if (!varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref),
-				      vset))
+	  if (ipa_ref_refering_varpool_node (ref)->in_other_partition
+	      || !varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref),
+				         vset))
 	    return true;
 	}
     }
@@ -343,7 +345,8 @@
   if (node->global.inlined_to)
     return false;
   for (e = node->callers; e; e = e->next_caller)
-    if (!cgraph_node_in_set_p (e->caller, set))
+    if (e->caller->in_other_partition
+	|| !cgraph_node_in_set_p (e->caller, set))
       return true;
   return false;
 }
@@ -503,6 +506,7 @@
   bp_pack_value (&bp, node->abstract_and_needed, 1);
   bp_pack_value (&bp, tag == LTO_cgraph_analyzed_node
 		 && !DECL_EXTERNAL (node->decl)
+		 && !DECL_COMDAT (node->decl)
 		 && (reachable_from_other_partition_p (node, set)
 		     || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
   bp_pack_value (&bp, node->lowered, 1);
@@ -576,7 +580,8 @@
   /* Constant pool initializers can be de-unified into individual ltrans units.
      FIXME: Alternatively at -Os we may want to avoid generating for them the local
      labels and share them across LTRANS partitions.  */
-  if (DECL_IN_CONSTANT_POOL (node->decl))
+  if (DECL_IN_CONSTANT_POOL (node->decl)
+      && !DECL_COMDAT (node->decl))
     {
       bp_pack_value (&bp, 0, 1);  /* used_from_other_parition.  */
       bp_pack_value (&bp, 0, 1);  /* in_other_partition.  */
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 161812)
+++ lto/lto.c	(working copy)
@@ -525,6 +525,9 @@
 
 static GTY (()) VEC(ltrans_partition, gc) *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);
+
 /* Create new partition with name NAME.  */
 static ltrans_partition
 new_partition (const char *name)
@@ -538,19 +541,79 @@
   return part;
 }
 
-/* Add NODE to partition as well as the inline callees into partition PART. */
+/* See all references that go to comdat objects and bring them into partition too.  */
+static void
+add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
+{
+  int i;
+  struct ipa_ref *ref;
+  for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
+    {
+      if (ref->refered_type == IPA_REF_CGRAPH
+	  && DECL_COMDAT (ipa_ref_node (ref)->decl)
+	  && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
+	add_cgraph_node_to_partition (part, ipa_ref_node (ref));
+      else
+	if (ref->refered_type == IPA_REF_VARPOOL
+	    && DECL_COMDAT (ipa_ref_varpool_node (ref)->decl)
+	    && !varpool_node_in_set_p (ipa_ref_varpool_node (ref), part->varpool_set))
+	  add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref));
+    }
+}
 
+/* 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;
+
   part->insns += node->local.inline_summary.self_size;
+
+  if (node->aux)
+    {
+      gcc_assert (node->aux != part);
+      node->in_other_partition = 1;
+    }
+  else
+    node->aux = part;
+
   cgraph_node_set_add (part->cgraph_set, node);
+
   for (e = node->callees; e; e = e->next_callee)
-    if (!e->inline_failed)
+    if ((!e->inline_failed || DECL_ONE_ONLY (e->callee->decl))
+	&& !cgraph_node_in_set_p (e->callee, part->cgraph_set))
       add_cgraph_node_to_partition (part, e->callee);
+
+  add_references_to_partition (part, &node->ref_list);
+
+  if (node->same_comdat_group
+      && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set))
+    add_cgraph_node_to_partition (part, node->same_comdat_group);
 }
 
+/* Add VNODE to partition as well as comdat references partition PART. */
+
+static void
+add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode)
+{
+  varpool_node_set_add (part->varpool_set, vnode);
+
+  if (vnode->aux)
+    {
+      gcc_assert (vnode->aux != part);
+      vnode->in_other_partition = 1;
+    }
+  else
+    vnode->aux = part;
+
+  add_references_to_partition (part, &vnode->ref_list);
+
+  if (vnode->same_comdat_group
+      && !varpool_node_in_set_p (vnode->same_comdat_group, part->varpool_set))
+    add_varpool_node_to_partition (part, vnode->same_comdat_group);
+}
+
 /* Group cgrah nodes by input files.  This is used mainly for testing
    right now.  */
 
@@ -577,6 +640,10 @@
       /* Nodes without a body do not need partitioning.  */
       if (!node->analyzed)
 	continue;
+      /* Extern inlines and comdat are always only in partitions they are needed.  */
+      if (DECL_EXTERNAL (node->decl)
+	  || DECL_COMDAT (node->decl))
+	continue;
 
       file_data = node->local.lto_file_data;
       gcc_assert (!node->same_body_alias && file_data);
@@ -599,6 +666,10 @@
     {
       if (vnode->alias || !vnode->needed)
 	continue;
+      /* Constant pool and comdat are always only in partitions they are needed.  */
+      if (DECL_IN_CONSTANT_POOL (vnode->decl)
+	  || DECL_COMDAT (vnode->decl))
+	continue;
       file_data = vnode->lto_file_data;
       slot = pointer_map_contains (pmap, file_data);
       if (slot)
@@ -611,8 +682,12 @@
 	  npartitions++;
 	}
 
-      varpool_node_set_add (partition->varpool_set, vnode);
+      add_varpool_node_to_partition (partition, vnode);
     }
+  for (node = cgraph_nodes; node; node = node->next)
+    node->aux = NULL;
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    vnode->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.  */
@@ -704,7 +779,7 @@
 	    continue;
 	  if (node->global.inlined_to)
 	    continue;
-	  if (!DECL_EXTERNAL (node->decl)
+	  if ((!DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
 	      && (referenced_from_other_partition_p (&node->ref_list, set, vset)
 		  || reachable_from_other_partition_p (node, set)))
 	    promote_fn (node);
@@ -715,10 +790,10 @@
 	  /* Constant pool references use internal labels and thus can not
 	     be made global.  It is sensible to keep those ltrans local to
 	     allow better optimization.  */
-	  if (!DECL_IN_CONSTANT_POOL (vnode->decl)
-	     && !vnode->externally_visible && vnode->analyzed
-	     && referenced_from_other_partition_p (&vnode->ref_list,
-						   set, vset))
+	  if (!DECL_IN_CONSTANT_POOL (vnode->decl) && !DECL_COMDAT (vnode->decl)
+	      && !vnode->externally_visible && vnode->analyzed
+	      && referenced_from_other_partition_p (&vnode->ref_list,
+						    set, vset))
 	    promote_var (vnode);
 	}
 
