]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
lto-streamer.c (lto_streamer_cache_insert_1): Accept to override other trees that...
authorMichael Matz <matz@suse.de>
Fri, 29 Apr 2011 12:27:26 +0000 (12:27 +0000)
committerMichael Matz <matz@gcc.gnu.org>
Fri, 29 Apr 2011 12:27:26 +0000 (12:27 +0000)
* lto-streamer.c (lto_streamer_cache_insert_1): Accept to override
other trees that just builtins.
(lto_record_common_node): Don't leave NULL TYPE_CANONICAL.

lto/
* lto.c (toplevel): Include tree-flow.h.
(lto_read_in_decl_state): Don't merge types here.
(tree_with_vars): New static hash table.
(remember_with_vars): New static functions.
(LTO_FIXUP_TYPE): New macro.
(lto_ft_common, lto_ft_decl_minimal, lto_ft_decl_common,
lto_ft_decl_with_vis, lto_ft_decl_non_common, lto_ft_function,
lto_ft_field_decl, lto_ft_type, lto_ft_binfo, lto_ft_constructor,
lto_ft_expr, lto_fixup_types, uniquify_nodes): New static functions.
(lto_read_decls): Uniquify while reading in trees.
(lto_fixup_data_t, LTO_FIXUP_SUBTREE,
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE, no_fixup_p, lto_fixup_common,
lto_fixup_decl_minimal, lto_fixup_decl_common, lto_fixup_decl_with_vis,
lto_fixup_decl_non_common, lto_fixup_function, lto_fixup_field_decl,
lto_fixup_type, lto_fixup_binfo, lto_fixup_constructor,
lto_fixup_tree): Remove.
(lto_fixup_state): Remove data argument.  Use
lto_symtab_prevailing_decl.
(LTO_SET_PREVAIL, LTO_NO_PREVAIL): New macros.
(lto_fixup_prevailing_decls): New function.
(lto_fixup_state_aux): Argument aux is unused.
(lto_fixup_decls): Don't allocate pointer sets, don't use
lto_fixup_tree, use lto_fixup_prevailing_decls.
(read_cgraph_and_symbols): Allocate and remove tree_with_vars.
* Make-lang.in (lto/lto.o): Depend on $(TREE_FLOW_H).

From-SVN: r173155

gcc/ChangeLog
gcc/lto-streamer.c
gcc/lto/ChangeLog
gcc/lto/Make-lang.in
gcc/lto/lto.c

index 13f36591d26dbc2e4d9a1dac723df5a078e2484b..6f7430c148364a429ad50d111b731500c2dad5e0 100644 (file)
@@ -1,3 +1,9 @@
+2011-04-29  Michael Matz  <matz@suse.de>
+
+       * lto-streamer.c (lto_streamer_cache_insert_1): Accept to override
+       other trees that just builtins.
+       (lto_record_common_node): Don't leave NULL TYPE_CANONICAL.
+
 2011-04-29  Richard Guenther  <rguenther@suse.de>
 
        * tree-nested.c (get_trampoline_type): Use size_int.
index 74034b0748564a09dd57d48252ece3846dc17d92..80927927dcc01f5f4e9921e6f1cdf8c33c388a95 100644 (file)
@@ -383,19 +383,8 @@ lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
        {
          /* If the caller wants to insert T at a specific slot
             location, and ENTRY->TO does not match *IX_P, add T to
-            the requested location slot.  This situation arises when
-            streaming builtin functions.
-
-            For instance, on the writer side we could have two
-            FUNCTION_DECLS T1 and T2 that are represented by the same
-            builtin function.  The reader will only instantiate the
-            canonical builtin, but since T1 and T2 had been
-            originally stored in different cache slots (S1 and S2),
-            the reader must be able to find the canonical builtin
-            function at slots S1 and S2.  */
-         gcc_assert (lto_stream_as_builtin_p (t));
+            the requested location slot.  */
          ix = *ix_p;
-
          lto_streamer_cache_add_to_node_array (cache, ix, t);
        }
 
@@ -513,6 +502,8 @@ lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
        TYPE_CANONICAL (node) = NULL_TREE;
       node = gimple_register_type (node);
       TYPE_CANONICAL (node) = gimple_register_canonical_type (node);
+      if (in_lto_p)
+       TYPE_CANONICAL (*nodep) = TYPE_CANONICAL (node);
       *nodep = node;
     }
 
index 507e9b22fd732a8baefde840c0a1e60ef52ae271..be3a873736aceb9d6dd4bd0ff44d42ce6464e6c5 100644 (file)
@@ -1,3 +1,31 @@
+2011-04-29  Michael Matz  <matz@suse.de>
+
+       * lto.c (toplevel): Include tree-flow.h.
+       (lto_read_in_decl_state): Don't merge types here.
+       (tree_with_vars): New static hash table.
+       (remember_with_vars): New static functions.
+       (LTO_FIXUP_TYPE): New macro.
+       (lto_ft_common, lto_ft_decl_minimal, lto_ft_decl_common,
+       lto_ft_decl_with_vis, lto_ft_decl_non_common, lto_ft_function,
+       lto_ft_field_decl, lto_ft_type, lto_ft_binfo, lto_ft_constructor,
+       lto_ft_expr, lto_fixup_types, uniquify_nodes): New static functions.
+       (lto_read_decls): Uniquify while reading in trees.
+       (lto_fixup_data_t, LTO_FIXUP_SUBTREE,
+       LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE, no_fixup_p, lto_fixup_common,
+       lto_fixup_decl_minimal, lto_fixup_decl_common, lto_fixup_decl_with_vis,
+       lto_fixup_decl_non_common, lto_fixup_function, lto_fixup_field_decl,
+       lto_fixup_type, lto_fixup_binfo, lto_fixup_constructor,
+       lto_fixup_tree): Remove.
+       (lto_fixup_state): Remove data argument.  Use
+       lto_symtab_prevailing_decl.
+       (LTO_SET_PREVAIL, LTO_NO_PREVAIL): New macros.
+       (lto_fixup_prevailing_decls): New function.
+       (lto_fixup_state_aux): Argument aux is unused.
+       (lto_fixup_decls): Don't allocate pointer sets, don't use
+       lto_fixup_tree, use lto_fixup_prevailing_decls.
+       (read_cgraph_and_symbols): Allocate and remove tree_with_vars.
+       * Make-lang.in (lto/lto.o): Depend on $(TREE_FLOW_H).
+
 2011-04-16  Eric Botcazou  <ebotcazou@adacore.com>
 
        * lto.c (lto_balanced_map): Fix typos in head comment.
