]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/varpool.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / varpool.c
index 79f07bfd2ff3abbcfa6b53a3444fc29feff654d0..458cdf1bf376d54ce441f9f79a934d35cc2b3fdd 100644 (file)
@@ -1,5 +1,5 @@
 /* Callgraph handling code.
-   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -21,24 +21,24 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "tree.h"
-#include "varasm.h"
-#include "cgraph.h"
-#include "langhooks.h"
-#include "diagnostic-core.h"
-#include "hashtab.h"
+#include "gimple.h"
 #include "timevar.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
+#include "varasm.h"
 #include "debug.h"
-#include "target.h"
 #include "output.h"
-#include "gimple-expr.h"
-#include "flags.h"
-#include "pointer-set.h"
+#include "omp-offload.h"
+#include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 
-const char * const tls_model_names[]={"none", "tls-emulated", "tls-real",
-                                     "tls-global-dynamic", "tls-local-dynamic",
-                                     "tls-initial-exec", "tls-local-exec"};
+const char * const tls_model_names[]={"none", "emulated",
+                                     "global-dynamic", "local-dynamic",
+                                     "initial-exec", "local-exec"};
 
 /* List of hooks triggered on varpool_node events.  */
 struct varpool_node_hook_list {
@@ -47,19 +47,14 @@ struct varpool_node_hook_list {
   struct varpool_node_hook_list *next;
 };
 
-/* List of hooks triggered when a node is removed.  */
-struct varpool_node_hook_list *first_varpool_node_removal_hook;
-/* List of hooks triggered when an variable is inserted.  */
-struct varpool_node_hook_list *first_varpool_variable_insertion_hook;
-
 /* Register HOOK to be called with DATA on each removed node.  */
-struct varpool_node_hook_list *
-varpool_add_node_removal_hook (varpool_node_hook hook, void *data)
+varpool_node_hook_list *
+symbol_table::add_varpool_removal_hook (varpool_node_hook hook, void *data)
 {
-  struct varpool_node_hook_list *entry;
-  struct varpool_node_hook_list **ptr = &first_varpool_node_removal_hook;
+  varpool_node_hook_list *entry;
+  varpool_node_hook_list **ptr = &m_first_varpool_removal_hook;
 
-  entry = (struct varpool_node_hook_list *) xmalloc (sizeof (*entry));
+  entry = (varpool_node_hook_list *) xmalloc (sizeof (*entry));
   entry->hook = hook;
   entry->data = data;
   entry->next = NULL;
@@ -71,9 +66,9 @@ varpool_add_node_removal_hook (varpool_node_hook hook, void *data)
 
 /* Remove ENTRY from the list of hooks called on removing nodes.  */
 void
-varpool_remove_node_removal_hook (struct varpool_node_hook_list *entry)
+symbol_table::remove_varpool_removal_hook (varpool_node_hook_list *entry)
 {
-  struct varpool_node_hook_list **ptr = &first_varpool_node_removal_hook;
+  varpool_node_hook_list **ptr = &m_first_varpool_removal_hook;
 
   while (*ptr != entry)
     ptr = &(*ptr)->next;
@@ -82,10 +77,10 @@ varpool_remove_node_removal_hook (struct varpool_node_hook_list *entry)
 }
 
 /* Call all node removal hooks.  */
-static void
-varpool_call_node_removal_hooks (varpool_node *node)
+void
+symbol_table::call_varpool_removal_hooks (varpool_node *node)
 {
-  struct varpool_node_hook_list *entry = first_varpool_node_removal_hook;
+  varpool_node_hook_list *entry = m_first_varpool_removal_hook;
   while (entry)
   {
     entry->hook (node, entry->data);
@@ -94,13 +89,13 @@ varpool_call_node_removal_hooks (varpool_node *node)
 }
 
 /* Register HOOK to be called with DATA on each inserted node.  */
-struct varpool_node_hook_list *
-varpool_add_variable_insertion_hook (varpool_node_hook hook, void *data)
+varpool_node_hook_list *
+symbol_table::add_varpool_insertion_hook (varpool_node_hook hook, void *data)
 {
-  struct varpool_node_hook_list *entry;
-  struct varpool_node_hook_list **ptr = &first_varpool_variable_insertion_hook;
+  varpool_node_hook_list *entry;
+  varpool_node_hook_list **ptr = &m_first_varpool_insertion_hook;
 
-  entry = (struct varpool_node_hook_list *) xmalloc (sizeof (*entry));
+  entry = (varpool_node_hook_list *) xmalloc (sizeof (*entry));
   entry->hook = hook;
   entry->data = data;
   entry->next = NULL;
@@ -112,9 +107,9 @@ varpool_add_variable_insertion_hook (varpool_node_hook hook, void *data)
 
 /* Remove ENTRY from the list of hooks called on inserted nodes.  */
 void
-varpool_remove_variable_insertion_hook (struct varpool_node_hook_list *entry)
+symbol_table::remove_varpool_insertion_hook (varpool_node_hook_list *entry)
 {
-  struct varpool_node_hook_list **ptr = &first_varpool_variable_insertion_hook;
+  varpool_node_hook_list **ptr = &m_first_varpool_insertion_hook;
 
   while (*ptr != entry)
     ptr = &(*ptr)->next;
@@ -124,9 +119,9 @@ varpool_remove_variable_insertion_hook (struct varpool_node_hook_list *entry)
 
 /* Call all node insertion hooks.  */
 void
-varpool_call_variable_insertion_hooks (varpool_node *node)
+symbol_table::call_varpool_insertion_hooks (varpool_node *node)
 {
-  struct varpool_node_hook_list *entry = first_varpool_variable_insertion_hook;
+  varpool_node_hook_list *entry = m_first_varpool_insertion_hook;
   while (entry)
   {
     entry->hook (node, entry->data);
@@ -137,125 +132,264 @@ varpool_call_variable_insertion_hooks (varpool_node *node)
 /* Allocate new callgraph node and insert it into basic data structures.  */
 
 varpool_node *
-varpool_create_empty_node (void)
-{   
-  varpool_node *node = ggc_cleared_alloc<varpool_node> ();
-  node->type = SYMTAB_VARIABLE;
-  return node;
+varpool_node::create_empty (void)
+{
+  return new (ggc_alloc<varpool_node> ()) varpool_node ();
 }   
 
 /* Return varpool node assigned to DECL.  Create new one when needed.  */
 varpool_node *
-varpool_node_for_decl (tree decl)
+varpool_node::get_create (tree decl)
 {
-  varpool_node *node = varpool_get_node (decl);
-  gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
+  varpool_node *node = varpool_node::get (decl);
+  gcc_checking_assert (VAR_P (decl));
   if (node)
     return node;
 
-  node = varpool_create_empty_node ();
+  node = varpool_node::create_empty ();
   node->decl = decl;
-  symtab_register_node (node);
+
+  if ((flag_openacc || flag_openmp)
+      && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)))
+    {
+      node->offloadable = 1;
+      if (ENABLE_OFFLOADING && !DECL_EXTERNAL (decl))
+       {
+         g->have_offload = true;
+         if (!in_lto_p)
+           vec_safe_push (offload_vars, decl);
+       }
+    }
+
+  node->register_symbol ();
   return node;
 }
 
-/* Remove node from the varpool.  */
+/* Remove variable from symbol table.  */
+
 void
-varpool_remove_node (varpool_node *node)
+varpool_node::remove (void)
 {
-  tree init;
-  varpool_call_node_removal_hooks (node);
-  symtab_unregister_node (node);
-
-  /* Because we remove references from external functions before final compilation,
-     we may end up removing useful constructors.
-     FIXME: We probably want to trace boundaries better.  */
-  if (cgraph_state == CGRAPH_LTO_STREAMING)
+  symtab->call_varpool_removal_hooks (this);
+  if (lto_file_data)
+    {
+      lto_free_function_in_decl_state_for_node (this);
+      lto_file_data = NULL;
+    }
+
+  /* When streaming we can have multiple nodes associated with decl.  */
+  if (symtab->state == LTO_STREAMING)
     ;
-  else if ((init = ctor_for_folding (node->decl)) == error_mark_node)
-    varpool_remove_initializer (node);
-  else
-    DECL_INITIAL (node->decl) = init;
-  ggc_free (node);
+  /* Keep constructor when it may be used for folding. We remove
+     references to external variables before final compilation.  */
+  else if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node
+          && !ctor_useable_for_folding_p ())
+    remove_initializer ();
+
+  unregister ();
+  ggc_free (this);
 }
 
-/* Renove node initializer when it is no longer needed.  */
+/* Remove node initializer when it is no longer needed.  */
 void
-varpool_remove_initializer (varpool_node *node)
+varpool_node::remove_initializer (void)
 {
-  if (DECL_INITIAL (node->decl)
-      && !DECL_IN_CONSTANT_POOL (node->decl)
+  if (DECL_INITIAL (decl)
+      && !DECL_IN_CONSTANT_POOL (decl)
       /* Keep vtables for BINFO folding.  */
-      && !DECL_VIRTUAL_P (node->decl)
+      && !DECL_VIRTUAL_P (decl)
       /* FIXME: http://gcc.gnu.org/PR55395 */
       && debug_info_level == DINFO_LEVEL_NONE
       /* When doing declaration merging we have duplicate
         entries for given decl.  Do not attempt to remove
-        the boides, or we will end up remiving
+        the bodies, or we will end up removing
         wrong one.  */
-      && cgraph_state != CGRAPH_LTO_STREAMING)
-    DECL_INITIAL (node->decl) = error_mark_node;
+      && symtab->state != LTO_STREAMING)
+    DECL_INITIAL (decl) = error_mark_node;
 }
 
-/* Dump given cgraph node.  */
+/* Dump given varpool node to F.  */
 void
-dump_varpool_node (FILE *f, varpool_node *node)
+varpool_node::dump (FILE *f)
 {
-  dump_symtab_base (f, node);
+  dump_base (f);
   fprintf (f, "  Availability: %s\n",
-          cgraph_function_flags_ready
-          ? cgraph_availability_names[cgraph_variable_initializer_availability (node)]
+          symtab->function_flags_ready
+          ? cgraph_availability_names[get_availability ()]
           : "not-ready");
   fprintf (f, "  Varpool flags:");
-  if (DECL_INITIAL (node->decl))
+  if (DECL_INITIAL (decl))
     fprintf (f, " initialized");
-  if (node->output)
+  if (output)
     fprintf (f, " output");
-  if (node->used_by_single_function)
+  if (used_by_single_function)
     fprintf (f, " used-by-single-function");
-  if (TREE_READONLY (node->decl))
+  if (TREE_READONLY (decl))
     fprintf (f, " read-only");
-  if (ctor_for_folding (node->decl) != error_mark_node)
+  if (ctor_useable_for_folding_p ())
     fprintf (f, " const-value-known");
-  if (node->writeonly)
+  if (writeonly)
     fprintf (f, " write-only");
-  if (node->tls_model)
-    fprintf (f, " %s", tls_model_names [node->tls_model]);
+  if (tls_model)
+    fprintf (f, " tls-%s", tls_model_names [tls_model]);
   fprintf (f, "\n");
 }
 
-/* Dump the variable pool.  */
+
+/* Dump given varpool node to stderr.  */
+void varpool_node::debug (void)
+{
+  varpool_node::dump (stderr);
+}
+
+/* Dump the variable pool to F.  */
 void
-dump_varpool (FILE *f)
+varpool_node::dump_varpool (FILE *f)
 {
   varpool_node *node;
 
   fprintf (f, "variable pool:\n\n");
   FOR_EACH_VARIABLE (node)
-    dump_varpool_node (f, node);
+    node->dump (f);
 }
 
 /* Dump the variable pool to stderr.  */
 
 DEBUG_FUNCTION void
-debug_varpool (void)
+varpool_node::debug_varpool (void)
 {
   dump_varpool (stderr);
 }
 
 /* Given an assembler name, lookup node.  */
 varpool_node *
-varpool_node_for_asm (tree asmname)
+varpool_node::get_for_asmname (tree asmname)
 {
-  if (symtab_node *node = symtab_node_for_asm (asmname))
+  if (symtab_node *node = symtab_node::get_for_asmname (asmname))
     return dyn_cast <varpool_node *> (node);
   else
     return NULL;
 }
 
-/* Return if DECL is constant and its initial value is known (so we can do
-   constant folding using DECL_INITIAL (decl)).
-   Return ERROR_MARK_NODE when value is unknown.  */
+/* When doing LTO, read variable's constructor from disk if
+   it is not already present.  */
+
+tree
+varpool_node::get_constructor (void)
+{
+  lto_file_decl_data *file_data;
+  const char *data, *name;
+  size_t len;
+
+  if (DECL_INITIAL (decl) != error_mark_node
+      || !in_lto_p
+      || !lto_file_data)
+    return DECL_INITIAL (decl);
+
+  timevar_push (TV_IPA_LTO_CTORS_IN);
+
+  file_data = lto_file_data;
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+  /* We may have renamed the declaration, e.g., a static function.  */
+  name = lto_get_decl_name_mapping (file_data, name);
+  struct lto_in_decl_state *decl_state
+        = lto_get_function_in_decl_state (file_data, decl);
+
+  data = lto_get_section_data (file_data, LTO_section_function_body,
+                              name, order - file_data->order_base,
+                              &len, decl_state->compressed);
+  if (!data)
+    fatal_error (input_location, "%s: section %s.%d is missing",
+                file_data->file_name,
+                name, order - file_data->order_base);
+
+  if (!quiet_flag)
+    fprintf (stderr, " in:%s", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+  lto_input_variable_constructor (file_data, this, data);
+  gcc_assert (DECL_INITIAL (decl) != error_mark_node);
+  lto_stats.num_function_bodies++;
+  lto_free_section_data (file_data, LTO_section_function_body, name,
+                        data, len, decl_state->compressed);
+  lto_free_function_in_decl_state_for_node (this);
+  timevar_pop (TV_IPA_LTO_CTORS_IN);
+  return DECL_INITIAL (decl);
+}
+
+/* Return true if variable has constructor that can be used for folding.  */
+
+bool
+varpool_node::ctor_useable_for_folding_p (void)
+{
+  varpool_node *real_node = this;
+
+  if (real_node->alias && real_node->definition)
+    real_node = ultimate_alias_target ();
+
+  if (TREE_CODE (decl) == CONST_DECL
+      || DECL_IN_CONSTANT_POOL (decl))
+    return true;
+  if (TREE_THIS_VOLATILE (decl))
+    return false;
+
+  /* Avoid attempts to load constructors that was not streamed.  */
+  if (in_lto_p && DECL_INITIAL (real_node->decl) == error_mark_node
+      && real_node->body_removed)
+    return false;
+
+  /* If we do not have a constructor, we can't use it.  */
+  if (DECL_INITIAL (real_node->decl) == error_mark_node
+      && !real_node->lto_file_data)
+    return false;
+
+  /* Vtables are defined by their types and must match no matter of interposition
+     rules.  */
+  if (DECL_VIRTUAL_P (decl))
+    {
+      /* The C++ front end creates VAR_DECLs for vtables of typeinfo
+        classes not defined in the current TU so that it can refer
+        to them from typeinfo objects.  Avoid returning NULL_TREE.  */
+      return DECL_INITIAL (real_node->decl) != NULL;
+    }
+
+  /* An alias of a read-only variable is also read-only, since the variable
+     is stored in read-only memory.  We also accept read-only aliases of
+     non-read-only locations assuming that the user knows what he is asking
+     for.  */
+  if (!TREE_READONLY (decl) && !TREE_READONLY (real_node->decl))
+    return false;
+
+  /* Variables declared 'const' without an initializer
+     have zero as the initializer if they may not be
+     overridden at link or run time.
+
+     It is actually requirement for C++ compiler to optimize const variables
+     consistently. As a GNU extension, do not enforce this rule for user defined
+     weak variables, so we support interposition on:
+     static const int dummy = 0;
+     extern const int foo __attribute__((__weak__, __alias__("dummy"))); 
+   */
+  if ((!DECL_INITIAL (real_node->decl)
+       || (DECL_WEAK (decl) && !DECL_COMDAT (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;
+}
+
+/* If DECLARATION is constant variable and its initial value is known
+   (so we can do constant folding), return its constructor (DECL_INITIAL).
+   This may be an expression or NULL when DECL is initialized to 0.
+   Return ERROR_MARK_NODE otherwise.
+
+   In LTO this may actually trigger reading the constructor from disk.
+   For this reason varpool_ctor_useable_for_folding_p should be used when
+   the actual constructor value is not needed.  */
 
 tree
 ctor_for_folding (tree decl)
@@ -263,8 +397,7 @@ ctor_for_folding (tree decl)
   varpool_node *node, *real_node;
   tree real_decl;
 
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != CONST_DECL)
+  if (!VAR_P (decl) && TREE_CODE (decl) != CONST_DECL)
     return error_mark_node;
 
   if (TREE_CODE (decl) == CONST_DECL
@@ -275,19 +408,19 @@ ctor_for_folding (tree decl)
     return error_mark_node;
 
   /* Do not care about automatic variables.  Those are never initialized
-     anyway, because gimplifier exapnds the code.  */
+     anyway, because gimplifier expands the code.  */
   if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
     {
       gcc_assert (!TREE_PUBLIC (decl));
       return error_mark_node;
     }
 
-  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  gcc_assert (VAR_P (decl));
 
-  node = varpool_get_node (decl);
+  real_node = node = varpool_node::get (decl);
   if (node)
     {
-      real_node = varpool_variable_node (node);
+      real_node = node->ultimate_alias_target ();
       real_decl = real_node->decl;
     }
   else
@@ -301,150 +434,129 @@ ctor_for_folding (tree decl)
   if (decl != real_decl)
     {
       gcc_assert (!DECL_INITIAL (decl)
+                 || (node->alias && node->get_alias_target () == real_node)
                  || DECL_INITIAL (decl) == error_mark_node);
-      if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+      while (node->transparent_alias && node->analyzed)
        {
-         node = varpool_alias_target (node);
+         node = node->get_alias_target ();
          decl = node->decl;
        }
     }
 
-  /* Vtables are defined by their types and must match no matter of interposition
-     rules.  */
-  if (DECL_VIRTUAL_P (real_decl))
-    {
-      gcc_checking_assert (TREE_READONLY (real_decl));
-      if (DECL_INITIAL (real_decl))
-       return DECL_INITIAL (real_decl);
-      else
-       {
-         /* The C++ front end creates VAR_DECLs for vtables of typeinfo
-            classes not defined in the current TU so that it can refer
-            to them from typeinfo objects.  Avoid returning NULL_TREE.  */
-         gcc_checking_assert (!COMPLETE_TYPE_P (DECL_CONTEXT (real_decl)));
-         return error_mark_node;
-       }
-    }
-
-  /* If there is no constructor, we have nothing to do.  */
-  if (DECL_INITIAL (real_decl) == error_mark_node)
-    return error_mark_node;
-
-  /* Non-readonly alias of readonly variable is also de-facto readonly,
-     because the variable itself is in readonly section.  
-     We also honnor READONLY flag on alias assuming that user knows
-     what he is doing.  */
-  if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl))
-    return error_mark_node;
-
-  /* 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 (real_decl)
-      && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl)))
+  if ((!DECL_VIRTUAL_P (real_decl)
+       || DECL_INITIAL (real_decl) == error_mark_node
+       || !DECL_INITIAL (real_decl))
+      && (!node || !node->ctor_useable_for_folding_p ()))
     return error_mark_node;
 
-  /* 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 DECL_INITIAL (real_decl);
+  /* OK, we can return constructor.  See if we need to fetch it from disk
+     in LTO mode.  */
+  if (DECL_INITIAL (real_decl) != error_mark_node
+      || !in_lto_p)
+    return DECL_INITIAL (real_decl);
+  return real_node->get_constructor ();
 }
 
 /* Add the variable DECL to the varpool.
-   Unlike varpool_finalize_decl function is intended to be used
+   Unlike 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)
+varpool_node::add (tree decl)
 {
   varpool_node *node;
-  varpool_finalize_decl (decl);
-  node = varpool_node_for_decl (decl);
-  varpool_call_variable_insertion_hooks (node);
-  if (varpool_externally_visible_p (node))
+  varpool_node::finalize_decl (decl);
+  node = varpool_node::get_create (decl);
+  symtab->call_varpool_insertion_hooks (node);
+  if (node->externally_visible_p ())
     node->externally_visible = true;
+  if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
+    node->no_reorder = 1;
 }
 
 /* Return variable availability.  See cgraph.h for description of individual
    return values.  */
 enum availability
-cgraph_variable_initializer_availability (varpool_node *node)
+varpool_node::get_availability (symtab_node *ref)
 {
-  if (!node->definition)
+  if (!definition)
     return AVAIL_NOT_AVAILABLE;
-  if (!TREE_PUBLIC (node->decl))
+  if (!TREE_PUBLIC (decl))
     return AVAIL_AVAILABLE;
-  if (DECL_IN_CONSTANT_POOL (node->decl)
-      || DECL_VIRTUAL_P (node->decl))
+  if (DECL_IN_CONSTANT_POOL (decl)
+      || DECL_VIRTUAL_P (decl))
     return AVAIL_AVAILABLE;
-  if (node->alias && node->weakref)
+  if (transparent_alias && definition)
     {
       enum availability avail;
 
-      cgraph_variable_initializer_availability
-             (varpool_variable_node (node, &avail));
+      ultimate_alias_target (&avail, ref);
       return avail;
     }
+  /* If this is a reference from symbol itself and there are no aliases, we
+     may be sure that the symbol was not interposed by something else because
+     the symbol itself would be unreachable otherwise.  */
+  if ((this == ref && !has_aliases_p ())
+      || (ref && get_comdat_group ()
+          && get_comdat_group () == ref->get_comdat_group ()))
+    return AVAIL_AVAILABLE;
   /* If the variable can be overwritten, return OVERWRITABLE.  Takes
      care of at least one notable extension - the COMDAT variables
      used to share template instantiations in C++.  */
-  if (decl_replaceable_p (node->decl)
-      || DECL_EXTERNAL (node->decl))
-    return AVAIL_OVERWRITABLE;
+  if (decl_replaceable_p (decl)
+      || DECL_EXTERNAL (decl))
+    return AVAIL_INTERPOSABLE;
   return AVAIL_AVAILABLE;
 }
 
 void
-varpool_analyze_node (varpool_node *node)
+varpool_node::analyze (void)
 {
-  tree decl = node->decl;
-
   /* When reading back varpool at LTO time, we re-construct the queue in order
      to have "needed" list right by inserting all needed nodes into varpool.
      We however don't want to re-analyze already analyzed nodes.  */
-  if (!node->analyzed)
+  if (!analyzed)
     {
-      gcc_assert (!in_lto_p || cgraph_function_flags_ready);
+      gcc_assert (!in_lto_p || symtab->function_flags_ready);
       /* Compute the alignment early so function body expanders are
         already informed about increased alignment.  */
       align_variable (decl, 0);
     }
-  if (node->alias)
-    symtab_resolve_alias
-       (node, varpool_get_node (node->alias_target));
+  if (alias)
+    resolve_alias (varpool_node::get (alias_target));
   else if (DECL_INITIAL (decl))
-    record_references_in_initializer (decl, node->analyzed);
-  node->analyzed = true;
+    record_references_in_initializer (decl, analyzed);
+  analyzed = true;
 }
 
-/* Assemble thunks and aliases associated to NODE.  */
+/* Assemble thunks and aliases associated to varpool node.  */
 
-static void
-assemble_aliases (varpool_node *node)
+void
+varpool_node::assemble_aliases (void)
 {
-  struct ipa_ref *ref;
+  ipa_ref *ref;
 
-  FOR_EACH_ALIAS (node, ref)
+  FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
-      do_assemble_alias (alias->decl,
-                        DECL_ASSEMBLER_NAME (node->decl));
-      assemble_aliases (alias);
+      if (alias->symver)
+       do_assemble_symver (alias->decl,
+                           DECL_ASSEMBLER_NAME (decl));
+      else if (!alias->transparent_alias)
+       do_assemble_alias (alias->decl,
+                          DECL_ASSEMBLER_NAME (decl));
+      alias->assemble_aliases ();
     }
 }
 
 /* Output one variable, if necessary.  Return whether we output it.  */
 
 bool
-varpool_assemble_decl (varpool_node *node)
+varpool_node::assemble_decl (void)
 {
-  tree decl = node->decl;
-
-  /* Aliases are outout when their target is produced or by
+  /* Aliases are output when their target is produced or by
      output_weakrefs.  */
-  if (node->alias)
+  if (alias)
     return false;
 
   /* Constant pool is output from RTL land when the reference
@@ -465,16 +577,21 @@ varpool_assemble_decl (varpool_node *node)
     return false;
 
   gcc_checking_assert (!TREE_ASM_WRITTEN (decl)
-                      && TREE_CODE (decl) == VAR_DECL
+                      && VAR_P (decl)
                       && !DECL_HAS_VALUE_EXPR_P (decl));
 
-  if (!node->in_other_partition
+  if (!in_other_partition
       && !DECL_EXTERNAL (decl))
     {
+      get_constructor ();
       assemble_variable (decl, 0, 1, 0);
       gcc_assert (TREE_ASM_WRITTEN (decl));
-      node->definition = true;
-      assemble_aliases (node);
+      gcc_assert (definition);
+      assemble_aliases ();
+      /* After the parser has generated debugging information, augment
+        this information with any new location/etc information that may
+        have become available after the compilation proper.  */
+      debug_hooks->late_global_decl (decl);
       return true;
     }
 
@@ -499,31 +616,31 @@ enqueue_node (varpool_node *node, varpool_node **first)
    reachability starting from variables that are either externally visible
    or was referred from the asm output routines.  */
 
-static void
-varpool_remove_unreferenced_decls (void)
+void
+symbol_table::remove_unreferenced_decls (void)
 {
   varpool_node *next, *node;
   varpool_node *first = (varpool_node *)(void *)1;
   int i;
-  struct ipa_ref *ref = NULL;
-  struct pointer_set_t *referenced = pointer_set_create ();
+  ipa_ref *ref = NULL;
+  hash_set<varpool_node *> referenced;
 
   if (seen_error ())
     return;
 
-  if (cgraph_dump_file)
-    fprintf (cgraph_dump_file, "Trivially needed variables:");
+  if (dump_file)
+    fprintf (dump_file, "Trivially needed variables:");
   FOR_EACH_DEFINED_VARIABLE (node)
     {
       if (node->analyzed
-         && (!varpool_can_remove_if_no_refs (node)
+         && (!node->can_remove_if_no_refs_p ()
              /* We just expanded all function bodies.  See if any of
                 them needed the variable.  */
              || DECL_RTL_SET_P (node->decl)))
        {
          enqueue_node (node, &first);
-          if (cgraph_dump_file)
-           fprintf (cgraph_dump_file, " %s", node->asm_name ());
+         if (dump_file)
+           fprintf (dump_file, " %s", node->dump_asm_name ());
        }
     }
   while (first != (varpool_node *)(void *)1)
@@ -539,7 +656,7 @@ varpool_remove_unreferenced_decls (void)
               next = next->same_comdat_group)
            {
              varpool_node *vnext = dyn_cast <varpool_node *> (next);
-             if (vnext && vnext->analyzed && !symtab_comdat_local_p (next))
+             if (vnext && vnext->analyzed && !next->comdat_local_p ())
                enqueue_node (vnext, &first);
            }
        }
@@ -553,27 +670,34 @@ varpool_remove_unreferenced_decls (void)
              && vnode->analyzed)
            enqueue_node (vnode, &first);
          else
-           pointer_set_insert (referenced, node);
+           {
+             referenced.add (vnode);
+             while (vnode && vnode->alias && vnode->definition)
+               {
+                 vnode = vnode->get_alias_target ();
+                 referenced.add (vnode);
+               }
+           }
        }
     }
-  if (cgraph_dump_file)
-    fprintf (cgraph_dump_file, "\nRemoving variables:");
-  for (node = varpool_first_defined_variable (); node; node = next)
+  if (dump_file)
+    fprintf (dump_file, "\nRemoving variables:");
+  for (node = first_defined_variable (); node; node = next)
     {
-      next = varpool_next_defined_variable (node);
-      if (!node->aux)
+      next = next_defined_variable (node);
+      if (!node->aux && !node->no_reorder)
        {
-          if (cgraph_dump_file)
-           fprintf (cgraph_dump_file, " %s", node->asm_name ());
-         if (pointer_set_contains (referenced, node))
-           varpool_remove_initializer (node);
+         if (dump_file)
+           fprintf (dump_file, " %s", node->dump_asm_name ());
+         if (referenced.contains(node))
+           node->remove_initializer ();
          else
-           varpool_remove_node (node);
+           node->remove ();
        }
     }
-  pointer_set_destroy (referenced);
-  if (cgraph_dump_file)
-    fprintf (cgraph_dump_file, "\n");
+
+  if (dump_file)
+    fprintf (dump_file, "\n");
 }
 
 /* For variables in named sections make sure get_variable_section
@@ -581,21 +705,21 @@ varpool_remove_unreferenced_decls (void)
    conflicts between read-only and read-only requiring relocations
    sections can be resolved.  */
 void
-varpool_finalize_named_section_flags (varpool_node *node)
+varpool_node::finalize_named_section_flags (void)
 {
-  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)
-      && node->get_section ())
-    get_variable_section (node->decl, false);
+  if (!TREE_ASM_WRITTEN (decl)
+      && !alias
+      && !in_other_partition
+      && !DECL_EXTERNAL (decl)
+      && VAR_P (decl)
+      && !DECL_HAS_VALUE_EXPR_P (decl)
+      && get_section ())
+    get_variable_section (decl, false);
 }
 
 /* Output all variables enqueued to be assembled.  */
 bool
