IPA-ref infrastructure and WPA partitioning

Jan Hubicka hubicka@ucw.cz
Wed May 5 22:22:00 GMT 2010


Hi,
as I noticed with some other testing, xalanbmk breaks with the patch with -O2
(but not with -O3).  This is latent issue in symtab merging related to fact
that we no longer stream unnecesary varpool nodes that affect the
prevailability.  SPEC tester seem to get same ICE at -O3 and couple extra
flags, but to reduce dependencies, here is patch with extra loop ensuring that
we still save all varpool nodes to every output file.  This is very ineffecient
for WHOPR, but otherwise it is not too bad.

This solves the ICE and I re-tested the patch at x86_64-linux, OK?
I will work on reducing testcase for the merging issue.

Honza

	* cgraphbuild.c (record_reference_ctx): Add varpool_node.
	(record_reference, mark_address, mark_load, mark_store): Record
	references.
	(record_references_in_initializer): Update call of record_references.
	(rebuild_cgraph_edges): Remove all references before rebuiding.
	* cgraph.c (cgraph_create_node): Clear ref list.
	(cgraph_remove_node): Remove references.
	(dump_cgraph_node): Dump references.
	(cgraph_clone_node): Clone references.
	* cgraph.h: Include ipa-ref.h and ipa-ref-inline.h
	(struct cgraph_node, varpool_node): Add ref_lst.
	* ipa-ref.c: New file.
	* ipa-ref.h: New file.
	* ipa-ref-inline.h: New file.
	* lto-cgraph.c (output_varpool): Take cgrag node set argument.
	(referenced_from_other_partition_p): New function.
	(lto_output_varpool_node): Take set arugment; call
	referenced_from_other_partition.
	(lto_output_ref): New.
	(add_references): New.
	(output_refs): New.
	(output_cgraph): Compute boundary based on references;
	output refs.
	(output_varpool): Accept cgraph_node_set argument.
	(input_ref): New.
	(input_refs): New.
	(input_cgraph): Call input_refs.
	* lto-section-in.c (lto_section_name): Add refs.
	* Makefile.in: (cgraph.h): Include ipa-ref.h and ipa-ref-inline.h
	(ipa-ref.o): New file.
	* varpool.c (varpool_node): Clear ipa ref list.
	(varpool_remove_node): Remove references.
	(dump_varpool_node): Dump references.
	(varpool_assemble_decl): Only compile finalized ones.
	(varpool_extra_name_alias): Initialize ref list.
	* lto-streamer.c (lto-get_section_name): Add .refs section.
	* lto-streamer.h (lto_section_type): Add LTO_section_refs.
	(referenced_from_other_partition_p): Declared.

	* lto/lto.c (lto_promote_cross_file_statics): Compute boundary based on refs.
Index: lto-symtab.c
===================================================================
*** lto-symtab.c	(revision 159061)
--- lto-symtab.c	(working copy)
*************** lto_cgraph_replace_node (struct cgraph_n
*** 214,219 ****
--- 214,221 ----
        next = e->next_caller;
        cgraph_redirect_edge_callee (e, prevailing_node);
      }
+   /* Redirect incomming references.  */
+   ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
  
    if (node->same_body)
      {
*************** lto_varpool_replace_node (struct varpool
*** 273,278 ****
--- 275,286 ----
    gcc_assert (!vnode->finalized || prevailing_node->finalized);
    gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
  
+   /* When replacing by an alias, the references goes to the original
+      variable.  */
+   if (prevailing_node->alias && prevailing_node->extra_name)
+     prevailing_node = prevailing_node->extra_name;
+   ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
+ 
    /* Finally remove the replaced node.  */
    varpool_remove_node (vnode);
  }
Index: cgraphbuild.c
===================================================================
*** cgraphbuild.c	(revision 159059)
--- cgraphbuild.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 37,42 ****
--- 37,43 ----
  struct record_reference_ctx
  {
    bool only_vars;
+   struct varpool_node *varpool_node;
  };
  
  /* Walk tree and record all calls and references to functions/variables.
*************** record_reference (tree *tp, int *walk_su
*** 63,77 ****
        /* Record dereferences to the functions.  This makes the
  	 functions reachable unconditionally.  */
        decl = get_base_var (*tp);
!       if (TREE_CODE (decl) == FUNCTION_DECL && !ctx->only_vars)
! 	cgraph_mark_address_taken_node (cgraph_node (decl));
  
        if (TREE_CODE (decl) == VAR_DECL)
  	{
! 	  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
  	  if (lang_hooks.callgraph.analyze_expr)
  	    lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
! 	  varpool_mark_needed_node (varpool_node (decl));
  	}
        *walk_subtrees = 0;
        break;
--- 64,89 ----
        /* Record dereferences to the functions.  This makes the
  	 functions reachable unconditionally.  */
        decl = get_base_var (*tp);
!       if (TREE_CODE (decl) == FUNCTION_DECL)
! 	{
! 	  if (!ctx->only_vars)
! 	  cgraph_mark_address_taken_node (cgraph_node (decl));
! 	  ipa_record_reference (NULL, ctx->varpool_node,
! 			        cgraph_node (decl), NULL,
! 			        IPA_REF_ADDR, NULL);
! 	}
  
        if (TREE_CODE (decl) == VAR_DECL)
  	{
! 	  struct varpool_node *vnode = varpool_node (decl);
  	  if (lang_hooks.callgraph.analyze_expr)
  	    lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
! 	  varpool_mark_needed_node (vnode);
! 	  if (vnode->alias && vnode->extra_name)
! 	    vnode = vnode->extra_name;
! 	  ipa_record_reference (NULL, ctx->varpool_node,
! 				NULL, vnode,
! 				IPA_REF_ADDR, NULL);
  	}
        *walk_subtrees = 0;
        break;
*************** mark_address (gimple stmt ATTRIBUTE_UNUS
*** 148,153 ****
--- 160,168 ----
      {
        struct cgraph_node *node = cgraph_node (addr);
        cgraph_mark_address_taken_node (node);
+       ipa_record_reference ((struct cgraph_node *)data, NULL,
+ 			    node, NULL,
+ 			    IPA_REF_ADDR, stmt);
      }
    else
      {
*************** mark_address (gimple stmt ATTRIBUTE_UNUS
*** 161,166 ****
--- 176,186 ----
  	  if (lang_hooks.callgraph.analyze_expr)
  	    lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
  	  varpool_mark_needed_node (vnode);
+ 	  if (vnode->alias && vnode->extra_name)
+ 	    vnode = vnode->extra_name;
+ 	  ipa_record_reference ((struct cgraph_node *)data, NULL,
+ 				NULL, vnode,
+ 				IPA_REF_ADDR, stmt);
  	}
      }
  
*************** mark_load (gimple stmt ATTRIBUTE_UNUSED,
*** 183,188 ****
--- 203,213 ----
        if (lang_hooks.callgraph.analyze_expr)
  	lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
        varpool_mark_needed_node (vnode);
+       if (vnode->alias && vnode->extra_name)
+ 	vnode = vnode->extra_name;
+       ipa_record_reference ((struct cgraph_node *)data, NULL,
+ 			    NULL, vnode,
+ 			    IPA_REF_LOAD, stmt);
      }
    return false;
  }
*************** mark_store (gimple stmt ATTRIBUTE_UNUSED
*** 203,208 ****
--- 228,238 ----
        if (lang_hooks.callgraph.analyze_expr)
  	lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
        varpool_mark_needed_node (vnode);
+       if (vnode->alias && vnode->extra_name)
+ 	vnode = vnode->extra_name;
+       ipa_record_reference ((struct cgraph_node *)data, NULL,
+ 			    NULL, vnode,
+ 			    IPA_REF_STORE, NULL);
       }
    return false;
  }
