lto-symtab.c (lto_varpool_replace_node): Remove code handling extra name aliases.
authorJan Hubicka <jh@suse.cz>
Sat, 18 Jun 2011 08:31:03 +0000 (10:31 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 18 Jun 2011 08:31:03 +0000 (08:31 +0000)
* lto-symtab.c (lto_varpool_replace_node): Remove code handling
extra name aliases.
(lto_symtab_resolve_can_prevail_p): Likewise.
(lto_symtab_merge_cgraph_nodes): Update alias_of pointers.
* cgraphbuild.c (record_reference): Remove extra body alias code.
(mark_load): Likewise.
(mark_store): Likewise.
* cgraph.h (varpool_node): Remove extra_name filed;
add alias_of and extraname_alias.
(varpool_create_variable_alias, varpool_for_node_and_aliases): Declare.
(varpool_alias_aliased_node): New inline function.
(varpool_variable_node): New function.
* cgraphunit.c (handle_alias_pairs): Handle also variable aliases.
* ipa-ref.c (ipa_record_reference): Allow aliases on variables.
* lto-cgraph.c (lto_output_varpool_node): Update streaming.
(input_varpool_node): Likewise.
* lto-streamer-out.c (produce_symtab): Remove extra name aliases.
(varpool_externally_visible_p): Remove extra body alias code.
(function_and_variable_visibility): Likewise.
* tree-ssa-structalias.c (associate_varinfo_to_alias_1): New function.
(ipa_pta_execute): Use it.
* varpool.c (varpool_remove_node): Remove extra name alias code.
(varpool_mark_needed_node): Likewise.
(varpool_analyze_pending_decls): Analyze aliases.
(assemble_aliases): New functoin.
(varpool_assemble_decl): Use it.
(varpool_create_variable_alias): New function.
(varpool_extra_name_alias): Rewrite.
(varpool_for_node_and_aliases): New function.

From-SVN: r175167

gcc/ChangeLog
gcc/cgraph.h
gcc/cgraphbuild.c
gcc/cgraphunit.c
gcc/ipa-ref.c
gcc/lto-cgraph.c
gcc/lto-streamer-out.c
gcc/lto-symtab.c
gcc/tree-ssa-structalias.c
gcc/varpool.c

index 80431630bf5392d99f9f0f567257dca0160fe850..4fe0b105bf0b7aaddaeca47c013f69145dd3bce4 100644 (file)
@@ -1,3 +1,35 @@
+2011-06-18  Jan Hubicka  <jh@suse.cz>
+
+       * lto-symtab.c (lto_varpool_replace_node): Remove code handling
+       extra name aliases.
+       (lto_symtab_resolve_can_prevail_p): Likewise.
+       (lto_symtab_merge_cgraph_nodes): Update alias_of pointers.
+       * cgraphbuild.c (record_reference): Remove extra body alias code.
+       (mark_load): Likewise.
+       (mark_store): Likewise.
+       * cgraph.h (varpool_node): Remove extra_name filed;
+       add alias_of and extraname_alias.
+       (varpool_create_variable_alias, varpool_for_node_and_aliases): Declare.
+       (varpool_alias_aliased_node): New inline function.
+       (varpool_variable_node): New function.
+       * cgraphunit.c (handle_alias_pairs): Handle also variable aliases.
+       * ipa-ref.c (ipa_record_reference): Allow aliases on variables.
+       * lto-cgraph.c (lto_output_varpool_node): Update streaming.
+       (input_varpool_node): Likewise.
+       * lto-streamer-out.c (produce_symtab): Remove extra name aliases.
+       (varpool_externally_visible_p): Remove extra body alias code.
+       (function_and_variable_visibility): Likewise.
+       * tree-ssa-structalias.c (associate_varinfo_to_alias_1): New function.
+       (ipa_pta_execute): Use it.
+       * varpool.c (varpool_remove_node): Remove extra name alias code.
+       (varpool_mark_needed_node): Likewise.
+       (varpool_analyze_pending_decls): Analyze aliases.
+       (assemble_aliases): New functoin.
+       (varpool_assemble_decl): Use it.
+       (varpool_create_variable_alias): New function.
+       (varpool_extra_name_alias): Rewrite.
+       (varpool_for_node_and_aliases): New function.
+
 2011-06-18  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/49411
index feb742d387e16bd07cb08e663e1b0f271604b405..dd08febaf124be293520f64fb3c4d303e3169130 100644 (file)
@@ -380,13 +380,12 @@ DEF_VEC_ALLOC_P(cgraph_edge_p,heap);
 
 struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
   tree decl;
+  /* For aliases points to declaration DECL is alias of.  */
+  tree alias_of;
   /* Pointer to the next function in varpool_nodes.  */
   struct varpool_node *next, *prev;
   /* Pointer to the next function in varpool_nodes_queue.  */
   struct varpool_node *next_needed, *prev_needed;
-  /* For normal nodes a pointer to the first extra name alias.  For alias
-     nodes a pointer to the normal node.  */
-  struct varpool_node *extra_name;
   /* Circular list of nodes in the same comdat group if non-NULL.  */
   struct varpool_node *same_comdat_group;
   struct ipa_ref_list ref_list;
@@ -415,6 +414,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
   /* Set for aliases once they got through assemble_alias.  Also set for
      extra name aliases in varpool_extra_name_alias.  */
   unsigned alias : 1;
+  unsigned extra_name_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.
@@ -665,9 +665,13 @@ bool varpool_analyze_pending_decls (void);
 void varpool_remove_unreferenced_decls (void);
 void varpool_empty_needed_queue (void);
 struct varpool_node * varpool_extra_name_alias (tree, tree);
+struct varpool_node * varpool_create_variable_alias (tree, tree);
 const char * varpool_node_name (struct varpool_node *node);
 void varpool_reset_queue (void);
 bool const_value_known_p (tree);
+bool varpool_for_node_and_aliases (struct varpool_node *,
+                                  bool (*) (struct varpool_node *, void *),
+                                  void *, bool);
 
 /* Walk all reachable static variables.  */
 #define FOR_EACH_STATIC_VARIABLE(node) \
@@ -968,6 +972,20 @@ cgraph_alias_aliased_node (struct cgraph_node *n)
   return NULL;
 }
 
