OSDN Git Service

2009-10-05 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 5 Oct 2009 14:05:54 +0000 (14:05 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 5 Oct 2009 14:05:54 +0000 (14:05 +0000)
PR lto/41552
PR lto/41487
* lto-symtab.c (struct lto_symtab_base_def): Remove.
(struct lto_symtab_identifier_def): Likewise.
(struct lto_symtab_decl_def): Likewise.
(struct lto_symtab_entry_def): New.
(lto_symtab_identifier_t): Rename to ...
(lto_symtab_entry_t): ... this.
(lto_symtab_decls): Remove.
(lto_symtab_base_hash): Rename to ...
(lto_symtab_entry_hash): ... this.
(lto_symtab_base_eq): Rename to ...
(lto_symtab_entry_eq): ... this.
(lto_symtab_base_marked_p): Rename to ...
(lto_symtab_entry_marked_p): ... this.
(lto_symtab_identifier_marked_p): Remove.
(lto_symtab_decl_marked_p): Likewise.
(lto_symtab_maybe_init_hash_tables): Rename to ...
(lto_symtab_maybe_init_hash_table): ... this.
(lto_symtab_set_resolution_and_file_data): Remove.
(lto_symtab_register_decl): New function.
(lto_symtab_get_identifier): Remove.
(lto_symtab_get): New function.
(lto_symtab_get_resolution): Adjust.
(lto_symtab_get_identifier_decl): Remove.
(lto_symtab_set_identifier_decl): Likewise.
(lto_symtab_merge_decl): Rename to ...
(lto_symtab_merge): ... this.  Rewrite.
(lto_symtab_merge_var): Remove.
(lto_symtab_merge_fn): Likewise.
(lto_symtab_prevailing_decl): Adjust.
(lto_cgraph_replace_node): New function.
(lto_symtab_merge_decls_2): Likewise.
(lto_symtab_merge_decls_1): Likewise.
(lto_symtab_fixup_var_decls): Likewise.
(lto_symtab_resolve_symbols): Likewise.
(lto_symtab_merge_decls): Likewise.
(lto_symtab_prevailing_decl): Adjust.
(lto_symtab_get_symtab_def): Remove.
(lto_symtab_get_file_data): Likewise.
(lto_symtab_clear_resolution): Adjust.
(lto_symtab_clear_resolution): Likewise.
* lto-cgraph.c (input_edge): Do not merge cgraph nodes here.
(input_cgraph_1): Likewise.
* lto-streamer-in.c (get_resolution): Do not provide fake
symbol resolutions here.
(deferred_global_decls): Remove.
(lto_register_deferred_decls_in_symtab): Likewise.
(lto_register_var_decl_in_symtab): Change signature, register
variable via lto_symtab_register_decl.
(lto_register_function_decl_in_symtab): Likewise.
(lto_read_tree): Adjust.
* lto-streamer.h (lto_register_deferred_decls_in_symtab): Remove.
(lto_symtab_merge_var): Likewise.
(lto_symtab_merge_fn): Likewise.
(lto_symtab_register_decl): Declare.
(lto_symtab_merge_decls): Likewise.

lto/
* lto.c (lto_read_decls): Do not register deferred decls.
(read_cgraph_and_symbols): Delay symbol and cgraph merging
until after reading the IPA summaries.

* g++.dg/lto/20091002-1_0.C: Adjust flags.
* g++.dg/lto/20091004-1_0.C: New testcase.
* g++.dg/lto/20091004-1_1.C: Likewise.
* g++.dg/lto/20091004-2_0.C: Likewise.
* g++.dg/lto/20091004-2_1.C: Likewise.
* g++.dg/lto/20091004-3_0.C: Likewise.
* g++.dg/lto/20091004-3_1.C: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152450 138bc75d-0d04-0410-961f-82ee72b054a4

15 files changed:
gcc/ChangeLog
gcc/lto-cgraph.c
gcc/lto-streamer-in.c
gcc/lto-streamer.h
gcc/lto-symtab.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lto/20091002-1_0.C
gcc/testsuite/g++.dg/lto/20091004-1_0.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/20091004-1_1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/20091004-2_0.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/20091004-2_1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/20091004-3_0.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/20091004-3_1.C [new file with mode: 0644]

index a5460f3..5da6b90 100644 (file)
@@ -1,5 +1,65 @@
 2009-10-05  Richard Guenther  <rguenther@suse.de>
 
+       PR lto/41552
+       PR lto/41487
+       * lto-symtab.c (struct lto_symtab_base_def): Remove.
+       (struct lto_symtab_identifier_def): Likewise.
+       (struct lto_symtab_decl_def): Likewise.
+       (struct lto_symtab_entry_def): New.
+       (lto_symtab_identifier_t): Rename to ...
+       (lto_symtab_entry_t): ... this.
+       (lto_symtab_decls): Remove.
+       (lto_symtab_base_hash): Rename to ...
+       (lto_symtab_entry_hash): ... this.
+       (lto_symtab_base_eq): Rename to ...
+       (lto_symtab_entry_eq): ... this.
+       (lto_symtab_base_marked_p): Rename to ...
+       (lto_symtab_entry_marked_p): ... this.
+       (lto_symtab_identifier_marked_p): Remove.
+       (lto_symtab_decl_marked_p): Likewise.
+       (lto_symtab_maybe_init_hash_tables): Rename to ...
+       (lto_symtab_maybe_init_hash_table): ... this.
+       (lto_symtab_set_resolution_and_file_data): Remove.
+       (lto_symtab_register_decl): New function.
+       (lto_symtab_get_identifier): Remove.
+       (lto_symtab_get): New function.
+       (lto_symtab_get_resolution): Adjust.
+       (lto_symtab_get_identifier_decl): Remove.
+       (lto_symtab_set_identifier_decl): Likewise.
+       (lto_symtab_merge_decl): Rename to ...
+       (lto_symtab_merge): ... this.  Rewrite.
+       (lto_symtab_merge_var): Remove.
+       (lto_symtab_merge_fn): Likewise.
+       (lto_symtab_prevailing_decl): Adjust.
+       (lto_cgraph_replace_node): New function.
+       (lto_symtab_merge_decls_2): Likewise.
+       (lto_symtab_merge_decls_1): Likewise.
+       (lto_symtab_fixup_var_decls): Likewise.
+       (lto_symtab_resolve_symbols): Likewise.
+       (lto_symtab_merge_decls): Likewise.
+       (lto_symtab_prevailing_decl): Adjust.
+       (lto_symtab_get_symtab_def): Remove.
+       (lto_symtab_get_file_data): Likewise.
+       (lto_symtab_clear_resolution): Adjust.
+       (lto_symtab_clear_resolution): Likewise.
+       * lto-cgraph.c (input_edge): Do not merge cgraph nodes here.
+       (input_cgraph_1): Likewise.
+       * lto-streamer-in.c (get_resolution): Do not provide fake
+       symbol resolutions here.
+       (deferred_global_decls): Remove.
+       (lto_register_deferred_decls_in_symtab): Likewise.
+       (lto_register_var_decl_in_symtab): Change signature, register
+       variable via lto_symtab_register_decl.
+       (lto_register_function_decl_in_symtab): Likewise.
+       (lto_read_tree): Adjust.
+       * lto-streamer.h (lto_register_deferred_decls_in_symtab): Remove.
+       (lto_symtab_merge_var): Likewise.
+       (lto_symtab_merge_fn): Likewise.
+       (lto_symtab_register_decl): Declare.
+       (lto_symtab_merge_decls): Likewise.
+
+2009-10-05  Richard Guenther  <rguenther@suse.de>
+
        PR tree-optimization/23821
        * tree-vrp.c (vrp_finalize): Do not perform copy propagation.
        * tree-ssa-dom.c (cprop_operand): Do not propagate copies into
index b11483c..47ccccd 100644 (file)
@@ -527,8 +527,6 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
   unsigned int nest;
   cgraph_inline_failed_t inline_failed;
   struct bitpack_d *bp;
-  tree prevailing_callee;
-  tree prevailing_caller;
   enum ld_plugin_symbol_resolution caller_resolution;
 
   caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
@@ -539,8 +537,6 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
   if (callee == NULL || callee->decl == NULL_TREE)
     internal_error ("bytecode stream: no callee found while reading edge");
 
-  caller_resolution = lto_symtab_get_resolution (caller->decl);
-
   count = (gcov_type) lto_input_sleb128 (ib);
 
   bp = lto_input_bitpack (ib);
@@ -550,37 +546,13 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
   freq = (int) bp_unpack_value (bp, HOST_BITS_PER_INT);
   nest = (unsigned) bp_unpack_value (bp, 30);
 
-  /* If the caller was preempted, don't create the edge.  */
+  /* If the caller was preempted, don't create the edge.
+     ???  Should we ever have edges from a preempted caller?  */
+  caller_resolution = lto_symtab_get_resolution (caller->decl);
   if (caller_resolution == LDPR_PREEMPTED_REG
       || caller_resolution == LDPR_PREEMPTED_IR)
     return;
 
-  prevailing_callee = lto_symtab_prevailing_decl (callee->decl);
-
-  /* Make sure the caller is the prevailing decl.  */
-  prevailing_caller = lto_symtab_prevailing_decl (caller->decl);
-
-  if (prevailing_callee != callee->decl)
-    {
-      struct lto_file_decl_data *file_data;
-
-      /* We cannot replace a clone!  */
-      gcc_assert (callee == cgraph_node (callee->decl));
-
-      callee = cgraph_node (prevailing_callee);
-      gcc_assert (callee);
-
-      /* If LGEN (cc1 or cc1plus) had nothing to do with the node, it
-        might not have created it. In this case, we just created a
-        new node in the above call to cgraph_node. Mark the file it
-        came from. */
-      file_data = lto_symtab_get_file_data (prevailing_callee);
-      if (callee->local.lto_file_data)
-       gcc_assert (callee->local.lto_file_data == file_data);
-      else
-       callee->local.lto_file_data = file_data;
-    }
-
   edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
   edge->lto_stmt_uid = stmt_id;
   edge->inline_failed = inline_failed;
@@ -630,21 +602,6 @@ input_cgraph_1 (struct lto_file_decl_data *file_data,
        node->global.inlined_to = NULL;
     }
 
-  for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
-    {
-      tree prevailing = lto_symtab_prevailing_decl (node->decl);
-
-      if (prevailing != node->decl)
-       {
-         cgraph_remove_node (node);
-         VEC_replace (cgraph_node_ptr, nodes, i, NULL);
-       }
-    }
-
-  for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
-    if (node && cgraph_decide_is_function_needed (node, node->decl))
-      cgraph_mark_needed_node (node);
-
   VEC_free (cgraph_node_ptr, heap, nodes);
 }
 