*************** void
*** 299,306 ****
  record_references_in_initializer (tree decl, bool only_vars)
  {
    struct pointer_set_t *visited_nodes = pointer_set_create ();
!   struct record_reference_ctx ctx = {false};
  
    ctx.only_vars = only_vars;
    walk_tree (&DECL_INITIAL (decl), record_reference,
               &ctx, visited_nodes);
--- 329,338 ----
  record_references_in_initializer (tree decl, bool only_vars)
  {
    struct pointer_set_t *visited_nodes = pointer_set_create ();
!   struct varpool_node *node = varpool_node (decl);
!   struct record_reference_ctx ctx = {false, NULL};
  
+   ctx.varpool_node = node;
    ctx.only_vars = only_vars;
    walk_tree (&DECL_INITIAL (decl), record_reference,
               &ctx, visited_nodes);
*************** rebuild_cgraph_edges (void)
*** 318,323 ****
--- 350,356 ----
    gimple_stmt_iterator gsi;
  
    cgraph_node_remove_callees (node);
+   ipa_remove_all_references (&node->ref_list);
  
    node->count = ENTRY_BLOCK_PTR->count;
  
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 159059)
--- cgraph.c	(working copy)
*************** cgraph_create_node (void)
*** 463,468 ****
--- 463,469 ----
    node->previous = NULL;
    node->global.estimated_growth = INT_MIN;
    node->frequency = NODE_FREQUENCY_NORMAL;
+   ipa_empty_ref_list (&node->ref_list);
    cgraph_nodes = node;
    cgraph_n_nodes++;
    return node;
*************** cgraph_remove_node (struct cgraph_node *
*** 1412,1417 ****
--- 1413,1420 ----
    cgraph_call_node_removal_hooks (node);
    cgraph_node_remove_callers (node);
    cgraph_node_remove_callees (node);
+   ipa_remove_all_references (&node->ref_list);
+   ipa_remove_all_refering (&node->ref_list);
    VEC_free (ipa_opt_pass, heap,
              node->ipa_transforms_to_apply);
  
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1853,1858 ****
--- 1856,1865 ----
  	fprintf(f, "(can throw external) ");
      }
    fprintf (f, "\n");
+   fprintf (f, "  References: ");
+   ipa_dump_references (f, &node->ref_list);
+   fprintf (f, "  Refering this function: ");
+   ipa_dump_refering (f, &node->ref_list);
  
    for (edge = node->indirect_calls; edge; edge = edge->next_callee)
      indirect_calls_count++;
*************** cgraph_clone_node (struct cgraph_node *n
*** 2081,2086 ****
--- 2088,2094 ----
    for (e = n->indirect_calls; e; e = e->next_callee)
      cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
  		       count_scale, freq, loop_nest, update_original);
+   ipa_clone_references (new_node, NULL, &n->ref_list);
  
    new_node->next_sibling_clone = n->clones;
    if (n->clones)
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 159059)
--- cgraph.h	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 23,28 ****
--- 23,29 ----
  #define GCC_CGRAPH_H
  #include "tree.h"
  #include "basic-block.h"