index 5287c12708885c44e087f0d072c7f49cff3ea46e..6b6930f25d98c368132f820a436efa353df73a1a 100644 (file)
@@ -81,7 +81,7 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
        $(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
        $(EXPR_H) $(LTO_STREAMER_H)
 lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
-       toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
+       toplev.h $(TREE_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
        $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \
        langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
        $(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
index 8215c02ca5b6f39ff87892af323a54c3a4a8bdf1..d8e69c57e80a5c3af2717982b7855eb316b7d205 100644 (file)
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "opts.h"
 #include "toplev.h"
 #include "tree.h"
+#include "tree-flow.h"
 #include "diagnostic-core.h"
 #include "tm.h"
 #include "cgraph.h"
@@ -215,24 +216,452 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data,
       tree *decls = ggc_alloc_vec_tree (size);
 
       for (j = 0; j < size; j++)
+       decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]);
+
+      state->streams[i].size = size;
+      state->streams[i].trees = decls;
+      data += size;
+    }
+
+  return data;
+}
+
+/* A hashtable of trees that potentially refer to variables or functions
+   that must be replaced with their prevailing variant.  */
+static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) htab_t
+  tree_with_vars;
+
+/* Remember that T is a tree that (potentially) refers to a variable
+   or function decl that may be replaced with its prevailing variant.  */
+static void
+remember_with_vars (tree t)
+{
+  *(tree *) htab_find_slot (tree_with_vars, t, INSERT) = t;
+}
+
+#define LTO_FIXUP_TREE(tt) \
+  do \
+    { \
+      if (tt) \
+       { \
+         if (TYPE_P (tt)) \
+           (tt) = gimple_register_type (tt); \
+         if (VAR_OR_FUNCTION_DECL_P (tt) && TREE_PUBLIC (tt)) \
+           remember_with_vars (t); \
+       } \
+    } while (0)
+
+static void lto_fixup_types (tree);
+
+/* Fix up fields of a tree_common T.  */
+
+static void
+lto_ft_common (tree t)
+{
+  /* The following re-creates the TYPE_REFERENCE_TO and TYPE_POINTER_TO
+     lists.  We do not stream TYPE_REFERENCE_TO, TYPE_POINTER_TO or
+     TYPE_NEXT_PTR_TO and TYPE_NEXT_REF_TO.
+     First remove us from any pointer list we are on.  */
+  if (TREE_CODE (t) == POINTER_TYPE)
+    {
+      if (TYPE_POINTER_TO (TREE_TYPE (t)) == t)
+       TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t);
+      else
        {
-         decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]);
+         tree tem = TYPE_POINTER_TO (TREE_TYPE (t));
+         while (tem && TYPE_NEXT_PTR_TO (tem) != t)
+           tem = TYPE_NEXT_PTR_TO (tem);
+         if (tem)
+           TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t);
+       }
+      TYPE_NEXT_PTR_TO (t) = NULL_TREE;
+    }
+  else if (TREE_CODE (t) == REFERENCE_TYPE)
+    {
+      if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t)
+       TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t);
+      else
+       {
+         tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t));
+         while (tem && TYPE_NEXT_REF_TO (tem) != t)
+           tem = TYPE_NEXT_REF_TO (tem);
+         if (tem)
+           TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t);
+       }
+      TYPE_NEXT_REF_TO (t) = NULL_TREE;
+    }
+
+  /* Fixup our type.  */
+  LTO_FIXUP_TREE (TREE_TYPE (t));
+
+  /* Second put us on the list of pointers of the new pointed-to type
+     if we are a main variant.  This is done in lto_ft_type after
+     fixing up our main variant.  */
+  LTO_FIXUP_TREE (TREE_CHAIN (t));
+}
+
+/* Fix up fields of a decl_minimal T.  */
+
+static void
+lto_ft_decl_minimal (tree t)
+{
+  lto_ft_common (t);
+  LTO_FIXUP_TREE (DECL_NAME (t));
+  LTO_FIXUP_TREE (DECL_CONTEXT (t));
+}
+
+/* Fix up fields of a decl_common T.  */
+
+static void
+lto_ft_decl_common (tree t)
+{
+  lto_ft_decl_minimal (t);
+  LTO_FIXUP_TREE (DECL_SIZE (t));
+  LTO_FIXUP_TREE (DECL_SIZE_UNIT (t));
+  LTO_FIXUP_TREE (DECL_INITIAL (t));
+  LTO_FIXUP_TREE (DECL_ATTRIBUTES (t));
+  LTO_FIXUP_TREE (DECL_ABSTRACT_ORIGIN (t));
+}
+
+/* Fix up fields of a decl_with_vis T.  */
+
+static void
+lto_ft_decl_with_vis (tree t)
+{
+  lto_ft_decl_common (t);
+
+  /* Accessor macro has side-effects, use field-name here. */
+  LTO_FIXUP_TREE (t->decl_with_vis.assembler_name);
+  LTO_FIXUP_TREE (DECL_SECTION_NAME (t));
+}
+
+/* Fix up fields of a decl_non_common T.  */
+
+static void
+lto_ft_decl_non_common (tree t)
+{
+  lto_ft_decl_with_vis (t);
+  LTO_FIXUP_TREE (DECL_ARGUMENT_FLD (t));
+  LTO_FIXUP_TREE (DECL_RESULT_FLD (t));
+  LTO_FIXUP_TREE (DECL_VINDEX (t));
+}
+
+/* Fix up fields of a decl_non_common T.  */
+
+static void
+lto_ft_function (tree t)
+{
+  lto_ft_decl_non_common (t);
+  LTO_FIXUP_TREE (DECL_FUNCTION_PERSONALITY (t));
+}
+
+/* Fix up fields of a field_decl T.  */
+
+static void
+lto_ft_field_decl (tree t)
+{
+  lto_ft_decl_common (t);
+  LTO_FIXUP_TREE (DECL_FIELD_OFFSET (t));
+  LTO_FIXUP_TREE (DECL_BIT_FIELD_TYPE (t));
+  LTO_FIXUP_TREE (DECL_QUALIFIER (t));
+  LTO_FIXUP_TREE (DECL_FIELD_BIT_OFFSET (t));
+  LTO_FIXUP_TREE (DECL_FCONTEXT (t));
+}
+
+/* Fix up fields of a type T.  */
+
+static void
+lto_ft_type (tree t)
+{
+  tree tem, mv;
+
+  lto_ft_common (t);
+  LTO_FIXUP_TREE (TYPE_CACHED_VALUES (t));
+  LTO_FIXUP_TREE (TYPE_SIZE (t));
+  LTO_FIXUP_TREE (TYPE_SIZE_UNIT (t));
+  LTO_FIXUP_TREE (TYPE_ATTRIBUTES (t));
+  LTO_FIXUP_TREE (TYPE_NAME (t));
+
+  /* Accessors are for derived node types only. */
+  if (!POINTER_TYPE_P (t))
+    LTO_FIXUP_TREE (t->type.minval);
+  LTO_FIXUP_TREE (t->type.maxval);
+
+  /* Accessor is for derived node types only. */
+  LTO_FIXUP_TREE (t->type.binfo);
+
+  LTO_FIXUP_TREE (TYPE_CONTEXT (t));
+
+  /* Compute the canonical type of t and fix that up.  From this point
+     there are no longer any types with TYPE_STRUCTURAL_EQUALITY_P
+     and its type-based alias problems.  */
+  if (!TYPE_CANONICAL (t))
+    {
+      TYPE_CANONICAL (t) = gimple_register_canonical_type (t);
+      LTO_FIXUP_TREE (TYPE_CANONICAL (t));
+    }
+
+  /* The following re-creates proper variant lists while fixing up
+     the variant leaders.  We do not stream TYPE_NEXT_VARIANT so the
+     variant list state before fixup is broken.  */
+
+  /* Remove us from our main variant list if we are not the variant leader.  */
+  if (TYPE_MAIN_VARIANT (t) != t)
+    {
+      tem = TYPE_MAIN_VARIANT (t);
+      while (tem && TYPE_NEXT_VARIANT (tem) != t)
+       tem = TYPE_NEXT_VARIANT (tem);
+      if (tem)
+       TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t);
+      TYPE_NEXT_VARIANT (t) = NULL_TREE;
+    }
+
+  /* Query our new main variant.  */
+  mv = gimple_register_type (TYPE_MAIN_VARIANT (t));
+
+  /* If we were the variant leader and we get replaced ourselves drop
+     all variants from our list.  */
+  if (TYPE_MAIN_VARIANT (t) == t
+      && mv != t)
+    {
+      tem = t;
+      while (tem)
+       {
+         tree tem2 = TYPE_NEXT_VARIANT (tem);
+         TYPE_NEXT_VARIANT (tem) = NULL_TREE;
+         tem = tem2;
+       }
+    }
+
+  /* Finally adjust our main variant and fix it up.  */
+  TYPE_MAIN_VARIANT (t) = mv;
+  LTO_FIXUP_TREE (TYPE_MAIN_VARIANT (t));
+
+  /* As the second step of reconstructing the pointer chains put us
+     on the list of pointers of the new pointed-to type
+     if we are a main variant.  See lto_ft_common for the first step.  */
+  if (TREE_CODE (t) == POINTER_TYPE
+      && TYPE_MAIN_VARIANT (t) == t)
+    {
+      TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (TREE_TYPE (t));
+      TYPE_POINTER_TO (TREE_TYPE (t)) = t;
+    }
+  else if (TREE_CODE (t) == REFERENCE_TYPE
+          && TYPE_MAIN_VARIANT (t) == t)
+    {
+      TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (TREE_TYPE (t));
+      TYPE_REFERENCE_TO (TREE_TYPE (t)) = t;
+    }
+}
+
+/* Fix up fields of a BINFO T.  */
+
+static void
+lto_ft_binfo (tree t)
+{
+  unsigned HOST_WIDE_INT i, n;
+  tree base, saved_base;
+
+  lto_ft_common (t);
+  LTO_FIXUP_TREE (BINFO_VTABLE (t));
+  LTO_FIXUP_TREE (BINFO_OFFSET (t));
+  LTO_FIXUP_TREE (BINFO_VIRTUALS (t));
+  LTO_FIXUP_TREE (BINFO_VPTR_FIELD (t));
+  n = VEC_length (tree, BINFO_BASE_ACCESSES (t));
+  for (i = 0; i < n; i++)
+    {
+      saved_base = base = BINFO_BASE_ACCESS (t, i);
+      LTO_FIXUP_TREE (base);
+      if (base != saved_base)
+       VEC_replace (tree, BINFO_BASE_ACCESSES (t), i, base);
+    }
+  LTO_FIXUP_TREE (BINFO_INHERITANCE_CHAIN (t));
+  LTO_FIXUP_TREE (BINFO_SUBVTT_INDEX (t));
+  LTO_FIXUP_TREE (BINFO_VPTR_INDEX (t));
+  n = BINFO_N_BASE_BINFOS (t);
+  for (i = 0; i < n; i++)
+    {
+      saved_base = base = BINFO_BASE_BINFO (t, i);
+      LTO_FIXUP_TREE (base);
+      if (base != saved_base)
+       VEC_replace (tree, BINFO_BASE_BINFOS (t), i, base);
+    }
+}
+
+/* Fix up fields of a CONSTRUCTOR T.  */
+
+static void
+lto_ft_constructor (tree t)
+{
+  unsigned HOST_WIDE_INT idx;
+  constructor_elt *ce;
+
+  LTO_FIXUP_TREE (TREE_TYPE (t));
+
+  for (idx = 0;
+       VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce);
+       idx++)
+    {
+      LTO_FIXUP_TREE (ce->index);
+      LTO_FIXUP_TREE (ce->value);
+    }
+}
+
+/* Fix up fields of an expression tree T.  */
+
+static void
+lto_ft_expr (tree t)
+{
+  int i;
+  lto_ft_common (t);
+  for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
+    LTO_FIXUP_TREE (TREE_OPERAND (t, i));
+}
+
+/* Given a tree T fixup fields of T by replacing types with their merged
+   variant and other entities by an equal entity from an earlier compilation
+   unit, or an entity being canonical in a different way.  This includes
+   for instance integer or string constants.  */
+
+static void
+lto_fixup_types (tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case IDENTIFIER_NODE:
+      break;
+
+    case TREE_LIST:
+      LTO_FIXUP_TREE (TREE_VALUE (t));
+      LTO_FIXUP_TREE (TREE_PURPOSE (t));
+      LTO_FIXUP_TREE (TREE_CHAIN (t));
+      break;
+
+    case FIELD_DECL:
+      lto_ft_field_decl (t);
+      break;
+
+    case LABEL_DECL:
+    case CONST_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case IMPORTED_DECL:
+      lto_ft_decl_common (t);
+      break;
+
+    case VAR_DECL:
+      lto_ft_decl_with_vis (t);
+      break;
+
+    case TYPE_DECL:
+      lto_ft_decl_non_common (t);
+      break;
+
+    case FUNCTION_DECL:
+      lto_ft_function (t);
+      break;
+
+    case TREE_BINFO:
+      lto_ft_binfo (t);
+      break;
+
+    case PLACEHOLDER_EXPR:
+      lto_ft_common (t);
+      break;
+
+    case BLOCK:
+    case TRANSLATION_UNIT_DECL:
+    case OPTIMIZATION_NODE:
+    case TARGET_OPTION_NODE:
+      break;
+
+    default:
+      if (TYPE_P (t))
+       lto_ft_type (t);
+      else if (TREE_CODE (t) == CONSTRUCTOR)
+       lto_ft_constructor (t);
+      else if (CONSTANT_CLASS_P (t))
+       LTO_FIXUP_TREE (TREE_TYPE (t));
+      else if (EXPR_P (t))
+       {
+         lto_ft_expr (t);
+       }
+      else
+       {
+         remember_with_vars (t);
+       }
+    }
+}
+
+/* Given a streamer cache structure DATA_IN (holding a sequence of trees
+   for one compilation unit) go over all trees starting at index FROM until the
+   end of the sequence and replace fields of those trees, and the trees
+   themself with their canonical variants as per gimple_register_type.  */
+
+static void
+uniquify_nodes (struct data_in *data_in, unsigned from)
+{
+  struct lto_streamer_cache_d *cache = data_in->reader_cache;
+  unsigned len = VEC_length (tree, cache->nodes);
+  unsigned i;
+  /* Go backwards because childs streamed for the first time come
+     as part of their parents, and hence are created after them.  */
+  for (i = len; i-- > from;)
+    {
+      tree t = VEC_index (tree, cache->nodes, i);
+      tree oldt = t;
+      if (!t)
+       continue;
+
+      /* First fixup the fields of T.  */
+      lto_fixup_types (t);
+
+      /* Now try to find a canonical variant of T itself.  */
+      if (TYPE_P (t))
+       {
+         t = gimple_register_type (t);
+         if (t == oldt
+             && TYPE_MAIN_VARIANT (t) != t)
+           {
+             /* If this is its own type, link it into the variant chain.  */
+             TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (t));
+             TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (t)) = t;
+           }
+       }
+      if (t != oldt)
+       {
+         if (RECORD_OR_UNION_TYPE_P (t))
+           {
+             tree f1, f2;
+             if (TYPE_FIELDS (t) != TYPE_FIELDS (oldt))
+               for (f1 = TYPE_FIELDS (t), f2 = TYPE_FIELDS (oldt);
+                    f1 && f2; f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
+                 {
+                   unsigned ix;
+                   gcc_assert (f1 != f2 && DECL_NAME (f1) == DECL_NAME (f2));
+                   if (!lto_streamer_cache_lookup (cache, f2, &ix))
+                     gcc_unreachable ();
+                   /* If we're going to replace an element which we'd
+                      still visit in the next iterations, we wouldn't
+                      handle it, so do it here.  We do have to handle it
+                      even though the field_decl itself will be removed,
+                      as it could refer to e.g. integer_cst which we
+                      wouldn't reach via any other way, hence they
+                      (and their type) would stay uncollected.  */
+                   if (ix < i)
+                     lto_fixup_types (f2);
+                   lto_streamer_cache_insert_at (cache, f1, ix);
+                 }
+           }
 
-         /* Register every type in the global type table.  If the
-            type existed already, use the existing type.  */
-         if (TYPE_P (decls[j]))
-           decls[j] = gimple_register_type (decls[j]);
+         /* If we found a tree that is equal to oldt replace it in the
+            cache, so that further users (in the various LTO sections)
+            make use of it.  */
+         lto_streamer_cache_insert_at (cache, t, i);
        }
-
-      state->streams[i].size = size;
-      state->streams[i].trees = decls;
-      data += size;
     }