index a8d2379..175a1e7 100644 (file)
@@ -1347,44 +1347,8 @@ get_resolution (struct data_in *data_in, unsigned index)
       return ret;
     }
   else
-    {
-      /* Fake symbol resolution if no resolution file was provided.  */
-      tree t = lto_streamer_cache_get (data_in->reader_cache, index);
-
-      gcc_assert (TREE_PUBLIC (t));
-
-      /* There should be no DECL_ABSTRACT in the middle end.  */
-      gcc_assert (!DECL_ABSTRACT (t));
-
-      /* If T is a weak definition, we select the first one we see to
-        be the prevailing definition.  */
-      if (DECL_WEAK (t))
-       {
-         tree prevailing_decl;
-         if (DECL_EXTERNAL (t))
-           return LDPR_RESOLVED_IR;
-
-         /* If this is the first time we see T, it won't have a
-            prevailing definition yet.  */
-         prevailing_decl = lto_symtab_prevailing_decl (t);
-         if (prevailing_decl == t
-             || prevailing_decl == NULL_TREE
-             || DECL_EXTERNAL (prevailing_decl))
-           return LDPR_PREVAILING_DEF;
-         else
-           return LDPR_PREEMPTED_IR;
-       }
-      else
-       {
-         /* For non-weak definitions, extern declarations are assumed
-            to be resolved elsewhere (LDPR_RESOLVED_IR), otherwise T
-            is a prevailing definition.  */
-         if (DECL_EXTERNAL (t))
-           return LDPR_RESOLVED_IR;
-         else
-           return LDPR_PREVAILING_DEF;
-       }
-    }
+    /* Delay resolution finding until decl merging.  */
+    return LDPR_UNKNOWN;
 }
 
 
@@ -2243,55 +2207,13 @@ lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
     }
 }
 
-static VEC(tree, heap) *deferred_global_decls;
-
-/* Register the queued global decls with the symtab.  DATA_IN contains
-   tables and descriptors for the file being read.*/
-
-void
-lto_register_deferred_decls_in_symtab (struct data_in *data_in)
-{
-  unsigned i;
-  tree decl;
-
-  for (i = 0; VEC_iterate (tree, deferred_global_decls, i, decl); ++i)
-    {
-      enum ld_plugin_symbol_resolution resolution;
-      int ix;
-
-      if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix))
-       gcc_unreachable ();
-
-      /* Register and adjust the decls type.  */
-      TREE_TYPE (decl) = gimple_register_type (TREE_TYPE (decl));
-
-      if (TREE_CODE (decl) == VAR_DECL)
-       {
-         gcc_assert (TREE_PUBLIC (decl));
-         resolution = get_resolution (data_in, ix);
-         lto_symtab_merge_var (decl, resolution);
-       }
-      else if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         gcc_assert (TREE_PUBLIC (decl) && !DECL_ABSTRACT (decl));
-         resolution = get_resolution (data_in, ix);
-         lto_symtab_merge_fn (decl, resolution, data_in->file_data);
-       }
-      else
-       gcc_unreachable ();
-    }
-
-  VEC_free (tree, heap, deferred_global_decls);
-  deferred_global_decls = NULL;
-}
-
 
 /* Register DECL with the global symbol table and change its
    name if necessary to avoid name clashes for static globals across
    different files.  */
 
 static void