+ #include "ipa-ref.h"
  
  enum availability
  {
*************** struct GTY((chain_next ("%h.next"), chai
*** 224,229 ****
--- 225,231 ----
       per-function in order to allow IPA passes to introduce new functions.  */
    VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
  
+   struct ipa_ref_list ref_list;
    struct cgraph_local_info local;
    struct cgraph_global_info global;
    struct cgraph_rtl_info rtl;
*************** DEF_VEC_ALLOC_P(cgraph_edge_p,heap);
*** 427,433 ****
  /* The varpool data structure.
     Each static variable decl has assigned varpool_node.  */
  
! struct GTY((chain_next ("%h.next"))) varpool_node {
    tree decl;
    /* Pointer to the next function in varpool_nodes.  */
    struct varpool_node *next, *prev;
--- 429,435 ----
  /* The varpool data structure.
     Each static variable decl has assigned varpool_node.  */
  
! struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
    tree decl;
    /* Pointer to the next function in varpool_nodes.  */
    struct varpool_node *next, *prev;
*************** struct GTY((chain_next ("%h.next"))) var
*** 436,441 ****
--- 438,444 ----
    /* For normal nodes a pointer to the first extra name alias.  For alias
       nodes a pointer to the normal node.  */
    struct varpool_node *extra_name;
+   struct ipa_ref_list ref_list;
    /* Ordering of all cgraph nodes.  */
    int order;
  
*************** cgraph_can_remove_if_no_direct_calls_p (
*** 864,867 ****
--- 867,872 ----
  /* Constant pool accessor function.  */
  htab_t constant_pool_htab (void);
  
+ #include "ipa-ref-inline.h"
+ 
  #endif  /* GCC_CGRAPH_H  */
Index: ipa-ref.c
===================================================================
*** ipa-ref.c	(revision 159062)
--- ipa-ref.c	(working copy)
***************
*** 0 ****
--- 1,235 ----
+ /* Interprocedural reference lists.
+    Copyright (C) 2010
+    Free Software Foundation, Inc.
+    Contributed by Jan Hubicka
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
+ #include "tree.h"
+ #include "ggc.h"
+ #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
+    of the use and STMT the statement (if it exists).  */
+ 
+ struct ipa_ref *
+ ipa_record_reference (struct cgraph_node *refering_node,
+ 		      struct varpool_node *refering_varpool_node,
+ 		      struct cgraph_node *refered_node,
+ 		      struct varpool_node *refered_varpool_node,
+ 		      enum ipa_ref_use use_type, gimple stmt)
+ {
+   struct ipa_ref *ref;
+   struct ipa_ref_list *list, *list2;
+   VEC(ipa_ref_t,gc) *old_references;
+   gcc_assert ((!refering_node) ^ (!refering_varpool_node));
+   gcc_assert ((!refered_node) ^ (!refered_varpool_node));
+   gcc_assert (!stmt || refering_node);
+ 
+   list = (refering_node ? &refering_node->ref_list
+ 	  : &refering_varpool_node->ref_list);
+   old_references = list->references;
+   VEC_safe_grow (ipa_ref_t, gc, list->references,
+ 		 VEC_length (ipa_ref_t, list->references) + 1);
+   ref = VEC_last (ipa_ref_t, list->references);
+ 
+   list2 = (refered_node ? &refered_node->ref_list
+ 	   : &refered_varpool_node->ref_list);
+   VEC_safe_push (ipa_ref_ptr, heap, list2->refering, ref);
+   ref->refered_index = VEC_length (ipa_ref_ptr, list2->refering) - 1;
+   if (refering_node)
+     {
+       ref->refering.cgraph_node = refering_node;
+       ref->refering_type = IPA_REF_CGRAPH;
+     }
+   else
+     {
+       ref->refering.varpool_node = refering_varpool_node;
+       ref->refering_type = IPA_REF_VARPOOL;
+       gcc_assert (use_type == IPA_REF_ADDR);
+     }
+   if (refered_node)
+     {
+       ref->refered.cgraph_node = refered_node;
+       ref->refered_type = IPA_REF_CGRAPH;
+       gcc_assert (use_type == IPA_REF_ADDR);
+     }
+   else
+     {
+       varpool_mark_needed_node (refered_varpool_node);
+       ref->refered.varpool_node = refered_varpool_node;
+       ref->refered_type = IPA_REF_VARPOOL;
+     }
+   ref->stmt = stmt;
+   ref->use = use_type;
+ 
+   /* If vector was moved in memory, update pointers.  */
+   if (old_references != list->references)
+     {
+       int i;
+       for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
+ 	VEC_replace (ipa_ref_ptr,
+ 		     ipa_ref_refered_ref_list (ref)->refering,
+ 		     ref->refered_index, ref);
+     }
+   return ref;
+ }
+ 
+ /* Remove reference REF.  */
+ 
+ void
+ ipa_remove_reference (struct ipa_ref *ref)
+ {
+   struct ipa_ref_list *list = ipa_ref_refered_ref_list (ref);
+   struct ipa_ref_list *list2 = ipa_ref_refering_ref_list (ref);
+   VEC(ipa_ref_t,gc) *old_references = list2->references;
+   struct ipa_ref *last;
+ 
+   gcc_assert (VEC_index (ipa_ref_ptr, list->refering, ref->refered_index) == ref);
+   last = VEC_last (ipa_ref_ptr, list->refering);
+   if (ref != last)
+     {
+       VEC_replace (ipa_ref_ptr, list->refering,
+ 		   ref->refered_index,
+ 		   VEC_last (ipa_ref_ptr, list->refering));
+       VEC_index (ipa_ref_ptr, list->refering,
+ 		 ref->refered_index)->refered_index = ref->refered_index;
+     }
+   VEC_pop (ipa_ref_ptr, list->refering);
+ 
+   last = VEC_last (ipa_ref_t, list2->references);
+   if (ref != last)
+     {
+       *ref = *last;
+       VEC_replace (ipa_ref_ptr,
+ 		   ipa_ref_refered_ref_list (ref)->refering,
+ 		   ref->refered_index, ref);
+     }
+   VEC_pop (ipa_ref_t, list2->references);
+   gcc_assert (list2->references == old_references);
+ }
+ 
+ /* Remove all references in ref list LIST.  */
+ 
+ void
+ ipa_remove_all_references (struct ipa_ref_list *list)
+ {
+   while (VEC_length (ipa_ref_t, list->references))
+     ipa_remove_reference (VEC_last (ipa_ref_t, list->references));
+   VEC_free (ipa_ref_t, gc, list->references);
+   list->references = NULL;
+ }
+ 
+ /* Remove all references in ref list LIST.  */
+ 
+ void
+ ipa_remove_all_refering (struct ipa_ref_list *list)
+ {
+   while (VEC_length (ipa_ref_ptr, list->refering))
+     ipa_remove_reference (VEC_last (ipa_ref_ptr, list->refering));
+   VEC_free (ipa_ref_ptr, heap, list->refering);
+   list->refering = NULL;
+ }
+ 
+ /* Dump references in LIST to FILE.  */
+ 
+ void
+ ipa_dump_references (FILE * file, struct ipa_ref_list *list)
+ {
+   struct ipa_ref *ref;
+   int i;
+   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
+     {
+       if (ref->refered_type == IPA_REF_CGRAPH)
+ 	{
+ 	  fprintf (file, " fn:%s/%i (%s)", cgraph_node_name (ipa_ref_node (ref)),
+ 		   ipa_ref_node (ref)->uid,
+ 		   ipa_ref_use_name [ref->use]);
+ 	}
+       else
+ 	fprintf (file, " var:%s (%s)",
+ 		 varpool_node_name (ipa_ref_varpool_node (ref)),
+ 		 ipa_ref_use_name [ref->use]);
+     }
+   fprintf (file, "\n");
+ }
+ 
+ /* Dump refering in LIST to FILE.  */
+ 
+ void
+ ipa_dump_refering (FILE * file, struct ipa_ref_list *list)
+ {
+   struct ipa_ref *ref;
+   int i;
+   for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++)
+     {
+       if (ref->refering_type == IPA_REF_CGRAPH)
+ 	fprintf (file, " fn:%s/%i (%s)",
+ 		 cgraph_node_name (ipa_ref_refering_node (ref)),
+ 		 ipa_ref_refering_node (ref)->uid,
+ 		 ipa_ref_use_name [ref->use]);
+       else
+ 	fprintf (file, " var:%s (%s)",
+ 		 varpool_node_name (ipa_ref_refering_varpool_node (ref)),
+ 		 ipa_ref_use_name [ref->use]);
+     }
+   fprintf (file, "\n");
+ }
+ 
+ /* Clone all references from SRC to DEST_NODE or DEST_VARPOL_NODE.  */
+ 
+ void
+ ipa_clone_references (struct cgraph_node *dest_node,
+ 		      struct varpool_node *dest_varpool_node,
+ 		      struct ipa_ref_list *src)
+ {
+   struct ipa_ref *ref;
+   int i;
+   for (i = 0; ipa_ref_list_reference_iterate (src, i, ref); i++)
+     ipa_record_reference (dest_node, dest_varpool_node,
+ 			  ref->refered_type == IPA_REF_CGRAPH
+ 			  ? ipa_ref_node (ref) : NULL,
+ 			  ref->refered_type == IPA_REF_VARPOOL
+ 			  ? ipa_ref_varpool_node (ref) : NULL,
+ 			  ref->use, ref->stmt);
+ }
+ 
+ /* Clone all refering from SRC to DEST_NODE or DEST_VARPOL_NODE.  */
+ 
+ void
+ ipa_clone_refering (struct cgraph_node *dest_node,
+ 		    struct varpool_node *dest_varpool_node,
+ 		    struct ipa_ref_list *src)
+ {
+   struct ipa_ref *ref;
+   int i;
+   for (i = 0; ipa_ref_list_refering_iterate (src, i, ref); i++)
+     ipa_record_reference (
+ 			  ref->refering_type == IPA_REF_CGRAPH
+ 			  ? ipa_ref_refering_node (ref) : NULL,
+ 			  ref->refering_type == IPA_REF_VARPOOL
+ 			  ? ipa_ref_refering_varpool_node (ref) : NULL,
+ 			  dest_node, dest_varpool_node,
+ 			  ref->use, ref->stmt);
+ }
Index: ipa-ref.h
===================================================================
*** ipa-ref.h	(revision 159062)
--- ipa-ref.h	(working copy)
***************
*** 0 ****
--- 1,91 ----
+ /* IPA reference lists.
+    Copyright (C) 2010
+    Free Software Foundation, Inc.
+    Contributed by Jan Hubicka
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ struct cgraph_node;
+ struct varpool_node;
+ 
+ /* How the reference is done.  */
+ enum GTY(()) ipa_ref_use
+ {
+   IPA_REF_LOAD,
+   IPA_REF_STORE,
+   IPA_REF_ADDR
+ };
+ 
+ /* Type of refering or refered type.  */
+ enum GTY(()) ipa_ref_type
+ {
+   IPA_REF_CGRAPH,
+   IPA_REF_VARPOOL
+ };
+ 
+ /* We can have references spanning both callgraph and varpool,
+    so all pointers needs to be of both types.  */
+ union GTY(()) ipa_ref_ptr_u
+ {
+   struct cgraph_node * GTY((tag ("IPA_REF_CGRAPH"))) cgraph_node;
+   struct varpool_node * GTY((tag ("IPA_REF_VARPOOL"))) varpool_node;
+ };
+ 
+ /* Record of reference in callgraph or varpool.  */
+ struct GTY(()) ipa_ref
+ {
+   union ipa_ref_ptr_u GTY ((desc ("%1.refering_type"))) refering;
+   union ipa_ref_ptr_u GTY ((desc ("%1.refered_type"))) refered;
+   gimple stmt;
+   unsigned int refered_index;
+   ENUM_BITFIELD (ipa_ref_type) refering_type:1;
+   ENUM_BITFIELD (ipa_ref_type) refered_type:1;
+   ENUM_BITFIELD (ipa_ref_use) use:2;
+ };
+ 
+ typedef struct ipa_ref ipa_ref_t;
+ typedef struct ipa_ref *ipa_ref_ptr;
+ 
+ DEF_VEC_O(ipa_ref_t);
+ DEF_VEC_ALLOC_O(ipa_ref_t,gc);
+ DEF_VEC_P(ipa_ref_ptr);
+ DEF_VEC_ALLOC_P(ipa_ref_ptr,heap);
+ 
+ /* List of references.  This is stored in both callgraph and varpool nodes.  */
+ struct GTY(()) ipa_ref_list
+ {
+   /* Store actual references in references vector.  */
+   VEC(ipa_ref_t,gc) *references;
+   /* Refering is vector of pointers to references.  It must not live in GGC space
+      or GGC will try to mark middle of references vectors.  */
+   VEC(ipa_ref_ptr,heap) * GTY((skip)) refering;
+ };
+ 
+ struct ipa_ref * ipa_record_reference (struct cgraph_node *,
+ 				       struct varpool_node *,
+ 				       struct cgraph_node *,
+ 				       struct varpool_node *,
+ 				       enum ipa_ref_use, gimple);
+ 
+ void ipa_remove_reference (struct ipa_ref *);
+ void ipa_remove_all_references (struct ipa_ref_list *);
+ void ipa_remove_all_refering (struct ipa_ref_list *);
+ void ipa_dump_references (FILE *, struct ipa_ref_list *);
+ void ipa_dump_refering (FILE *, struct ipa_ref_list *);
+ 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 *);
+ 
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c	(revision 159075)
--- lto-cgraph.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 46,52 ****
  #include "lto-streamer.h"
  #include "gcov-io.h"
  
! static void output_varpool (varpool_node_set);
  
  /* Cgraph streaming is organized as set of record whose type
     is indicated by a tag.  */
--- 46,52 ----
  #include "lto-streamer.h"
  #include "gcov-io.h"
  
! static void output_varpool (cgraph_node_set, varpool_node_set);
  
  /* Cgraph streaming is organized as set of record whose type
     is indicated by a tag.  */
*************** lto_output_edge (struct lto_simple_outpu
*** 286,291 ****
--- 286,315 ----
    bitpack_delete (bp);
  }
  
+ /* Return if LIST contain references from other partitions.  */
+ bool
+ referenced_from_other_partition_p (struct ipa_ref_list *list, cgraph_node_set set,
+ 				   varpool_node_set vset)
+ {
+   int i;
+   struct ipa_ref *ref;
+   for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++)
+     {
+       if (ref->refering_type == IPA_REF_CGRAPH)
+ 	{
+ 	  if (!cgraph_node_in_set_p (ipa_ref_refering_node (ref), set))
+ 	    return true;
+ 	}
+       else
+ 	{
+ 	  if (!varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref),
+ 				      vset))
+ 	    return true;
+ 	}
+     }
+   return false;
+ }
+ 
  /* Return true when node is reachable from other partition.  */
  
  static bool