+/* Return node that alias N is aliasing.  */
+
+static inline struct varpool_node *
+varpool_alias_aliased_node (struct varpool_node *n)
+{
+  struct ipa_ref *ref;
+
+  ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
+  gcc_checking_assert (ref->use == IPA_REF_ALIAS);
+  if (ref->refered_type == IPA_REF_CGRAPH)
+    return ipa_ref_varpool_node (ref);
+  return NULL;
+}
+
 /* Given NODE, walk the alias chain to return the function NODE is alias of.
    Walk through thunk, too.
    When AVAILABILITY is non-NULL, get minimal availablity in the chain.  */
@@ -1026,6 +1044,34 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai
   return NULL;
 }
 
+/* Given NODE, walk the alias chain to return the function NODE is alias of.
+   Do not walk through thunks.
+   When AVAILABILITY is non-NULL, get minimal availablity in the chain.  */
+
+static inline struct varpool_node *
+varpool_variable_node (struct varpool_node *node, enum availability *availability)
+{
+  if (availability)
+    *availability = cgraph_variable_initializer_availability (node);
+  while (node)
+    {
+      if (node->alias && node->analyzed)
+       node = varpool_alias_aliased_node (node);
+      else
+       return node;
+      if (node && availability)
+       {
+         enum availability a;
+         a = cgraph_variable_initializer_availability (node);
+         if (a < *availability)
+           *availability = a;
+       }
+    }
+  if (*availability)
+    *availability = AVAIL_NOT_AVAILABLE;
+  return NULL;
+}
+
 /* Return true when the edge E represents a direct recursion.  */
 static inline bool
 cgraph_edge_recursive_p (struct cgraph_edge *e)
index 961804b415e04d312c8fcbc1e1e206d1b161c692..8bf883005936bbf12058860a85e56faad480e236 100644 (file)
@@ -87,8 +87,6 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
          if (lang_hooks.callgraph.analyze_expr)
            lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
          varpool_mark_needed_node (vnode);
-         if (vnode->alias && vnode->extra_name)
-           vnode = vnode->extra_name;
          ipa_record_reference (NULL, ctx->varpool_node,
                                NULL, vnode,
                                IPA_REF_ADDR, NULL);
@@ -261,8 +259,6 @@ mark_address (gimple stmt, tree addr, void *data)
       if (lang_hooks.callgraph.analyze_expr)
        lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
       varpool_mark_needed_node (vnode);
