This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH][LTO] Re-write decl & cgraph merging


On Sun, 4 Oct 2009, Richard Guenther wrote:

> 
> The following is an attempt to solve PRs 41552 and 41487.
> 
> It delays decl merging until after the cgraph and the IPA summaries
> are read in and also performs cgraph node merging as part of decl
> merging.
> 
> This patch bootstraps and tests fine and solves all but one
> link error in SPEC2006 for me.
> 
> Of course it is a hack and the proper patch is still in the works
> (but of _course_ - everytime you clean things up you break the thing....)
> 
> That is - feedback still welcome.  The cleanup will remove all the
> deferred decl stuff and records decl, resolution and file_data in a
> single LTO symtab which we iterate over for merging purposes.

This is the "final" version which I am putting to full testing now
(a slightly older version was ok).

Comments?

Thanks,
Richard.

2009-10-04  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_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.

Index: gcc/lto-symtab.c
===================================================================
*** gcc/lto-symtab.c.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/lto-symtab.c	2009-10-04 22:00:31.000000000 +0200
*************** along with GCC; see the file COPYING3.  
*** 33,146 ****
  /* 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.  */
  
! struct GTY(()) lto_symtab_base_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;
    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;
    struct lto_file_decl_data * GTY((skip (""))) file_data;
  };
! typedef struct lto_symtab_decl_def *lto_symtab_decl_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)))
    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.  */
  
  static hashval_t
! lto_symtab_base_hash (const void *p)
  {
!   const struct lto_symtab_base_def *base =
!     (const struct lto_symtab_base_def*) p;
!   return htab_hash_pointer (base->node);
  }
  
! /* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
!    corresponding to the same tree node.  */
  
  static int
! lto_symtab_base_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);
  }
  
! /* Returns non-zero if P points to an lto_symtab_base_def struct that needs
     to be marked for GC.  */ 
  
  static int
! lto_symtab_base_marked_p (const void *p)
  {
!   const struct lto_symtab_base_def *base =
!      (const struct lto_symtab_base_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);
  }
  
- #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)
  {
!   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);
!     }
  }
  
  /* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
--- 33,112 ----
  /* Vector to keep track of external variables we've seen so far.  */
  VEC(tree,gc) *lto_global_var_decls;
  
! /* Symbol table entry.  */
  
! struct GTY(()) lto_symtab_entry_def
  {
!   /* The symbol table entry key, an IDENTIFIER.  */
!   tree id;
!   /* The symbol table entry, a DECL.  */
    tree decl;
!   /* 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_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_entry_marked_p"),
! 	     param_is (struct lto_symtab_entry_def)))
    htab_t lto_symtab_identifiers;
  
! /* Return the hash value of an lto_symtab_entry_t object pointed to by P.  */
  
  static hashval_t
! lto_symtab_entry_hash (const void *p)
  {
!   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_entry_def structs
!    corresponding to the same symbol.  */
  
  static int
! lto_symtab_entry_eq (const void *p1, const void *p2)
  {
!   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_entry_def struct that needs
     to be marked for GC.  */ 
  
  static int
! lto_symtab_entry_marked_p (const void *p)
  {
!   const struct lto_symtab_entry_def *base =
!      (const struct lto_symtab_entry_def *) 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)));
  }
  
  /* Lazily initialize resolution hash tables.  */
  
  static void
! lto_symtab_maybe_init_hash_table (void)
  {
!   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
*************** lto_symtab_compatible (tree old_decl, tr
*** 465,701 ****
    return true;
  }
  
  
! /* 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)
  {
!   lto_symtab_decl_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;
    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);
    *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.  */
  
! static lto_symtab_identifier_t
! lto_symtab_get_identifier (tree id, bool insert_p)
  {
!   struct lto_symtab_identifier_def temp;
!   lto_symtab_identifier_t symtab_id;
    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;
  }
  
! /* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
!    if there is none.  */
  
! static tree
! lto_symtab_get_identifier_decl (tree id)
  {
!   lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
!   return symtab_id ? symtab_id->decl : NULL_TREE;
! }
  
! /* SET the associated DECL of an IDENTIFIER ID to be 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;
  }
  
! /* 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. */
  
  static void
! lto_symtab_merge_decl (tree new_decl,
! 		       enum ld_plugin_symbol_resolution resolution,
! 		       struct lto_file_decl_data *file_data)
  {
!   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)));
  
!   /* Remember the resolution of this symbol. */
!   lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data);
  
!   /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
!   gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl));
  
!   /* Retrieve the previous declaration.  */
!   name = DECL_ASSEMBLER_NAME (new_decl);
!   old_decl = lto_symtab_get_identifier_decl (name);
! 
!   /* 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;
!     }
  
    /* Give ODR violation errors.  */