-varpool_output_variables (void)
+symbol_table::output_variables (void)
 {
   bool changed = false;
   varpool_node *node;
@@ -603,57 +727,53 @@ varpool_output_variables (void)
   if (seen_error ())
     return false;
 
-  varpool_remove_unreferenced_decls ();
+  remove_unreferenced_decls ();
 
   timevar_push (TV_VAROUT);
 
   FOR_EACH_DEFINED_VARIABLE (node)
-    varpool_finalize_named_section_flags (node);
+    {
+      /* Handled in output_in_order.  */
+      if (node->no_reorder)
+       continue;
 
-  FOR_EACH_DEFINED_VARIABLE (node)
-    if (varpool_assemble_decl (node))
-      changed = true;
+      node->finalize_named_section_flags ();
+    }
+
+  /* There is a similar loop in output_in_order.  Please keep them in sync.  */
+  FOR_EACH_VARIABLE (node)
+    {
+      /* Handled in output_in_order.  */
+      if (node->no_reorder)
+       continue;
+      if (DECL_HARD_REGISTER (node->decl)
+         || DECL_HAS_VALUE_EXPR_P (node->decl))
+       continue;
+      if (node->definition)
+       changed |= node->assemble_decl ();
+      else
+       assemble_undefined_decl (node->decl);
+    }
   timevar_pop (TV_VAROUT);
   return changed;
 }
 