-
-  return data;
 }
 
-
 /* Read all the symbols from buffer DATA, using descriptors in DECL_DATA.
    RESOLUTIONS is the set of symbols picked by the linker (read from the
    resolution file when the linker plugin is being used).  */
@@ -260,8 +689,11 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
   /* Read the global declarations and types.  */
   while (ib_main.p < ib_main.len)
     {
-      tree t = lto_input_tree (&ib_main, data_in);
+      tree t;
+      unsigned from = VEC_length (tree, data_in->reader_cache->nodes);
+      t = lto_input_tree (&ib_main, data_in);
       gcc_assert (t && ib_main.p <= ib_main.len);
+      uniquify_nodes (data_in, from);
     }
 
   /* Read in lto_in_decl_state objects.  */
@@ -1514,7 +1946,7 @@ lto_wpa_write_files (void)
        fprintf (stderr, " %s (%s %i insns)", temp_filename, part->name, part->insns);
       if (cgraph_dump_file)
        {
-         fprintf (cgraph_dump_file, "Writting partition %s to file %s, %i insns\n",
+         fprintf (cgraph_dump_file, "Writing partition %s to file %s, %i insns\n",
                   part->name, temp_filename, part->insns);
          fprintf (cgraph_dump_file, "cgraph nodes:");
          dump_cgraph_node_set (cgraph_dump_file, set);
@@ -1548,416 +1980,106 @@ lto_wpa_write_files (void)
 }
 
 
-typedef struct {
-  struct pointer_set_t *seen;
-} lto_fixup_data_t;
-
-#define LTO_FIXUP_SUBTREE(t) \
-  do \
-    walk_tree (&(t), lto_fixup_tree, data, NULL); \
-  while (0)
-
-#define LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE(t) \
-  do \
-    { \
-      if (t) \
-       (t) = gimple_register_type (t); \
-      walk_tree (&(t), lto_fixup_tree, data, NULL); \
-    } \
-  while (0)
-
-static tree lto_fixup_tree (tree *, int *, void *);
-
-/* Return true if T does not need to be fixed up recursively.  */
-
-static inline bool
-no_fixup_p (tree t)
-{
-  return (t == NULL
-         || CONSTANT_CLASS_P (t)
-         || TREE_CODE (t) == IDENTIFIER_NODE);
-}
+/* If TT is a variable or function decl replace it with its
+   prevailing variant.  */
+#define LTO_SET_PREVAIL(tt) \
+  do {\
+    if ((tt) && VAR_OR_FUNCTION_DECL_P (tt)) \
+      tt = lto_symtab_prevailing_decl (tt); \
+  } while (0)
 
-/* Fix up fields of a tree_common T.  DATA points to fix-up states.  */
+/* Ensure that TT isn't a replacable var of function decl.  */
+#define LTO_NO_PREVAIL(tt) \
+  gcc_assert (!(tt) || !VAR_OR_FUNCTION_DECL_P (tt))
 
+/* Given a tree T replace all fields referring to variables or functions
+   with their prevailing variant.  */
 static void
-lto_fixup_common (tree t, void *data)
+lto_fixup_prevailing_decls (tree t)
 {
-  /* The following re-creates the TYPE_REFERENCE_TO and TYPE_POINTER_TO
-     lists.  We do not stream TYPE_REFERENCE_TO, TYPE_POINTER_TO or
-     TYPE_NEXT_PTR_TO and TYPE_NEXT_REF_TO.
-     First remove us from any pointer list we are on.  */
-  if (TREE_CODE (t) == POINTER_TYPE)
+  enum tree_code code = TREE_CODE (t);
+  LTO_NO_PREVAIL (TREE_TYPE (t));
+  LTO_NO_PREVAIL (TREE_CHAIN (t));
+  if (DECL_P (t))
     {
-      if (TYPE_POINTER_TO (TREE_TYPE (t)) == t)
-       TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t);
-      else
+      LTO_NO_PREVAIL (DECL_NAME (t));
+      LTO_SET_PREVAIL (DECL_CONTEXT (t));
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
        {
-         tree tem = TYPE_POINTER_TO (TREE_TYPE (t));
-         while (tem && TYPE_NEXT_PTR_TO (tem) != t)
-           tem = TYPE_NEXT_PTR_TO (tem);
-         if (tem)
-           TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t);
+         LTO_SET_PREVAIL (DECL_SIZE (t));
+         LTO_SET_PREVAIL (DECL_SIZE_UNIT (t));
+         LTO_SET_PREVAIL (DECL_INITIAL (t));
+         LTO_NO_PREVAIL (DECL_ATTRIBUTES (t));
+         LTO_SET_PREVAIL (DECL_ABSTRACT_ORIGIN (t));
        }
-      TYPE_NEXT_PTR_TO (t) = NULL_TREE;
-    }
-  else if (TREE_CODE (t) == REFERENCE_TYPE)
-    {
-      if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t)
-       TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t);
-      else
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
        {
-         tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t));
-         while (tem && TYPE_NEXT_REF_TO (tem) != t)
-           tem = TYPE_NEXT_REF_TO (tem);
-         if (tem)
-           TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t);
+         LTO_NO_PREVAIL (t->decl_with_vis.assembler_name);
+         LTO_NO_PREVAIL (DECL_SECTION_NAME (t));
        }
