Cgraph alias reorg 15/14 (New infrastructure for same body aliases)

Jan Hubicka hubicka@ucw.cz
Sat Jun 11 14:22:00 GMT 2011


Hi,
this patch complettes the same body alias rework by removing the old same body
alias code and adding new representation.  Same body aliases are now separate
function nodes that have IPA_REF_ALIAS reference to the node they are alias of.

I am still getting one failure:
FAIL: g++.dg/torture/pr43879-1_1.C

It tests IPA PTA in presence of same body aliases.  I honestly have no idea
what is wrong there.  I decided to go ahead with the patch anyway, given the
current state of affair of aliases and IPA-PTA. Hope Richard will help me
fixing this on Monday.

The major pain with this change is that C++ FE gets same body aliases wrong.
It creates them with random visibilities that are not final ones, it also
creates them late in game via DECL_ASSEMBLER_NAME langhook, it forgets to set
them same_comdat_group links and it do not set DECLARED_INLINE and
DISREGARD_INLINE_LIMITS flags.

I fix that up at cgraphunit side for now, but it would be cool to resolve those
problems.

I will followup with two extra fixes needed to fully build Mozilla with LTO
again.  Once things settle down, I will switch real aliases to the new
infrastructure, too.

Bootstrapped/regtested x86_64-linux, will commit it today.


	* lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
	(lto_symtab_resolve_can_prevail_p): Likewise.
	(lto_symtab_merge_cgraph_nodes): Update merging of aliases.
	* cgraph.c (same_body_aliases_done): New global var.
	(cgraph_same_body_alias_1): Rename to ...
	(cgraph_create_function_alias): ... this one; reorg to new
	representation.
	(cgraph_same_body_alias): Use cgraph_create_function_alias;
	record references when asked to.
	(cgraph_add_thunk): Fix formating.
	(cgraph_get_node): Kill same body alias code.
	(cgraph_node_for_asm): Likewise.
	(cgraph_remove_same_body_alias): Remove.
	(cgraph_remove_node): Kill same body alias code.
	(cgraph_mark_address_taken_node): Mark also the aliased function
	as having address taken.
	(dump_cgraph_node): Dump same body aliases.
	(cgraph_for_node_thunks_and_aliases): Update for new alias
	representation.
	(cgraph_for_node_and_aliases): Likewise.
	* cgraph.h (same_body): Kll pointer.
	(same_body_alias): Update comment.
	(same_body_aliases_done): Declare.
	(cgraph_remove_same_body_alias): Remove declaration.
	(cgraph_create_function_alias): Declare.
	(cgraph_process_same_body_aliases): Declare.
	(cgraph_function_with_gimple_body_p): Check for alias.
	(cgraph_can_remove_if_no_direct_calls_p): Look for aliases.
	(cgraph_alias_aliased_node): New function.
	(cgraph_function_node): Update for new aliases.
	(cgraph_function_or_thunk_node): Likewise.
	* ipa-inline-transform.c (can_remove_node_now_p): Look for aliases.
	(inline_call): Remove dead aliases.
	* cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name
	hack for same body aliases.
	(clone_of_p): Look through aliases.
	(verify_cgraph_node): Verify aliases.
	(cgraph_analyze_function): Analyze aliases; fixup C++ bugs.
	(cgraph_process_same_body_aliases): New function.
	(process_function_and_variable_attributes): Disable weakref warning on
	alias.
	(cgraph_analyze_functions): Handle aliases.
	(cgraph_mark_functions_to_output): Handle aliases same way as thunks.
	(assemble_thunks): Rename to ...
	(assemble_thunks_and_aliases): ... this one; handle aliases, too.
	(cgraph_expand_function): Remove alias output code.
	(cgraph_output_in_order): Skip aliases.
	(cgraph_preserve_function_body_p): Aliases don't need preserving.
	* ipa-ref.c (ipa_ref_use_name): Add alias reference.
	(ipa_record_reference): Do not assert on alias references.
	(ipa_ref_has_aliases_p): New function.
	* ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS.
	(ipa_ref_has_aliases_p): Declare.
	* lto-cgraph.c (lto_output_node): Handle aliases.
	(input_node): Likewise.
	* lto-streamer-out.c (lto_output): Skip aliases.
	(produce_symtab): Kill same_body_alias code.
	* ipa-utils.c (ipa_reverse_postorder): Add FIXME.
	(ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p.
	* ipa-inline.c (update_caller_keys): Walk aliases.
	(inline_small_functions): Fix thinko in previous patch.
	* ipa.c (cgraph_externally_visible_p): Do not walk aliases.
	(function_and_variable_visibility): Do not walk same body aliases.
	* tree-ssa-structalias.c (associate_varinfo_to_alias): New function.
	(ipa_pta_execute): Use it.

	* lto.c (add_cgraph_node_to_partition_1): Break out from ...
	(add_cgraph_node_to_partition) ... here; walk aliases.
	(lto_1_to_1_map): Remove same body alias code.
	(promote_fn): Likewise.
	(lto_promote_cross_file_statics): Update comment.

	* decl2.c (cp_write_global_declarations): Process aliases; look trhough
	same body aliases.
Index: lto-symtab.c
===================================================================
*** lto-symtab.c	(revision 174944)
--- lto-symtab.c	(working copy)
*************** lto_cgraph_replace_node (struct cgraph_n
*** 209,215 ****
  			 struct cgraph_node *prevailing_node)
  {
    struct cgraph_edge *e, *next;
-   bool no_aliases_please = false;
    bool compatible_p;
  
    if (cgraph_dump_file)
--- 209,214 ----
*************** lto_cgraph_replace_node (struct cgraph_n
*** 223,235 ****
  		 (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)))));
      }
  
-   if (prevailing_node->same_body_alias)
-     {
-       if (prevailing_node->thunk.thunk_p)
- 	no_aliases_please = true;
-       prevailing_node = prevailing_node->same_body;
-     }
- 
    /* Merge node flags.  */
    if (node->needed)
      cgraph_mark_needed_node (prevailing_node);
--- 222,227 ----
*************** lto_cgraph_replace_node (struct cgraph_n
*** 259,294 ****
    /* Redirect incomming references.  */
    ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
  
-   /* If we have aliases, redirect them to the prevailing node.  */
-   if (!node->same_body_alias && node->same_body)
-     {
-       struct cgraph_node *alias, *last;
-       /* We prevail aliases/tunks by a thunk.  This is doable but
-          would need thunk combination.  Hopefully no ABI changes will
-          every be crazy enough.  */
-       gcc_assert (!no_aliases_please);
- 
-       for (alias = node->same_body; alias; alias = alias->next)
- 	{
- 	  last = alias;
- 	  gcc_assert (alias->same_body_alias);
- 	  alias->same_body = prevailing_node;
- 	}
-       last->next = prevailing_node->same_body;
-       /* Node with aliases is prevailed by alias.
- 	 We could handle this, but combining thunks together will be tricky.
- 	 Hopefully this does not happen.  */
-       if (prevailing_node->same_body)
- 	prevailing_node->same_body->previous = last;
-       prevailing_node->same_body = node->same_body;
-       node->same_body = NULL;
-     }
- 
    /* Finally remove the replaced node.  */
!   if (node->same_body_alias)
!     cgraph_remove_same_body_alias (node);
!   else
!     cgraph_remove_node (node);
  }
  
  /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
--- 251,258 ----
    /* Redirect incomming references.  */
    ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
  
    /* Finally remove the replaced node.  */
!   cgraph_remove_node (node);
  }
  
  /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