-lto_register_var_decl_in_symtab (tree decl)
+lto_register_var_decl_in_symtab (struct data_in *data_in, tree decl)
 {
   /* Register symbols with file or global scope to mark what input
      file has their definition.  */
@@ -2319,7 +2241,13 @@ lto_register_var_decl_in_symtab (tree decl)
   /* If this variable has already been declared, queue the
      declaration for merging.  */
   if (TREE_PUBLIC (decl))
-    VEC_safe_push (tree, heap, deferred_global_decls, decl);
+    {
+      int ix;
+      if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix))
+       gcc_unreachable ();
+      lto_symtab_register_decl (decl, get_resolution (data_in, ix),
+                               data_in->file_data);
+    }
 }
 
 
@@ -2380,7 +2308,13 @@ lto_register_function_decl_in_symtab (struct data_in *data_in, tree decl)
   /* If this variable has already been declared, queue the
      declaration for merging.  */
   if (TREE_PUBLIC (decl) && !DECL_ABSTRACT (decl))
-    VEC_safe_push (tree, heap, deferred_global_decls, decl);
+    {
+      int ix;
+      if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix))
+       gcc_unreachable ();
+      lto_symtab_register_decl (decl, get_resolution (data_in, ix),
+                               data_in->file_data);
+    }
 }
 
 
@@ -2481,7 +2415,7 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
     gcc_assert (!lto_stream_as_builtin_p (result));
 
   if (TREE_CODE (result) == VAR_DECL)
-    lto_register_var_decl_in_symtab (result);
+    lto_register_var_decl_in_symtab (data_in, result);
   else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result))
     lto_register_function_decl_in_symtab (data_in, result);
 
index b156ff4..c4d66b7 100644 (file)
@@ -823,7 +823,6 @@ extern struct data_in *lto_data_in_create (struct lto_file_decl_data *,
                                    const char *, unsigned,
                                    VEC(ld_plugin_symbol_resolution_t,heap) *);
 extern void lto_data_in_delete (struct data_in *);
-extern void lto_register_deferred_decls_in_symtab (struct data_in *);
 
 
 /* In lto-streamer-out.c  */
@@ -845,12 +844,11 @@ void input_cgraph (void);
 
 
 /* In lto-symtab.c.  */
-extern void lto_symtab_merge_var (tree, enum ld_plugin_symbol_resolution);
-extern void lto_symtab_merge_fn (tree, enum ld_plugin_symbol_resolution,
-                                 struct lto_file_decl_data *);
+extern void lto_symtab_register_decl (tree, ld_plugin_symbol_resolution_t,
+                                     struct lto_file_decl_data *);
+extern void lto_symtab_merge_decls (void);
 extern tree lto_symtab_prevailing_decl (tree decl);
 extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl);
-struct lto_file_decl_data *lto_symtab_get_file_data (tree decl);
 extern void lto_symtab_clear_resolution (tree decl);
 
 
index 90a200f..85e3c6c 100644 (file)
@@ -33,114 +33,80 @@ along with GCC; see the file COPYING3.  If not see
 /* Vector to keep track of external variables we've seen so far.  */
 VEC(tree,gc) *lto_global_var_decls;
 
-/* Base type for resolution map. It maps NODE to resolution.  */
+/* Symbol table entry.  */
 
-struct GTY(()) lto_symtab_base_def
+struct GTY(()) lto_symtab_entry_def
 {
-  /* Key is either an IDENTIFIER or a DECL.  */
-  tree node;
-};
-typedef struct lto_symtab_base_def *lto_symtab_base_t;
-
-struct GTY(()) lto_symtab_identifier_def
-{
-  struct lto_symtab_base_def base;
+  /* The symbol table entry key, an IDENTIFIER.  */
+  tree id;
+  /* The symbol table entry, a DECL.  */
   tree decl;
-};
-typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t;
-
-struct GTY(()) lto_symtab_decl_def
-{
-  struct lto_symtab_base_def base;
-  enum ld_plugin_symbol_resolution resolution;
+  /* LTO file-data and symbol resolution for this decl.  */
   struct lto_file_decl_data * GTY((skip (""))) file_data;
+  enum ld_plugin_symbol_resolution resolution;
+  /* Pointer to the next entry with the same key.  Before decl merging
+     this links all symbols from the different TUs.  After decl merging
+     this links merged but incompatible decls, thus all prevailing ones
+     remaining.  */
+  struct lto_symtab_entry_def *next;
 };
-typedef struct lto_symtab_decl_def *lto_symtab_decl_t;
+typedef struct lto_symtab_entry_def *lto_symtab_entry_t;
 
 /* A poor man's symbol table. This hashes identifier to prevailing DECL
    if there is one. */
 
-static GTY ((if_marked ("lto_symtab_identifier_marked_p"),
-            param_is (struct lto_symtab_identifier_def)))
+static GTY ((if_marked ("lto_symtab_entry_marked_p"),
+            param_is (struct lto_symtab_entry_def)))
   htab_t lto_symtab_identifiers;
 
-static GTY ((if_marked ("lto_symtab_decl_marked_p"),
-            param_is (struct lto_symtab_decl_def)))
-  htab_t lto_symtab_decls;
-
-/* Return the hash value of an lto_symtab_base_t object pointed to by P.  */
+/* Return the hash value of an lto_symtab_entry_t object pointed to by P.  */
 
 static hashval_t
-lto_symtab_base_hash (const void *p)
+lto_symtab_entry_hash (const void *p)
 {
-  const struct lto_symtab_base_def *base =
-    (const struct lto_symtab_base_def*) p;
-  return htab_hash_pointer (base->node);
+  const struct lto_symtab_entry_def *base =
+    (const struct lto_symtab_entry_def *) p;
+  return htab_hash_pointer (base->id);
 }
 
-/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
-   corresponding to the same tree node.  */
+/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
+   corresponding to the same symbol.  */
 
 static int
-lto_symtab_base_eq (const void *p1, const void *p2)
+lto_symtab_entry_eq (const void *p1, const void *p2)
 {
-  const struct lto_symtab_base_def *base1 =
-     (const struct lto_symtab_base_def *) p1;
-  const struct lto_symtab_base_def *base2 =
-     (const struct lto_symtab_base_def *) p2;
-  return (base1->node == base2->node);
+  const struct lto_symtab_entry_def *base1 =
+     (const struct lto_symtab_entry_def *) p1;
+  const struct lto_symtab_entry_def *base2 =
+     (const struct lto_symtab_entry_def *) p2;
+  return (base1->id == base2->id);
 }
 
-/* Returns non-zero if P points to an lto_symtab_base_def struct that needs
+/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
    to be marked for GC.  */ 
 
 static int