-      if (vnode->alias && vnode->extra_name)
-       vnode = vnode->extra_name;
       ipa_record_reference ((struct cgraph_node *)data, NULL,
                            NULL, vnode,
                            IPA_REF_ADDR, stmt);
@@ -296,8 +292,6 @@ mark_load (gimple stmt, tree t, void *data)
       if (lang_hooks.callgraph.analyze_expr)
        lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
       varpool_mark_needed_node (vnode);
-      if (vnode->alias && vnode->extra_name)
-       vnode = vnode->extra_name;
       ipa_record_reference ((struct cgraph_node *)data, NULL,
                            NULL, vnode,
                            IPA_REF_LOAD, stmt);
@@ -320,8 +314,6 @@ mark_store (gimple stmt, tree t, void *data)
       if (lang_hooks.callgraph.analyze_expr)
        lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
       varpool_mark_needed_node (vnode);
-      if (vnode->alias && vnode->extra_name)
-       vnode = vnode->extra_name;
       ipa_record_reference ((struct cgraph_node *)data, NULL,
                            NULL, vnode,
                            IPA_REF_STORE, stmt);
index 88d0face01036a86e42dae49ea96ef7af56ebfae..6683d2a5df375f62cec0792d94bdd90ca3ce11ed 100644 (file)
@@ -1186,6 +1186,7 @@ handle_alias_pairs (void)
   unsigned i;
   struct cgraph_node *target_node;
   struct cgraph_node *src_node;
+  struct varpool_node *target_vnode;
   
   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p);)
     {
@@ -1206,6 +1207,20 @@ handle_alias_pairs (void)
          cgraph_create_function_alias (p->decl, target_node->decl);
          VEC_unordered_remove (alias_pair, alias_pairs, i);
        }
+      else if (TREE_CODE (p->decl) == VAR_DECL
+              && !lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+              && (target_vnode = varpool_node_for_asm (p->target)) != NULL)
+       {
+         /* Normally EXTERNAL flag is used to mark external inlines,
+            however for aliases it seems to be allowed to use it w/o
+            any meaning. See gcc.dg/attr-alias-3.c  
+            However for weakref we insist on EXTERNAL flag being set.
+            See gcc.dg/attr-alias-5.c  */
+         if (DECL_EXTERNAL (p->decl))
+           DECL_EXTERNAL (p->decl) = 0;
+         varpool_create_variable_alias (p->decl, target_vnode->decl);
+         VEC_unordered_remove (alias_pair, alias_pairs, i);
+       }
       else
        {
          if (dump_file)
index f5fd03f67fba09abb8035a7fa91ac96d600815a9..8520bca33acf3d5e6c8fb2fef42d48ee7d42bf97 100644 (file)
@@ -68,7 +68,7 @@ ipa_record_reference (struct cgraph_node *refering_node,
     {
       ref->refering.varpool_node = refering_varpool_node;
       ref->refering_type = IPA_REF_VARPOOL;
-      gcc_assert (use_type == IPA_REF_ADDR);
+      gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS);
     }
   if (refered_node)
     {
index 169de382dbe3a35df6437064fc0344e4afa7039e..9d9cb4366a0bfb2fce7cace7d61c623a1d6d2eac 100644 (file)
@@ -544,8 +544,6 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
 {
   bool boundary_p = !varpool_node_in_set_p (node, vset) && node->analyzed;
   struct bitpack_d bp;
-  struct varpool_node *alias;
-  int count = 0;
   int ref;
 
   lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->decl);
@@ -554,7 +552,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->finalized, 1);
   bp_pack_value (&bp, node->alias, 1);
-  gcc_assert (!node->alias || !node->extra_name);
+  bp_pack_value (&bp, node->alias_of != NULL, 1);
   gcc_assert (node->finalized || !node->analyzed);
   gcc_assert (node->needed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
@@ -573,11 +571,9 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
                                                           set, vset), 1);
       bp_pack_value (&bp, boundary_p, 1);  /* in_other_partition.  */
     }
-  /* Also emit any extra name aliases.  */
-  for (alias = node->extra_name; alias; alias = alias->next)
-    count++;
-  bp_pack_value (&bp, count != 0, 1);
   lto_output_bitpack (&bp);
+  if (node->alias_of)
+    lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->alias_of);
   if (node->same_comdat_group && !boundary_p)
     {
       ref = lto_varpool_encoder_lookup (varpool_encoder, node->same_comdat_group);
@@ -588,17 +584,6 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
   lto_output_sleb128_stream (ob->main_stream, ref);
   lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution,
                   LDPR_NUM_KNOWN, node->resolution);