*************** lto_output_node (struct lto_simple_outpu
*** 460,468 ****
  
  static void
  lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
! 		         varpool_node_set set)
  {
!   bool boundary_p = !varpool_node_in_set_p (node, set) && node->analyzed;
    struct bitpack_d *bp;
    struct varpool_node *alias;
    int count = 0;
--- 484,492 ----
  
  static void
  lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
! 		         cgraph_node_set set, varpool_node_set vset)
  {
!   bool boundary_p = !varpool_node_in_set_p (node, vset) && node->analyzed;
    struct bitpack_d *bp;
    struct varpool_node *alias;
    int count = 0;
*************** lto_output_varpool_node (struct lto_simp
*** 486,494 ****
      }
    else
      {
!       /* FIXME: We have no idea how we move references around.  For moment assume that
! 	 everything is used externally.  */
!       bp_pack_value (bp, flag_wpa, 1);  /* used_from_other_parition.  */
        bp_pack_value (bp, boundary_p, 1);  /* in_other_partition.  */
      }
    /* Also emit any extra name aliases.  */
--- 510,518 ----
      }
    else
      {
!       bp_pack_value (bp, node->analyzed
! 		     && referenced_from_other_partition_p (&node->ref_list,
! 							   set, vset), 1);
        bp_pack_value (bp, boundary_p, 1);  /* in_other_partition.  */
      }
    /* Also emit any extra name aliases.  */