!   old_resolution = lto_symtab_get_resolution (old_decl);
!   if (resolution == LDPR_PREVAILING_DEF
!       || resolution == LDPR_PREVAILING_DEF_IRONLY)
      {
        if ((old_resolution == LDPR_PREVAILING_DEF
  	   || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
! 	  && (old_resolution != 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;
  	}
      }
  
!   /* 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;
!     }
  
    /* 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
  	      && old_resolution != LDPR_UNKNOWN
  	      && old_resolution != LDPR_UNDEF);
  
!   if (resolution == LDPR_PREVAILING_DEF
!       || resolution == LDPR_PREVAILING_DEF_IRONLY)
      {
!       tree decl;
!       gcc_assert (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;
      }
  
!   if (resolution == LDPR_PREEMPTED_REG
!       || resolution == LDPR_RESOLVED_EXEC
!       || 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)
      gcc_assert (old_resolution == LDPR_PREVAILING_DEF
  		|| old_resolution == LDPR_PREVAILING_DEF_IRONLY
  		|| old_resolution == LDPR_PREEMPTED_IR
  		|| old_resolution == LDPR_RESOLVED_IR);
  
!   return;
  }
  
  
! /* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
!    declaration with the same name. */
  
! void
! lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
  {
!   lto_symtab_merge_decl (new_var, resolution, NULL);
  }
  
! /* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
!    declaration with the same name. */
  
  void
! lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution,
! 		     struct lto_file_decl_data *file_data)
  {
!   lto_symtab_merge_decl (new_fn, resolution, file_data);
  }
  
  /* Given the decl DECL, return the prevailing decl with the same name. */
  
  tree
  lto_symtab_prevailing_decl (tree decl)
  {
!   tree ret;
!   gcc_assert (decl);
  
    /* Builtins and local symbols are their own prevailing decl.  */
    if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
--- 431,767 ----
    return true;
  }
  
+ /* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+    and read from FILE_DATA. */
  
! void
! lto_symtab_register_decl (tree decl,
! 			  ld_plugin_symbol_resolution_t resolution,
! 			  struct lto_file_decl_data *file_data)
  {
!   lto_symtab_entry_t new_entry;
    void **slot;
  
!   /* 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_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_entry_def struct associated with ID
!    if there is one.  */
  
! static lto_symtab_entry_t
! lto_symtab_get (tree id)
  {
!   struct lto_symtab_entry_def temp;
    void **slot;
  
!   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;
  }
  
! /* Get the linker resolution for DECL.  */
  
! enum ld_plugin_symbol_resolution
! lto_symtab_get_resolution (tree decl)
  {
!   lto_symtab_entry_t e;
  
!   gcc_assert (DECL_ASSEMBLER_NAME_SET_P (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;
  }
  
! /* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging
!    all edges and removing the old node.  */
  
  static void
! lto_cgraph_replace_node (struct cgraph_node *old_node,
! 			 struct cgraph_node *new_node)
  {
!   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);
!     }
  
!   /* 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);
!     }
  
!   /* Finally remove the replaced node.  */
!   cgraph_remove_node (old_node);
! }
  
! /* Merge two variable or function symbol table entries ENTRY1 and ENTRY2.
!    Return the prevailing one or NULL if a merge is not possible.  */
  
! static lto_symtab_entry_t
! lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
! {
!   tree new_decl;
!   tree old_decl;
!   ld_plugin_symbol_resolution_t new_resolution;
!   ld_plugin_symbol_resolution_t old_resolution;
!   struct cgraph_node *old_node = NULL;
!   struct cgraph_node *new_node = NULL;
  
!   old_decl = entry1->decl;
!   old_resolution = entry1->resolution;
!   new_decl = entry2->decl;
!   new_resolution = entry2->resolution;
  
    /* Give ODR violation errors.  */
!   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 != 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 NULL;
  	}
      }
  
!   /* 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 (new_resolution != LDPR_UNKNOWN
! 	      && new_resolution != LDPR_UNDEF
  	      && old_resolution != LDPR_UNKNOWN
  	      && old_resolution != LDPR_UNDEF);
  
!   if (new_resolution == LDPR_PREVAILING_DEF
!       || new_resolution == LDPR_PREVAILING_DEF_IRONLY
!       || (!old_node && new_node))
      {
!       gcc_assert ((!old_node && new_node)
! 		  || old_resolution == LDPR_PREEMPTED_IR
  		  || old_resolution ==  LDPR_RESOLVED_IR
! 		  || (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 (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 (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);
  
!   if (new_node)
!     lto_cgraph_replace_node (new_node, old_node);
! 
!   /* Choose old_decl, entry1.  */
!   return entry1;
  }
  
+ /* Merge one symbol table chain.  */
  