-
-  if (count)
-    {
-      lto_output_uleb128_stream (ob->main_stream, count);
-      for (alias = node->extra_name; alias; alias = alias->next)
-       {
-         lto_output_var_decl_index (ob->decl_state, ob->main_stream, alias->decl);
-         lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution,
-                          LDPR_NUM_KNOWN, alias->resolution);
-       }
-    }
 }
 
 /* Output the varpool NODE to OB. 
@@ -780,7 +765,7 @@ compute_ltrans_boundary (struct lto_out_decl_state *state,
   for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
     {
       struct varpool_node *vnode = vsi_node (vsi);
-      gcc_assert (!vnode->alias);
+      gcc_assert (!vnode->alias || vnode->alias_of);
       lto_varpool_encoder_encode (varpool_encoder, vnode);
       lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
       add_references (encoder, varpool_encoder, &vnode->ref_list);
@@ -1054,9 +1039,8 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   tree var_decl;
   struct varpool_node *node;
   struct bitpack_d bp;
-  bool aliases_p;
-  int count;
   int ref = LCC_NOT_FOUND;
+  bool non_null_aliasof;
 
   decl_index = lto_input_uleb128 (ib);
   var_decl = lto_file_decl_data_get_var_decl (file_data, decl_index);
@@ -1068,6 +1052,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   node->force_output = bp_unpack_value (&bp, 1);
   node->finalized = bp_unpack_value (&bp, 1);
   node->alias = bp_unpack_value (&bp, 1);
+  non_null_aliasof = bp_unpack_value (&bp, 1);
   node->analyzed = node->finalized; 
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
@@ -1076,27 +1061,19 @@ input_varpool_node (struct lto_file_decl_data *file_data,
       DECL_EXTERNAL (node->decl) = 1;
       TREE_STATIC (node->decl) = 0;
     }
-  aliases_p = bp_unpack_value (&bp, 1);
   if (node->finalized)
     varpool_mark_needed_node (node);
+  if (non_null_aliasof)
+    {
+      decl_index = lto_input_uleb128 (ib);
+      node->alias_of = lto_file_decl_data_get_var_decl (file_data, decl_index);
+    }
   ref = lto_input_sleb128 (ib);
   /* Store a reference for now, and fix up later to be a pointer.  */
   node->same_comdat_group = (struct varpool_node *) (intptr_t) ref;
   node->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution,
                                     LDPR_NUM_KNOWN);
-  if (aliases_p)
-    {
-      count = lto_input_uleb128 (ib);
-      for (; count > 0; count --)
-       {
-         tree decl = lto_file_decl_data_get_var_decl (file_data,
-                                                      lto_input_uleb128 (ib));
-         struct varpool_node *alias;
-         alias = varpool_extra_name_alias (decl, var_decl);
-         alias->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution,
-                                             LDPR_NUM_KNOWN);
-       }
-    }
+
   return node;
 }
 
index a28e857617d5290c65748a36ace1d429d835a8bb..19b0ae8bb1e59627a8a96d27620eb389778f60cb 100644 (file)
@@ -2557,7 +2557,7 @@ produce_symtab (struct output_block *ob,
   char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
   struct pointer_set_t *seen;
   struct cgraph_node *node;
-  struct varpool_node *vnode, *valias;
+  struct varpool_node *vnode;
   struct lto_output_stream stream;
   lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
   lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder;
@@ -2617,11 +2617,9 @@ produce_symtab (struct output_block *ob,
          && vnode->finalized 
          && DECL_VIRTUAL_P (vnode->decl))
        continue;
-      if (vnode->alias)
+      if (vnode->alias && !vnode->alias_of)
        continue;
       write_symbol (cache, &stream, vnode->decl, seen, false);
-      for (valias = vnode->extra_name; valias; valias = valias->next)
-        write_symbol (cache, &stream, valias->decl, seen, true);
     }
   for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++)
     {
@@ -2633,11 +2631,9 @@ produce_symtab (struct output_block *ob,
          && vnode->finalized 
          && DECL_VIRTUAL_P (vnode->decl))
        continue;
-      if (vnode->alias)
+      if (vnode->alias && !vnode->alias_of)
        continue;
       write_symbol (cache, &stream, vnode->decl, seen, false);
-      for (valias = vnode->extra_name; valias; valias = valias->next)
-        write_symbol (cache, &stream, valias->decl, seen, true);
     }
 
   /* Write all aliases.  */