*************** lto_symtab_resolve_can_prevail_p (lto_sy
*** 472,480 ****
  
    /* For functions we need a non-discarded body.  */
    if (TREE_CODE (e->decl) == FUNCTION_DECL)
!     return (e->node
! 	    && (e->node->analyzed
! 	        || (e->node->same_body_alias && e->node->same_body->analyzed)));
  
    /* A variable should have a size.  */
    else if (TREE_CODE (e->decl) == VAR_DECL)
--- 436,442 ----
  
    /* For functions we need a non-discarded body.  */
    if (TREE_CODE (e->decl) == FUNCTION_DECL)
!     return (e->node && e->node->analyzed);
  
    /* A variable should have a size.  */
    else if (TREE_CODE (e->decl) == VAR_DECL)
*************** lto_symtab_merge_cgraph_nodes_1 (void **
*** 816,835 ****
  void
  lto_symtab_merge_cgraph_nodes (void)
  {
!   struct cgraph_node *node, *alias, *next;
    lto_symtab_maybe_init_hash_table ();
    htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
  
    for (node = cgraph_nodes; node; node = node->next)
!     {
!       if (node->thunk.thunk_p)
!         node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
!       for (alias = node->same_body; alias; alias = next)
! 	{
! 	  next = alias->next;
! 	  alias->thunk.alias = lto_symtab_prevailing_decl (alias->thunk.alias);
! 	}
!     }
  }
  
  /* Given the decl DECL, return the prevailing decl with the same name. */
--- 778,791 ----
  void
  lto_symtab_merge_cgraph_nodes (void)
  {
!   struct cgraph_node *node;
    lto_symtab_maybe_init_hash_table ();
    htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
  
    for (node = cgraph_nodes; node; node = node->next)
!     if ((node->thunk.thunk_p || node->alias)
! 	&& node->thunk.alias)
!       node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
  }
  
  /* Given the decl DECL, return the prevailing decl with the same name. */
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 174944)
--- cgraph.c	(working copy)
*************** static GTY(()) struct cgraph_node *free_
*** 208,213 ****
--- 208,216 ----
     Do not GTY((delete)) this list so UIDs gets reliably recycled.  */
  static GTY(()) struct cgraph_edge *free_edges;
  
+ /* Did procss_same_body_aliases run?  */
+ bool same_body_aliases_done;
+ 
  /* Macros to access the next item in the list of free cgraph nodes and
     edges. */
  #define NEXT_FREE_NODE(NODE) (NODE)->next
*************** cgraph_get_create_node (tree decl)
*** 542,574 ****
  /* Mark ALIAS as an alias to DECL.  DECL_NODE is cgraph node representing
     the function body is associated with (not neccesarily cgraph_node (DECL).  */
  
! static struct cgraph_node *
! cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl)
  {
!   struct cgraph_node key, *alias_node, **slot;
  
    gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
    gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
! 
!   key.decl = alias;
! 
!   slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
! 
!   /* If the cgraph_node has been already created, fail.  */
!   if (*slot)
!     return NULL;
! 
!   alias_node = cgraph_allocate_node ();
!   alias_node->decl = alias;
!   alias_node->same_body_alias = 1;
!   alias_node->same_body = decl_node;
!   alias_node->previous = NULL;
!   if (decl_node->same_body)
!     decl_node->same_body->previous = alias_node;
!   alias_node->next = decl_node->same_body;
    alias_node->thunk.alias = decl;
!   decl_node->same_body = alias_node;
!   *slot = alias_node;
    return alias_node;
  }
  
--- 545,567 ----
  /* Mark ALIAS as an alias to DECL.  DECL_NODE is cgraph node representing
     the function body is associated with (not neccesarily cgraph_node (DECL).  */
  
! struct cgraph_node *
! cgraph_create_function_alias (tree alias, tree decl)
  {
!   struct cgraph_node *alias_node;
  
    gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
    gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
!   alias_node = cgraph_get_create_node (alias);
!   gcc_assert (!alias_node->local.finalized);
    alias_node->thunk.alias = decl;
!   alias_node->local.finalized = true;
!   alias_node->alias = 1;
! 
!   if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias))
!       || (DECL_VIRTUAL_P (alias)
! 	  && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias))))
!     cgraph_mark_reachable_node (alias_node);
    return alias_node;
  }
  
*************** cgraph_same_body_alias_1 (struct cgraph_
*** 578,593 ****
     and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL).  */
  
  struct cgraph_node *
! cgraph_same_body_alias (struct cgraph_node *decl_node, tree alias, tree decl)
  {
  #ifndef ASM_OUTPUT_DEF
    /* If aliases aren't supported by the assembler, fail.  */
    return NULL;
  #endif
  
!   /*gcc_assert (!assembler_name_hash);*/
! 
!   return cgraph_same_body_alias_1 (decl_node, alias, decl);
  }
  
  /* Add thunk alias into callgraph.  The alias declaration is ALIAS and it
--- 571,594 ----
     and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL).  */
  
  struct cgraph_node *
! cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree alias, tree decl)
  {
+   struct cgraph_node *n;
  #ifndef ASM_OUTPUT_DEF
    /* If aliases aren't supported by the assembler, fail.  */
    return NULL;
  #endif
+   /* Langhooks can create same body aliases of symbols not defined.
+      Those are useless. Drop them on the floor.  */
+   if (cgraph_global_info_ready)
+     return NULL;
  
!   n = cgraph_create_function_alias (alias, decl);
!   n->same_body_alias = true;
!   if (same_body_aliases_done)
!     ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS,
! 			  NULL);
!   return n;
  }
  
  /* Add thunk alias into callgraph.  The alias declaration is ALIAS and it
*************** cgraph_add_thunk (struct cgraph_node *de
*** 633,638 ****
--- 634,640 ----
        || (DECL_VIRTUAL_P (decl)
  	  && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
      cgraph_mark_reachable_node (node);
+ 
    return node;
  }
  
*************** cgraph_get_node (const_tree decl)
*** 678,688 ****
  						 NO_INSERT);
  
    if (slot && *slot)
!     {
!       node = *slot;
!       if (node->same_body_alias)
! 	node = node->same_body;
!     }
    return node;
  }
  
--- 680,686 ----
  						 NO_INSERT);
  
    if (slot && *slot)
!     node = *slot;
    return node;
  }
  
*************** cgraph_node_for_asm (tree asmname)
*** 745,765 ****
  	       so lets hope for the best.  */
  	    if (!*slot)
  	      *slot = node;
- 	    if (node->same_body)
- 	      {
- 		struct cgraph_node *alias;
- 
- 		for (alias = node->same_body; alias; alias = alias->next)
- 		  {
- 		    hashval_t hash;
- 		    name = DECL_ASSEMBLER_NAME (alias->decl);
- 		    hash = decl_assembler_name_hash (name);
- 		    slot = htab_find_slot_with_hash (assembler_name_hash, name,
- 						     hash,  INSERT);
- 		    if (!*slot)
- 		      *slot = alias;
- 		  }
- 	      }
  	  }
      }
  
--- 743,748 ----
*************** cgraph_node_for_asm (tree asmname)
*** 770,777 ****
    if (slot)
      {
        node = (struct cgraph_node *) *slot;
-       if (node->same_body_alias)
- 	node = node->same_body;
        return node;
      }
    return NULL;
--- 753,758 ----
*************** cgraph_release_function_body (struct cgr
*** 1432,1475 ****
      DECL_INITIAL (node->decl) = error_mark_node;
  }
  
- /* Remove same body alias node.  */
- 
- void
- cgraph_remove_same_body_alias (struct cgraph_node *node)
- {
-   void **slot;
-   int uid = node->uid;
- 
-   gcc_assert (node->same_body_alias);
-   if (node->previous)
-     node->previous->next = node->next;
-   else
-     node->same_body->same_body = node->next;
-   if (node->next)
-     node->next->previous = node->previous;
-   node->next = NULL;
-   node->previous = NULL;
-   slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
-   if (*slot == node)
-     htab_clear_slot (cgraph_hash, slot);
-   if (assembler_name_hash)
-     {
-       tree name = DECL_ASSEMBLER_NAME (node->decl);
-       slot = htab_find_slot_with_hash (assembler_name_hash, name,
- 				       decl_assembler_name_hash (name),
- 				       NO_INSERT);
-       if (slot && *slot == node)
- 	htab_clear_slot (assembler_name_hash, slot);
-     }
- 
-   /* Clear out the node to NULL all pointers and add the node to the free
-      list.  */
-   memset (node, 0, sizeof(*node));
-   node->uid = uid;
-   NEXT_FREE_NODE (node) = free_nodes;
-   free_nodes = node;
- }
- 
  /* Remove the node from cgraph.  */
  
  void
--- 1413,1418 ----
*************** cgraph_remove_node (struct cgraph_node *
*** 1631,1639 ****
  	}
      }
  
-   while (node->same_body)
-     cgraph_remove_same_body_alias (node->same_body);
- 
    if (node->same_comdat_group)
      {
        struct cgraph_node *prev;
--- 1574,1579 ----
*************** cgraph_mark_address_taken_node (struct c
*** 1747,1752 ****
--- 1687,1700 ----
  {
    gcc_assert (!node->global.inlined_to);
    cgraph_mark_reachable_node (node);
+   /* FIXME: address_taken flag is used both as a shortcut for testing whether
+      IPA_REF_ADDR reference exists (and thus it should be set on node
+      representing alias we take address of) and as a test whether address
+      of the object was taken (and thus it should be set on node alias is
+      referring to).  We should remove the first use and the remove the
+      following set.  */
+   node->address_taken = 1;
+   node = cgraph_function_or_thunk_node (node, NULL);
    node->address_taken = 1;
  }
  
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1902,1907 ****
--- 1850,1864 ----
  	       (int)node->thunk.virtual_value,
  	       (int)node->thunk.virtual_offset_p);
      }
