OSDN Git Service

* gcc-interface/trans.c (Call_to_gnu): Robustify test for function case
[pf3gnuchains/gcc-fork.git] / gcc / varpool.c
index a3be262..c2d88c3 100644 (file)
@@ -1,5 +1,5 @@
 /* Callgraph handling code.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
@@ -107,15 +107,16 @@ eq_varpool_node (const void *p1, const void *p2)
 
 /* Return varpool node assigned to DECL without creating new one.  */
 struct varpool_node *
-varpool_get_node (tree decl)
+varpool_get_node (const_tree decl)
 {
   struct varpool_node key, **slot;
 
-  gcc_assert (DECL_P (decl) && TREE_CODE (decl) != FUNCTION_DECL);
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)));
 
   if (!varpool_hash)
     return NULL;
-  key.decl = decl;
+  key.decl = CONST_CAST2 (tree, const_tree, decl);
   slot = (struct varpool_node **)
     htab_find_slot (varpool_hash, &key, NO_INSERT);
   if (!slot)
@@ -129,7 +130,8 @@ varpool_node (tree decl)
 {
   struct varpool_node key, *node, **slot;
 
-  gcc_assert (DECL_P (decl) && TREE_CODE (decl) != FUNCTION_DECL);
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p));
 
   if (!varpool_hash)
     varpool_hash = htab_create_ggc (10, hash_varpool_node,
@@ -139,7 +141,7 @@ varpool_node (tree decl)
     htab_find_slot (varpool_hash, &key, INSERT);
   if (*slot)
     return *slot;
-  node = GGC_CNEW (struct varpool_node);
+  node = ggc_alloc_cleared_varpool_node ();
   node->decl = decl;
   node->order = cgraph_order++;
   node->next = varpool_nodes;
@@ -160,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;
@@ -239,6 +230,9 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
     fprintf (f, " output");
   if (node->externally_visible)
     fprintf (f, " externally_visible");
+  if (node->resolution != LDPR_UNKNOWN)
+    fprintf (f, " %s",
+            ld_plugin_symbol_resolution_names[(int)node->resolution]);
   if (node->in_other_partition)
     fprintf (f, " in_other_partition");
   else if (node->used_from_other_partition)
@@ -306,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);
@@ -329,42 +321,64 @@ varpool_reset_queue (void)
 bool
 decide_is_variable_needed (struct varpool_node *node, tree decl)
 {
-  if (node->used_from_other_partition)
-    return true;
   /* If the user told us it is used, then it must be so.  */
-  if ((node->externally_visible && !DECL_COMDAT (decl))
-      || node->force_output)
+  if (node->force_output)
     return true;
 
+  gcc_assert (!DECL_EXTERNAL (decl));
+
   /* Externally visible variables must be output.  The exception is
      COMDAT variables that must be output only when they are needed.  */
   if (TREE_PUBLIC (decl)
-      && !flag_whole_program
-      && !flag_lto
-      && !flag_whopr
       && !DECL_COMDAT (decl)
       && !DECL_EXTERNAL (decl))
     return true;
 
-  /* When emulating tls, we actually see references to the control
-     variable, rather than the user-level variable.  */
-  if (!targetm.have_tls
-      && TREE_CODE (decl) == VAR_DECL
-      && DECL_THREAD_LOCAL_P (decl))
-    {
-      tree control = emutls_decl (decl);
-      if (decide_is_variable_needed (varpool_node (control), control))
-       return true;
-    }
-
   /* When not reordering top level variables, we have to assume that
      we are going to keep everything.  */
-  if (flag_toplevel_reorder)
+  if (!flag_toplevel_reorder)
+    return true;
+  return false;
+}
+
+/* Return if DECL is constant and its initial value is known (so we can do
+   constant folding using DECL_INITIAL (decl)).  */
+
+bool
+const_value_known_p (tree decl)
+{
+  if (TREE_CODE (decl) != VAR_DECL
+      &&TREE_CODE (decl) != CONST_DECL)
+    return false;
+
+  if (TREE_CODE (decl) == CONST_DECL
+      || DECL_IN_CONSTANT_POOL (decl))
+    return true;
+
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+  if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl))
     return false;
 
-  /* We want to emit COMDAT variables only when absolutely necessary.  */
-  if (DECL_COMDAT (decl))
+  /* Gimplifier takes away constructors of local vars  */
+  if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+    return DECL_INITIAL (decl) != NULL;
+
+  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
+
+  /* Variables declared 'const' without an initializer
+     have zero as the initializer if they may not be
+     overridden at link or run time.  */
+  if (!DECL_INITIAL (decl)
+      && (DECL_EXTERNAL (decl)
+         || decl_replaceable_p (decl)))
     return false;
+
+  /* Variables declared `const' with an initializer are considered
+     to not be overwritable with different initializer by default. 
+
+     ??? Previously we behaved so for scalar variables but not for array
+     accesses.  */
   return true;
 }
 