*************** lto_output_varpool_node (struct lto_simp
*** 506,511 ****
--- 530,563 ----
      }
  }
  
+ /* Output the varpool NODE to OB. 
+    If NODE is not in SET, then NODE is a boundary.  */
+ 
+ static void
+ lto_output_ref (struct lto_simple_output_block *ob, struct ipa_ref *ref,
+ 		lto_cgraph_encoder_t encoder,
+ 		lto_varpool_encoder_t varpool_encoder)
+ {
+   struct bitpack_d *bp = bitpack_create ();
+   bp_pack_value (bp, ref->refered_type, 1);
+   bp_pack_value (bp, ref->use, 2);
+   lto_output_bitpack (ob->main_stream, bp);
+   bitpack_delete (bp);
+   if (ref->refered_type == IPA_REF_CGRAPH)
+     {
+       int nref = lto_cgraph_encoder_lookup (encoder, ipa_ref_node (ref));
+       gcc_assert (nref != LCC_NOT_FOUND);
+       lto_output_sleb128_stream (ob->main_stream, nref);
+     }
+   else
+     {
+       int nref = lto_varpool_encoder_lookup (varpool_encoder,
+ 				             ipa_ref_varpool_node (ref));
+       gcc_assert (nref != LCC_NOT_FOUND);
+       lto_output_sleb128_stream (ob->main_stream, nref);
+     }
+ }
+ 
  /* Stream out profile_summary to OB.  */
  
  static void
*************** add_node_to (lto_cgraph_encoder_t encode
*** 534,539 ****
--- 586,610 ----
    lto_cgraph_encoder_encode (encoder, node);
  }
  
+ /* Add all references in LIST to encoders.  */
+ 
+ static void
+ add_references (lto_cgraph_encoder_t encoder,
+ 		lto_varpool_encoder_t varpool_encoder,
+ 		struct ipa_ref_list *list)
+ {
+   int i;
+   struct ipa_ref *ref;
+   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
+     if (ref->refered_type == IPA_REF_CGRAPH)
+       add_node_to (encoder, ipa_ref_node (ref));
+     else
+       {
+ 	struct varpool_node *vnode = ipa_ref_varpool_node (ref);
+         lto_varpool_encoder_encode (varpool_encoder, vnode);
+       }
+ }
+ 
  /* Output all callees or indirect outgoing edges.  EDGE must be the first such
     edge.  */
  