-      TYPE_NEXT_REF_TO (t) = NULL_TREE;
-    }
-
-  /* Fixup our type.  */
-  LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
-
-  /* Second put us on the list of pointers of the new pointed-to type
-     if we are a main variant.  This is done in lto_fixup_type after
-     fixing up our main variant.  */
-
-  /* This is not very efficient because we cannot do tail-recursion with
-     a long chain of trees. */
-  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
-    LTO_FIXUP_SUBTREE (TREE_CHAIN (t));
-}
-
-/* Fix up fields of a decl_minimal T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_decl_minimal (tree t, void *data)
-{
-  lto_fixup_common (t, data);
-  LTO_FIXUP_SUBTREE (DECL_NAME (t));
-  LTO_FIXUP_SUBTREE (DECL_CONTEXT (t));
-}
-
-/* Fix up fields of a decl_common T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_decl_common (tree t, void *data)
-{
-  lto_fixup_decl_minimal (t, data);
-  LTO_FIXUP_SUBTREE (DECL_SIZE (t));
-  LTO_FIXUP_SUBTREE (DECL_SIZE_UNIT (t));
-  LTO_FIXUP_SUBTREE (DECL_INITIAL (t));
-  LTO_FIXUP_SUBTREE (DECL_ATTRIBUTES (t));
-  LTO_FIXUP_SUBTREE (DECL_ABSTRACT_ORIGIN (t));
-}
-
-/* Fix up fields of a decl_with_vis T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_decl_with_vis (tree t, void *data)
-{
-  lto_fixup_decl_common (t, data);
-
-  /* Accessor macro has side-effects, use field-name here. */
-  LTO_FIXUP_SUBTREE (t->decl_with_vis.assembler_name);
-
-  gcc_assert (no_fixup_p (DECL_SECTION_NAME (t)));
-}
-
-/* Fix up fields of a decl_non_common T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_decl_non_common (tree t, void *data)
-{
-  lto_fixup_decl_with_vis (t, data);
-  LTO_FIXUP_SUBTREE (DECL_ARGUMENT_FLD (t));
-  LTO_FIXUP_SUBTREE (DECL_RESULT_FLD (t));
-  LTO_FIXUP_SUBTREE (DECL_VINDEX (t));
-
-  /* SAVED_TREE should not cleared by now.  Also no accessor for base type. */
-  gcc_assert (no_fixup_p (t->decl_non_common.saved_tree));
-}
-
-/* Fix up fields of a decl_non_common T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_function (tree t, void *data)
-{
-  lto_fixup_decl_non_common (t, data);
-  LTO_FIXUP_SUBTREE (DECL_FUNCTION_PERSONALITY (t));
-}
-
-/* Fix up fields of a field_decl T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_field_decl (tree t, void *data)
-{
-  lto_fixup_decl_common (t, data);
-  LTO_FIXUP_SUBTREE (DECL_FIELD_OFFSET (t));
-  LTO_FIXUP_SUBTREE (DECL_BIT_FIELD_TYPE (t));
-  LTO_FIXUP_SUBTREE (DECL_QUALIFIER (t));
-  gcc_assert (no_fixup_p (DECL_FIELD_BIT_OFFSET (t)));
-  LTO_FIXUP_SUBTREE (DECL_FCONTEXT (t));
-}
-
-/* Fix up fields of a type T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_type (tree t, void *data)
-{
-  tree tem, mv;
-
-  lto_fixup_common (t, data);
-  LTO_FIXUP_SUBTREE (TYPE_CACHED_VALUES (t));
-  LTO_FIXUP_SUBTREE (TYPE_SIZE (t));
-  LTO_FIXUP_SUBTREE (TYPE_SIZE_UNIT (t));
-  LTO_FIXUP_SUBTREE (TYPE_ATTRIBUTES (t));
-  LTO_FIXUP_SUBTREE (TYPE_NAME (t));
-
-  /* Accessors are for derived node types only. */
-  if (!POINTER_TYPE_P (t))
-    LTO_FIXUP_SUBTREE (t->type.minval);
-  LTO_FIXUP_SUBTREE (t->type.maxval);
-
-  /* Accessor is for derived node types only. */
-  LTO_FIXUP_SUBTREE (t->type.binfo);
-
-  if (TYPE_CONTEXT (t))
-    {
-      if (TYPE_P (TYPE_CONTEXT (t)))
-       LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CONTEXT (t));
-      else
-       LTO_FIXUP_SUBTREE (TYPE_CONTEXT (t));
-    }
-
-  /* Compute the canonical type of t and fix that up.  From this point
-     there are no longer any types with TYPE_STRUCTURAL_EQUALITY_P
-     and its type-based alias problems.  */
-  if (!TYPE_CANONICAL (t))
-    {
-      TYPE_CANONICAL (t) = gimple_register_canonical_type (t);
-      LTO_FIXUP_SUBTREE (TYPE_CANONICAL (t));
-    }
-
-  /* The following re-creates proper variant lists while fixing up
-     the variant leaders.  We do not stream TYPE_NEXT_VARIANT so the
-     variant list state before fixup is broken.  */
-
-  /* Remove us from our main variant list if we are not the variant leader.  */
-  if (TYPE_MAIN_VARIANT (t) != t)
-    {
-      tem = TYPE_MAIN_VARIANT (t);
-      while (tem && TYPE_NEXT_VARIANT (tem) != t)
-       tem = TYPE_NEXT_VARIANT (tem);
-      if (tem)
-       TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t);
-      TYPE_NEXT_VARIANT (t) = NULL_TREE;
-    }
-
-  /* Query our new main variant.  */
-  mv = gimple_register_type (TYPE_MAIN_VARIANT (t));
-
-  /* If we were the variant leader and we get replaced ourselves drop
-     all variants from our list.  */
-  if (TYPE_MAIN_VARIANT (t) == t
-      && mv != t)
-    {
-      tem = t;
-      while (tem)
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
        {
-         tree tem2 = TYPE_NEXT_VARIANT (tem);
-         TYPE_NEXT_VARIANT (tem) = NULL_TREE;
-         tem = tem2;
+         LTO_NO_PREVAIL (DECL_ARGUMENT_FLD (t));
+         LTO_NO_PREVAIL (DECL_RESULT_FLD (t));
+         LTO_NO_PREVAIL (DECL_VINDEX (t));
+       }
+      if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
+       LTO_SET_PREVAIL (DECL_FUNCTION_PERSONALITY (t));
+      if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
+       {
+         LTO_NO_PREVAIL (DECL_FIELD_OFFSET (t));
+         LTO_NO_PREVAIL (DECL_BIT_FIELD_TYPE (t));
+         LTO_NO_PREVAIL (DECL_QUALIFIER (t));
+         LTO_NO_PREVAIL (DECL_FIELD_BIT_OFFSET (t));
+         LTO_NO_PREVAIL (DECL_FCONTEXT (t));
        }
     }