index d58da8df2db7e3d2b9f1435788cacc99ccfa0edc..2bbf064ee7d52be4fd99a2e9ee2ad519f04b6f71 100644 (file)
@@ -268,32 +268,9 @@ lto_varpool_replace_node (struct varpool_node *vnode,
       gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
       varpool_mark_needed_node (prevailing_node);
     }
-  /* Relink aliases.  */
-  if (vnode->extra_name && !vnode->alias)
-    {
-      struct varpool_node *alias, *last;
-      for (alias = vnode->extra_name;
-          alias; alias = alias->next)
-       {
-         last = alias;
-         alias->extra_name = prevailing_node;
-       }
-
-      if (prevailing_node->extra_name)
-       {
-         last->next = prevailing_node->extra_name;
-         prevailing_node->extra_name->prev = last;
-       }
-      prevailing_node->extra_name = vnode->extra_name;
-      vnode->extra_name = NULL;
-    }
   gcc_assert (!vnode->finalized || prevailing_node->finalized);
   gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
 
-  /* When replacing by an alias, the references goes to the original
-     variable.  */
-  if (prevailing_node->alias && prevailing_node->extra_name)
-    prevailing_node = prevailing_node->extra_name;
   ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
 
   /* Be sure we can garbage collect the initializer.  */
@@ -438,14 +415,11 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
   if (TREE_CODE (e->decl) == FUNCTION_DECL)
     return (e->node && e->node->analyzed);
 
-  /* A variable should have a size.  */
   else if (TREE_CODE (e->decl) == VAR_DECL)
     {
       if (!e->vnode)
        return false;
-      if (e->vnode->finalized)
-       return true;
-      return e->vnode->alias && e->vnode->extra_name->finalized;
+      return e->vnode->finalized;
     }
 
   gcc_unreachable ();
@@ -779,6 +753,7 @@ void
 lto_symtab_merge_cgraph_nodes (void)
 {
   struct cgraph_node *node;
+  struct varpool_node *vnode;
   lto_symtab_maybe_init_hash_table ();
   htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
 
@@ -786,6 +761,9 @@ lto_symtab_merge_cgraph_nodes (void)
     if ((node->thunk.thunk_p || node->alias)
        && node->thunk.alias)
       node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    if (vnode->alias_of)
+      vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of);
 }
 
 /* Given the decl DECL, return the prevailing decl with the same name. */
index d5516e673fa8e8422204719f78612dccac6f6ceb..6f076dcd3e7a5c13b87e4edc665429331c5eab58 100644 (file)
@@ -6685,6 +6685,16 @@ associate_varinfo_to_alias (struct cgraph_node *node, void *data)
   return false;
 }
 
+/* Associate node with varinfo DATA. Worker for
+   varpool_for_node_and_aliases.  */
+static bool
+associate_varinfo_to_alias_1 (struct varpool_node *node, void *data)
+{
+  if (node->alias)
+    insert_vi_for_tree (node->decl, (varinfo_t)data);
+  return false;
+}
+
 /* Execute the driver for IPA PTA.  */
 static unsigned int
 ipa_pta_execute (void)
@@ -6716,14 +6726,12 @@ ipa_pta_execute (void)
   /* Create constraints for global variables and their initializers.  */
   for (var = varpool_nodes; var; var = var->next)
     {
-      struct varpool_node *alias;
       varinfo_t vi;
+      if (var->alias)
+       continue;
 
       vi = get_vi_for_tree (var->decl);
-
-      /* Associate the varinfo node with all aliases.  */
-      for (alias = var->extra_name; alias; alias = alias->next)
-       insert_vi_for_tree (alias->decl, vi);
+      varpool_for_node_and_aliases (var, associate_varinfo_to_alias_1, vi, true);
     }
 
   if (dump_file)
