Index: ipa.c
===================================================================
--- ipa.c	(revision 165655)
+++ ipa.c	(working copy)
@@ -607,6 +607,11 @@ cgraph_externally_visible_p (struct cgra
   /* If linker counts on us, we must preserve the function.  */
   if (cgraph_used_from_object_file_p (node))
     return true;
+  if (DECL_PRESERVE_P (node->decl))
+    return true;
+  if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
+    return true;
+
   /* When doing link time optimizations, hidden symbols become local.  */
   if (in_lto_p
       && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
@@ -638,11 +643,64 @@ cgraph_externally_visible_p (struct cgra
 	      return true;
 	}
     }
-  if (DECL_PRESERVE_P (node->decl))
-    return true;
+
   if (MAIN_NAME_P (DECL_NAME (node->decl)))
     return true;
-  if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
+
+  return false;
+}
+
+/* Return true when variable VNODE should be considered externally visible.  */
+
+static bool
+varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
+{
+  if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl))
+    return false;
+
+  /* Do not even try to be smart about aliased nodes.  Until we properly
+     represent everything by same body alias, these are just evil.  */
+  if (aliased)
+    return true;
+
+  /* If linker counts on us, we must preserve the function.  */
+  if (varpool_used_from_object_file_p (vnode))
+    return true;
+
+  if (DECL_PRESERVE_P (vnode->decl))
+    return true;
+  if (lookup_attribute ("externally_visible",
+			DECL_ATTRIBUTES (vnode->decl)))
+    return true;
+
+  /* See if we have linker information about symbol not being used or
+     if we need to make guess based on the declaration.
+
+     Even if the linker clams the symbol is unused, never bring internal
+     symbols that are declared by user as used or externally visible.
+     This is needed for i.e. references from asm statements.   */
+  if (varpool_used_from_object_file_p (vnode))
+    return true;
+
+  /* When doing link time optimizations, hidden symbols become local.  */
+  if (in_lto_p
+      && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN
+	  || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL)
+      /* Be sure that node is defined in IR file, not in other object
+	 file.  In that case we don't set used_from_other_object_file.  */
+      && vnode->finalized)
+    ;
+  else if (!flag_whole_program)
+    return true;
+
+  /* Do not attempt to privatize COMDATS by default.
+     This would break linking with C++ libraries sharing
+     inline definitions.
+
+     FIXME: We can do so for readonly vars with no address taken and
+     possibly also for vtables since no direct pointer comparsion is done.
+     It might be interesting to do so to reduce linking overhead.  */
+  if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl))
     return true;
   return false;
 }
@@ -798,27 +856,9 @@ function_and_variable_visibility (bool w
       if (!vnode->finalized)
         continue;
       if (vnode->needed
-	  && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
-	  && (((!whole_program
-	        /* We can privatize comdat readonly variables whose address is
-		   not taken, but doing so is not going to bring us
-		   optimization oppurtunities until we start reordering
-		   datastructures.  */
-		|| DECL_COMDAT (vnode->decl)
-		|| DECL_WEAK (vnode->decl))
-	       /* When doing linktime optimizations, all hidden symbols will
-		  become local.  */
-	       && (!in_lto_p
-		   || (DECL_VISIBILITY (vnode->decl) != VISIBILITY_HIDDEN
-		       && DECL_VISIBILITY (vnode->decl) != VISIBILITY_INTERNAL)
-		   /* We can get prevailing decision in other object file.
-		      In this case we do not sed used_from_object_file.  */
-		   || !vnode->finalized))
-	      || DECL_PRESERVE_P (vnode->decl)
-              || varpool_used_from_object_file_p (vnode)
-	      || pointer_set_contains (aliased_vnodes, vnode)
-	      || lookup_attribute ("externally_visible",
-				   DECL_ATTRIBUTES (vnode->decl))))
+	  && varpool_externally_visible_p
+	      (vnode, 
+	       pointer_set_contains (aliased_vnodes, vnode)))
 	vnode->externally_visible = true;
       else
         vnode->externally_visible = false;