-/* Create a new global variable of type TYPE.  */
-tree
-add_new_static_var (tree type)
-{
-  tree new_decl;
-  varpool_node *new_node;
-
-  new_decl = create_tmp_var_raw (type, NULL);
-  DECL_NAME (new_decl) = create_tmp_var_name (NULL);
-  TREE_READONLY (new_decl) = 0;
-  TREE_STATIC (new_decl) = 1;
-  TREE_USED (new_decl) = 1;
-  DECL_CONTEXT (new_decl) = NULL_TREE;
-  DECL_ABSTRACT (new_decl) = 0;
-  lang_hooks.dup_lang_specific_decl (new_decl);
-  new_node = varpool_node_for_decl (new_decl);
-  varpool_finalize_decl (new_decl);
-
-  return new_node->decl;
-}
-
 /* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
    Extra name aliases are output whenever DECL is output.  */
 
 varpool_node *
-varpool_create_variable_alias (tree alias, tree decl)
+varpool_node::create_alias (tree alias, tree decl)
 {
   varpool_node *alias_node;
 
-  gcc_assert (TREE_CODE (decl) == VAR_DECL);
-  gcc_assert (TREE_CODE (alias) == VAR_DECL);
-  alias_node = varpool_node_for_decl (alias);
+  gcc_assert (VAR_P (decl));
+  gcc_assert (VAR_P (alias));
+  alias_node = varpool_node::get_create (alias);
   alias_node->alias = true;
   alias_node->definition = true;
   alias_node->alias_target = decl;
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
-    alias_node->weakref = true;
+    alias_node->weakref = alias_node->transparent_alias = true;
   return alias_node;
 }
 