-lto_symtab_base_marked_p (const void *p)
+lto_symtab_entry_marked_p (const void *p)
 {
-  const struct lto_symtab_base_def *base =
-     (const struct lto_symtab_base_def *) p;
+  const struct lto_symtab_entry_def *base =
+     (const struct lto_symtab_entry_def *) p;
 
-  /* Keep this only if the key node is marked.  */
-  return ggc_marked_p (base->node);
-}
-
-/* Returns non-zero if P points to an lto_symtab_identifier_def struct that
-   needs to be marked for GC.  */ 
-
-static int
-lto_symtab_identifier_marked_p (const void *p)
-{
-  return lto_symtab_base_marked_p (p);
-}
-
-/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs
-   to be marked for GC.  */ 
-
-static int
-lto_symtab_decl_marked_p (const void *p)
-{
-  return lto_symtab_base_marked_p (p);
+  /* Keep this only if the decl or the chain is marked.  */
+  return (ggc_marked_p (base->decl)
+         || (base->next && ggc_marked_p (base->next)));
 }
 
-#define lto_symtab_identifier_eq       lto_symtab_base_eq
-#define lto_symtab_identifier_hash     lto_symtab_base_hash
-#define lto_symtab_decl_eq             lto_symtab_base_eq
-#define lto_symtab_decl_hash           lto_symtab_base_hash
-
 /* Lazily initialize resolution hash tables.  */
 
 static void
-lto_symtab_maybe_init_hash_tables (void)
+lto_symtab_maybe_init_hash_table (void)
 {
-  if (!lto_symtab_identifiers)
-    {
-      lto_symtab_identifiers =
-       htab_create_ggc (1021, lto_symtab_identifier_hash,
-                        lto_symtab_identifier_eq, NULL);
-      lto_symtab_decls =
-       htab_create_ggc (1021, lto_symtab_decl_hash,
-                        lto_symtab_decl_eq, NULL);
-    }
+  if (lto_symtab_identifiers)
+    return;
+
+  lto_symtab_identifiers =
+    htab_create_ggc (1021, lto_symtab_entry_hash,
+                    lto_symtab_entry_eq, NULL);
 }
 
 /* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
@@ -465,237 +431,366 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
   return true;
 }
 
+/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+   and read from FILE_DATA. */
 
-/* Marks decl DECL as having resolution RESOLUTION. */
-
-static void
-lto_symtab_set_resolution_and_file_data (tree decl,
-                                        ld_plugin_symbol_resolution_t
-                                        resolution,
-                                        struct lto_file_decl_data *file_data)
+void
+lto_symtab_register_decl (tree decl,
+                         ld_plugin_symbol_resolution_t resolution,
+                         struct lto_file_decl_data *file_data)
 {
-  lto_symtab_decl_t new_entry;
+  lto_symtab_entry_t new_entry;
   void **slot;
 
-  gcc_assert (decl);
-
-  gcc_assert (TREE_PUBLIC (decl));
-  gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
-
-  new_entry = GGC_CNEW (struct lto_symtab_decl_def);
-  new_entry->base.node = decl;
+  /* Check that declarations reaching this function do not have
+     properties inconsistent with having external linkage.  If any of
+     these asertions fail, then the object file reader has failed to
+     detect these cases and issue appropriate error messages.  */
+  gcc_assert (decl
+             && TREE_PUBLIC (decl)
+             && (TREE_CODE (decl) == VAR_DECL
+                 || TREE_CODE (decl) == FUNCTION_DECL)
+             && DECL_ASSEMBLER_NAME_SET_P (decl));
+  if (TREE_CODE (decl) == VAR_DECL)
+    gcc_assert (!(DECL_EXTERNAL (decl) && DECL_INITIAL (decl)));
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    gcc_assert (!DECL_ABSTRACT (decl));
+
+  new_entry = GGC_CNEW (struct lto_symtab_entry_def);
+  new_entry->id = DECL_ASSEMBLER_NAME (decl);
+  new_entry->decl = decl;
   new_entry->resolution = resolution;
   new_entry->file_data = file_data;
   
-  lto_symtab_maybe_init_hash_tables ();
-  slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT);
-  gcc_assert (!*slot);
+  lto_symtab_maybe_init_hash_table ();
+  slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT);
+  new_entry->next = (lto_symtab_entry_t) *slot;
   *slot = new_entry;
 }
 
-/* Get the lto_symtab_identifier_def struct associated with ID
-   if there is one.  If there is none and INSERT_P is true, create
-   a new one.  */
+/* Get the lto_symtab_entry_def struct associated with ID
+   if there is one.  */
 
-static lto_symtab_identifier_t
-lto_symtab_get_identifier (tree id, bool insert_p)
+static lto_symtab_entry_t
+lto_symtab_get (tree id)
 {
-  struct lto_symtab_identifier_def temp;
-  lto_symtab_identifier_t symtab_id;
+  struct lto_symtab_entry_def temp;
   void **slot;
 
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = id;
-  slot = htab_find_slot (lto_symtab_identifiers, &temp,
-                        insert_p ? INSERT : NO_INSERT);
-  if (insert_p)
-    {
-      if (*slot)
-       return (lto_symtab_identifier_t) *slot;
-      else
-       {
-         symtab_id = GGC_CNEW (struct lto_symtab_identifier_def);
-         symtab_id->base.node = id;
-         *slot = symtab_id;
-         return symtab_id;
-       }
-    }
-  else
-    return slot ? (lto_symtab_identifier_t) *slot : NULL;
+  lto_symtab_maybe_init_hash_table ();
+  temp.id = id;
+  slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
+  return slot ? (lto_symtab_entry_t) *slot : NULL;
 }
 
-/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
-   if there is none.  */
+/* Get the linker resolution for DECL.  */
 
-static tree
-lto_symtab_get_identifier_decl (tree id)
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
 {
-  lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
-  return symtab_id ? symtab_id->decl : NULL_TREE;
-}
+  lto_symtab_entry_t e;
 
-/* SET the associated DECL of an IDENTIFIER ID to be DECL.  */
+  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
 
-static void
-lto_symtab_set_identifier_decl (tree id, tree decl)
-{
-  lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true);
-  symtab_id->decl = decl;
+  e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+  while (e && e->decl != decl)
+    e = e->next;
+  if (!e)
+    return LDPR_UNKNOWN;
+
+  return e->resolution;
 }
 
-/* Common helper function for merging variable and function declarations.
-   NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
-   provided by the linker. */
+/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging
+   all edges and removing the old node.  */
 
 static void