-
-  /* If we are not our own variant leader link us into our new leaders
-     variant list.  */
-  if (mv != t)
-    {
-      TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (mv);
-      TYPE_NEXT_VARIANT (mv) = t;
-    }
-
-  /* Finally adjust our main variant and fix it up.  */
-  TYPE_MAIN_VARIANT (t) = mv;
-  LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
-
-  /* As the second step of reconstructing the pointer chains put us
-     on the list of pointers of the new pointed-to type
-     if we are a main variant.  See lto_fixup_common for the first step.  */
-  if (TREE_CODE (t) == POINTER_TYPE
-      && TYPE_MAIN_VARIANT (t) == t)
-    {
-      TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (TREE_TYPE (t));
-      TYPE_POINTER_TO (TREE_TYPE (t)) = t;
-    }
-  else if (TREE_CODE (t) == REFERENCE_TYPE
-          && TYPE_MAIN_VARIANT (t) == t)
-    {
-      TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (TREE_TYPE (t));
-      TYPE_REFERENCE_TO (TREE_TYPE (t)) = t;
-    }
-}
-
-/* Fix up fields of a BINFO T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_binfo (tree t, void *data)
-{
-  unsigned HOST_WIDE_INT i, n;
-  tree base, saved_base;
-
-  lto_fixup_common (t, data);
-  gcc_assert (no_fixup_p (BINFO_OFFSET (t)));
-  LTO_FIXUP_SUBTREE (BINFO_VTABLE (t));
-  LTO_FIXUP_SUBTREE (BINFO_VIRTUALS (t));
-  LTO_FIXUP_SUBTREE (BINFO_VPTR_FIELD (t));
-  n = VEC_length (tree, BINFO_BASE_ACCESSES (t));
-  for (i = 0; i < n; i++)
-    {
-      saved_base = base = BINFO_BASE_ACCESS (t, i);
-      LTO_FIXUP_SUBTREE (base);
-      if (base != saved_base)
-       VEC_replace (tree, BINFO_BASE_ACCESSES (t), i, base);
-    }
-  LTO_FIXUP_SUBTREE (BINFO_INHERITANCE_CHAIN (t));
-  LTO_FIXUP_SUBTREE (BINFO_SUBVTT_INDEX (t));
-  LTO_FIXUP_SUBTREE (BINFO_VPTR_INDEX (t));
-  n = BINFO_N_BASE_BINFOS (t);
-  for (i = 0; i < n; i++)
-    {
-      saved_base = base = BINFO_BASE_BINFO (t, i);
-      LTO_FIXUP_SUBTREE (base);
-      if (base != saved_base)
-       VEC_replace (tree, BINFO_BASE_BINFOS (t), i, base);
-    }
-}
-
-/* Fix up fields of a CONSTRUCTOR T.  DATA points to fix-up states.  */
-
-static void
-lto_fixup_constructor (tree t, void *data)
-{
-  unsigned HOST_WIDE_INT idx;
-  constructor_elt *ce;
-
-  LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
-
-  for (idx = 0;
-       VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce);
-       idx++)
+  else if (TYPE_P (t))
     {
-      LTO_FIXUP_SUBTREE (ce->index);
-      LTO_FIXUP_SUBTREE (ce->value);
-    }
-}
+      LTO_NO_PREVAIL (TYPE_CACHED_VALUES (t));
+      LTO_SET_PREVAIL (TYPE_SIZE (t));
+      LTO_SET_PREVAIL (TYPE_SIZE_UNIT (t));
+      LTO_NO_PREVAIL (TYPE_ATTRIBUTES (t));
+      LTO_NO_PREVAIL (TYPE_NAME (t));
 