*************** output_outgoing_cgraph_edges (struct cgr
*** 555,560 ****
--- 626,686 ----
  
  /* Output the part of the cgraph in SET.  */
  
+ static void
+ output_refs (cgraph_node_set set, varpool_node_set vset,
+ 	     lto_cgraph_encoder_t encoder,
+ 	     lto_varpool_encoder_t varpool_encoder)
+ {
+   cgraph_node_set_iterator csi;
+   varpool_node_set_iterator vsi;
+   struct lto_simple_output_block *ob;
+   int count;
+   struct ipa_ref *ref;
+   int i;
+ 
+   ob = lto_create_simple_output_block (LTO_section_refs);
+ 
+   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+     {
+       struct cgraph_node *node = csi_node (csi);
+ 
+       count = ipa_ref_list_nreferences (&node->ref_list);
+       if (count)
+ 	{
+ 	  lto_output_uleb128_stream (ob->main_stream, count);
+ 	  lto_output_uleb128_stream (ob->main_stream,
+ 				     lto_cgraph_encoder_lookup (encoder, node));
+ 	  for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+ 	    lto_output_ref (ob, ref, encoder, varpool_encoder);
+ 	}
+     }
+ 
+   lto_output_uleb128_stream (ob->main_stream, 0);
+ 
+   for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
+     {
+       struct varpool_node *node = vsi_node (vsi);
+ 
+       count = ipa_ref_list_nreferences (&node->ref_list);
+       if (count)
+ 	{
+ 	  lto_output_uleb128_stream (ob->main_stream, count);
+ 	  lto_output_uleb128_stream (ob->main_stream,
+ 				     lto_varpool_encoder_lookup (varpool_encoder,
+ 								 node));
+ 	  for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+ 	    lto_output_ref (ob, ref, encoder, varpool_encoder);
+ 	}
+     }
+ 
+   lto_output_uleb128_stream (ob->main_stream, 0);
+ 
+   lto_destroy_simple_output_block (ob);
+ }
+ 
+ 
+ /* Output the part of the cgraph in SET.  */
+ 
  void
  output_cgraph (cgraph_node_set set, varpool_node_set vset)
  {
*************** output_cgraph (cgraph_node_set set, varp
*** 591,596 ****
--- 717,723 ----
      {
        node = csi_node (csi);
        add_node_to (encoder, node);
+       add_references (encoder, varpool_encoder, &node->ref_list);
      }
    for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
      {
*************** output_cgraph (cgraph_node_set set, varp
*** 598,606 ****
        gcc_assert (!vnode->alias);
        lto_varpool_encoder_encode (varpool_encoder, vnode);
        lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
      }
!   /* FIXME: We do not track references, so for now we need to include all possibly
!      used variables in the encoder set.  */
    for (vnode = varpool_nodes; vnode; vnode = vnode->next)
      if (vnode->needed)
        lto_varpool_encoder_encode (varpool_encoder, vnode);
--- 725,734 ----
        gcc_assert (!vnode->alias);
        lto_varpool_encoder_encode (varpool_encoder, vnode);
        lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
+       add_references (encoder, varpool_encoder, &vnode->ref_list);
      }
!   /* FIXME: We can not currenlty remove any varpool nodes or we get ICE merging
!      binfos.  */
    for (vnode = varpool_nodes; vnode; vnode = vnode->next)
      if (vnode->needed)
        lto_varpool_encoder_encode (varpool_encoder, vnode);
*************** output_cgraph (cgraph_node_set set, varp
*** 617,622 ****
--- 745,751 ----
  	      ||  TREE_READONLY (vnode->decl)))
  	{
  	  lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
+ 	  add_references (encoder, varpool_encoder, &vnode->ref_list);
  	}
      }
  
*************** output_cgraph (cgraph_node_set set, varp
*** 672,678 ****
    lto_output_uleb128_stream (ob->main_stream, 0);
  
    lto_destroy_simple_output_block (ob);
!   output_varpool (vset);
  }
  
  /* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
--- 801,808 ----
    lto_output_uleb128_stream (ob->main_stream, 0);
  
    lto_destroy_simple_output_block (ob);
!   output_varpool (set, vset);
!   output_refs (set, vset, encoder, varpool_encoder);
  }
  
  /* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
*************** input_overwrite_node (struct lto_file_de
*** 727,733 ****
  /* Output the part of the cgraph in SET.  */
  
  static void
! output_varpool (varpool_node_set vset)
  {
    struct lto_simple_output_block *ob = lto_create_simple_output_block (LTO_section_varpool);
    lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
--- 857,863 ----
  /* Output the part of the cgraph in SET.  */
  
  static void
! output_varpool (cgraph_node_set set, varpool_node_set vset)
  {
    struct lto_simple_output_block *ob = lto_create_simple_output_block (LTO_section_varpool);
    lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
*************** output_varpool (varpool_node_set vset)
*** 741,747 ****
    for (i = 0; i < len; i++)
      {
        lto_output_varpool_node (ob, lto_varpool_encoder_deref (varpool_encoder, i),
! 			       vset);
      }
  
    lto_destroy_simple_output_block (ob);
--- 871,877 ----
    for (i = 0; i < len; i++)
      {
        lto_output_varpool_node (ob, lto_varpool_encoder_deref (varpool_encoder, i),
! 			       set, vset);
      }
  
    lto_destroy_simple_output_block (ob);
*************** input_varpool_node (struct lto_file_decl
*** 889,894 ****
--- 1019,1051 ----
    return node;
  }
  
+ /* Read a node from input_block IB.  TAG is the node's tag just read.
+    Return the node read or overwriten.  */
+ 
+ static void
+ input_ref (struct lto_input_block *ib,
+ 	   struct cgraph_node *refering_node,
+ 	   struct varpool_node *refering_varpool_node,
+ 	   VEC(cgraph_node_ptr, heap) *nodes,
+ 	   VEC(varpool_node_ptr, heap) *varpool_nodes)
+ {
+   struct cgraph_node *node = NULL;
+   struct varpool_node *varpool_node = NULL;
+   struct bitpack_d *bp;
+   enum ipa_ref_type type;
+   enum ipa_ref_use use;
+ 
+   bp = lto_input_bitpack (ib);
+   type = (enum ipa_ref_type) bp_unpack_value (bp, 1);
+   use = (enum ipa_ref_use) bp_unpack_value (bp, 2);
+   bitpack_delete (bp);
+   if (type == IPA_REF_CGRAPH)
+     node = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
+   else
+     varpool_node = VEC_index (varpool_node_ptr, varpool_nodes, lto_input_sleb128 (ib));
+   ipa_record_reference (refering_node, refering_varpool_node,
+ 		        node, varpool_node, use, NULL);
+ }
  
  /* Read an edge from IB.  NODES points to a vector of previously read nodes for
     decoding caller and callee of the edge to be read.  If INDIRECT is true, the
*************** input_varpool_1 (struct lto_file_decl_da
*** 1036,1041 ****
--- 1193,1236 ----
    return varpool;
  }
  
+ /* Input ipa_refs.  */
+ 
+ static void
+ input_refs (struct lto_input_block *ib,
+ 	    VEC(cgraph_node_ptr, heap) *nodes,
+ 	    VEC(varpool_node_ptr, heap) *varpool)
+ {
+   int count;
+   int idx;
+   while (true)
+     {
+       struct cgraph_node *node;
+       count = lto_input_uleb128 (ib);
+       if (!count)
+ 	break;
+       idx = lto_input_uleb128 (ib);
+       node = VEC_index (cgraph_node_ptr, nodes, idx);
+       while (count)
+ 	{
+ 	  input_ref (ib, node, NULL, nodes, varpool);
+ 	  count--;
+ 	}
+     }
+   while (true)
+     {
+       struct varpool_node *node;
+       count = lto_input_uleb128 (ib);
+       if (!count)
+ 	break;
+       node = VEC_index (varpool_node_ptr, varpool, lto_input_uleb128 (ib));
+       while (count)
+ 	{
+ 	  input_ref (ib, NULL, node, nodes, varpool);
+ 	  count--;
+ 	}
+     }
+ }
+ 	    
  
  static struct gcov_ctr_summary lto_gcov_summary;
  
*************** input_cgraph (void)
*** 1100,1105 ****
--- 1295,1305 ----
        lto_destroy_simple_input_block (file_data, LTO_section_varpool,
  				      ib, data, len);
  
+       ib = lto_create_simple_input_block (file_data, LTO_section_refs,
+ 					  &data, &len);
+       input_refs (ib, nodes, varpool);
+       lto_destroy_simple_input_block (file_data, LTO_section_refs,
+ 				      ib, data, len);
        VEC_free (cgraph_node_ptr, heap, nodes);
        VEC_free (varpool_node_ptr, heap, varpool);
      }
Index: ipa-ref-inline.h
===================================================================
*** ipa-ref-inline.h	(revision 159062)
--- ipa-ref-inline.h	(working copy)
***************
*** 0 ****
--- 1,119 ----
+ /* IPA reference lists.
+    Copyright (C) 2010
+    Free Software Foundation, Inc.
+    Contributed by Jan Hubicka
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ /* Return callgraph node REF is refering.  */
+ static inline struct cgraph_node *
+ ipa_ref_node (struct ipa_ref *ref)
+ {
+   gcc_assert (ref->refered_type == IPA_REF_CGRAPH);
+   return ref->refered.cgraph_node;
+ }
+ 
+ /* Return varpool node REF is refering.  */
+ 
+ static inline struct varpool_node *
+ ipa_ref_varpool_node (struct ipa_ref *ref)
+ {
+   gcc_assert (ref->refered_type == IPA_REF_VARPOOL);
+   return ref->refered.varpool_node;
+ }
+ 
+ /* Return cgraph node REF is in.  */
+ 
+ static inline struct cgraph_node *
+ ipa_ref_refering_node (struct ipa_ref *ref)
+ {
+   gcc_assert (ref->refering_type == IPA_REF_CGRAPH);
+   return ref->refering.cgraph_node;
+ }
+ 
+ /* Return varpool node REF is in.  */
+ 
+ static inline struct varpool_node *
+ ipa_ref_refering_varpool_node (struct ipa_ref *ref)
+ {
+   gcc_assert (ref->refering_type == IPA_REF_VARPOOL);
+   return ref->refering.varpool_node;
+ }
+ 
+ /* Return reference list REF is in.  */
+ 
+ static inline struct ipa_ref_list *
+ ipa_ref_refering_ref_list (struct ipa_ref *ref)
+ {
+   if (ref->refering_type == IPA_REF_CGRAPH)
+     return &ipa_ref_refering_node (ref)->ref_list;
+   else
+     return &ipa_ref_refering_varpool_node (ref)->ref_list;
+ }
+ 
+ /* Return reference list REF is in.  */
+ 
+ static inline struct ipa_ref_list *
+ ipa_ref_refered_ref_list (struct ipa_ref *ref)
+ {
+   if (ref->refered_type == IPA_REF_CGRAPH)
+     return &ipa_ref_node (ref)->ref_list;
+   else
+     return &ipa_ref_varpool_node (ref)->ref_list;
+ }
+ 
+ /* Return first reference in LIST or NULL if empty.  */
+ 
+ static inline struct ipa_ref *
+ ipa_ref_list_first_reference (struct ipa_ref_list *list)
+ {
+   if (!VEC_length (ipa_ref_t, list->references))
+     return NULL;
+   return VEC_index (ipa_ref_t, list->references, 0);
+ }
+ 
+ /* Return first refering ref in LIST or NULL if empty.  */
+ 
+ static inline struct ipa_ref *
+ ipa_ref_list_first_refering (struct ipa_ref_list *list)
+ {
+   if (!VEC_length (ipa_ref_ptr, list->refering))
+     return NULL;
+   return VEC_index (ipa_ref_ptr, list->refering, 0);
+ }
+ 
+ /* Clear reference list.  */
+ 
+ static inline void
+ ipa_empty_ref_list (struct ipa_ref_list *list)
+ {
+   list->refering = NULL;
+   list->references = NULL;
+ }
+ 
+ /* Clear reference list.  */
+ 
+ static inline unsigned int
+ ipa_ref_list_nreferences (struct ipa_ref_list *list)
+ {
+   return VEC_length (ipa_ref_t, list->references);
+ }
+ 
+ #define ipa_ref_list_reference_iterate(L,I,P) \
+    VEC_iterate(ipa_ref_t, (L)->references, (I), (P))
+ #define ipa_ref_list_refering_iterate(L,I,P) \
+    VEC_iterate(ipa_ref_ptr, (L)->refering, (I), (P))
Index: lto-section-in.c
===================================================================
*** lto-section-in.c	(revision 159059)
--- lto-section-in.c	(working copy)
*************** const char *lto_section_name[LTO_N_SECTI
*** 53,58 ****
--- 53,59 ----
    "static_initializer",
    "cgraph",
    "varpool",
+   "refs",
    "jump_funcs"
    "ipa_pure_const",
    "ipa_reference",
Index: lto/lto.c
===================================================================
*** lto/lto.c	(revision 159062)
--- lto/lto.c	(working copy)
*************** lto_promote_cross_file_statics (void)
*** 718,753 ****
    struct varpool_node *vnode;
    unsigned i, n_sets;
    cgraph_node_set set;
    cgraph_node_set_iterator csi;
  
    gcc_assert (flag_wpa);
  
-   /* At moment we make no attempt to figure out who is refering the variables,
-      so all must become global.  
- 
-      Constant pool references use internal labels and thus can not be made global.
-      It is sensible to keep those ltrans local to allow better optimization.  */
-   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
-     if (!vnode->externally_visible && vnode->analyzed
- 	&& !DECL_IN_CONSTANT_POOL (vnode->decl))
-        {
- 	  TREE_PUBLIC (vnode->decl) = 1;
- 	  DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
-        }
    n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets);
    for (i = 0; i < n_sets; i++)
      {
        set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
  
        /* 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);
! 	  bool globalize = node->address_taken || node->local.vtable_method;
  	  struct cgraph_edge *e;
  	  if (node->local.externally_visible)
  	    continue;
  	  for (e = node->callers; e && !globalize; e = e->next_caller)
  	    {
  	      struct cgraph_node *caller = e->caller;
--- 718,747 ----
    struct varpool_node *vnode;
    unsigned i, n_sets;
    cgraph_node_set set;
+   varpool_node_set vset;
    cgraph_node_set_iterator csi;
+   varpool_node_set_iterator vsi;
  
    gcc_assert (flag_wpa);
  
    n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets);
    for (i = 0; i < n_sets; i++)
      {
        set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
+       vset = VEC_index (varpool_node_set, lto_varpool_node_sets, i);
  
        /* 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);
! 	  bool globalize = node->local.vtable_method;
  	  struct cgraph_edge *e;
  	  if (node->local.externally_visible)
  	    continue;
+ 	  if (!globalize
+ 	      && referenced_from_other_partition_p (&node->ref_list, set, vset))
+ 	    globalize = true;
  	  for (e = node->callers; e && !globalize; e = e->next_caller)
  	    {
  	      struct cgraph_node *caller = e->caller;
*************** lto_promote_cross_file_statics (void)
*** 758,763 ****
--- 752,758 ----
  	    }
  	  if (globalize)
  	     {
+ 		gcc_assert (flag_wpa);
  		TREE_PUBLIC (node->decl) = 1;
  		DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
  		if (node->same_body)
*************** lto_promote_cross_file_statics (void)
*** 772,777 ****
--- 767,787 ----
  		  }
  	     }
  	}
+       for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
+ 	{
+ 	  vnode = vsi_node (vsi);
+ 	  /* Constant pool references use internal labels and thus can not
+ 	     be made global.  It is sensible to keep those ltrans local to
+ 	     allow better optimization.  */
+ 	  if (!DECL_IN_CONSTANT_POOL (vnode->decl)
+ 	      && !vnode->externally_visible && vnode->analyzed
+ 	      && referenced_from_other_partition_p (&vnode->ref_list, set, vset))
+ 	    {
+ 	      gcc_assert (flag_wpa);
+ 	      TREE_PUBLIC (vnode->decl) = 1;
+ 	      DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
+ 	    }
+ 	}
  
      }
  }