-lto_symtab_merge_decl (tree new_decl,
-                      enum ld_plugin_symbol_resolution resolution,
-                      struct lto_file_decl_data *file_data)
+lto_cgraph_replace_node (struct cgraph_node *old_node,
+                        struct cgraph_node *new_node)
 {
-  tree old_decl;
-  tree name;
-  ld_plugin_symbol_resolution_t old_resolution;
-
-  gcc_assert (TREE_CODE (new_decl) == VAR_DECL
-             || TREE_CODE (new_decl) == FUNCTION_DECL);
-
-  gcc_assert (TREE_PUBLIC (new_decl));
-
-  gcc_assert (DECL_LANG_SPECIFIC (new_decl) == NULL);
-
-  /* Check that declarations reaching this function do not have
-     properties inconsistent with having external linkage.  If any of
-     these asertions fail, then the object file reader has failed to
-     detect these cases and issue appropriate error messages.  */
-  if (TREE_CODE (new_decl) == VAR_DECL)
-    gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
+  struct cgraph_edge *e, *next;
+
+  /* Merge node flags.  */
+  if (old_node->needed)
+    cgraph_mark_needed_node (new_node);
+  if (old_node->reachable)
+    cgraph_mark_reachable_node (new_node);
+  if (old_node->address_taken)
+    cgraph_mark_address_taken_node (new_node);
+
+  /* Redirect all incoming edges.  */
+  for (e = old_node->callers; e; e = next)
+    {
+      next = e->next_caller;
+      cgraph_redirect_edge_callee (e, new_node);
+    }
 
-  /* Remember the resolution of this symbol. */
-  lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data);
+  /* There are not supposed to be any outgoing edges from a node we
+     replace.  Still this can happen for multiple instances of weak
+     functions.
+     ???  For now do what the old code did.  Do not create edges for them.  */
+  for (e = old_node->callees; e; e = next)
+    {
+      next = e->next_callee;
+      cgraph_remove_edge (e);
+    }
 
-  /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
-  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl));
+  /* Finally remove the replaced node.  */
+  cgraph_remove_node (old_node);
+}
 
-  /* Retrieve the previous declaration.  */
-  name = DECL_ASSEMBLER_NAME (new_decl);
-  old_decl = lto_symtab_get_identifier_decl (name);
+/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2.
+   Return the prevailing one or NULL if a merge is not possible.  */
 
-  /* If there was no previous declaration, then there is nothing to
-     merge.  */
-  if (!old_decl)
-    {
-      lto_symtab_set_identifier_decl (name, new_decl);
-      VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
-      return;
-    }
+static lto_symtab_entry_t
+lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
+{
+  tree old_decl = entry1->decl;
+  tree new_decl = entry2->decl;
+  ld_plugin_symbol_resolution_t old_resolution = entry1->resolution;
+  ld_plugin_symbol_resolution_t new_resolution = entry2->resolution;
+  struct cgraph_node *old_node = NULL;
+  struct cgraph_node *new_node = NULL;
 
   /* Give ODR violation errors.  */
-  old_resolution = lto_symtab_get_resolution (old_decl);
-  if (resolution == LDPR_PREVAILING_DEF
-      || resolution == LDPR_PREVAILING_DEF_IRONLY)
+  if (new_resolution == LDPR_PREVAILING_DEF
+      || new_resolution == LDPR_PREVAILING_DEF_IRONLY)
     {
       if ((old_resolution == LDPR_PREVAILING_DEF
           || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
-         && (old_resolution != resolution || flag_no_common))
+         && (old_resolution != new_resolution || flag_no_common))
        {
          error_at (DECL_SOURCE_LOCATION (new_decl),
                    "%qD has already been defined", new_decl);
          inform (DECL_SOURCE_LOCATION (old_decl),
                  "previously defined here");
-         return;
+         return NULL;
        }
     }
 
-  /* The linker may ask us to combine two incompatible symbols.
-     Find a decl we can merge with or chain it in the list of decls
-     for that symbol.  */
-  while (old_decl
-        && !lto_symtab_compatible (old_decl, new_decl))
-    old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
-  if (!old_decl)
-    {
-      old_decl = lto_symtab_get_identifier_decl (name);
-      while (DECL_LANG_SPECIFIC (old_decl) != NULL)
-       old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
-      DECL_LANG_SPECIFIC (old_decl) = (struct lang_decl *) new_decl;
-      return;
-    }
+  /* The linker may ask us to combine two incompatible symbols.  */
+  if (!lto_symtab_compatible (old_decl, new_decl))
+    return NULL;
+
+  if (TREE_CODE (old_decl) == FUNCTION_DECL)
+    old_node = cgraph_get_node (old_decl);
+  if (TREE_CODE (new_decl) == FUNCTION_DECL)
+    new_node = cgraph_get_node (new_decl);
 
   /* Merge decl state in both directions, we may still end up using
      the new decl.  */
   TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl);
   TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_decl);
 
-  gcc_assert (resolution != LDPR_UNKNOWN
-             && resolution != LDPR_UNDEF
+  gcc_assert (new_resolution != LDPR_UNKNOWN
+             && new_resolution != LDPR_UNDEF
              && old_resolution != LDPR_UNKNOWN
              && old_resolution != LDPR_UNDEF);
 
-  if (resolution == LDPR_PREVAILING_DEF
-      || resolution == LDPR_PREVAILING_DEF_IRONLY)
+  if (new_resolution == LDPR_PREVAILING_DEF
+      || new_resolution == LDPR_PREVAILING_DEF_IRONLY
+      || (!old_node && new_node))
     {
-      tree decl;
-      gcc_assert (old_resolution == LDPR_PREEMPTED_IR
+      gcc_assert ((!old_node && new_node)
+                 || old_resolution == LDPR_PREEMPTED_IR
                  || old_resolution ==  LDPR_RESOLVED_IR
-                 || (old_resolution == resolution && !flag_no_common));
-      DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
-      DECL_LANG_SPECIFIC (old_decl) = NULL;
-      decl = lto_symtab_get_identifier_decl (name);
-      if (decl == old_decl)
-       {
-         lto_symtab_set_identifier_decl (name, new_decl);
-         return;
-       }
-      while ((tree) DECL_LANG_SPECIFIC (decl) != old_decl)
-       decl = (tree) DECL_LANG_SPECIFIC (decl);
-      DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) new_decl;
-      return;
+                 || (old_resolution == new_resolution && !flag_no_common));
+      if (old_node)
+       lto_cgraph_replace_node (old_node, new_node);
+      /* Choose new_decl, entry2.  */
+      return entry2;
     }
 
-  if (resolution == LDPR_PREEMPTED_REG
-      || resolution == LDPR_RESOLVED_EXEC
-      || resolution == LDPR_RESOLVED_DYN)
+  if (new_resolution == LDPR_PREEMPTED_REG
+      || new_resolution == LDPR_RESOLVED_EXEC
+      || new_resolution == LDPR_RESOLVED_DYN)
     gcc_assert (old_resolution == LDPR_PREEMPTED_REG
                || old_resolution == LDPR_RESOLVED_EXEC
                || old_resolution == LDPR_RESOLVED_DYN);
 