-/* A walk_tree callback used by lto_fixup_state. TP is the pointer to the
-   current tree. WALK_SUBTREES indicates if the subtrees will be walked.
-   DATA is a pointer set to record visited nodes. */
+      LTO_SET_PREVAIL (t->type.minval);
+      LTO_SET_PREVAIL (t->type.maxval);
+      LTO_SET_PREVAIL (t->type.binfo);
 
-static tree
-lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
-{
-  tree t;
-  lto_fixup_data_t *fixup_data = (lto_fixup_data_t *) data;
-  tree prevailing;
-
-  t = *tp;
-  *walk_subtrees = 0;
-  if (!t || pointer_set_contains (fixup_data->seen, t))
-    return NULL;
+      LTO_SET_PREVAIL (TYPE_CONTEXT (t));
 
-  if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
-    {
-      prevailing = lto_symtab_prevailing_decl (t);
-
-      if (t != prevailing)
-       {
-          /* Also replace t with prevailing defintion.  We don't want to
-             insert the other defintion in the seen set as we want to
-             replace all instances of it.  */
-         *tp = prevailing;
-         t = prevailing;
-       }
+      LTO_NO_PREVAIL (TYPE_CANONICAL (t));
+      LTO_NO_PREVAIL (TYPE_MAIN_VARIANT (t));
+      LTO_NO_PREVAIL (TYPE_NEXT_VARIANT (t));
     }
-  else if (TYPE_P (t))
+  else if (EXPR_P (t))
     {
-      /* Replace t with the prevailing type.  We don't want to insert the
-         other type in the seen set as we want to replace all instances of it.  */
-      t = gimple_register_type (t);
-      *tp = t;
+      int i;
+      LTO_NO_PREVAIL (t->exp.block);
+      for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
+       LTO_SET_PREVAIL (TREE_OPERAND (t, i));
     }
-
-  if (pointer_set_insert (fixup_data->seen, t))
-    return NULL;
-
-  /* walk_tree does not visit all reachable nodes that need to be fixed up.
-     Hence we do special processing here for those kind of nodes. */
-  switch (TREE_CODE (t))
+  else
     {
-    case FIELD_DECL:
-      lto_fixup_field_decl (t, data);
-      break;
-
-    case LABEL_DECL:
-    case CONST_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case IMPORTED_DECL:
-      lto_fixup_decl_common (t, data);
-      break;
-
-    case VAR_DECL:
-      lto_fixup_decl_with_vis (t, data);
-      break;   
-
-    case TYPE_DECL:
-      lto_fixup_decl_non_common (t, data);
-      break;
-
-    case FUNCTION_DECL:
-      lto_fixup_function (t, data);
-      break;
-
-    case TREE_BINFO:
-      lto_fixup_binfo (t, data);
-      break;
-
-    default:
-      if (TYPE_P (t))
-       lto_fixup_type (t, data);
-      else if (TREE_CODE (t) == CONSTRUCTOR)
-       lto_fixup_constructor (t, data);
-      else if (CONSTANT_CLASS_P (t))
-       LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
-      else if (EXPR_P (t))
+      switch (code)
        {
-         /* walk_tree only handles TREE_OPERANDs. Do the rest here.  */
-         lto_fixup_common (t, data);
-         LTO_FIXUP_SUBTREE (t->exp.block);
-         *walk_subtrees = 1;
-       }
-      else
-       {
-         /* Let walk_tree handle sub-trees.  */
-         *walk_subtrees = 1;
+       case TREE_LIST:
+         LTO_SET_PREVAIL (TREE_VALUE (t));
+         LTO_SET_PREVAIL (TREE_PURPOSE (t));
+         break;
+       default:
+         gcc_unreachable ();
        }
     }
-
-  return NULL;
 }