! static void
! lto_symtab_merge_decls_2 (void **slot)
! {
!   lto_symtab_entry_t e2, e1 = (lto_symtab_entry_t) *slot;
!   lto_symtab_entry_t e;
!   tree size;
! 
!   /* Adjust unknown resolutions with cgraph data we have now and register
!      and adjust the decl types.  */
!   for (e = e1; e; e = e->next)
!     {
!       TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl));
!       if (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;
! 	    }
! 	}
!     }
  
!   /* Nothing more to do for a single entry.  */
!   if (!e1->next)
!     return;
! 
!   /* ???  This is lame.  */
! restart:
!   for (; e1; e1 = e1->next)
!     for (e2 = e1->next; e2; e2 = e2->next)
!       {
! 	e = lto_symtab_merge (e1, e2);
! 	if (e == e1)
! 	  {
! 	    while (e->next != e2)
! 	      e = e->next;
! 	    e->next = e2->next;
! 	    e2->next = NULL;
! 	    e2 = e;
! 	  }
! 	else if (e == e2)
! 	  {
! 	    e = (lto_symtab_entry_t) *slot;
! 	    if (e == e1)
! 	      {
! 		*slot = e1->next;
! 		e = e1->next;
! 	      }
! 	    else
! 	      {
! 		while (e->next != e1)
! 		  e = e->next;
! 		e->next = e1->next;
! 	      }
! 	    e1->next = NULL;
! 	    e1 = e;
! 	    goto restart;
! 	  }
!       }
! 
!   /* After merging what is possible see if this is a variable declaration
!      and sort the chain so the largest one is the first one in the chain.  */
!   e = (lto_symtab_entry_t) *slot;
!   if (!e->next
!       || TREE_CODE (e->decl) != VAR_DECL)
!     return;
! 
!   /* Find the largest decl and move it to the front of the chain.  */
!   size = DECL_SIZE (e->decl);
!   for (; e->next;)
!     {
!       lto_symtab_entry_t next = e->next;
!       if (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_entry_t e;
! 
!   /* Process the chain.  */
!   lto_symtab_merge_decls_2 (slot);
! 
!   /* All done for FUNCTION_DECLs.  */
!   e = (lto_symtab_entry_t) *slot;
!   if (TREE_CODE (e->decl) != VAR_DECL)
!     return 1;
! 
!   /* Insert all variable decls into the global variable decl vector.  */
!   for (; e; e = e->next)
!     VEC_safe_push (tree, gc, lto_global_var_decls, e->decl);
! 
!   return 1;
  }
  
! /* Merge all symbol table chains.  */
  
  void
! lto_symtab_merge_decls (void)
  {
!   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)
  {
!   lto_symtab_entry_t ret;
  
    /* Builtins and local symbols are their own prevailing decl.  */
    if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
*************** lto_symtab_prevailing_decl (tree decl)
*** 709,782 ****
    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;
  
    /* 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;
  
!       ret = (tree) DECL_LANG_SPECIFIC (ret);
      }
  
    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);
  
    if (!TREE_PUBLIC (decl))
      return;
--- 775,809 ----
    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 (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->decl)))
! 	return ret->decl;
  
!       ret = ret->next;
      }
  
    gcc_unreachable ();
  }
  
  /* Remove any storage used to store resolution of DECL.  */
  
  void
  lto_symtab_clear_resolution (tree decl)
  {
!   struct lto_symtab_entry_def temp;
!   lto_symtab_entry_t head;
!   void **slot;
  
    if (!TREE_PUBLIC (decl))
      return;
*************** lto_symtab_clear_resolution (tree decl)
*** 785,793 ****
    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);
  }
  
  #include "gt-lto-symtab.h"
--- 812,848 ----
    if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
      return;
  
!   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: gcc/lto-cgraph.c
===================================================================
*** gcc/lto-cgraph.c.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/lto-cgraph.c	2009-10-04 21:44:48.000000000 +0200
*************** input_edge (struct lto_input_block *ib, 
*** 527,534 ****
    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));
--- 527,532 ----
*************** input_edge (struct lto_input_block *ib, 
*** 539,546 ****
    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);
--- 537,542 ----
*************** input_edge (struct lto_input_block *ib, 
*** 550,586 ****
    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 (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;
--- 546,558 ----
    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.
!      ???  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;
  
    edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
    edge->lto_stmt_uid = stmt_id;
    edge->inline_failed = inline_failed;
*************** input_cgraph_1 (struct lto_file_decl_dat
*** 630,650 ****
  	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);
  }
  
--- 602,607 ----
Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/lto-streamer-in.c	2009-10-04 21:44:48.000000000 +0200
*************** get_resolution (struct data_in *data_in,
*** 1347,1390 ****
        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;
! 	}
!     }
  }
  
  
--- 1347,1354 ----
        return ret;
      }
    else