*************** lto_fixup_tree (tree *tp, int *walk_subt
*** 1457,1463 ****
  
    t = *tp;
    *walk_subtrees = 0;
!   if (pointer_set_contains (fixup_data->seen, t))
      return NULL;
  
    if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
--- 1467,1473 ----
  
    t = *tp;
    *walk_subtrees = 0;
!   if (!t || pointer_set_contains (fixup_data->seen, t))
      return NULL;
  
    if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 159059)
--- Makefile.in	(working copy)
*************** CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $
*** 904,910 ****
  IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
  IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
  IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H)
! CGRAPH_H = cgraph.h $(TREE_H) $(BASIC_BLOCK_H) cif-code.def
  DF_H = df.h $(BITMAP_H) $(BASIC_BLOCK_H) alloc-pool.h $(TIMEVAR_H)
  RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
  DDG_H = ddg.h sbitmap.h $(DF_H)
--- 904,910 ----
  IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
  IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
  IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H)
! CGRAPH_H = cgraph.h $(TREE_H) $(BASIC_BLOCK_H) cif-code.def ipa-ref.h ipa-ref-inline.h
  DF_H = df.h $(BITMAP_H) $(BASIC_BLOCK_H) alloc-pool.h $(TIMEVAR_H)
  RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
  DDG_H = ddg.h sbitmap.h $(DF_H)