-  if (resolution == LDPR_PREEMPTED_IR
-      || resolution == LDPR_RESOLVED_IR)
+  if (new_resolution == LDPR_PREEMPTED_IR
+      || new_resolution == LDPR_RESOLVED_IR)
     gcc_assert (old_resolution == LDPR_PREVAILING_DEF
                || old_resolution == LDPR_PREVAILING_DEF_IRONLY
                || old_resolution == LDPR_PREEMPTED_IR
                || old_resolution == LDPR_RESOLVED_IR);
 
-  return;
+  if (new_node)
+    lto_cgraph_replace_node (new_node, old_node);
+
+  /* Choose old_decl, entry1.  */
+  return entry1;
 }
 
+/* Resolve the symbol with the candidates in the chain *SLOT and store
+   their resolutions.  */
 
-/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
-   declaration with the same name. */
+static void
+lto_symtab_resolve_symbols (void **slot)
+{
+  lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
 
-void
-lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
+  /* If the chain is already resolved there is nothing to do.  */
+  if (e->resolution != LDPR_UNKNOWN)
+    return;
+
+  /* This is a poor mans resolver.  */
+  for (; e; e = e->next)
+    {
+      gcc_assert (e->resolution == LDPR_UNKNOWN);
+      if (DECL_EXTERNAL (e->decl)
+         || (TREE_CODE (e->decl) == FUNCTION_DECL
+             && !cgraph_get_node (e->decl)))
+       e->resolution = LDPR_RESOLVED_IR;
+      else
+       {
+         if (TREE_READONLY (e->decl))
+           e->resolution = LDPR_PREVAILING_DEF_IRONLY;
+         else
+           e->resolution = LDPR_PREVAILING_DEF;
+       }
+    }
+}
+
+/* Merge one symbol table chain to a (set of) prevailing decls.  */
+
+static void
+lto_symtab_merge_decls_2 (void **slot)
+{
+  lto_symtab_entry_t e2, e1;
+
+  /* Nothing to do for a single entry.  */
+  e1 = (lto_symtab_entry_t) *slot;
+  if (!e1->next)
+    return;
+
+  /* Try to merge each entry with each other entry.  In case of a
+     single prevailing decl this is linear.  */
+restart:
+  for (; e1; e1 = e1->next)
+    for (e2 = e1->next; e2; e2 = e2->next)
+      {
+       lto_symtab_entry_t prevailing = lto_symtab_merge (e1, e2);
+       if (prevailing == e1)
+         {
+           lto_symtab_entry_t tmp = prevailing;
+           while (tmp->next != e2)
+             tmp = tmp->next;
+           tmp->next = e2->next;
+           e2->next = NULL;
+           e2 = tmp;
+         }
+       else if (prevailing == e2)
+         {
+           lto_symtab_entry_t tmp = (lto_symtab_entry_t) *slot;
+           if (tmp == e1)
+             {
+               *slot = e1->next;
+               tmp = e1->next;
+             }
+           else
+             {
+               while (tmp->next != e1)
+                 tmp = tmp->next;
+               tmp->next = e1->next;
+             }
+           e1->next = NULL;
+           e1 = tmp;
+           goto restart;
+         }
+      }
+}
+
+/* Fixup the chain of prevailing variable decls *SLOT that are commonized
+   during link-time.  */
+
+static void
+lto_symtab_fixup_var_decls (void **slot)
+{
+  lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+  tree size = bitsize_zero_node;
+
+  /* Find the largest prevailing decl and move it to the front of the chain.
+     This is the decl we will output as representative for the common
+     section.  */
+  size = bitsize_zero_node;
+  if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
+      || e->resolution == LDPR_PREVAILING_DEF)
+    size = DECL_SIZE (e->decl);
+  for (; e->next;)
+    {
+      lto_symtab_entry_t next = e->next;
+      if ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
+          || next->resolution == LDPR_PREVAILING_DEF)
+         && tree_int_cst_lt (size, DECL_SIZE (next->decl)))
+       {
+         size = DECL_SIZE (next->decl);
+         e->next = next->next;
+         next->next = (lto_symtab_entry_t) *slot;
+         *slot = next;
+       }
+      else
+       e = next;
+    }
+
+  /* Mark everything apart from the first var as written out.  */
+  e = (lto_symtab_entry_t) *slot;
+  for (e = e->next; e; e = e->next)
+    TREE_ASM_WRITTEN (e->decl) = true;
+}
+
+/* Helper to process the decl chain for the symbol table entry *SLOT.  */
+
+static int
+lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
 {
-  lto_symtab_merge_decl (new_var, resolution, NULL);
+  lto_symtab_entry_t e;
+
+  /* Compute the symbol resolutions.  */
+  lto_symtab_resolve_symbols (slot);
+
+  /* Register and adjust types of the entries.  */
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+    TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl));
+
+  /* Merge the chain to a (hopefully) single prevailing decl.  */
+  lto_symtab_merge_decls_2 (slot);
+
+  /* ???  Ideally we should delay all diagnostics until this point to
+     avoid duplicates.  */
+
+  /* All done for FUNCTION_DECLs.  */
+  e = (lto_symtab_entry_t) *slot;
+  if (TREE_CODE (e->decl) == FUNCTION_DECL)
+    return 1;
+
+  /* Fixup variables in case there are multiple prevailing ones.  */
+  if (e->next)
+    lto_symtab_fixup_var_decls (slot);
+
+  /* Insert all variable decls into the global variable decl vector.  */
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+    VEC_safe_push (tree, gc, lto_global_var_decls, e->decl);
+
+  return 1;
 }
 
-/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
-   declaration with the same name. */
+/* Resolve and merge all symbol table chains to a prevailing decl.  */
 
 void
-lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution,
-                    struct lto_file_decl_data *file_data)
+lto_symtab_merge_decls (void)
 {
-  lto_symtab_merge_decl (new_fn, resolution, file_data);
+  lto_symtab_maybe_init_hash_table ();
+  htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
 }
 
+
 /* Given the decl DECL, return the prevailing decl with the same name. */
 
 tree
 lto_symtab_prevailing_decl (tree decl)
 {
-  tree ret;
-  gcc_assert (decl);
+  lto_symtab_entry_t ret;
 
   /* Builtins and local symbols are their own prevailing decl.  */
   if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
@@ -709,74 +804,35 @@ lto_symtab_prevailing_decl (tree decl)
   gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
 
   /* Walk through the list of candidates and return the one we merged to.  */
-  ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl));
-  if (!ret
-      || DECL_LANG_SPECIFIC (ret) == NULL)
-    return ret;
+  ret = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+  if (!ret)
+    return NULL_TREE;
+
+  /* If there is only one candidate return it.  */
+  if (ret->next == NULL)
+    return ret->decl;
 
   /* If there are multiple decls to choose from find the one we merged
      with and return that.  */
   while (ret)
     {
-      if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret)))
-       return ret;
+      if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret->decl)))
+       return ret->decl;
 
-      ret = (tree) DECL_LANG_SPECIFIC (ret);
+      ret = ret->next;
     }
 
   gcc_unreachable ();
 }
 