!     /* Delay resolution finding until decl merging.  */
!     return LDPR_UNKNOWN;
  }
  
  
*************** lto_input_tree_pointers (struct lto_inpu
*** 2243,2297 ****
      }
  }
  
- 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)
  {
    /* Register symbols with file or global scope to mark what input
       file has their definition.  */
--- 2207,2219 ----
      }
  }
  
  
  /* 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 (struct data_in *data_in, tree decl)
  {
    /* Register symbols with file or global scope to mark what input
       file has their definition.  */
*************** lto_register_var_decl_in_symtab (tree de
*** 2319,2325 ****
    /* 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);
  }
  
  
--- 2241,2253 ----
    /* If this variable has already been declared, queue the
       declaration for merging.  */
    if (TREE_PUBLIC (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);
!     }
  }
  
  
*************** lto_register_function_decl_in_symtab (st
*** 2380,2386 ****
    /* 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);
  }
  
  
--- 2308,2320 ----
    /* If this variable has already been declared, queue the
       declaration for merging.  */
    if (TREE_PUBLIC (decl) && !DECL_ABSTRACT (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);
!     }
  }
  
  
*************** lto_read_tree (struct lto_input_block *i
*** 2481,2487 ****
      gcc_assert (!lto_stream_as_builtin_p (result));
  
    if (TREE_CODE (result) == VAR_DECL)
!     lto_register_var_decl_in_symtab (result);
    else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result))
      lto_register_function_decl_in_symtab (data_in, result);
  
--- 2415,2421 ----
      gcc_assert (!lto_stream_as_builtin_p (result));
  
    if (TREE_CODE (result) == VAR_DECL)
!     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: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/lto-streamer.h	2009-10-04 22:13:09.000000000 +0200
*************** extern struct data_in *lto_data_in_creat
*** 823,829 ****
  				    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  */
--- 823,828 ----
*************** void input_cgraph (void);
*** 845,856 ****
  
  
  /* 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 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);
  
  
--- 844,854 ----
  
  
  /* In lto-symtab.c.  */
! 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);
  extern void lto_symtab_clear_resolution (tree decl);
  
  
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/lto/lto.c	2009-10-04 21:44:48.000000000 +0200
*************** lto_read_decls (struct lto_file_decl_dat
*** 244,253 ****
    /* 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);
  }
  
--- 244,249 ----
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1763,1768 ****
--- 1759,1765 ----
    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;
  
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1821,1880 ****
    /* Read the callgraph.  */
    input_cgraph ();
  
    ipa_read_summaries ();
  
!   timevar_push (TV_IPA_LTO_DECL_IO);
! 
!   lto_fixup_decls (all_file_decl_data);
! 
!   /* 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));
  
!       /* 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);
! 	}
  
!       /* 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;
! 	}
!     }
  
    /* FIXME lto. This loop needs to be changed to use the pass manager to
       call the ipa passes directly.  */
--- 1818,1839 ----
    /* Read the callgraph.  */
    input_cgraph ();
  
+   /* Read the IPA summary data.  */
    ipa_read_summaries ();
  
!   /* Merge global decls.  */
!   lto_symtab_merge_decls ();
  
!   /* 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);
  
!   timevar_push (TV_IPA_LTO_DECL_IO);
  
!   /* 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: gcc/testsuite/g++.dg/lto/20091002-1_0.C
===================================================================
*** gcc/testsuite/g++.dg/lto/20091002-1_0.C.orig	2009-10-04 21:43:21.000000000 +0200
--- gcc/testsuite/g++.dg/lto/20091002-1_0.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 1,5 ****
  // { dg-lto-do link }
! // { dg-lto-options {{-fPIC}} }
  // { dg-extra-ld-options "-fPIC -shared" }
  
  namespace std __attribute__ ((__visibility__ ("default")))
--- 1,5 ----
  // { dg-lto-do link }
! // { dg-lto-options {{-fPIC -flto}} }
  // { dg-extra-ld-options "-fPIC -shared" }
  
  namespace std __attribute__ ((__visibility__ ("default")))
Index: gcc/testsuite/g++.dg/lto/20091004-1_0.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-1_0.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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() {}
+ 
Index: gcc/testsuite/g++.dg/lto/20091004-1_1.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-1_1.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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;
+ }
Index: gcc/testsuite/g++.dg/lto/20091004-2_0.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-2_0.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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;
+ }
Index: gcc/testsuite/g++.dg/lto/20091004-2_1.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-2_1.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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() {}
+ 
Index: gcc/testsuite/g++.dg/lto/20091004-3_0.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-3_0.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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);
+ }
Index: gcc/testsuite/g++.dg/lto/20091004-3_1.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/lto/20091004-3_1.C	2009-10-04 21:44:48.000000000 +0200
***************
*** 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);
+ }
+ 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]