index 43ee22903896b6171a4cfbb729ba5237e8ca599f..d223779a5c195e877688d6e36f4d30798249f47a 100644 (file)
@@ -131,7 +131,7 @@ varpool_node (tree decl)
   struct varpool_node key, *node, **slot;
 
   gcc_assert (TREE_CODE (decl) == VAR_DECL
-             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)));
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p));
 
   if (!varpool_hash)
     varpool_hash = htab_create_ggc (10, hash_varpool_node,
@@ -162,25 +162,14 @@ varpool_remove_node (struct varpool_node *node)
   gcc_assert (*slot == node);
   htab_clear_slot (varpool_hash, slot);
   gcc_assert (!varpool_assembled_nodes_queue);
-  if (!node->alias)
-    while (node->extra_name)
-      varpool_remove_node (node->extra_name);
   if (node->next)
     node->next->prev = node->prev;
   if (node->prev)
     node->prev->next = node->next;
   else
     {
-      if (node->alias && node->extra_name)
-       {
-          gcc_assert (node->extra_name->extra_name == node);
-         node->extra_name->extra_name = node->next;
-       }
-      else
-       {
-          gcc_assert (varpool_nodes == node);
-          varpool_nodes = node->next;
-       }
+      gcc_assert (varpool_nodes == node);
+      varpool_nodes = node->next;
     }
   if (varpool_first_unanalyzed_node == node)
     varpool_first_unanalyzed_node = node->next_needed;
@@ -311,8 +300,6 @@ varpool_enqueue_needed_node (struct varpool_node *node)
 void
 varpool_mark_needed_node (struct varpool_node *node)
 {
-  if (node->alias && node->extra_name)
-    node = node->extra_name;
   if (!node->needed && node->finalized
       && !TREE_ASM_WRITTEN (node->decl))
     varpool_enqueue_needed_node (node);
@@ -473,7 +460,40 @@ varpool_analyze_pending_decls (void)
             already informed about increased alignment.  */
           align_variable (decl, 0);
        }
-      if (DECL_INITIAL (decl))
+      if (node->alias && node->alias_of)
+       {
+         struct varpool_node *tgt = varpool_node (node->alias_of);
+         if (!VEC_length (ipa_ref_t, node->ref_list.references))
+           ipa_record_reference (NULL, node, NULL, tgt, IPA_REF_ALIAS, NULL);
+         /* C++ FE sometimes change linkage flags after producing same body aliases.  */
+         if (node->extra_name_alias)
+           {
+             DECL_WEAK (node->decl) = DECL_WEAK (node->alias_of);
+             TREE_PUBLIC (node->decl) = TREE_PUBLIC (node->alias_of);
+             DECL_VISIBILITY (node->decl) = DECL_VISIBILITY (node->alias_of);
+             if (TREE_PUBLIC (node->decl))
+               {
+                 DECL_COMDAT (node->decl) = DECL_COMDAT (node->alias_of);
+                 DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->alias_of);
+                 if (DECL_ONE_ONLY (node->alias_of) && !node->same_comdat_group)
+                   {
+                     node->same_comdat_group = tgt;
+                     if (!tgt->same_comdat_group)
+                       tgt->same_comdat_group = node;
+                     else
+                       {
+                         struct varpool_node *n;
+                         for (n = tgt->same_comdat_group;
+                              n->same_comdat_group != tgt;
+                              n = n->same_comdat_group)
+                           ;
+                         n->same_comdat_group = node;
+                       }
+                   }
+               }
+           }
+       }
+      else if (DECL_INITIAL (decl))
        record_references_in_initializer (decl, analyzed);
       if (node->same_comdat_group)
        {
@@ -488,6 +508,23 @@ varpool_analyze_pending_decls (void)
   return changed;
 }
 
+/* Assemble thunks and aliases asociated to NODE.  */
+
+static void
+assemble_aliases (struct varpool_node *node)
+{
+  int i;
+  struct ipa_ref *ref;
+  for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+    if (ref->use == IPA_REF_ALIAS)
+      {
+       struct varpool_node *alias = ipa_ref_refering_varpool_node (ref);
+       assemble_alias (alias->decl,
+                       DECL_ASSEMBLER_NAME (alias->alias_of));
+       assemble_aliases (alias);
+      }
+}
+
 /* Output one variable, if necessary.  Return whether we output it.  */
 bool
 varpool_assemble_decl (struct varpool_node *node)