+   if (node->alias && node->thunk.alias)
+     {
+       fprintf (f, "  alias of %s",
+ 	       lang_hooks.decl_printable_name (node->thunk.alias, 2));
+       if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias))
+         fprintf (f, " (asm: %s)",
+ 		 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)));
+       fprintf (f, "\n");
+     }
    
    fprintf (f, "  called by: ");
  
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1952,1970 ****
    if (indirect_calls_count)
      fprintf (f, "  has %i outgoing edges for indirect calls.\n",
  	     indirect_calls_count);
- 
-   if (node->same_body)
-     {
-       struct cgraph_node *n;
-       fprintf (f, "  aliases:");
-       for (n = node->same_body; n; n = n->next)
-         {
-           fprintf (f, " %s/%i", cgraph_node_name (n), n->uid);
- 	  if (DECL_ASSEMBLER_NAME_SET_P (n->decl))
- 	    fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
- 	}
-       fprintf (f, "\n");
-     }
  }
  
  
--- 1909,1914 ----
*************** cgraph_for_node_thunks_and_aliases (stru
*** 2614,2631 ****
  				    bool include_overwritable)
  {
    struct cgraph_edge *e;
!   struct cgraph_node *alias;
  
    if (callback (node, data))
      return true;
-   for (alias = node->same_body; alias; alias = alias->next)
-     if (callback (alias, data))
-       return true;
    for (e = node->callers; e; e = e->next_caller)
      if (e->caller->thunk.thunk_p
  	&& (include_overwritable
! 	    || cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE))
        cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
    return false;
  }
  
--- 2558,2581 ----
  				    bool include_overwritable)
  {
    struct cgraph_edge *e;
!   int i;
!   struct ipa_ref *ref;
  
    if (callback (node, data))
      return true;
    for (e = node->callers; e; e = e->next_caller)
      if (e->caller->thunk.thunk_p
  	&& (include_overwritable
! 	    || cgraph_function_body_availability (e->caller)))
        cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
+   for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+     if (ref->use == IPA_REF_ALIAS)
+       {
+ 	struct cgraph_node *alias = ipa_ref_refering_node (ref);
+ 	if (include_overwritable
+ 	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
+           cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable);
+       }
    return false;
  }
  
*************** bool
*** 2637,2651 ****
  cgraph_for_node_and_aliases (struct cgraph_node *node,
  			     bool (*callback) (struct cgraph_node *, void *),
  			     void *data,
! 			     bool include_overwritable ATTRIBUTE_UNUSED)
  {
!   struct cgraph_node *alias;
  
    if (callback (node, data))
      return true;
!   for (alias = node->same_body; alias; alias = alias->next)
!     if (callback (alias, data))
!       return true;
    return false;
  }
  
--- 2587,2607 ----
  cgraph_for_node_and_aliases (struct cgraph_node *node,
  			     bool (*callback) (struct cgraph_node *, void *),
  			     void *data,
! 			     bool include_overwritable)
  {
!   int i;
!   struct ipa_ref *ref;
  
    if (callback (node, data))
      return true;
!   for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
!     if (ref->use == IPA_REF_ALIAS)
!       {
! 	struct cgraph_node *alias = ipa_ref_refering_node (ref);
! 	if (include_overwritable
! 	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
!           cgraph_for_node_and_aliases (alias, callback, data, include_overwritable);
!       }
    return false;
  }
  
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 174944)
--- cgraph.h	(working copy)
*************** struct GTY((chain_next ("%h.next"), chai
*** 165,173 ****
    struct cgraph_node *prev_sibling_clone;
    struct cgraph_node *clones;
    struct cgraph_node *clone_of;
-   /* For normal nodes pointer to the list of alias and thunk nodes,
-      in alias/thunk nodes pointer to the normal node.  */
-   struct cgraph_node *same_body;
    /* Circular list of nodes in the same comdat group if non-NULL.  */
    struct cgraph_node *same_comdat_group;
    /* For functions with many calls sites it holds map from call expression
--- 165,170 ----
*************** struct GTY((chain_next ("%h.next"), chai
*** 236,243 ****
    unsigned process : 1;
    /* Set for aliases once they got through assemble_alias.  */
    unsigned alias : 1;
!   /* Set for alias and thunk nodes, same_body points to the node they are alias
!      of and they are linked through the next/previous pointers.  */
    unsigned same_body_alias : 1;
    /* How commonly executed the node is.  Initialized during branch
       probabilities pass.  */
--- 233,239 ----
    unsigned process : 1;
    /* Set for aliases once they got through assemble_alias.  */
    unsigned alias : 1;
!   /* Set for aliases created as C++ same body aliases.  */
    unsigned same_body_alias : 1;
    /* How commonly executed the node is.  Initialized during branch
       probabilities pass.  */
*************** extern GTY(()) struct cgraph_node *cgrap
*** 463,468 ****
--- 459,465 ----
  
  extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
  extern GTY(()) int cgraph_order;
+ extern bool same_body_aliases_done;
  
  /* In cgraph.c  */
  void dump_cgraph (FILE *);
*************** struct cgraph_node * cgraph_get_create_n
*** 488,494 ****
  struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree);
  struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT,
  				       HOST_WIDE_INT, tree, tree);
- void cgraph_remove_same_body_alias (struct cgraph_node *);
  struct cgraph_node *cgraph_node_for_asm (tree);
  struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
  void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
--- 485,490 ----
*************** struct cgraph_edge * cgraph_clone_edge (
*** 508,513 ****
--- 504,510 ----
  struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
  					int, bool, VEC(cgraph_edge_p,heap) *,
  					bool);
+ struct cgraph_node *cgraph_create_function_alias (tree, tree);
  
  void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
  void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
*************** void tree_function_versioning (tree, tre
*** 577,582 ****
--- 574,580 ----
  			       bitmap, basic_block);
  void record_references_in_initializer (tree, bool);
  bool cgraph_process_new_functions (void);
+ void cgraph_process_same_body_aliases (void);
  
  bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
  