*************** OBJS-archive = \
*** 1425,1430 ****
--- 1425,1431 ----
  	ipa-prop.o \
  	ipa-pure-const.o \
  	ipa-reference.o \
+ 	ipa-ref.o \
  	ipa-struct-reorg.o \
  	ipa-type-escape.o \
  	ipa-utils.o \
*************** ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SY
*** 2902,2907 ****
--- 2903,2911 ----
     langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
     $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
     $(TREE_INLINE_H) $(TIMEVAR_H)
+ ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H)  $(TREE_H) $(TARGET_H) \
+    $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H) 
  ipa-cp.o : ipa-cp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h  \
     $(TREE_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(TREE_FLOW_H) \
     $(TREE_PASS_H) $(FLAGS_H) $(TIMEVAR_H) $(DIAGNOSTIC_H) $(TREE_DUMP_H) \
*************** GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
*** 3584,3590 ****
    $(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
    $(srcdir)/fixed-value.h \
    $(srcdir)/ipa-reference.h $(srcdir)/output.h $(srcdir)/cfgloop.h \
!   $(srcdir)/cselib.h $(srcdir)/basic-block.h  $(srcdir)/cgraph.h \
    $(srcdir)/reload.h $(srcdir)/caller-save.c \
    $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
    $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-inline.c $(srcdir)/matrix-reorg.c \
--- 3588,3594 ----
    $(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
    $(srcdir)/fixed-value.h \
    $(srcdir)/ipa-reference.h $(srcdir)/output.h $(srcdir)/cfgloop.h \
!   $(srcdir)/cselib.h $(srcdir)/basic-block.h  $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \
    $(srcdir)/reload.h $(srcdir)/caller-save.c \
    $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
    $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-inline.c $(srcdir)/matrix-reorg.c \
Index: varpool.c
===================================================================
*** varpool.c	(revision 159059)
--- varpool.c	(working copy)
*************** varpool_node (tree decl)
*** 141,146 ****
--- 141,147 ----
    node->decl = decl;
    node->order = cgraph_order++;
    node->next = varpool_nodes;
+   ipa_empty_ref_list (&node->ref_list);
    if (varpool_nodes)
      varpool_nodes->prev = node;
    varpool_nodes = node;
*************** varpool_remove_node (struct varpool_node
*** 193,198 ****
--- 194,201 ----
        gcc_assert (varpool_nodes_queue == node);
        varpool_nodes_queue = node->next_needed;
      }
+   ipa_remove_all_references (&node->ref_list);
+   ipa_remove_all_refering (&node->ref_list);
    if (DECL_INITIAL (node->decl))
      DECL_INITIAL (node->decl) = error_mark_node;
    ggc_free (node);
*************** dump_varpool_node (FILE *f, struct varpo
*** 228,233 ****
--- 231,240 ----
    else if (node->used_from_other_partition)
      fprintf (f, " used_from_other_partition");
    fprintf (f, "\n");
+   fprintf (f, "  References: ");
+   ipa_dump_references (f, &node->ref_list);
+   fprintf (f, "  Refering this var: ");
+   ipa_dump_refering (f, &node->ref_list);
  }
  
  /* Dump the variable pool.  */
*************** varpool_extra_name_alias (tree alias, tr
*** 633,638 ****
--- 640,646 ----
    alias_node->alias = 1;
    alias_node->extra_name = decl_node;
    alias_node->next = decl_node->extra_name;
+   ipa_empty_ref_list (&alias_node->ref_list);
    if (decl_node->extra_name)
      decl_node->extra_name->prev = alias_node;
    decl_node->extra_name = alias_node;
Index: lto-streamer.c
===================================================================
*** lto-streamer.c	(revision 159059)
--- lto-streamer.c	(working copy)
*************** lto_get_section_name (int section_type, 
*** 163,168 ****
--- 163,171 ----
      case LTO_section_varpool:
        return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL);
  
+     case LTO_section_refs:
+       return concat (LTO_SECTION_NAME_PREFIX, ".refs", NULL);
+ 
      case LTO_section_jump_functions:
        return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL);
  
Index: lto-streamer.h
===================================================================
*** lto-streamer.h	(revision 159062)
--- lto-streamer.h	(working copy)
*************** enum lto_section_type
*** 257,262 ****
--- 257,263 ----
    LTO_section_static_initializer,
    LTO_section_cgraph,
    LTO_section_varpool,
+   LTO_section_refs,
    LTO_section_jump_functions,
    LTO_section_ipa_pure_const,
    LTO_section_ipa_reference,
*************** bool lto_varpool_encoder_encode_initiali
*** 855,860 ****
--- 856,864 ----
  					       struct varpool_node *);
  void output_cgraph (cgraph_node_set, varpool_node_set);
  void input_cgraph (void);
+ bool referenced_from_other_partition_p (struct ipa_ref_list *,
+ 				        cgraph_node_set,
+ 				        varpool_node_set vset);
  
  
  /* In lto-symtab.c.  */



More information about the Gcc-patches mailing list