Hi,

for various changes we can run into the situation that frontends fill the 
cache with a different number of common nodes than the LTO frontend, 
leading to confusion of which numbers mean which tree.  This can happen 
when some global trees are NULL, or when some global trees are 
pointer-equal to others in one frontend but not the other.  We can't 
really avoid filling the cache with doubled pointers if need be.  So, do 
away with the pointer map and just always append to the cache.

Based on a patch from Richi.  Regstrapping on x86_64-linux in progress.
Okay for trunk?


Ciao,
Michael.

        * lto-streamer.c (lto_record_common_node): Don't track seen nodes,
        use lto_streamer_cache_append directly instead of returning a VEC.
        (preload_common_node): Remove.
        (lto_get_common_nodes): Rename to lto_preload_common_nodes, don't
        track seen nodes.
        (lto_streamer_cache_create): Call lto_preload_common_nodes.

Index: lto-streamer.c
===================================================================
--- lto-streamer.c      (revision 173940)
+++ lto-streamer.c      (working copy)
@@ -475,17 +475,21 @@ lto_streamer_cache_get (struct lto_strea
 }
 
 
-/* Record NODE in COMMON_NODES if it is not NULL and is not already in
-   SEEN_NODES.  */
+/* Record NODE in CACHE.  */
 
 static void
-lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
-                       struct pointer_set_t *seen_nodes)
+lto_record_common_node (struct lto_streamer_cache_d *cache, tree *nodep)
 {
   tree node = *nodep;
 
-  if (node == NULL_TREE)
-    return;
+  /* We have to make sure to fill exactly the same number of
+     elements for all frontends.  That can include NULL trees.
+     As our hash table can't deal with zero entries we'll simply stream
+     a random other tree.  A NULL tree never will be looked up so it
+     doesn't matter which tree we replace it with, just to be sure
+     use error_mark_node.  */
+  if (!node)
+    node = error_mark_node;
 
   if (TYPE_P (node))
     {
@@ -500,28 +504,32 @@ lto_record_common_node (tree *nodep, VEC
       *nodep = node;
     }
 
-  /* Return if node is already seen.  */
-  if (pointer_set_insert (seen_nodes, node))
-    return;
-
-  VEC_safe_push (tree, heap, *common_nodes, node);
+  lto_streamer_cache_append (cache, node);
 
   if (POINTER_TYPE_P (node)
       || TREE_CODE (node) == COMPLEX_TYPE
       || TREE_CODE (node) == ARRAY_TYPE)
-    lto_record_common_node (&TREE_TYPE (node), common_nodes, seen_nodes);
+    lto_record_common_node (cache, &TREE_TYPE (node));
+  else if (TREE_CODE (node) == RECORD_TYPE)
+    {
+      /* The FIELD_DECLs of structures should be shared, so that every
+        COMPONENT_REF uses the same tree node when referencing a field.
+        Pointer equality between FIELD_DECLs is used by the alias
+        machinery to compute overlapping memory references (See
+        nonoverlapping_component_refs_p).  */
+      tree f;
+      for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
+       lto_record_common_node (cache, &f);
+    }
 }
 
-
-/* Generate a vector of common nodes and make sure they are merged
+/* Preload common nodes into CACHE and make sure they are merged
    properly according to the gimple type table.  */
 
-static VEC(tree,heap) *
-lto_get_common_nodes (void)
+static void
+lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
 {
   unsigned i;
-  VEC(tree,heap) *common_nodes = NULL;
-  struct pointer_set_t *seen_nodes;
 
   /* The MAIN_IDENTIFIER_NODE is normally set up by the front-end, but the
      LTO back-end must agree. Currently, the only languages that set this
@@ -545,59 +553,24 @@ lto_get_common_nodes (void)
   gcc_assert (fileptr_type_node == ptr_type_node);
   gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
 
-  seen_nodes = pointer_set_create ();
-
   /* Skip itk_char.  char_type_node is shared with the appropriately
      signed variant.  */
   for (i = itk_signed_char; i < itk_none; i++)
-    lto_record_common_node (&integer_types[i], &common_nodes, seen_nodes);
+    lto_record_common_node (cache, &integer_types[i]);
 
   for (i = 0; i < TYPE_KIND_LAST; i++)
-    lto_record_common_node (&sizetype_tab[i], &common_nodes, seen_nodes);
+    lto_record_common_node (cache, &sizetype_tab[i]);
 
   for (i = 0; i < TI_MAX; i++)
-    lto_record_common_node (&global_trees[i], &common_nodes, seen_nodes);
-
-  pointer_set_destroy (seen_nodes);
-
-  return common_nodes;
-}
-
-
-/* Assign an index to tree node T and enter it in the streamer cache
-   CACHE.  */
-
-static void
-preload_common_node (struct lto_streamer_cache_d *cache, tree t)
-{
-  gcc_assert (t);
-
-  lto_streamer_cache_insert (cache, t, NULL);
-
- /* The FIELD_DECLs of structures should be shared, so that every
-    COMPONENT_REF uses the same tree node when referencing a field.
-    Pointer equality between FIELD_DECLs is used by the alias
-    machinery to compute overlapping memory references (See
-    nonoverlapping_component_refs_p).  */
- if (TREE_CODE (t) == RECORD_TYPE)
-   {
-     tree f;
-
-     for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f))
-       preload_common_node (cache, f);
-   }
+    lto_record_common_node (cache, &global_trees[i]);
 }
 
-
 /* Create a cache of pickled nodes.  */
 
 struct lto_streamer_cache_d *
 lto_streamer_cache_create (void)
 {
   struct lto_streamer_cache_d *cache;
-  VEC(tree, heap) *common_nodes;
-  unsigned i;
-  tree node;
 
   cache = XCNEW (struct lto_streamer_cache_d);
 
@@ -606,12 +579,7 @@ lto_streamer_cache_create (void)
   /* Load all the well-known tree nodes that are always created by
      the compiler on startup.  This prevents writing them out
      unnecessarily.  */
-  common_nodes = lto_get_common_nodes ();
-
-  FOR_EACH_VEC_ELT (tree, common_nodes, i, node)
-    preload_common_node (cache, node);
-
-  VEC_free(tree, heap, common_nodes);
+  lto_preload_common_nodes (cache);
 
   return cache;
 }

Reply via email to