+#undef LTO_SET_PREVAIL
+#undef LTO_NO_PREVAIL
 
 /* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE,
-   replaces var and function decls with the corresponding prevailing def and
-   records the old decl in the free-list in DATA. We also record visted nodes
-   in the seen-set in DATA to avoid multiple visit for nodes that need not
-   to be replaced.  */
+   replaces var and function decls with the corresponding prevailing def.  */
 
 static void
-lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data)
+lto_fixup_state (struct lto_in_decl_state *state)
 {
   unsigned i, si;
   struct lto_tree_ref_table *table;
@@ -1969,18 +2091,22 @@ lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data)
     {
       table = &state->streams[si];
       for (i = 0; i < table->size; i++)
-       walk_tree (table->trees + i, lto_fixup_tree, data, NULL);
+       {
+         tree *tp = table->trees + i;
+         if (VAR_OR_FUNCTION_DECL_P (*tp))
+           *tp = lto_symtab_prevailing_decl (*tp);
+       }
     }
 }
 
-/* A callback of htab_traverse. Just extract a state from SLOT and the
-   lto_fixup_data_t object from AUX and calls lto_fixup_state. */
+/* A callback of htab_traverse. Just extracts a state from SLOT
+   and calls lto_fixup_state. */
 
 static int
-lto_fixup_state_aux (void **slot, void *aux)
+lto_fixup_state_aux (void **slot, void *aux ATTRIBUTE_UNUSED)
 {
   struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot;
-  lto_fixup_state (state, (lto_fixup_data_t *) aux);
+  lto_fixup_state (state);
   return 1;
 }
 