-/* Return the hash table entry of DECL. */
-
-static struct lto_symtab_decl_def *
-lto_symtab_get_symtab_def (tree decl)
-{
-  struct lto_symtab_decl_def temp, *symtab_decl;
-  void **slot;
-
-  gcc_assert (decl);
-
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = decl;
-  slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT);
-  gcc_assert (slot && *slot);
-  symtab_decl = (struct lto_symtab_decl_def*) *slot;
-  return symtab_decl;
-}
-
-/* Return the resolution of DECL. */
-
-enum ld_plugin_symbol_resolution
-lto_symtab_get_resolution (tree decl)
-{
-  gcc_assert (decl);
-
-  if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
-    return LDPR_PREVAILING_DEF_IRONLY;
-
-  /* FIXME lto: There should be no DECL_ABSTRACT in the middle end. */
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
-    return LDPR_PREVAILING_DEF_IRONLY;
-
-  return lto_symtab_get_symtab_def (decl)->resolution;
-}
-
-/* Return the file of DECL. */
-
-struct lto_file_decl_data *
-lto_symtab_get_file_data (tree decl)
-{
-  return lto_symtab_get_symtab_def (decl)->file_data;
-}
-
 /* Remove any storage used to store resolution of DECL.  */
 
 void
 lto_symtab_clear_resolution (tree decl)
 {
-  struct lto_symtab_decl_def temp;
-  gcc_assert (decl);
+  struct lto_symtab_entry_def temp;
+  lto_symtab_entry_t head;
+  void **slot;
 
   if (!TREE_PUBLIC (decl))
     return;
@@ -785,9 +841,37 @@ lto_symtab_clear_resolution (tree decl)
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
     return;
 
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = decl;
-  htab_remove_elt (lto_symtab_decls, &temp);
+  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+
+  lto_symtab_maybe_init_hash_table ();
+  temp.id = DECL_ASSEMBLER_NAME (decl);
+  slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
+  if (!*slot)
+    return;
+
+  head = (lto_symtab_entry_t) *slot;
+  if (head->decl == decl)
+    {
+      if (head->next)
+       {
+         *slot = head->next;
+         head->next = NULL;
+       }
+      else
+       htab_remove_elt (lto_symtab_identifiers, &temp);
+    }
+  else
+    {
+      lto_symtab_entry_t e;
+      while (head->next && head->next->decl != decl)
+       head = head->next;
+      if (head->next)
+       {
+         e = head->next;
+         head->next = e->next;
+         e->next = NULL;
+       }
+    }
 }
 
 #include "gt-lto-symtab.h"
index 3ccce8f..c4ee42a 100644 (file)
@@ -1,3 +1,11 @@
+2009-10-05  Richard Guenther  <rguenther@suse.de>
+
+       PR lto/41552
+       PR lto/41487
+       * lto.c (lto_read_decls): Do not register deferred decls.
+       (read_cgraph_and_symbols): Delay symbol and cgraph merging
+       until after reading the IPA summaries.
+
 2009-10-02  Rafael Avila de Espindola  <espindola@google.com>
 
        * Make-lang.in (lto/lto-lang.o): Don't depend on lto/common.h.
index 056d249..daefa82 100644 (file)
@@ -244,10 +244,6 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
   /* Set the current decl state to be the global state. */
   decl_data->current_decl_state = decl_data->global_decl_state;
 
-  /* After each CU is read register and possibly merge global
-     symbols and their types.  */
-  lto_register_deferred_decls_in_symtab (data_in);
-
   lto_data_in_delete (data_in);
 }
 
@@ -1763,6 +1759,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   unsigned int i, last_file_ix;
   struct lto_file_decl_data **all_file_decl_data;
   FILE *resolution;
+  struct cgraph_node *node;
 
   lto_stats.num_input_files = nfiles;
 
@@ -1821,60 +1818,22 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   /* Read the callgraph.  */
   input_cgraph ();
 
+  /* Read the IPA summary data.  */
   ipa_read_summaries ();
 
-  timevar_push (TV_IPA_LTO_DECL_IO);
-
-  lto_fixup_decls (all_file_decl_data);
+  /* Merge global decls.  */
+  lto_symtab_merge_decls ();
 
-  /* See if we have multiple decls for a symbol and choose the largest
-     one to generate the common.  */
-  for (i = 0; i < VEC_length (tree, lto_global_var_decls); ++i)
-    {
-      tree decl = VEC_index (tree, lto_global_var_decls, i);
-      tree prev_decl = NULL_TREE;
-      tree size;
-
-      if (TREE_CODE (decl) != VAR_DECL
-         || !DECL_LANG_SPECIFIC (decl))
-       continue;
-
-      /* Find the preceeding decl of the largest one.  */
-      size = DECL_SIZE (decl);
-      do
-       {
-         tree next = (tree) DECL_LANG_SPECIFIC (decl);
-         if (tree_int_cst_lt (size, DECL_SIZE (next)))
-           {
-             size = DECL_SIZE (next);
-             prev_decl = decl;
-           }
-         decl = next;
-       }
-      while (DECL_LANG_SPECIFIC (decl));
+  /* Mark cgraph nodes needed in the merged cgraph.
+     ???  Is this really necessary?  */
+  for (node = cgraph_nodes; node; node = node->next)
+    if (cgraph_decide_is_function_needed (node, node->decl))
+      cgraph_mark_needed_node (node);
 
-      /* If necessary move the largest decl to the front of the
-        chain.  */
-      if (prev_decl != NULL_TREE)
-       {
-         decl = (tree) DECL_LANG_SPECIFIC (prev_decl);
-         DECL_LANG_SPECIFIC (prev_decl) = DECL_LANG_SPECIFIC (decl);
-         DECL_LANG_SPECIFIC (decl)
-           = (struct lang_decl *) VEC_index (tree, lto_global_var_decls, i);
-         VEC_replace (tree, lto_global_var_decls, i, decl);
-       }
+  timevar_push (TV_IPA_LTO_DECL_IO);
 
-      /* Mark everything apart from the first var as written out and
-         unlink the chain.  */
-      decl = VEC_index (tree, lto_global_var_decls, i);
-      while (DECL_LANG_SPECIFIC (decl))
-       {
-         tree next = (tree) DECL_LANG_SPECIFIC (decl);
-         DECL_LANG_SPECIFIC (decl) = NULL;
-         decl = next;
-         TREE_ASM_WRITTEN (decl) = true;
-       }
-    }
+  /* Fixup all decls and types.  */
+  lto_fixup_decls (all_file_decl_data);
 
   /* FIXME lto. This loop needs to be changed to use the pass manager to
      call the ipa passes directly.  */
index ce023aa..67a7428 100644 (file)
@@ -1,5 +1,17 @@
 2009-10-05  Richard Guenther  <rguenther@suse.de>
 