@@ -661,49 +781,43 @@ varpool_create_variable_alias (tree alias, tree decl)
    Extra name aliases are output whenever DECL is output.  */
 
 varpool_node *
-varpool_extra_name_alias (tree alias, tree decl)
+varpool_node::create_extra_name_alias (tree alias, tree decl)
 {
   varpool_node *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);
+  if (!TARGET_SUPPORTS_ALIASES)
+    return NULL;
+
+  alias_node = varpool_node::create_alias (alias, decl);
   alias_node->cpp_implicit_alias = true;
 
-  /* Extra name alias mechanizm creates aliases really late
-     via DECL_ASSEMBLER_NAME mechanizm.
+  /* Extra name alias mechanism creates aliases really late
+     via DECL_ASSEMBLER_NAME mechanism.
      This is unfortunate because they are not going through the
      standard channels.  Ensure they get output.  */
-  if (cpp_implicit_aliases_done)
-    symtab_resolve_alias (alias_node,
-                         varpool_node_for_decl (decl));
+  if (symtab->cpp_implicit_aliases_done)
+    alias_node->resolve_alias (varpool_node::get_create (decl));
   return alias_node;
 }
 
-/* Call calback on NODE and aliases associated to NODE. 
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
+/* Worker for call_for_symbol_and_aliases.  */
 
 bool
-varpool_for_node_and_aliases (varpool_node *node,
-                             bool (*callback) (varpool_node *, void *),
-                             void *data,
-                             bool include_overwritable)
+varpool_node::call_for_symbol_and_aliases_1 (bool (*callback) (varpool_node *,
+                                                              void *),
+                                            void *data,
+                                            bool include_overwritable)
 {
-  struct ipa_ref *ref;
-
-  if (callback (node, data))
-    return true;
+  ipa_ref *ref;
 
-  FOR_EACH_ALIAS (node, ref)
+  FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
       if (include_overwritable
-         || cgraph_variable_initializer_availability (alias) > AVAIL_OVERWRITABLE)
-       if (varpool_for_node_and_aliases (alias, callback, data,
-                                        include_overwritable))
+         || alias->get_availability () > AVAIL_INTERPOSABLE)
+       if (alias->call_for_symbol_and_aliases (callback, data,
+                                               include_overwritable))
          return true;
     }
   return false;