*************** cgraph_next_defined_function (struct cgr
*** 746,752 ****
  static inline bool
  cgraph_function_with_gimple_body_p (struct cgraph_node *node)
  {
!   return node->analyzed && !node->thunk.thunk_p;
  }
  
  /* Return first function with body defined.  */
--- 744,750 ----
  static inline bool
  cgraph_function_with_gimple_body_p (struct cgraph_node *node)
  {
!   return node->analyzed && !node->thunk.thunk_p && !node->alias;
  }
  
  /* Return first function with body defined.  */
*************** cgraph_can_remove_if_no_direct_calls_p (
*** 934,940 ****
    if (DECL_EXTERNAL (node->decl))
      return true;
    return (!node->address_taken
! 	  && cgraph_can_remove_if_no_direct_calls_and_refs_p (node));
  }
  
  /* Return true when function NODE can be removed from callgraph
--- 932,939 ----
    if (DECL_EXTERNAL (node->decl))
      return true;
    return (!node->address_taken
! 	  && cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
! 	  && !ipa_ref_has_aliases_p (&node->ref_list));
  }
  
  /* Return true when function NODE can be removed from callgraph
*************** htab_t constant_pool_htab (void);
*** 968,973 ****
--- 967,986 ----
  /* FIXME: inappropriate dependency of cgraph on IPA.  */
  #include "ipa-ref-inline.h"
  
+ /* Return node that alias N is aliasing.  */
+ 
+ static inline struct cgraph_node *
+ cgraph_alias_aliased_node (struct cgraph_node *n)
+ {
+   struct ipa_ref *ref;
+ 
+   ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
+   gcc_checking_assert (ref->use == IPA_REF_ALIAS);
+   if (ref->refered_type == IPA_REF_CGRAPH)
+     return ipa_ref_node (ref);
+   return NULL;
+ }
+ 
  /* Given NODE, walk the alias chain to return the function NODE is alias of.
     Walk through thunk, too.
     When AVAILABILITY is non-NULL, get minimal availablity in the chain.  */
*************** cgraph_function_node (struct cgraph_node
*** 979,989 ****
      *availability = cgraph_function_body_availability (node);
    while (node)
      {
!       if (node->thunk.thunk_p)
  	node = node->callees->callee;
        else
  	return node;
!       if (availability)
  	{
  	  enum availability a;
  	  a = cgraph_function_body_availability (node);
--- 992,1004 ----
      *availability = cgraph_function_body_availability (node);
    while (node)
      {
!       if (node->alias && node->analyzed)
! 	node = cgraph_alias_aliased_node (node);
!       else if (node->thunk.thunk_p)
  	node = node->callees->callee;
        else
  	return node;
!       if (node && availability)
  	{
  	  enum availability a;
  	  a = cgraph_function_body_availability (node);
*************** cgraph_function_node (struct cgraph_node
*** 991,996 ****
--- 1006,1013 ----
  	    *availability = a;
  	}
      }
+   if (*availability)
+     *availability = AVAIL_NOT_AVAILABLE;
    return NULL;
  }
  
*************** cgraph_function_or_thunk_node (struct cg
*** 1003,1009 ****
  {
    if (availability)
      *availability = cgraph_function_body_availability (node);
!   return node;
    return NULL;
  }
  
--- 1020,1041 ----
  {
    if (availability)
      *availability = cgraph_function_body_availability (node);
!   while (node)
!     {
!       if (node->alias && node->analyzed)
! 	node = cgraph_alias_aliased_node (node);
!       else
! 	return node;
!       if (node && availability)
! 	{
! 	  enum availability a;
! 	  a = cgraph_function_body_availability (node);
! 	  if (a < *availability)
! 	    *availability = a;
! 	}
!     }
!   if (*availability)
!     *availability = AVAIL_NOT_AVAILABLE;
    return NULL;
  }
  
Index: ipa-inline-transform.c
===================================================================
*** ipa-inline-transform.c	(revision 174944)
--- ipa-inline-transform.c	(working copy)
*************** can_remove_node_now_p (struct cgraph_nod
*** 88,93 ****
--- 88,94 ----
       can remove its offline copy, but we would need to keep unanalyzed node in
       the callgraph so references can point to it.  */
    return (!node->address_taken
+ 	  && !ipa_ref_has_aliases_p (&node->ref_list)
  	  && cgraph_can_remove_if_no_direct_calls_p (node)
  	  /* Inlining might enable more devirtualizing, so we want to remove
  	     those only after all devirtualizable virtual calls are processed.
*************** inline_call (struct cgraph_edge *e, bool
*** 192,198 ****
    /* If aliases are involved, redirect edge to the actual destination and
       possibly remove the aliases.  */
    if (e->callee != callee)
!     cgraph_redirect_edge_callee (e, callee);
  
    clone_inlined_nodes (e, true, update_original, overall_size);
  
--- 193,214 ----
    /* If aliases are involved, redirect edge to the actual destination and
       possibly remove the aliases.  */
    if (e->callee != callee)
!     {
!       struct cgraph_node *alias = e->callee, *next_alias;
!       cgraph_redirect_edge_callee (e, callee);
!       while (alias && alias != callee)
! 	{
! 	  if (!alias->callers
! 	      && can_remove_node_now_p (alias))
! 	    {
! 	      next_alias = cgraph_alias_aliased_node (alias);
! 	      cgraph_remove_node (alias);
! 	      alias = next_alias;
! 	    }
! 	  else
! 	    break;
! 	}
!     }
  
    clone_inlined_nodes (e, true, update_original, overall_size);
  
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 174944)
--- cgraphunit.c	(working copy)
*************** cgraph_decide_is_function_needed (struct
*** 167,172 ****
--- 167,173 ----
       the name later after finalizing the function and the fact is noticed
       in assemble_name then.  This is arguably a bug.  */
    if (DECL_ASSEMBLER_NAME_SET_P (decl)
+       && (!node->thunk.thunk_p && !node->same_body_alias)
        && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
      return true;
  
*************** cgraph_mark_if_needed (tree decl)
*** 391,396 ****
--- 392,399 ----
  static bool
  clone_of_p (struct cgraph_node *node, struct cgraph_node *node2)
  {
+   node = cgraph_function_or_thunk_node (node, NULL);
+   node2 = cgraph_function_or_thunk_node (node2, NULL);
    while (node != node2 && node2)
      node2 = node2->clone_of;
    return node2 != NULL;
*************** verify_cgraph_node (struct cgraph_node *
*** 619,624 ****
--- 622,657 ----
        while (n != node);
      }
  
+   if (node->analyzed && node->alias)
+     {
+       bool ref_found = false;
+       int i;
+       struct ipa_ref *ref;
+ 
+       if (node->callees)
+ 	{
+ 	  error ("Alias has call edges");
+           error_found = true;
+ 	}
+       for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+ 	if (ref->use != IPA_REF_ALIAS)
+ 	  {
+ 	    error ("Alias has non-alias refernece");
+ 	    error_found = true;
+ 	  }
+ 	else if (ref_found)
+ 	  {
+ 	    error ("Alias has more than one alias reference");
+ 	    error_found = true;
+ 	  }
+ 	else
+ 	  ref_found = true;
+ 	if (!ref_found)
+ 	  {
+ 	    error ("Analyzed alias has no reference");
+ 	    error_found = true;
+ 	  }
+     }
    if (node->analyzed && node->thunk.thunk_p)
      {
        if (!node->callees)
*************** verify_cgraph_node (struct cgraph_node *
*** 669,687 ****
  			  }
  			if (!e->indirect_unknown_callee)
  			  {
! 			    if (e->callee->same_body_alias)
! 			      {
! 				error ("edge points to same body alias:");
! 				debug_tree (e->callee->decl);
! 				error_found = true;
! 			      }
! 			    else if (!e->callee->global.inlined_to
! 				     && decl
! 				     && cgraph_get_node (decl)
! 				     && (e->callee->former_clone_of
! 					 != cgraph_get_node (decl)->decl)
! 				     && !clone_of_p (cgraph_get_node (decl),
! 						     e->callee))
  			      {
  				error ("edge points to wrong declaration:");
  				debug_tree (e->callee->decl);
--- 702,718 ----
  			  }
  			if (!e->indirect_unknown_callee)
  			  {
! 			    if (!e->callee->global.inlined_to
! 			        && decl
! 			        && cgraph_get_node (decl)
! 			        && (e->callee->former_clone_of
! 				    != cgraph_get_node (decl)->decl)
! 				/* IPA-CP sometimes redirect edge to clone and then back to the former
! 				   function.  This ping-pong has to go, eventaully.  */
! 				&& (cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL)
! 				    != cgraph_function_or_thunk_node (e->callee, NULL))
! 				&& !clone_of_p (cgraph_get_node (decl),
! 					        e->callee))
  			      {
  				error ("edge points to wrong declaration:");
  				debug_tree (e->callee->decl);
*************** cgraph_analyze_function (struct cgraph_n
*** 781,787 ****
    tree save = current_function_decl;
    tree decl = node->decl;
  
!   if (node->thunk.thunk_p)
      {
        cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
  			  NULL, 0, CGRAPH_FREQ_BASE);
--- 812,864 ----
    tree save = current_function_decl;
    tree decl = node->decl;
  
!   if (node->alias && node->thunk.alias)
!     {
!       struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
!       if (!VEC_length (ipa_ref_t, node->ref_list.references))
!         ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL);
!       if (node->same_body_alias)
! 	{ 
! 	  DECL_VIRTUAL_P (node->decl) = DECL_VIRTUAL_P (node->thunk.alias);
! 	  DECL_DECLARED_INLINE_P (node->decl)
! 	     = DECL_DECLARED_INLINE_P (node->thunk.alias);
! 	  DECL_DISREGARD_INLINE_LIMITS (node->decl)
! 	     = DECL_DISREGARD_INLINE_LIMITS (node->thunk.alias);
! 	}
! 
!       /* Fixup visibility nonsences C++ frontend produce on same body aliases.  */
!       if (TREE_PUBLIC (node->decl) && node->same_body_alias)
! 	{
!           DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->thunk.alias);
! 	  if (DECL_COMDAT (node->thunk.alias))
! 	    {
! 	      DECL_COMDAT (node->decl) = 1;
! 	      DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->thunk.alias);
! 	      if (DECL_ONE_ONLY (node->thunk.alias) && !node->same_comdat_group)
! 		{
! 		  struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
! 		  node->same_comdat_group = tgt;
! 		  if (!tgt->same_comdat_group)
! 		    tgt->same_comdat_group = node;
! 		  else
! 		    {
! 		      struct cgraph_node *n;
! 		      for (n = tgt->same_comdat_group;
! 			   n->same_comdat_group != tgt;
! 			   n = n->same_comdat_group)
! 			;
! 		      n->same_comdat_group = node;
! 		    }
! 		}
! 	    }
! 	}
!       cgraph_mark_reachable_node (cgraph_alias_aliased_node (node));
!       if (node->address_taken)
! 	cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node));
!       if (cgraph_decide_is_function_needed (node, node->decl))
! 	cgraph_mark_needed_node (node);
!     }
!   else if (node->thunk.thunk_p)
      {
        cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
  			  NULL, 0, CGRAPH_FREQ_BASE);
*************** cgraph_analyze_function (struct cgraph_n
*** 809,814 ****
--- 886,911 ----
    current_function_decl = save;
  }
  
+ /* C++ frontend produce same body aliases all over the place, even before PCH
+    gets streamed out. It relies on us linking the aliases with their function
+    in order to do the fixups, but ipa-ref is not PCH safe.  Consequentely we
+    first produce aliases without links, but once C++ FE is sure he won't sream
+    PCH we build the links via this function.  */
+ 
+ void
+ cgraph_process_same_body_aliases (void)
+ {
+   struct cgraph_node *node;
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->same_body_alias
+ 	&& !VEC_length (ipa_ref_t, node->ref_list.references))
+       {
+         struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
+         ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL);
+       }
+   same_body_aliases_done = true;
+ }
+ 
  /* Process attributes common for vars and functions.  */
  
  static void
*************** process_function_and_variable_attributes
*** 880,886 ****
  	     cgraph_mark_needed_node (node);
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
! 	  && node->local.finalized)
  	{
  	  warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
  		      "%<weakref%> attribute ignored"
--- 977,983 ----
  	     cgraph_mark_needed_node (node);
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
! 	  && (node->local.finalized && !node->alias))
  	{
  	  warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
  		      "%<weakref%> attribute ignored"
*************** cgraph_analyze_functions (void)
*** 979,984 ****
--- 1076,1082 ----
  	 weak alias attribute to kill its body. See
  	 gcc.c-torture/compile/20011119-1.c  */
        if (!DECL_STRUCT_FUNCTION (decl)
+ 	  && (!node->alias || !node->thunk.alias)
  	  && !node->thunk.thunk_p)
  	{
  	  cgraph_reset_node (node);
*************** cgraph_analyze_functions (void)
*** 1046,1056 ****
        next = node->next;
  
        if (node->local.finalized && !gimple_has_body_p (decl)
  	  && !node->thunk.thunk_p)
  	cgraph_reset_node (node);
  
        if (!node->reachable
! 	  && (gimple_has_body_p (decl) || node->thunk.thunk_p))
  	{
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
--- 1144,1156 ----
        next = node->next;
  
        if (node->local.finalized && !gimple_has_body_p (decl)
+ 	  && !node->alias
  	  && !node->thunk.thunk_p)
  	cgraph_reset_node (node);
  
        if (!node->reachable
! 	  && (gimple_has_body_p (decl) || node->thunk.thunk_p
! 	      || (node->alias && node->thunk.alias)))
  	{
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
*************** cgraph_analyze_functions (void)
*** 1060,1065 ****
--- 1160,1166 ----
        else
  	node->next_needed = NULL;
        gcc_assert (!node->local.finalized || node->thunk.thunk_p
+ 		  || node->alias
  		  || gimple_has_body_p (decl));
        gcc_assert (node->analyzed == node->local.finalized);
      }
*************** cgraph_mark_functions_to_output (void)
*** 1157,1165 ****
  	 outside the current compilation unit.  */
        if (node->analyzed
  	  && !node->thunk.thunk_p
  	  && !node->global.inlined_to
  	  && (!cgraph_only_called_directly_p (node)
! 	      || (e && node->reachable))
  	  && !TREE_ASM_WRITTEN (decl)
  	  && !DECL_EXTERNAL (decl))
  	{
--- 1258,1268 ----
  	 outside the current compilation unit.  */
        if (node->analyzed
  	  && !node->thunk.thunk_p
+ 	  && !node->alias
  	  && !node->global.inlined_to
  	  && (!cgraph_only_called_directly_p (node)
! 	      || ((e || ipa_ref_has_aliases_p (&node->ref_list))
! 		  && node->reachable))
  	  && !TREE_ASM_WRITTEN (decl)
  	  && !DECL_EXTERNAL (decl))
  	{
*************** cgraph_mark_functions_to_output (void)
*** 1170,1176 ****
  	      for (next = node->same_comdat_group;
  		   next != node;
  		   next = next->same_comdat_group)
! 		if (!next->thunk.thunk_p)
  		  next->process = 1;
  	    }
  	}
--- 1273,1279 ----
  	      for (next = node->same_comdat_group;
  		   next != node;
  		   next = next->same_comdat_group)
! 		if (!next->thunk.thunk_p && !next->alias)
  		  next->process = 1;
  	    }
  	}
*************** cgraph_mark_functions_to_output (void)
*** 1190,1195 ****
--- 1293,1299 ----
  		 are inside partition, we can end up not removing the body since we no longer
  		 have analyzed node pointing to it.  */
  	      && !node->in_other_partition
+ 	      && !node->alias
  	      && !DECL_EXTERNAL (decl))
  	    {
  	      dump_cgraph_node (stderr, node);
*************** cgraph_mark_functions_to_output (void)
*** 1219,1225 ****
  	      && !DECL_EXTERNAL (decl))
  	    {
  	      dump_cgraph_node (stderr, node);
! 	      internal_error ("failed to reclaim unneeded function");
  	    }
  	}
  #endif
--- 1323,1329 ----
  	      && !DECL_EXTERNAL (decl))
  	    {
  	      dump_cgraph_node (stderr, node);
! 	      internal_error ("failed to reclaim unneeded functionin same comdat group");
  	    }
  	}
  #endif
*************** assemble_thunk (struct cgraph_node *node
*** 1569,1591 ****
  }
  
  
! /* Assemble thunks asociated to NODE.  */
  
  static void
! assemble_thunks (struct cgraph_node *node)
  {
    struct cgraph_edge *e;
    for (e = node->callers; e;)
      if (e->caller->thunk.thunk_p)
        {
  	struct cgraph_node *thunk = e->caller;
  
  	e = e->next_caller;
! 	assemble_thunks (thunk);
          assemble_thunk (thunk);
        }
      else
        e = e->next_caller;
  }
  
  /* Expand function specified by NODE.  */
--- 1673,1707 ----
  }
  
  
! 
! /* Assemble thunks and aliases asociated to NODE.  */
  
  static void
! assemble_thunks_and_aliases (struct cgraph_node *node)
  {
    struct cgraph_edge *e;
+   int i;
+   struct ipa_ref *ref;
+ 
    for (e = node->callers; e;)
      if (e->caller->thunk.thunk_p)
        {
  	struct cgraph_node *thunk = e->caller;
  
  	e = e->next_caller;
! 	assemble_thunks_and_aliases (thunk);
          assemble_thunk (thunk);
        }
      else
        e = e->next_caller;
+   for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+     if (ref->use == IPA_REF_ALIAS)
+       {
+ 	struct cgraph_node *alias = ipa_ref_refering_node (ref);
+ 	assemble_alias (alias->decl,
+ 			DECL_ASSEMBLER_NAME (alias->thunk.alias));
+ 	assemble_thunks_and_aliases (alias);
+       }
  }
  
  /* Expand function specified by NODE.  */
*************** cgraph_expand_function (struct cgraph_no
*** 1600,1626 ****
  
    announce_function (decl);
    node->process = 0;
!   if (node->same_body)
!     {
!       struct cgraph_node *alias, *next;
!       bool saved_alias = node->alias;
!       for (alias = node->same_body;
!       	   alias && alias->next; alias = alias->next)
!         ;
!       /* Walk aliases in the order they were created; it is possible that
!          thunks refers to the aliases made earlier.  */
!       for (; alias; alias = next)
!         {
! 	  next = alias->previous;
! 	  if (!alias->thunk.thunk_p)
! 	    assemble_alias (alias->decl,
! 			    DECL_ASSEMBLER_NAME (alias->thunk.alias));
! 	}
!       node->alias = saved_alias;
!       cgraph_process_new_functions ();
!     }
! 
!   assemble_thunks (node);
    gcc_assert (node->lowered);
  
    /* Generate RTL for the body of DECL.  */
--- 1716,1722 ----
  
    announce_function (decl);
    node->process = 0;
!   assemble_thunks_and_aliases (node);
    gcc_assert (node->lowered);
  
    /* Generate RTL for the body of DECL.  */
*************** cgraph_output_in_order (void)
*** 1736,1742 ****
  
    for (pf = cgraph_nodes; pf; pf = pf->next)
      {
!       if (pf->process && !pf->thunk.thunk_p)
  	{
  	  i = pf->order;
  	  gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
--- 1832,1838 ----
  
    for (pf = cgraph_nodes; pf; pf = pf->next)
      {
!       if (pf->process && !pf->thunk.thunk_p && !pf->alias)
  	{
  	  i = pf->order;
  	  gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
*************** bool
*** 1810,1816 ****
  cgraph_preserve_function_body_p (struct cgraph_node *node)
  {
    gcc_assert (cgraph_global_info_ready);
!   gcc_assert (!node->same_body_alias);
  
    /* Look if there is any clone around.  */
    if (node->clones)
--- 1906,1912 ----
  cgraph_preserve_function_body_p (struct cgraph_node *node)
  {
    gcc_assert (cgraph_global_info_ready);
!   gcc_assert (!node->alias && !node->thunk.thunk_p);
  
    /* Look if there is any clone around.  */
    if (node->clones)
Index: cp/tree.c
===================================================================
*** cp/tree.c	(revision 174944)
--- cp/tree.c	(working copy)
*************** cp_fix_function_decl_p (tree decl)
*** 3363,3371 ****
  
        /* Don't fix same_body aliases.  Although they don't have their own
  	 CFG, they share it with what they alias to.  */
!       if (!node
! 	  || node->decl == decl
! 	  || !node->same_body)
  	return true;
      }
  
--- 3363,3370 ----
  
        /* Don't fix same_body aliases.  Although they don't have their own
  	 CFG, they share it with what they alias to.  */
!       if (!node || !node->alias
! 	  || !VEC_length (ipa_ref_t, node->ref_list.references))
  	return true;
      }
  
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 174944)
--- cp/decl2.c	(working copy)
*************** cp_write_global_declarations (void)
*** 3672,3677 ****
--- 3672,3679 ----
    if (pch_file)
      c_common_write_pch ();
  
+   cgraph_process_same_body_aliases ();
+ 
    /* Handle -fdump-ada-spec[-slim] */
    if (dump_enabled_p (TDI_ada))
      {
*************** cp_write_global_declarations (void)
*** 3869,3874 ****
--- 3871,3878 ----
  	      struct cgraph_node *node, *next;
  
  	      node = cgraph_get_node (decl);
+ 	      if (node->same_body_alias)
+ 		node = cgraph_alias_aliased_node (node);
  
  	      cgraph_for_node_and_aliases (node, clear_decl_external,
  					   NULL, true);
Index: ipa-ref.c
===================================================================
*** ipa-ref.c	(revision 174944)
--- ipa-ref.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 27,33 ****
  #include "target.h"
  #include "cgraph.h"
  
! static const char *ipa_ref_use_name[] = {"read","write","addr"};
  
  /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
     to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
--- 27,33 ----
  #include "target.h"
  #include "cgraph.h"
  
! static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
  
  /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
     to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
*************** ipa_record_reference (struct cgraph_node
*** 46,51 ****
--- 46,52 ----
    gcc_assert ((!refering_node) ^ (!refering_varpool_node));
    gcc_assert ((!refered_node) ^ (!refered_varpool_node));
    gcc_assert (!stmt || refering_node);
+   gcc_assert (use_type != IPA_REF_ALIAS || !stmt);
  
    list = (refering_node ? &refering_node->ref_list
  	  : &refering_varpool_node->ref_list);
*************** ipa_record_reference (struct cgraph_node
*** 73,79 ****
      {
        ref->refered.cgraph_node = refered_node;
        ref->refered_type = IPA_REF_CGRAPH;
!       gcc_assert (use_type == IPA_REF_ADDR);
      }
    else
      {
--- 74,80 ----
      {
        ref->refered.cgraph_node = refered_node;
        ref->refered_type = IPA_REF_CGRAPH;
!       gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS);
      }
    else
      {
*************** ipa_ref_cannot_lead_to_return (struct ip
*** 241,243 ****
--- 242,256 ----
  {
    return cgraph_node_cannot_return (ipa_ref_refering_node (ref));
  }
+ 
+ /* Return true if list contains an alias.  */
+ bool
+ ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list)
+ {
+   struct ipa_ref *ref;
+   int i;
+   for (i = 0; ipa_ref_list_refering_iterate (ref_list, i, ref); i++)
+     if (ref->use == IPA_REF_ALIAS)
+       return true;
+   return false;
+ }
Index: ipa-ref.h
===================================================================
*** ipa-ref.h	(revision 174944)
--- ipa-ref.h	(working copy)
*************** enum GTY(()) ipa_ref_use
*** 27,33 ****
  {
    IPA_REF_LOAD,
    IPA_REF_STORE,
!   IPA_REF_ADDR
  };
  
  /* Type of refering or refered type.  */
--- 27,34 ----
  {
    IPA_REF_LOAD,
    IPA_REF_STORE,
!   IPA_REF_ADDR,
!   IPA_REF_ALIAS
  };
  
  /* Type of refering or refered type.  */
*************** void ipa_dump_refering (FILE *, struct i
*** 89,92 ****
  void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
  void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
  bool ipa_ref_cannot_lead_to_return (struct ipa_ref *);
! 
--- 90,93 ----
  void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
  void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
  bool ipa_ref_cannot_lead_to_return (struct ipa_ref *);
! bool ipa_ref_has_aliases_p (struct ipa_ref_list *);
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c	(revision 174944)
--- lto-cgraph.c	(working copy)
*************** lto_output_node (struct lto_simple_outpu
*** 504,510 ****
  		     || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
    bp_pack_value (&bp, node->lowered, 1);
    bp_pack_value (&bp, in_other_partition, 1);
!   bp_pack_value (&bp, node->alias, 1);
    bp_pack_value (&bp, node->frequency, 2);
    bp_pack_value (&bp, node->only_called_at_startup, 1);
    bp_pack_value (&bp, node->only_called_at_exit, 1);
--- 504,510 ----
  		     || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
    bp_pack_value (&bp, node->lowered, 1);
    bp_pack_value (&bp, in_other_partition, 1);
!   bp_pack_value (&bp, node->alias && !boundary_p, 1);
    bp_pack_value (&bp, node->frequency, 2);
    bp_pack_value (&bp, node->only_called_at_startup, 1);
    bp_pack_value (&bp, node->only_called_at_exit, 1);
*************** lto_output_node (struct lto_simple_outpu
*** 523,554 ****
  				 node->thunk.fixed_offset);
        lto_output_uleb128_stream (ob->main_stream,
  				 node->thunk.virtual_value);
-       lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
- 				node->thunk.alias);
      }
! 
!   if (node->same_body)
      {
!       struct cgraph_node *alias;
!       unsigned long alias_count = 1;
!       for (alias = node->same_body; alias->next; alias = alias->next)
! 	alias_count++;
!       lto_output_uleb128_stream (ob->main_stream, alias_count);
!       do
! 	{
! 	  lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
! 				    alias->decl);
! 	  lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
! 				    alias->thunk.alias);
! 	  gcc_assert (cgraph_get_node (alias->thunk.alias) == node);
! 	  lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution,
! 			   LDPR_NUM_KNOWN, alias->resolution);
! 	  alias = alias->previous;
! 	}
!       while (alias);
      }
-   else
-     lto_output_uleb128_stream (ob->main_stream, 0);
  }
  
  /* Output the varpool NODE to OB. 
--- 523,537 ----
  				 node->thunk.fixed_offset);
        lto_output_uleb128_stream (ob->main_stream,
  				 node->thunk.virtual_value);
      }
!   if ((node->alias || node->thunk.thunk_p) && !boundary_p)
      {
!       lto_output_int_in_range (ob->main_stream, 0, 1,
! 			       node->thunk.alias != NULL);
!       if (node->thunk.alias != NULL)
!         lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
! 			          node->thunk.alias);
      }
  }
  
  /* Output the varpool NODE to OB. 
*************** input_node (struct lto_file_decl_data *f
*** 997,1003 ****
    struct bitpack_d bp;
    unsigned decl_index;
    int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
-   unsigned long same_body_count = 0;
    int clone_ref;
  
    clone_ref = lto_input_sleb128 (ib);
--- 980,985 ----
*************** input_node (struct lto_file_decl_data *f
*** 1043,1073 ****
        int type = lto_input_uleb128 (ib);
        HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib);
        HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib);
-       tree real_alias;
  
-       decl_index = lto_input_uleb128 (ib);
-       real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
        node->thunk.fixed_offset = fixed_offset;
        node->thunk.this_adjusting = (type & 2);
        node->thunk.virtual_value = virtual_value;
        node->thunk.virtual_offset_p = (type & 4);
-       node->thunk.alias = real_alias;
      }
! 
!   same_body_count = lto_input_uleb128 (ib);
!   while (same_body_count-- > 0)
      {
!       tree alias_decl, real_alias;
!       struct cgraph_node *alias;
! 
!       decl_index = lto_input_uleb128 (ib);
!       alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
!       decl_index = lto_input_uleb128 (ib);
!       real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
!       alias = cgraph_same_body_alias (node, alias_decl, real_alias);
!       gcc_assert (alias);
!       alias->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution,
! 					  LDPR_NUM_KNOWN);
      }
    return node;
  }
--- 1025,1044 ----
        int type = lto_input_uleb128 (ib);
        HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib);
        HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib);
  
        node->thunk.fixed_offset = fixed_offset;
        node->thunk.this_adjusting = (type & 2);
        node->thunk.virtual_value = virtual_value;
        node->thunk.virtual_offset_p = (type & 4);
      }
!   if (node->thunk.thunk_p || node->alias)
      {
!       if (lto_input_int_in_range (ib, "alias nonzero flag", 0, 1))
! 	{
!           decl_index = lto_input_uleb128 (ib);
!           node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data,
! 							      decl_index);
! 	}
      }
    return node;
  }
Index: lto-streamer-out.c
===================================================================
*** lto-streamer-out.c	(revision 174944)
--- lto-streamer-out.c	(working copy)
*************** lto_output (cgraph_node_set set, varpool
*** 2253,2258 ****
--- 2253,2259 ----
      {
        node = lto_cgraph_encoder_deref (encoder, i);
        if (lto_cgraph_encoder_encode_body_p (encoder, node)
+ 	  && !node->alias
  	  && !node->thunk.thunk_p)
  	{
  #ifdef ENABLE_CHECKING
*************** produce_symtab (struct output_block *ob,
*** 2551,2557 ****
    struct lto_streamer_cache_d *cache = ob->writer_cache;
    char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
    struct pointer_set_t *seen;
!   struct cgraph_node *node, *alias;
    struct varpool_node *vnode, *valias;
    struct lto_output_stream stream;
    lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
--- 2552,2558 ----
    struct lto_streamer_cache_d *cache = ob->writer_cache;
    char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
    struct pointer_set_t *seen;
!   struct cgraph_node *node;
    struct varpool_node *vnode, *valias;
    struct lto_output_stream stream;
    lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
*************** produce_symtab (struct output_block *ob,
*** 2584,2591 ****
        if (node->alias || node->global.inlined_to)
  	continue;
        write_symbol (cache, &stream, node->decl, seen, false);
-       for (alias = node->same_body; alias; alias = alias->next)
-         write_symbol (cache, &stream, alias->decl, seen, true);
      }
    for (i = 0; i < lto_cgraph_encoder_size (encoder); i++)
      {
--- 2585,2590 ----
*************** produce_symtab (struct output_block *ob,
*** 2598,2605 ****
        if (node->alias || node->global.inlined_to)
  	continue;
        write_symbol (cache, &stream, node->decl, seen, false);
-       for (alias = node->same_body; alias; alias = alias->next)
-         write_symbol (cache, &stream, alias->decl, seen, true);
      }
  
    /* Write all variables.  */
--- 2597,2602 ----
Index: ipa-utils.c
===================================================================
*** ipa-utils.c	(revision 174944)
--- ipa-utils.c	(working copy)
*************** ipa_free_postorder_info (void)
*** 234,240 ****
  }
  
  /* Fill array order with all nodes with output flag set in the reverse
!    topological order.  Return the number of elements in the array.  */
  
  int
  ipa_reverse_postorder (struct cgraph_node **order)
--- 234,241 ----
  }
  
  /* Fill array order with all nodes with output flag set in the reverse
!    topological order.  Return the number of elements in the array.
!    FIXME: While walking, consider aliases, too.  */
  
  int
  ipa_reverse_postorder (struct cgraph_node **order)
*************** ipa_reverse_postorder (struct cgraph_nod
*** 260,266 ****
  	  && (pass
  	      || (!node->address_taken
  		  && !node->global.inlined_to
! 		  && !cgraph_only_called_directly_p (node))))
  	{
  	  node2 = node;
  	  if (!node->callers)
--- 261,267 ----
  	  && (pass
  	      || (!node->address_taken
  		  && !node->global.inlined_to
! 		  && !cgraph_only_called_directly_or_aliased_p (node))))
  	{
  	  node2 = node;
  	  if (!node->callers)
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 174944)
--- ipa-inline.c	(working copy)
*************** update_caller_keys (fibheap_t heap, stru
*** 965,970 ****
--- 965,972 ----
  		    struct cgraph_edge *check_inlinablity_for)
  {
    struct cgraph_edge *edge;
+   int i;
+   struct ipa_ref *ref;
  
    if (!inline_summary (node)->inlinable
        || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
*************** update_caller_keys (fibheap_t heap, stru
*** 973,978 ****
--- 975,987 ----
    if (!bitmap_set_bit (updated_nodes, node->uid))
      return;
  
+   for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+     if (ref->use == IPA_REF_ALIAS)
+       {
+ 	struct cgraph_node *alias = ipa_ref_refering_node (ref);
+         update_caller_keys (heap, alias, updated_nodes, check_inlinablity_for);
+       }
+ 
    for (edge = node->callers; edge; edge = edge->next_caller)
      if (edge->inline_failed)
        {
*************** inline_small_functions (void)
*** 1451,1457 ****
  	  where = edge->caller;
  	  while (where->global.inlined_to)
  	    {
! 	      if (where->decl == edge->callee->decl)
  		outer_node = where, depth++;
  	      where = where->callers->caller;
  	    }
--- 1460,1466 ----
  	  where = edge->caller;
  	  while (where->global.inlined_to)
  	    {
! 	      if (where->decl == callee->decl)
  		outer_node = where, depth++;
  	      where = where->callers->caller;
  	    }
Index: ipa.c
===================================================================
*** ipa.c	(revision 174944)
--- ipa.c	(working copy)
*************** cgraph_comdat_can_be_unshared_p (struct 
*** 581,589 ****
  /* Return true when function NODE should be considered externally visible.  */
  
  static bool
! cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased)
  {
-   struct cgraph_node *alias;
    if (!node->local.finalized)
      return false;
    if (!DECL_COMDAT (node->decl)
--- 581,589 ----
  /* Return true when function NODE should be considered externally visible.  */
  
  static bool
! cgraph_externally_visible_p (struct cgraph_node *node,
! 			     bool whole_program, bool aliased)
  {
    if (!node->local.finalized)
      return false;
    if (!DECL_COMDAT (node->decl)
*************** cgraph_externally_visible_p (struct cgra
*** 630,647 ****
        && cgraph_comdat_can_be_unshared_p (node))
      return false;
  
-   /* See if we have linker information about symbol not being used or
-      if we need to make guess based on the declaration.
- 
-      Even if the linker clams the symbol is unused, never bring internal
-      symbols that are declared by user as used or externally visible.
-      This is needed for i.e. references from asm statements.   */
-   for (alias = node->same_body; alias; alias = alias->next)
-     if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY)
-       break;
-   if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY)
-     return false;
- 
    /* When doing link time optimizations, hidden symbols become local.  */
    if (in_lto_p
        && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
--- 630,635 ----
*************** function_and_variable_visibility (bool w
*** 881,892 ****
        if (!node->local.externally_visible && node->analyzed
  	  && !DECL_EXTERNAL (node->decl))
  	{
-           struct cgraph_node *alias;
  	  gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
  	  cgraph_make_decl_local (node->decl);
  	  node->resolution = LDPR_PREVAILING_DEF_IRONLY;
- 	  for (alias = node->same_body; alias; alias = alias->next)
- 	    cgraph_make_decl_local (alias->decl);
  	  if (node->same_comdat_group)
  	    /* cgraph_externally_visible_p has already checked all other nodes
  	       in the group and they will all be made local.  We need to
--- 869,877 ----
*************** function_and_variable_visibility (bool w
*** 900,907 ****
  	{
  	  struct cgraph_node *decl_node = node;
  
! 	  while (decl_node->thunk.thunk_p)
! 	    decl_node = decl_node->callees->callee;
  
  	  /* Thunks have the same visibility as function they are attached to.
  	     For some reason C++ frontend don't seem to care. I.e. in 
--- 885,891 ----
  	{
  	  struct cgraph_node *decl_node = node;
  
! 	  decl_node = cgraph_function_node (decl_node->callees->callee, NULL);
  
  	  /* Thunks have the same visibility as function they are attached to.
  	     For some reason C++ frontend don't seem to care. I.e. in 
*************** function_and_variable_visibility (bool w
*** 933,941 ****
  	  if (DECL_EXTERNAL (decl_node->decl))
  	    DECL_EXTERNAL (node->decl) = 1;
  	}
-       node->local.local = cgraph_local_node_p (node);
- 
      }
    for (vnode = varpool_nodes; vnode; vnode = vnode->next)
      {
        /* weak flag makes no sense on local variables.  */
--- 917,925 ----
  	  if (DECL_EXTERNAL (decl_node->decl))
  	    DECL_EXTERNAL (node->decl) = 1;
  	}
      }
+   for (node = cgraph_nodes; node; node = node->next)
+     node->local.local = cgraph_local_node_p (node);
    for (vnode = varpool_nodes; vnode; vnode = vnode->next)
      {
        /* weak flag makes no sense on local variables.  */
Index: lto/lto.c
===================================================================
*** lto/lto.c	(revision 174944)
--- lto/lto.c	(working copy)
*************** add_references_to_partition (ltrans_part
*** 1319,1325 ****
    for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
      {
        if (ref->refered_type == IPA_REF_CGRAPH
! 	  && DECL_COMDAT (ipa_ref_node (ref)->decl)
  	  && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
  	add_cgraph_node_to_partition (part, ipa_ref_node (ref));
        else
--- 1319,1325 ----
    for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
      {
        if (ref->refered_type == IPA_REF_CGRAPH
! 	  && DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), NULL)->decl)
  	  && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
  	add_cgraph_node_to_partition (part, ipa_ref_node (ref));
        else
*************** add_references_to_partition (ltrans_part
*** 1330,1335 ****
--- 1330,1363 ----
      }
  }
  
+ /* Worker for add_cgraph_node_to_partition.  */
+ 
+ static bool
+ add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
+ {
+   ltrans_partition part = (ltrans_partition) data;
+ 
+   /* non-COMDAT aliases of COMDAT functions needs to be output just once.  */
+   if (!DECL_COMDAT (node->decl)
+       && !node->global.inlined_to
+       && node->aux)
+     {
+       gcc_assert (node->thunk.thunk_p || node->alias);
+       return false;
+     }
+ 
+   if (node->aux)
+     {
+       node->in_other_partition = 1;
+       if (cgraph_dump_file)
+         fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
+ 		 cgraph_node_name (node), node->uid);
+     }
+   node->aux = (void *)((size_t)node->aux + 1);
+   cgraph_node_set_add (part->cgraph_set, node);
+   return false;
+ }
+ 
  /* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
  
  static void
*************** add_cgraph_node_to_partition (ltrans_par
*** 1337,1378 ****
  {
    struct cgraph_edge *e;
    cgraph_node_set_iterator csi;
  
    /* If NODE is already there, we have nothing to do.  */
    csi = cgraph_node_set_find (part->cgraph_set, node);
    if (!csi_end_p (csi))
      return;
  
    part->insns += inline_summary (node)->self_size;
  
-   if (node->aux)
-     {
-       node->in_other_partition = 1;
-       if (cgraph_dump_file)
-         fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
- 		 cgraph_node_name (node), node->uid);
-     }
-   node->aux = (void *)((size_t)node->aux + 1);
  
    cgraph_node_set_add (part->cgraph_set, node);
  
-   /* Thunks always must go along with function they reffer to.  */
-   if (node->thunk.thunk_p)
-     add_cgraph_node_to_partition (part, node->callees->callee);
-   for (e = node->callers; e; e = e->next_caller)
-     if (e->caller->thunk.thunk_p)
-       add_cgraph_node_to_partition (part, e->caller);
- 
    for (e = node->callees; e; e = e->next_callee)
!     if ((!e->inline_failed || DECL_COMDAT (e->callee->decl))
  	&& !cgraph_node_in_set_p (e->callee, part->cgraph_set))
        add_cgraph_node_to_partition (part, e->callee);
  
    add_references_to_partition (part, &node->ref_list);
  
!   if (node->same_comdat_group
!       && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set))
!     add_cgraph_node_to_partition (part, node->same_comdat_group);
  }
  
  /* Add VNODE to partition as well as comdat references partition PART. */
--- 1365,1398 ----
  {
    struct cgraph_edge *e;
    cgraph_node_set_iterator csi;
+   struct cgraph_node *n;
+ 
+   /* We always decide on functions, not associated thunks and aliases.  */
+   node = cgraph_function_node (node, NULL);
  
    /* If NODE is already there, we have nothing to do.  */
    csi = cgraph_node_set_find (part->cgraph_set, node);
    if (!csi_end_p (csi))
      return;
  
+   cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
+ 
    part->insns += inline_summary (node)->self_size;
  
  
    cgraph_node_set_add (part->cgraph_set, node);
  
    for (e = node->callees; e; e = e->next_callee)
!     if ((!e->inline_failed
! 	 || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl))
  	&& !cgraph_node_in_set_p (e->callee, part->cgraph_set))
        add_cgraph_node_to_partition (part, e->callee);
  
    add_references_to_partition (part, &node->ref_list);
  
!   if (node->same_comdat_group)
!     for (n = node->same_comdat_group; n != node; n = n->same_comdat_group)
!       add_cgraph_node_to_partition (part, n);
  }
  
  /* Add VNODE to partition as well as comdat references partition PART. */
*************** lto_1_to_1_map (void)
*** 1500,1506 ****
  	continue;
  
        file_data = node->local.lto_file_data;
-       gcc_assert (!node->same_body_alias);
  
        if (file_data)
  	{
--- 1520,1525 ----
*************** promote_fn (struct cgraph_node *node)
*** 1900,1916 ****
    TREE_PUBLIC (node->decl) = 1;
    DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
    DECL_VISIBILITY_SPECIFIED (node->decl) = true;
-   if (node->same_body)
-     {
-       struct cgraph_node *alias;
-       for (alias = node->same_body;
- 	   alias; alias = alias->next)
- 	{
- 	  TREE_PUBLIC (alias->decl) = 1;
- 	  DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
- 	  DECL_VISIBILITY_SPECIFIED (alias->decl) = true;
- 	}
-     }
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
  	     "Promoting function as hidden: %s/%i\n",
--- 1919,1924 ----
*************** lto_promote_cross_file_statics (void)
*** 1944,1951 ****
        set = part->cgraph_set;
        vset = part->varpool_set;
  
!       /* If node has either address taken (and we have no clue from where)
! 	 or it is called from other partition, it needs to be globalized.  */
        for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
  	{
  	  struct cgraph_node *node = csi_node (csi);
--- 1952,1959 ----
        set = part->cgraph_set;
        vset = part->varpool_set;
  
!       /* If node called or referred to from other partition, it needs to be
! 	 globalized.  */
        for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
  	{
  	  struct cgraph_node *node = csi_node (csi);
Index: tree-ssa-structalias.c
===================================================================
*** tree-ssa-structalias.c	(revision 174944)
--- tree-ssa-structalias.c	(working copy)
*************** gate_ipa_pta (void)
*** 6675,6680 ****
--- 6675,6690 ----
  struct pt_solution ipa_escaped_pt
    = { true, false, false, false, false, false, false, NULL };
  
+ /* Associate node with varinfo DATA. Worker for
+    cgraph_for_node_and_aliases.  */
+ static bool
+ associate_varinfo_to_alias (struct cgraph_node *node, void *data)
+ {
+   if (node->alias || node->thunk.thunk_p)
+     insert_vi_for_tree (node->decl, (varinfo_t)data);
+   return false;
+ }
+ 
  /* Execute the driver for IPA PTA.  */
  static unsigned int
  ipa_pta_execute (void)
*************** ipa_pta_execute (void)
*** 6690,6711 ****
    /* Build the constraints.  */
    for (node = cgraph_nodes; node; node = node->next)
      {
-       struct cgraph_node *alias;
        varinfo_t vi;
- 
        /* Nodes without a body are not interesting.  Especially do not
           visit clones at this point for now - we get duplicate decls
  	 there for inline clones at least.  */
!       if (!gimple_has_body_p (node->decl)
  	  || node->clone_of)
  	continue;
  
        vi = create_function_info_for (node->decl,
! 				     alias_get_name (node->decl));
! 
!       /* Associate the varinfo node with all aliases.  */
!       for (alias = node->same_body; alias; alias = alias->next)
! 	insert_vi_for_tree (alias->decl, vi);
      }
  
    /* Create constraints for global variables and their initializers.  */
--- 6700,6716 ----
    /* Build the constraints.  */
    for (node = cgraph_nodes; node; node = node->next)
      {
        varinfo_t vi;
        /* Nodes without a body are not interesting.  Especially do not
           visit clones at this point for now - we get duplicate decls
  	 there for inline clones at least.  */
!       if (!cgraph_function_with_gimple_body_p (node)
  	  || node->clone_of)
  	continue;
  
        vi = create_function_info_for (node->decl,
! 			             alias_get_name (node->decl));
!       cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
      }
  
    /* Create constraints for global variables and their initializers.  */
*************** ipa_pta_execute (void)
*** 6737,6743 ****
        tree old_func_decl;
  
        /* Nodes without a body are not interesting.  */
!       if (!gimple_has_body_p (node->decl)
  	  || node->clone_of)
  	continue;
  
--- 6742,6748 ----
        tree old_func_decl;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node)
  	  || node->clone_of)
  	continue;
  
*************** ipa_pta_execute (void)
*** 6846,6852 ****
        struct cgraph_edge *e;
  
        /* Nodes without a body are not interesting.  */
!       if (!gimple_has_body_p (node->decl)
  	  || node->clone_of)
  	continue;
  
--- 6851,6857 ----
        struct cgraph_edge *e;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node)
  	  || node->clone_of)
  	continue;
  



More information about the Gcc-patches mailing list