@@ -503,25 +540,13 @@ varpool_assemble_decl (struct varpool_node *node)
       assemble_variable (decl, 0, 1, 0);
       if (TREE_ASM_WRITTEN (decl))
        {
-         struct varpool_node *alias;
-
          node->next_needed = varpool_assembled_nodes_queue;
          node->prev_needed = NULL;
          if (varpool_assembled_nodes_queue)
            varpool_assembled_nodes_queue->prev_needed = node;
          varpool_assembled_nodes_queue = node;
          node->finalized = 1;
-
-         /* Also emit any extra name aliases.  */
-         for (alias = node->extra_name; alias; alias = alias->next)
-           {
-             /* Update linkage fields in case they've changed.  */
-             DECL_WEAK (alias->decl) = DECL_WEAK (decl);
-             TREE_PUBLIC (alias->decl) = TREE_PUBLIC (decl);
-             DECL_VISIBILITY (alias->decl) = DECL_VISIBILITY (decl);
-             assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl));
-           }
-
+         assemble_aliases (node);
          return true;
        }
     }
@@ -670,38 +695,36 @@ add_new_static_var (tree type)
    Extra name aliases are output whenever DECL is output.  */
 
 struct varpool_node *
-varpool_extra_name_alias (tree alias, tree decl)
+varpool_create_variable_alias (tree alias, tree decl)
 {
-  struct varpool_node key, *alias_node, *decl_node, **slot;
-
-#ifndef ASM_OUTPUT_DEF
-  /* If aliases aren't supported by the assembler, fail.  */
-  return NULL;
-#endif
+  struct varpool_node *alias_node;
 
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
   gcc_assert (TREE_CODE (alias) == VAR_DECL);
-  /* Make sure the hash table has been created.  */
-  decl_node = varpool_node (decl);
-
-  key.decl = alias;
+  alias_node = varpool_node (alias);
+  alias_node->alias = 1;
+  alias_node->finalized = 1;
+  alias_node->alias_of = decl;
+  if (decide_is_variable_needed (alias_node, alias)
+      || alias_node->needed)
+    varpool_mark_needed_node (alias_node);
+  return alias_node;
+}
 
-  slot = (struct varpool_node **) htab_find_slot (varpool_hash, &key, INSERT);
+/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+   Extra name aliases are output whenever DECL is output.  */
 
-  /* If the varpool_node has been already created, fail.  */
-  if (*slot)
-    return NULL;
+struct varpool_node *
+varpool_extra_name_alias (tree alias, tree decl)
+{
+  struct varpool_node *alias_node;
 
-  alias_node = ggc_alloc_cleared_varpool_node ();
-  alias_node->decl = alias;
-  alias_node->alias = 1;
-  alias_node->extra_name = decl_node;
-  alias_node->next = decl_node->extra_name;
-  ipa_empty_ref_list (&alias_node->ref_list);
-  if (decl_node->extra_name)
-    decl_node->extra_name->prev = alias_node;
-  decl_node->extra_name = alias_node;
-  *slot = alias_node;
+#ifndef ASM_OUTPUT_DEF
+  /* If aliases aren't supported by the assembler, fail.  */
+  return NULL;
+#endif
+  alias_node = varpool_create_variable_alias (alias, decl);
+  alias_node->extra_name_alias = true;
   return alias_node;
 }
 
@@ -711,17 +734,38 @@ varpool_extra_name_alias (tree alias, tree decl)
 bool
 varpool_used_from_object_file_p (struct varpool_node *node)
 {
-  struct varpool_node *alias;
-
   if (!TREE_PUBLIC (node->decl))
     return false;
   if (resolution_used_from_other_file_p (node->resolution))
     return true;
-  for (alias = node->extra_name; alias; alias = alias->next)
-    if (TREE_PUBLIC (alias->decl)
-       && resolution_used_from_other_file_p (alias->resolution))
-      return true;
   return false;
 }
 
+/* Call calback on NODE and aliases asociated to NODE. 
+   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   skipped. */
+
+bool
+varpool_for_node_and_aliases (struct varpool_node *node,
+                             bool (*callback) (struct varpool_node *, void *),
+                             void *data,
+                             bool include_overwritable)
+{
+  int i;
+  struct ipa_ref *ref;
+
+  if (callback (node, data))
+    return true;
+  for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+    if (ref->use == IPA_REF_ALIAS)
+      {
+       struct varpool_node *alias = ipa_ref_refering_varpool_node (ref);
+       if (include_overwritable
+           || cgraph_variable_initializer_availability (alias) > AVAIL_OVERWRITABLE)
+          if (varpool_for_node_and_aliases (alias, callback, data,
+                                          include_overwritable))
+           return true;
+      }
+  return false;
+}
 #include "gt-varpool.h"