OSDN Git Service

* gcc-interface/trans.c (can_equal_min_or_max_val_p): Be prepared for
[pf3gnuchains/gcc-fork.git] / gcc / varpool.c
index 43ee229..c2d88c3 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);
@@ -427,6 +414,20 @@ varpool_finalize_decl (tree decl)
     varpool_assemble_pending_decls ();
 }
 
+/* Add the variable DECL to the varpool.
+   Unlike varpool_finalize_decl function is intended to be used
+   by middle end and allows insertion of new variable at arbitrary point
+   of compilation.  */
+void
+varpool_add_new_variable (tree decl)
+{
+  struct varpool_node *node;
+  varpool_finalize_decl (decl);
+  node = varpool_node (decl);
+  if (varpool_externally_visible_p (node, false))
+    node->externally_visible = true;
+}
+
 /* Return variable availability.  See cgraph.h for description of individual
    return values.  */
 enum availability
@@ -473,7 +474,51 @@ 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);
+          struct varpool_node *n;
+
+         for (n = tgt; n && n->alias;
+              n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
+           if (n == node)
+             {
+               error ("variable %q+D part of alias cycle", node->decl);
+               node->alias = false;
+               continue;
+             }
+         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_EXTERNAL (node->decl) = DECL_EXTERNAL (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 +533,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 +565,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 +720,38 @@ 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;
+  if (!DECL_EXTERNAL (alias))
+    alias_node->finalized = 1;
+  alias_node->alias_of = decl;
+  if ((!DECL_EXTERNAL (alias)
+       && 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 +761,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"