+       PR lto/41552
+       PR lto/41487
+       * g++.dg/lto/20091002-1_0.C: Adjust flags.
+       * g++.dg/lto/20091004-1_0.C: New testcase.
+       * g++.dg/lto/20091004-1_1.C: Likewise.
+       * g++.dg/lto/20091004-2_0.C: Likewise.
+       * g++.dg/lto/20091004-2_1.C: Likewise.
+       * g++.dg/lto/20091004-3_0.C: Likewise.
+       * g++.dg/lto/20091004-3_1.C: Likewise.
+
+2009-10-05  Richard Guenther  <rguenther@suse.de>
+
        PR tree-optimization/23821
        * gcc.dg/torture/pr23821.c: New testcase.
 
index d348e9c..ad1ecf6 100644 (file)
@@ -1,5 +1,5 @@
 // { dg-lto-do link }
-// { dg-lto-options {{-fPIC}} }
+// { dg-lto-options {{-fPIC -flto}} }
 // { dg-extra-ld-options "-fPIC -shared" }
 
 namespace std __attribute__ ((__visibility__ ("default")))
diff --git a/gcc/testsuite/g++.dg/lto/20091004-1_0.C b/gcc/testsuite/g++.dg/lto/20091004-1_0.C
new file mode 100644 (file)
index 0000000..d65cf29
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-lto-do link }
+// { dg-lto-options {{-fPIC -O -flto}} }
+
+typedef double Real;
+class Vector {
+    int dimen;
+    Real* val;
+public:
+    Vector& operator=(const Vector& vec);
+    Vector(int p_dimen, Real *p_val)
+       : dimen(p_dimen), val(p_val)    { }
+    int dim() const;
+};
+class DVector : public Vector {
+public:
+    void reDim(int newdim);
+    explicit DVector(const Vector& old);
+    DVector& operator=(const Vector& vec)    {
+       reDim(vec.dim());
+       Vector::operator=(vec);
+    }
+};
+Vector& Vector::operator=(const Vector& vec)
+{
+  dimen = vec.dimen;
+  val = vec.val;
+}
+int Vector::dim() const { return dimen; }
+DVector::DVector(const Vector& old) : Vector(0, 0)
+{
+  *this = old;
+}
+void DVector::reDim(int newdim) {}
+int main() {}
+
diff --git a/gcc/testsuite/g++.dg/lto/20091004-1_1.C b/gcc/testsuite/g++.dg/lto/20091004-1_1.C
new file mode 100644 (file)
index 0000000..0328aba
--- /dev/null
@@ -0,0 +1,26 @@
+typedef double Real;
+class Vector {
+    int dimen;
+    Real* val;
+public:
+    Vector& operator=(const Vector& vec);
+    Vector(int p_dimen, Real *p_val)
+       : dimen(p_dimen), val(p_val)    { }
+    int dim() const;
+};
+class DVector : public Vector {
+public:
+    void reDim(int newdim);
+    explicit DVector(const Vector& old);
+    DVector& operator=(const Vector& vec)    {
+       reDim(vec.dim());
+       Vector::operator=(vec);
+    }
+};
+class SLUFactor  {
+    DVector vec;
+    void solveRight (Vector& x, const Vector& b);
+};
+void SLUFactor::solveRight (Vector& x, const Vector& b) {
+    vec = b;
+}
diff --git a/gcc/testsuite/g++.dg/lto/20091004-2_0.C b/gcc/testsuite/g++.dg/lto/20091004-2_0.C
new file mode 100644 (file)
index 0000000..321e50b
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-lto-do link }
+// { dg-lto-options {{-fPIC -O -flto}} }
+
+typedef double Real;
+class Vector {
+    int dimen;
+    Real* val;
+public:
+    Vector& operator=(const Vector& vec);
+    Vector(int p_dimen, Real *p_val)
+       : dimen(p_dimen), val(p_val)    { }
+    int dim() const;
+};
+class DVector : public Vector {
+public:
+    void reDim(int newdim);
+    explicit DVector(const Vector& old);
+    DVector& operator=(const Vector& vec)    {
+       reDim(vec.dim());
+       Vector::operator=(vec);
+    }
+};
+class SLUFactor  {
+    DVector vec;
+    void solveRight (Vector& x, const Vector& b);
+};
+void SLUFactor::solveRight (Vector& x, const Vector& b) {
+    vec = b;
+}
diff --git a/gcc/testsuite/g++.dg/lto/20091004-2_1.C b/gcc/testsuite/g++.dg/lto/20091004-2_1.C
new file mode 100644 (file)
index 0000000..9bbcd51
--- /dev/null
@@ -0,0 +1,32 @@
+typedef double Real;
+class Vector {
+    int dimen;
+    Real* val;
+public:
+    Vector& operator=(const Vector& vec);
+    Vector(int p_dimen, Real *p_val)
+       : dimen(p_dimen), val(p_val)    { }
+    int dim() const;
+};
+class DVector : public Vector {
+public:
+    void reDim(int newdim);
+    explicit DVector(const Vector& old);
+    DVector& operator=(const Vector& vec)    {
+       reDim(vec.dim());
+       Vector::operator=(vec);
+    }
+};
+Vector& Vector::operator=(const Vector& vec)
+{
+  dimen = vec.dimen;
+  val = vec.val;
+}
+int Vector::dim() const { return dimen; }
+DVector::DVector(const Vector& old) : Vector(0, 0)
+{
+  *this = old;
+}
+void DVector::reDim(int newdim) {}
+int main() {}
+
diff --git a/gcc/testsuite/g++.dg/lto/20091004-3_0.C b/gcc/testsuite/g++.dg/lto/20091004-3_0.C
new file mode 100644 (file)
index 0000000..124eea5
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-lto-do assemble }
+// { dg-lto-options {{-O -flto}} }
+
+extern "C" double sqrt (double __x) throw ();
+typedef double VECTOR[3];
+enum { X = 0,  Y = 1,  Z = 2,  T = 3 };
+inline void VLength(double& a, const VECTOR b)
+{
+  a = sqrt(b[X] * b[X] + b[Y] * b[Y] + b[Z] * b[Z]);
+}
+void
+determine_subpatch_flatness(void)
+{
+  double temp1;
+  VECTOR TempV;
+  VLength(temp1, TempV);
+  VLength(temp1, TempV);
+}
diff --git a/gcc/testsuite/g++.dg/lto/20091004-3_1.C b/gcc/testsuite/g++.dg/lto/20091004-3_1.C
new file mode 100644 (file)
index 0000000..641c749
--- /dev/null
@@ -0,0 +1,16 @@
+extern "C" double sqrt (double __x) throw ();
+typedef double VECTOR[3];
+enum { X = 0,  Y = 1,  Z = 2,  T = 3 };
+inline void VLength(double& a, const VECTOR b)
+{
+  a = sqrt(b[X] * b[X] + b[Y] * b[Y] + b[Z] * b[Z]);
+}
+int
+All_Torus_Intersections(void)
+{
+  double len;
+  VECTOR D;
+  VLength(len, D);
+  VLength(len, D);
+}
+