@@ -1991,29 +2117,20 @@ static void
 lto_fixup_decls (struct lto_file_decl_data **files)
 {
   unsigned int i;
-  tree decl;
-  struct pointer_set_t *seen = pointer_set_create ();
-  lto_fixup_data_t data;
+  htab_iterator hi;
+  tree t;
+
+  FOR_EACH_HTAB_ELEMENT (tree_with_vars, t, tree, hi)
+    lto_fixup_prevailing_decls (t);
 
-  data.seen = seen;
   for (i = 0; files[i]; i++)
     {
       struct lto_file_decl_data *file = files[i];
       struct lto_in_decl_state *state = file->global_decl_state;
-      lto_fixup_state (state, &data);
-
-      htab_traverse (file->function_decl_states, lto_fixup_state_aux, &data);
-    }
+      lto_fixup_state (state);
 
-  FOR_EACH_VEC_ELT (tree, lto_global_var_decls, i, decl)
-    {
-      tree saved_decl = decl;
-      walk_tree (&decl, lto_fixup_tree, &data, NULL);
-      if (decl != saved_decl)
-       VEC_replace (tree, lto_global_var_decls, i, decl);
+      htab_traverse (file->function_decl_states, lto_fixup_state_aux, NULL);
     }
-
-  pointer_set_destroy (seen);
 }
 
 /* Read the options saved from each file in the command line.  Called
@@ -2144,6 +2261,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
       gcc_assert (num_objects == nfiles);
     }
 
+  tree_with_vars = htab_create_ggc (101, htab_hash_pointer, htab_eq_pointer,
+                                   NULL);
+
   if (!quiet_flag)
     fprintf (stderr, "Reading object files:");
 
@@ -2211,6 +2331,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
 
   /* Fixup all decls and types and free the type hash tables.  */
   lto_fixup_decls (all_file_decl_data);
+  htab_delete (tree_with_vars);
+  tree_with_vars = NULL;
   free_gimple_type_tables ();
   ggc_collect ();