@@ -376,6 +390,8 @@ varpool_finalize_decl (tree decl)
 {
   struct varpool_node *node = varpool_node (decl);
 
+  gcc_assert (TREE_STATIC (decl));
+
   /* The first declaration of a variable that comes through this function
      decides whether it is global (in C, has external linkage)
      or local (in C, has internal linkage).  So do nothing more
@@ -394,15 +410,24 @@ varpool_finalize_decl (tree decl)
 
   if (decide_is_variable_needed (node, decl))
     varpool_mark_needed_node (node);
-  /* Since we reclaim unreachable nodes at the end of every language
-     level unit, we need to be conservative about possible entry points
-     there.  */
-  else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
-    varpool_mark_needed_node (node);
   if (cgraph_global_info_ready)
     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
@@ -416,7 +441,7 @@ cgraph_variable_initializer_availability (struct varpool_node *node)
   /* If the variable can be overwritten, return OVERWRITABLE.  Takes
      care of at least two notable extensions - the COMDAT variables
      used to share template instantiations in C++.  */
-  if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
+  if (!decl_replaceable_p (node->decl))
     return AVAIL_OVERWRITABLE;
   return AVAIL_AVAILABLE;
 }
@@ -449,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)
        {
@@ -464,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)
@@ -479,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;
        }
     }
@@ -524,18 +598,14 @@ varpool_remove_unreferenced_decls (void)
 
   while (node)
     {
-      tree decl = node->decl;
       next = node->next_needed;
       node->needed = 0;
 
-      if (node->finalized
-         && (decide_is_variable_needed (node, decl)
-             /* ??? Cgraph does not yet rule the world with an iron hand,
-                and does not control the emission of debug information.
-                After a variable has its DECL_RTL set, we must assume that
-                it may be referenced by the debug information, and we can
-                no longer elide it.  */
-             || DECL_RTL_SET_P (decl)))
+      if (node->analyzed
+         && (!varpool_can_remove_if_no_refs (node)
+             /* We just expanded all function bodies.  See if any of
+                them needed the variable.  */
+             || DECL_RTL_SET_P (node->decl)))
        varpool_mark_needed_node (node);
 
       node = next;
@@ -545,11 +615,29 @@ varpool_remove_unreferenced_decls (void)
   varpool_analyze_pending_decls ();
 }
 
+/* For variables in named sections make sure get_variable_section
+   is called before we switch to those sections.  Then section
+   conflicts between read-only and read-only requiring relocations
+   sections can be resolved.  */
+void
+varpool_finalize_named_section_flags (struct varpool_node *node)
+{
+  if (!TREE_ASM_WRITTEN (node->decl)
+      && !node->alias
+      && !node->in_other_partition
+      && !DECL_EXTERNAL (node->decl)
+      && TREE_CODE (node->decl) == VAR_DECL
+      && !DECL_HAS_VALUE_EXPR_P (node->decl)
+      && DECL_SECTION_NAME (node->decl))
+    get_variable_section (node->decl, false);
+}
+
 /* Output all variables enqueued to be assembled.  */
 bool
 varpool_assemble_pending_decls (void)
 {
   bool changed = false;
+  struct varpool_node *node;
 
   if (seen_error ())
     return false;
@@ -560,6 +648,9 @@ varpool_assemble_pending_decls (void)
      elsewhere.  */
   varpool_analyze_pending_decls ();
 
+  for (node = varpool_nodes_queue; node; node = node->next_needed)
+    varpool_finalize_named_section_flags (node);
+
   while (varpool_nodes_queue)
     {
       struct varpool_node *node = varpool_nodes_queue;
@@ -628,40 +719,80 @@ add_new_static_var (tree type)
 /* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
    Extra name aliases are output whenever DECL is output.  */
 
-bool
+struct varpool_node *
+varpool_create_variable_alias (tree alias, tree decl)
+{
+  struct varpool_node *alias_node;
+
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  gcc_assert (TREE_CODE (alias) == VAR_DECL);
+  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;
+}
+
+/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+   Extra name aliases are output whenever DECL is output.  */
+
+struct varpool_node *
 varpool_extra_name_alias (tree alias, tree decl)
 {
-  struct varpool_node key, *alias_node, *decl_node, **slot;
+  struct varpool_node *alias_node;
 
 #ifndef ASM_OUTPUT_DEF
   /* If aliases aren't supported by the assembler, fail.  */
-  return false;
+  return NULL;
 #endif
+  alias_node = varpool_create_variable_alias (alias, decl);
+  alias_node->extra_name_alias = true;
+  return 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);
+/* Return true when NODE is known to be used from other (non-LTO) object file.
+   Known only when doing LTO via linker plugin.  */
 
-  key.decl = alias;
+bool
+varpool_used_from_object_file_p (struct varpool_node *node)
+{
+  if (!TREE_PUBLIC (node->decl))
+    return false;
+  if (resolution_used_from_other_file_p (node->resolution))
+    return true;
+  return false;
+}
 
-  slot = (struct varpool_node **) htab_find_slot (varpool_hash, &key, INSERT);
+/* Call calback on NODE and aliases asociated to NODE. 
+   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   skipped. */
 
-  /* If the varpool_node has been already created, fail.  */
-  if (*slot)
-    return false;
+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;
 
-  alias_node = GGC_CNEW (struct 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;
-  return true;
+  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"