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


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

[RFC/RFA] Add reference lists into callgraph/varpool and improve WHOPR partitioning


Hi,
this patch adds summaries about references (addresses taken, loads and stores)
into cgraph and varpool nodes.  This is something I wanted to do for a while
since it enables us:

  1) Improve unreachable function/variable removal.  At moment as soon as
     cgraph sees derefernce of function it will never remove it or optimize as
     local since it has no track if the derefernece was removed
     In particular 
  2) Cleanup way virtual tables are handled.  Since we lack 1) we are working
     around with virtual tables to enable virtual functions to be optimized out
     when virtual table is.
  3) Produce smaller ltrans partitions in WHOPR: since we have no idea who is
     refering to what we simply output all functions with address takena nd
     variables into each WHOPR partition.
     This is very suboptimal causing a lot of disk I/O.
     With this patch the partition get resonably sized (about 3 times bigger
     than original .o files at average still)
  4) Allow promotion of variables to constant, write only (that will be
     optimzed out) and functions to local as the references get optimized out during
     IPA passes.
  5) Simplify ipa-reference implementation.

I always got somewhat discougrated by fact that references may go from cgraph
node or varpool node to cgraph node or varpool node, so technically there are 4
types of edges.  Representing those needs a bit abstraction.

The patch adds ipa-ref.h with the abstraction API.  All types of edges are
represented via single ipa_ref record that has refering and refered pointers
that both can be cgraph or varpool.  There are some accestors to make operation
easier.

Memory representation is via vector of actual ipa_ref structures listing all
references (so we have good memory locality).  Way to get all refering nodes is
via vector of pointers pointing into the other vector.  This needs some
updating when first vector gets resized and also means that references will
move in memory. But unlike for cgraph edges I don't see much need to store some
additional info to the edges and adding API for that is also simple.  As a
result the meory usage is pretty low  (usually less than 5% of cgraph edge
memory use)

Patch currently impents only 3) that already expose some problems.

There are two new falures with the patch:
FAIL: g++.dg/abi/vtt1.C scan-assembler _ZTT1B
g++.dg/lto/20081204-1 cp_lto_20081204-1_0.o-cp_lto_20081204-1_1.o link

First one is because there is weak variable _ZTT1B that we now optimize away
since i tis not referenced in the unit.  I think this is correct transform and
if not, C++ frotnend has to mark it with DECL_PRESERVE_P.  Do we really need to
output this?

Second testcase is tricky.  We get
warning: type of '_ZTVN10__cxxabiv120__si_class_type_infoE' does not match original declaration
that is wrong.

We already output number of such confused warnings I did not notice previously.
There are two issues.  First since we now take care to output only varpool
nodes needed by the program, we have variables without any varpool entry for
it.  lto-symtab allows prevailing only with variables with varpool entry on it
and in this case there is none.

So we end up chosing wrong variant (one without initializer in it and whtout
readonly flag) resulting in the warning.  I guess we should fix lto-symtab to
chose with a priority variable with varpool node (i.e. from unit where it is
actually needed) and if that fails a variable according to original logic
preffering initialized ones and constant ones.

THe other problem is that this partiuclar variable should have varpool node.
This is frontend bug.  The vtable in question is refered from other vtable but
C++ frontend forgets to finalize it.  I am not quite sure how to fix this, as I
have no idea what si_class_type is and why it is handled in this special way.
But somehow decl_needed_p predicate in C++ FE returns false here, so I suppose
it is missing set of flag somewhere.

Same problem leads to ICE building xalanbmk with chekcing enabled (we ICE later
on type mismatch anyway) this is just another symtom 

                  /* In case of type mismatches across units we can fail
                     to unify some types and thus not find a proper
                     field-decl here.  So only assert here if checking
                     is enabled.  */
#ifdef ENABLE_CHECKING
                  gcc_assert (tem != NULL_TREE);
#endif

of fact that we don't merge some decls we can.

The patch suffers from significant snowballing effect.  So if possible I would
like to cut the work in this form implementing the missing features and
resolving those issues incrementally (or in parallel), so I would like to ask
for review of this patch.

I will try to send separate patches for those three problems since they can all
be fixed independently on rest of changes.

Bootstrapped/regtested x86_64-linux.

	* lto-symtab.c (lto_cgraph_replace_node): Do not remove outgoing edges,
	cgraph_remove will do so; update refering list.
	(lto_varpool_replace_node): Handle aliases; fix sanity check;
	update refering list.
	(lto_symtab_resolve_can_prevail_p): Look into aliases.
	* cgraphbuild.c: Include ipa-utils.h
	(record_reference_ctx): New.
	(record_reference): Use ipa_record_reference.
	(mark_address, mark_load, mark_store): New.
	(build_cgraph_edges): Rewrite.
	(record_references_in_initializer): UPdate calll of record_reference.
	(rebuild_cgraph_edges): Rewrite.
	* cgraph.c (cgraph_create_node): Initialize ref_list.
	(cgraph_remove_node): Clear ref list.
	(dump_cgraph_node): Dump ref list.
	(cgraph_clone_node): Call ipa_clone_references.
	* cgraph.h: Include ipa-ref.h and ipa-ref-inline.h.
	(struct cgraph_node, struct varpool_node): Add ref_list.
	* ipa-ref.c: New file.
	* ipa-ref.h: New file.
	* ipa-ref-inline.h: New file.
	* lto-cgraph.c (output_varpool): Forward declare.
	(lto_varpool_encoder_new, lto_varpool_encoder_delete,
	lto_varpool_encoder_encode, lto_varpool_encoder_lookup,
	lto_varpool_encoder_deref, lto_varpool_encoder_size,
	lto_varpool_encoder_encode_initializer_p,
	lto_set_varpool_encoder_encode_initializer): New.
	(referenced_from_other_partition_p): New.
	(lto_output_varpool_node): Partition properly.
	(lto_output_ref): New function.
	(add_references): New function.
	(output_refs): New function.
	(output_cgraph): Take varpool_node_set too; handle output of varpool
	and references; compute boundaries based on references.
	(output_varpool): Use encoder.
	(input_varpool_node): Set analyze flag correctly.
	(input_ref): New function.
	(input_cgraph_1): Record vector of nodes read.
	(input_varpool_1): Likewise.
	(input_refs): New function.
	(input_cgraph): Handle input of refs and varpool.
	* lto-streamer-out.c (lto_output_ts_decl_common_tree_pointers): Output
	only initializers needed.
	(lto_output): Call only output_cgraph.
	(produce_asm_for_decls): Delete varpool encoer.
	* lto-section-in.c (lto_section_name): Add refs.
	* Makefile.in (CGRAPH_H): Add new dependencies.
	(ipa-ref.o): New file.
	* varpool.c (varpool_node): Initialize ref_list.
	(varpool_remove_node): Remove aliases correctly; remove ref list;
	remove DECL_INITIAL
	(dump_varpool_node): Dump refernces.
	(varpool_assemble_decl): Output only finalized vars.
	(varpool_extra_name_alias): Otput empty ref list.
	* lto-section-out.c (lto_new_out_decl_state): Initialize varpool encoder.
	* lto-streamer.c (lto_get_section_name): Add LTO_section_refs.
	* lto-streamer.h (LTO_section_refs): New enum valie.
	(lto_varpool_encoder_d): New struct.
	(lto_out_decl_state, lto_file_decl_data): Add varpool_node_encoder.
	(lto_cgraph_encoder_delete, output_cgraph): Update prototype.
	(output_varpool, input_varpool): Remove.
	(lto_cgraph_encoder_delete, lto_varpool_encoder_deref,
	lto_varpool_encoder_lookup, lto_varpool_encoder_new,
	lto_varpool_encoder_encode, lto_varpool_encoder_delete,
	lto_varpool_encoder_encode_initializer_p): New.

	* lto.c (lto_1_to_1_map): Skip unneded nodes.
	(lto_promote_cross_file_statics): Do proper boundary analysis.
	
Index: lto-symtab.c
===================================================================
--- lto-symtab.c	(revision 158944)
+++ lto-symtab.c	(working copy)
@@ -214,15 +214,8 @@ lto_cgraph_replace_node (struct cgraph_n
       next = e->next_caller;
       cgraph_redirect_edge_callee (e, prevailing_node);
     }
-
-  /* There are not supposed to be any outgoing edges from a node we
-     replace.  Still this can happen for multiple instances of weak
-     functions.  */
-  for (e = node->callees; e; e = next)
-    {
-      next = e->next_callee;
-      cgraph_remove_edge (e);
-    }
+  /* Redirect incomming references.  */
+  ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
 
   if (node->same_body)
     {
@@ -257,11 +250,33 @@ lto_varpool_replace_node (struct varpool
   /* Merge node flags.  */
   if (vnode->needed)
     {
-      gcc_assert (prevailing_node->analyzed);
+      gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
       varpool_mark_needed_node (prevailing_node);
     }
+  /* Relink aliases.  */
+  if (vnode->extra_name && !vnode->alias)
+    {
+      struct varpool_node *alias, *last;
+      for (alias = vnode->extra_name;
+	   alias; alias = alias->next)
+	{
+	  last = alias;
+	  alias->extra_name = prevailing_node;
+	}
+
+      if (prevailing_node->extra_name)
+	{
+	  last->next = prevailing_node->extra_name;
+	  prevailing_node->extra_name->prev = last;
+	}
+      prevailing_node->extra_name = vnode->extra_name;
+      vnode->extra_name = NULL;
+    }
   gcc_assert (!vnode->finalized || prevailing_node->finalized);
   gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+  if (prevailing_node->alias)
+    prevailing_node = prevailing_node->extra_name;
+  ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
 
   /* Finally remove the replaced node.  */
   varpool_remove_node (vnode);
@@ -404,9 +419,16 @@ lto_symtab_resolve_can_prevail_p (lto_sy
   if (TREE_CODE (e->decl) == FUNCTION_DECL)
     return (e->node && e->node->analyzed);
 
-  /* A variable should have a size.  */
+  /* Variable should be one with initializer or alias of initialized
+     variable.  */
   else if (TREE_CODE (e->decl) == VAR_DECL)
-    return (e->vnode && e->vnode->finalized);
+    {
+      if (!e->vnode)
+	return false;
+      if (e->vnode->finalized)
	return true;
+      return e->vnode->alias && e->vnode->extra_name->finalized;
+    }
 
   gcc_unreachable ();
 }
Index: cgraphbuild.c
===================================================================
--- cgraphbuild.c	(revision 158941)
+++ cgraphbuild.c	(working copy)
@@ -31,6 +31,15 @@ along with GCC; see the file COPYING3.  
 #include "intl.h"
 #include "gimple.h"
 #include "tree-pass.h"
+#include "ipa-utils.h"
+
+/* Context of record_reference.  */
+struct record_reference_ctx
+{
+  bool only_vars;
+  struct cgraph_node *node;
+  struct varpool_node *varpool_node;
+};
 
 /* Walk tree and record all calls and references to functions/variables.
    Called via walk_tree: TP is pointer to tree to be examined.
@@ -42,26 +51,36 @@ record_reference (tree *tp, int *walk_su
 {
   tree t = *tp;
   tree decl;
-  bool do_callgraph = data != NULL;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *)data;
+  struct record_reference_ctx *ctx = (struct record_reference_ctx *)wi->info;
 
   switch (TREE_CODE (t))
     {
     case VAR_DECL:
-      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
-	{
-	  varpool_mark_needed_node (varpool_node (t));
-	  if (lang_hooks.callgraph.analyze_expr)
-	    return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
-	}
+    case FUNCTION_DECL:
+      gcc_unreachable ();
       break;
 
     case FDESC_EXPR:
     case ADDR_EXPR:
       /* Record dereferences to the functions.  This makes the
 	 functions reachable unconditionally.  */
-      decl = TREE_OPERAND (*tp, 0);
-      if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph)
+      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) == FUNCTION_DECL)
+	ipa_record_reference (ctx->node, ctx->varpool_node,
+			      cgraph_node (decl), NULL,
+			      IPA_REF_ADDR, NULL);
+      if (TREE_CODE (decl) == VAR_DECL)
+	{
+	  struct varpool_node *vnode = varpool_node (decl);
+	  ipa_record_reference (ctx->node, ctx->varpool_node,
+			        NULL, varpool_node (decl),
+			        IPA_REF_ADDR, NULL);
+	}
+      *walk_subtrees = 0;
       break;
 
     default:
@@ -126,6 +145,69 @@ compute_call_stmt_bb_frequency (tree dec
   return freq;
 }
 
+/* Mark address taken in STMT.  */
+
+static bool
+mark_address (gimple stmt, tree addr, void *data)
+{
+  if (TREE_CODE (addr) == FUNCTION_DECL)
+    {
+      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
+    {
+      addr = get_base_address (addr);
+      if (addr && TREE_CODE (addr) == VAR_DECL
+	  && (TREE_STATIC (addr) || DECL_EXTERNAL (addr)))
+	{
+	  struct varpool_node *vnode = varpool_node (addr);
+	  ipa_record_reference ((struct cgraph_node *)data, NULL,
+				NULL, vnode,
+				IPA_REF_ADDR, stmt);
+	}
+    }
+
+  return false;
+}
+
+/* Mark load of T.  */
+
+static bool
+mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
+{
+  t = get_base_address (t);
+  if (TREE_CODE (t) == VAR_DECL
+      && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+    {
+      struct varpool_node *vnode = varpool_node (t);
+      ipa_record_reference ((struct cgraph_node *)data, NULL,
+			    NULL, vnode,
+			    IPA_REF_LOAD, stmt);
+    }
+  return false;
+}
+
+/* Mark store of T.  */
+
+static bool
+mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
+{
+  t = get_base_address (t);
+  if (TREE_CODE (t) == VAR_DECL
+      && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+    {
+      struct varpool_node *vnode = varpool_node (t);
+      ipa_record_reference ((struct cgraph_node *)data, NULL,
+			    NULL, vnode,
+			    IPA_REF_STORE, NULL);
+     }
+  return false;
+}
+
 /* Create cgraph edges for function calls.
    Also look for functions and variables having addresses taken.  */
 
@@ -137,53 +219,47 @@ build_cgraph_edges (void)
   struct pointer_set_t *visited_nodes = pointer_set_create ();
   gimple_stmt_iterator gsi;
   tree step;
+  struct record_reference_ctx ctx = {false, NULL, NULL};
+  struct walk_stmt_info wi;
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = &ctx;
+  wi.pset = visited_nodes;
+  ctx.node = node;
 
   /* Create the callgraph edges and record the nodes referenced by the function.
      body.  */
   FOR_EACH_BB (bb)
-    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-      {
-	gimple stmt = gsi_stmt (gsi);
-	tree decl;
-
-	if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
-	  {
-	    size_t i;
-	    size_t n = gimple_call_num_args (stmt);
+    {
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  gimple stmt = gsi_stmt (gsi);
+	  tree decl;
+
+	  if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
 	    cgraph_create_edge (node, cgraph_node (decl), stmt,
 				bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
 				bb->loop_depth);
-	    for (i = 0; i < n; i++)
-	      walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
-			 node, visited_nodes);
-	    if (gimple_call_lhs (stmt))
-	      walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node,
-		         visited_nodes);
-	  }
-	else
-	  {
-	    struct walk_stmt_info wi;
-	    memset (&wi, 0, sizeof (wi));
-	    wi.info = node;
-	    wi.pset = visited_nodes;
-	    walk_gimple_op (stmt, record_reference, &wi);
-	    if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
-		&& gimple_omp_parallel_child_fn (stmt))
-	      {
-		tree fn = gimple_omp_parallel_child_fn (stmt);
+	  walk_stmt_load_store_addr_ops (stmt, node, mark_load, mark_store, mark_address);
+	  if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
+	      && gimple_omp_parallel_child_fn (stmt))
+	    {
+	      tree fn = gimple_omp_parallel_child_fn (stmt);
+	      cgraph_mark_needed_node (cgraph_node (fn));
+	    }
+	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
+	    {
+	      tree fn = gimple_omp_task_child_fn (stmt);
+	      if (fn)
+		cgraph_mark_needed_node (cgraph_node (fn));
+	      fn = gimple_omp_task_copy_fn (stmt);
+	      if (fn)
 		cgraph_mark_needed_node (cgraph_node (fn));
-	      }
-	    if (gimple_code (stmt) == GIMPLE_OMP_TASK)
-	      {
-		tree fn = gimple_omp_task_child_fn (stmt);
-		if (fn)
-		  cgraph_mark_needed_node (cgraph_node (fn));
-		fn = gimple_omp_task_copy_fn (stmt);
-		if (fn)
-		  cgraph_mark_needed_node (cgraph_node (fn));
-	      }
-	  }
-      }
+	    }
+	}
+      for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
+	walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, mark_load, mark_store, mark_address);
+   }
 
   /* Look for initializers of constant variables and private statics.  */
   for (step = cfun->local_decls;
@@ -194,8 +270,6 @@ build_cgraph_edges (void)
       if (TREE_CODE (decl) == VAR_DECL
 	  && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
 	varpool_finalize_decl (decl);
-      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
-	walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
     }
 
   pointer_set_destroy (visited_nodes);
@@ -229,8 +303,17 @@ void
 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, NULL};
+  struct walk_stmt_info wi;
+
+  ctx.varpool_node = node;
+  ctx.only_vars = only_vars;
+  memset (&wi, 0, sizeof (wi));
+  wi.info = &ctx;
+  wi.pset = visited_nodes;
   walk_tree (&DECL_INITIAL (decl), record_reference,
-            only_vars ? NULL : decl, visited_nodes);
+            &wi, visited_nodes);
   pointer_set_destroy (visited_nodes);
 }
 
@@ -245,23 +328,29 @@ rebuild_cgraph_edges (void)
   gimple_stmt_iterator gsi;
 
   cgraph_node_remove_callees (node);
+  ipa_remove_all_references (&node->ref_list);
 
   node->count = ENTRY_BLOCK_PTR->count;
 
   FOR_EACH_BB (bb)
-    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-      {
-	gimple stmt = gsi_stmt (gsi);
-	tree decl;
-
-	if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
-	  cgraph_create_edge (node, cgraph_node (decl), stmt,
-			      bb->count,
-			      compute_call_stmt_bb_frequency
-			        (current_function_decl, bb),
-			      bb->loop_depth);
+    {
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  gimple stmt = gsi_stmt (gsi);
+	  tree decl;
 
-      }
+	  if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
+	    cgraph_create_edge (node, cgraph_node (decl), stmt,
+				bb->count,
+				compute_call_stmt_bb_frequency
+				  (current_function_decl, bb),
+				bb->loop_depth);
+	  walk_stmt_load_store_addr_ops (stmt, node, mark_load, mark_store, mark_address);
+
+	}
+      for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
+	walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, mark_load, mark_store, mark_address);
+    }
   gcc_assert (!node->global.inlined_to);
 
   return 0;
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 158941)
+++ cgraph.c	(working copy)
@@ -463,6 +463,7 @@ cgraph_create_node (void)
   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;
@@ -1412,6 +1413,8 @@ cgraph_remove_node (struct cgraph_node *
   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);
 
@@ -1853,6 +1856,10 @@ dump_cgraph_node (FILE *f, struct cgraph
 	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++;
@@ -2081,6 +2088,7 @@ cgraph_clone_node (struct cgraph_node *n
   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 158943)
+++ cgraph.h	(working copy)
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  
 #define GCC_CGRAPH_H
 #include "tree.h"
 #include "basic-block.h"
+#include "ipa-ref.h"
 
 enum availability
 {
@@ -224,6 +225,7 @@ struct GTY((chain_next ("%h.next"), chai
      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;
@@ -427,7 +429,7 @@ DEF_VEC_ALLOC_P(cgraph_edge_p,heap);
 /* The varpool data structure.
    Each static variable decl has assigned varpool_node.  */
 
-struct GTY((chain_next ("%h.next"))) 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;
@@ -436,6 +438,7 @@ struct GTY((chain_next ("%h.next"))) var
   /* 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;
 
@@ -864,4 +867,6 @@ cgraph_can_remove_if_no_direct_calls_p (
 /* 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 0)
+++ ipa-ref.c	(revision 0)
@@ -0,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 0)
+++ ipa-ref.h	(revision 0)
@@ -0,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
+{
+  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 GTY ((desc ("%1.refering_type"))) refering;
+  union ipa_ref_ptr 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 158943)
+++ lto-cgraph.c	(working copy)
@@ -46,6 +46,8 @@ along with GCC; see the file COPYING3.  
 #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.  */
 enum LTO_cgraph_tags
@@ -143,6 +145,107 @@ lto_cgraph_encoder_size (lto_cgraph_enco
   return VEC_length (cgraph_node_ptr, encoder->nodes);
 }
 
+/* Create a new varpool encoder.  */
+
+lto_varpool_encoder_t
+lto_varpool_encoder_new (void)
+{
+  lto_varpool_encoder_t encoder = XCNEW (struct lto_varpool_encoder_d);
+  encoder->map = pointer_map_create ();
+  encoder->initializer = pointer_set_create ();
+  encoder->nodes = NULL;
+  return encoder;
+}
+
+
+/* Delete ENCODER and its components.  */
+
+void
+lto_varpool_encoder_delete (lto_varpool_encoder_t encoder)
+{
+   VEC_free (varpool_node_ptr, heap, encoder->nodes);
+   pointer_map_destroy (encoder->map);
+   pointer_set_destroy (encoder->initializer);
+   free (encoder);
+}
+
+
+/* Return the existing reference number of NODE in the varpool encoder in
+   output block OB.  Assign a new reference if this is the first time
+   NODE is encoded.  */
+
+int
+lto_varpool_encoder_encode (lto_varpool_encoder_t encoder,
+			   struct varpool_node *node)
+{
+  int ref;
+  void **slot;
+
+  slot = pointer_map_contains (encoder->map, node);
+  if (!slot)
+    {
+      ref = VEC_length (varpool_node_ptr, encoder->nodes);
+      slot = pointer_map_insert (encoder->map, node);
+      *slot = (void *) (intptr_t) ref;
+      VEC_safe_push (varpool_node_ptr, heap, encoder->nodes, node);
+    }
+  else
+    ref = (int) (intptr_t) *slot;
+
+  return ref;
+}
+
+#define LCC_NOT_FOUND	(-1)
+
+/* Look up NODE in encoder.  Return NODE's reference if it has been encoded
+   or LCC_NOT_FOUND if it is not there.  */
+
+int
+lto_varpool_encoder_lookup (lto_varpool_encoder_t encoder,
+			   struct varpool_node *node)
+{
+  void **slot = pointer_map_contains (encoder->map, node);
+  return (slot ? (int) (intptr_t) *slot : LCC_NOT_FOUND);
+}
+
+
+/* Return the varpool node corresponding to REF using ENCODER.  */
+
+struct varpool_node *
+lto_varpool_encoder_deref (lto_varpool_encoder_t encoder, int ref)
+{
+  if (ref == LCC_NOT_FOUND)
+    return NULL;
+
+  return VEC_index (varpool_node_ptr, encoder->nodes, ref);
+}
+
+
+/* Return number of encoded nodes in ENCODER.  */
+
+static int
+lto_varpool_encoder_size (lto_varpool_encoder_t encoder)
+{
+  return VEC_length (varpool_node_ptr, encoder->nodes);
+}
+
+/* Return TRUE if we should encode initializer of NODE (if any).  */
+
+bool
+lto_varpool_encoder_encode_initializer_p (lto_varpool_encoder_t encoder,
+					  struct varpool_node *node)
+{
+  return pointer_set_contains (encoder->initializer, node);
+}
+
+/* Return TRUE if we should encode initializer of NODE (if any).  */
+
+static void
+lto_set_varpool_encoder_encode_initializer (lto_varpool_encoder_t encoder,
+					    struct varpool_node *node)
+{
+  pointer_set_insert (encoder->initializer, node);
+}
 
 /* Output the cgraph EDGE to OB using ENCODER.  */
 
@@ -185,6 +288,30 @@ lto_output_edge (struct lto_simple_outpu
   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
@@ -359,9 +486,9 @@ lto_output_node (struct lto_simple_outpu
 
 static void
 lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
-		         varpool_node_set set)
+		         cgraph_node_set set, varpool_node_set vset)
 {
-  bool boundary_p = !varpool_node_in_set_p (node, set) && node->analyzed;
+  bool boundary_p = !varpool_node_in_set_p (node, vset) && node->analyzed;
   struct bitpack_d *bp;
   struct varpool_node *alias;
   int count = 0;
@@ -372,8 +499,8 @@ lto_output_varpool_node (struct lto_simp
   bp_pack_value (bp, node->force_output, 1);
   bp_pack_value (bp, node->finalized, 1);
   gcc_assert (node->finalized || !node->analyzed);
-  gcc_assert (node->needed);
   gcc_assert (!node->alias);
+  gcc_assert (node->needed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
      FIXME: Alternatively at -Os we may want to avoid generating for them the local
      labels and share them across LTRANS partitions.  */
@@ -384,9 +511,9 @@ lto_output_varpool_node (struct lto_simp
     }
   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, 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.  */
@@ -404,6 +531,34 @@ lto_output_varpool_node (struct lto_simp
     }
 }
 
+/* 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
@@ -432,6 +587,27 @@ add_node_to (lto_cgraph_encoder_t encode
   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);
+	if (vnode->alias)
+	  vnode = vnode->extra_name;
+        lto_varpool_encoder_encode (varpool_encoder, vnode);
+      }
+}
+
 /* Output all callees or indirect outgoing edges.  EDGE must be the first such
    edge.  */
 
@@ -453,16 +629,73 @@ output_outgoing_cgraph_edges (struct cgr
 
 /* 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)
+output_cgraph (cgraph_node_set set, varpool_node_set vset)
 {
   struct cgraph_node *node;
   struct lto_simple_output_block *ob;
   cgraph_node_set_iterator csi;
+  varpool_node_set_iterator vsi;
   struct cgraph_edge *edge;
   int i, n_nodes;
   bitmap written_decls;
   lto_cgraph_encoder_t encoder;
+  lto_varpool_encoder_t varpool_encoder;
   struct cgraph_asm_node *can;
 
   ob = lto_create_simple_output_block (LTO_section_cgraph);
@@ -472,7 +705,9 @@ output_cgraph (cgraph_node_set set)
   /* An encoder for cgraph nodes should have been created by
      ipa_write_summaries_1.  */
   gcc_assert (ob->decl_state->cgraph_node_encoder);
+  gcc_assert (ob->decl_state->varpool_node_encoder);
   encoder = ob->decl_state->cgraph_node_encoder;
+  varpool_encoder = ob->decl_state->varpool_node_encoder;
 
   /* The FUNCTION_DECLs for which we have written a node.  The first
      node found is written as the "original" node, the remaining nodes
@@ -484,6 +719,31 @@ output_cgraph (cgraph_node_set set)
     {
       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))
+    {
+      struct varpool_node *vnode = vsi_node (vsi);
+      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);
+    }
+  /* Pickle in also the initializer of all referenced readonly variables
+     to help folding.  Constant pool variables are not shared, so we must
+     pickle those too.  */
+  for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++)
+    {
+      struct varpool_node *vnode = lto_varpool_encoder_deref (varpool_encoder, i);
+      if (DECL_INITIAL (vnode->decl)
+	  && !lto_varpool_encoder_encode_initializer_p (varpool_encoder,
+						        vnode)
+	  && (DECL_IN_CONSTANT_POOL (vnode->decl)
+	      ||  TREE_READONLY (vnode->decl)))
+	{
+	  lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
+	  add_references (encoder, varpool_encoder, &vnode->ref_list);
+	}
     }
 
   /* Go over all the nodes again to include callees that are not in
@@ -538,6 +798,8 @@ output_cgraph (cgraph_node_set set)
   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,
@@ -591,27 +853,23 @@ input_overwrite_node (struct lto_file_de
 
 /* Output the part of the cgraph in SET.  */
 
-void
-output_varpool (varpool_node_set set)
+static void
+output_varpool (cgraph_node_set set, varpool_node_set vset)
 {
-  struct varpool_node *node;
-  struct lto_simple_output_block *ob;
-  int len = 0;
-
-  ob = lto_create_simple_output_block (LTO_section_varpool);
-
-  for (node = varpool_nodes; node; node = node->next)
-    if (node->needed && node->analyzed)
-      len++;
+  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;
+  int len = lto_varpool_encoder_size (varpool_encoder), i;
 
   lto_output_uleb128_stream (ob->main_stream, len);
 
   /* Write out the nodes.  We must first output a node and then its clones,
      otherwise at a time reading back the node there would be nothing to clone
      from.  */
-  for (node = varpool_nodes; node; node = node->next)
-    if (node->needed && node->analyzed)
-      lto_output_varpool_node (ob, node, set);
+  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);
 }
@@ -737,7 +995,7 @@ input_varpool_node (struct lto_file_decl
   node->externally_visible = bp_unpack_value (bp, 1);
   node->force_output = bp_unpack_value (bp, 1);
   node->finalized = bp_unpack_value (bp, 1);
-  node->analyzed = 1; 
+  node->analyzed = node->finalized; 
   node->used_from_other_partition = bp_unpack_value (bp, 1);
   node->in_other_partition = bp_unpack_value (bp, 1);
   aliases_p = bp_unpack_value (bp, 1);
@@ -757,6 +1015,33 @@ input_varpool_node (struct lto_file_decl
   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 = bp_unpack_value (bp, 1);
+  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
@@ -822,7 +1107,7 @@ input_edge (struct lto_input_block *ib, 
 
 /* Read a cgraph from IB using the info in FILE_DATA.  */
 
-static void
+static VEC(cgraph_node_ptr, heap) *
 input_cgraph_1 (struct lto_file_decl_data *file_data,
 		struct lto_input_block *ib)
 {
@@ -882,25 +1167,66 @@ input_cgraph_1 (struct lto_file_decl_dat
       else
 	node->same_comdat_group = NULL;
     }
-
-  VEC_free (cgraph_node_ptr, heap, nodes);
+  return nodes;
 }
 
 /* Read a varpool from IB using the info in FILE_DATA.  */
 
-static void
+static VEC(varpool_node_ptr, heap) *
 input_varpool_1 (struct lto_file_decl_data *file_data,
 		struct lto_input_block *ib)
 {
   unsigned HOST_WIDE_INT len;
+  VEC(varpool_node_ptr, heap) *varpool = NULL;
 
   len = lto_input_uleb128 (ib);
   while (len)
     {
-      input_varpool_node (file_data, ib);
+      VEC_safe_push (varpool_node_ptr, heap, varpool,
+		     input_varpool_node (file_data, ib));
       len--;
     }
+  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;
 
@@ -948,20 +1274,30 @@ input_cgraph (void)
       const char *data;
       size_t len;
       struct lto_input_block *ib;
+      VEC(cgraph_node_ptr, heap) *nodes;
+      VEC(varpool_node_ptr, heap) *varpool;
 
       ib = lto_create_simple_input_block (file_data, LTO_section_cgraph,
 					  &data, &len);
       input_profile_summary (ib);
       file_data->cgraph_node_encoder = lto_cgraph_encoder_new ();
-      input_cgraph_1 (file_data, ib);
+      nodes = input_cgraph_1 (file_data, ib);
       lto_destroy_simple_input_block (file_data, LTO_section_cgraph,
 				      ib, data, len);
 
       ib = lto_create_simple_input_block (file_data, LTO_section_varpool,
 					  &data, &len);
-      input_varpool_1 (file_data, ib);
+      varpool = input_varpool_1 (file_data, ib);
       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);
     }
 
   /* Clear out the aux field that was used to store enough state to
Index: ipa-ref-inline.h
===================================================================
--- ipa-ref-inline.h	(revision 0)
+++ ipa-ref-inline.h	(revision 0)
@@ -0,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-streamer-out.c
===================================================================
--- lto-streamer-out.c	(revision 158941)
+++ lto-streamer-out.c	(working copy)
@@ -844,7 +844,23 @@ lto_output_ts_decl_common_tree_pointers 
   lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
 
   if (TREE_CODE (expr) != FUNCTION_DECL)
-    lto_output_tree_or_ref (ob, DECL_INITIAL (expr), ref_p);
+    {
+      tree initial = DECL_INITIAL (expr);
+      if (TREE_CODE (expr) == VAR_DECL
+	  && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
+	  && initial)
+	{
+	  lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
+	  struct varpool_node *vnode = varpool_get_node (expr);
+	  if (!vnode)
+	    initial = error_mark_node;
+	  else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
+							      vnode))
+	    initial = NULL;
+	}
+    
+      lto_output_tree_or_ref (ob, initial, ref_p);
+    }
 
   lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
   lto_output_tree_or_ref (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
@@ -2102,8 +2118,7 @@ lto_output (cgraph_node_set set, varpool
      be done now to make sure that all the statements in every function
      have been renumbered so that edges can be associated with call
      statements using the statement UIDs.  */
-  output_cgraph (set);
-  output_varpool (vset);
+  output_cgraph (set, vset);
 
   lto_bitmap_free (output);
 }
@@ -2507,6 +2522,7 @@ produce_asm_for_decls (cgraph_node_set s
 
   /* Deallocate memory and clean up.  */
   lto_cgraph_encoder_delete (ob->decl_state->cgraph_node_encoder);
+  lto_varpool_encoder_delete (ob->decl_state->varpool_node_encoder);
   VEC_free (lto_out_decl_state_ptr, heap, lto_function_decl_states);
   lto_function_decl_states = NULL;
   destroy_output_block (ob);
Index: lto-section-in.c
===================================================================
--- lto-section-in.c	(revision 158941)
+++ lto-section-in.c	(working copy)
@@ -53,6 +53,7 @@ const char *lto_section_name[LTO_N_SECTI
   "static_initializer",
   "cgraph",
   "varpool",
+  "refs",
   "jump_funcs"
   "ipa_pure_const",
   "ipa_reference",
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 158943)
+++ lto/lto.c	(working copy)
@@ -584,7 +584,7 @@ lto_1_to_1_map (void)
 
   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
     {
-      if (vnode->alias)
+      if (vnode->alias || !vnode->needed)
 	continue;
       slot = pointer_map_contains (vpmap, file_data);
       if (slot)
@@ -718,36 +718,30 @@ lto_promote_cross_file_statics (void)
   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);
 
-  /* 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);
+      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->address_taken || node->local.vtable_method;
+	  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;
@@ -758,6 +752,7 @@ lto_promote_cross_file_statics (void)
 	    }
 	  if (globalize)
 	     {
+		gcc_assert (flag_wpa);
 		TREE_PUBLIC (node->decl) = 1;
 		DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
 		if (node->same_body)
@@ -772,6 +767,21 @@ lto_promote_cross_file_statics (void)
 		  }
 	     }
 	}
+      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;
+	    }
+	}
 
     }
 }
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 158941)
+++ Makefile.in	(working copy)
@@ -904,7 +904,7 @@ CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $
 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
+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)
@@ -1425,6 +1425,7 @@ OBJS-archive = \
 	ipa-prop.o \
 	ipa-pure-const.o \
 	ipa-reference.o \
+	ipa-ref.o \
 	ipa-struct-reorg.o \
 	ipa-type-escape.o \
 	ipa-utils.o \
@@ -2902,6 +2903,9 @@ ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SY
    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) \
@@ -3583,7 +3587,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
   $(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)/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 158941)
+++ varpool.c	(working copy)
@@ -141,6 +141,7 @@ varpool_node (tree decl)
   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;
@@ -157,14 +158,25 @@ varpool_remove_node (struct varpool_node
   gcc_assert (*slot == node);
   htab_clear_slot (varpool_hash, slot);
   gcc_assert (!varpool_assembled_nodes_queue);
+  if (!node->alias)
+    while (node->extra_name)
+      varpool_remove_node (node->extra_name);
   if (node->next)
     node->next->prev = node->prev;
   if (node->prev)
     node->prev->next = node->next;
-  else if (node->next)
+  else
     {
-      gcc_assert (varpool_nodes == node);
-      varpool_nodes = node->next;
+      if (node->alias)
+	{
+          gcc_assert (node->extra_name->extra_name == node);
+	  node->extra_name->extra_name = node->next;
+	}
+      else
+	{
+          gcc_assert (varpool_nodes == node);
+          varpool_nodes = node->next;
+	}
     }
   if (varpool_first_unanalyzed_node == node)
     varpool_first_unanalyzed_node = node->next_needed;
@@ -182,7 +194,11 @@ varpool_remove_node (struct varpool_node
       gcc_assert (varpool_nodes_queue == node);
       varpool_nodes_queue = node->next_needed;
     }
-  node->decl = NULL;
+  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 given cgraph node.  */
@@ -215,6 +231,10 @@ dump_varpool_node (FILE *f, struct varpo
   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.  */
@@ -437,6 +457,7 @@ varpool_assemble_decl (struct varpool_no
   if (!TREE_ASM_WRITTEN (decl)
       && !node->alias
       && !node->in_other_partition
+      && node->finalized
       && !DECL_EXTERNAL (decl)
       && (TREE_CODE (decl) != VAR_DECL || !DECL_HAS_VALUE_EXPR_P (decl)))
     {
@@ -620,6 +641,7 @@ varpool_extra_name_alias (tree alias, tr
   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-section-out.c
===================================================================
--- lto-section-out.c	(revision 158941)
+++ lto-section-out.c	(working copy)
@@ -543,6 +543,7 @@ lto_new_out_decl_state (void)
     }
 
   state->cgraph_node_encoder = lto_cgraph_encoder_new ();
+  state->varpool_node_encoder = lto_varpool_encoder_new ();
 
   return state;
 }
Index: lto-streamer.c
===================================================================
--- lto-streamer.c	(revision 158941)
+++ lto-streamer.c	(working copy)
@@ -163,6 +163,9 @@ lto_get_section_name (int section_type, 
     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 158943)
+++ lto-streamer.h	(working copy)
@@ -257,6 +257,7 @@ enum lto_section_type
   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,
@@ -466,6 +467,20 @@ struct lto_cgraph_encoder_d
 
 typedef struct lto_cgraph_encoder_d *lto_cgraph_encoder_t;
 
+/* Encoder data structure used to stream callgraph nodes.  */
+struct lto_varpool_encoder_d
+{
+  /* Map nodes to reference number. */
+  struct pointer_map_t *map;
+
+  /* Map reference number to node. */
+  VEC(varpool_node_ptr,heap) *nodes;
+
+  /* Map of nodes where we want to output initializer.  */
+  struct pointer_set_t *initializer;
+};
+typedef struct lto_varpool_encoder_d *lto_varpool_encoder_t;
+
 /* Mapping from indices to trees.  */
 struct GTY(()) lto_tree_ref_table
 {
@@ -520,6 +535,9 @@ struct lto_out_decl_state
   /* Encoder for cgraph nodes.  */
   lto_cgraph_encoder_t cgraph_node_encoder;
 
+  /* Encoder for varpool nodes.  */
+  lto_varpool_encoder_t varpool_node_encoder;
+
   /* If this out-decl state belongs to a function, fn_decl points to that
      function.  Otherwise, it is NULL. */
   tree fn_decl;
@@ -546,6 +564,9 @@ struct GTY(()) lto_file_decl_data
   /* Table of cgraph nodes present in this file.  */
   lto_cgraph_encoder_t GTY((skip)) cgraph_node_encoder;
 
+  /* Table of varpool nodes present in this file.  */
+  lto_varpool_encoder_t GTY((skip)) varpool_node_encoder;
+
   /* Hash table maps lto-related section names to location in file.  */
   htab_t GTY((param_is (struct lto_in_decl_state))) function_decl_states;
 
@@ -825,11 +846,19 @@ struct cgraph_node *lto_cgraph_encoder_d
 int lto_cgraph_encoder_lookup (lto_cgraph_encoder_t, struct cgraph_node *);
 lto_cgraph_encoder_t lto_cgraph_encoder_new (void);
 int lto_cgraph_encoder_encode (lto_cgraph_encoder_t, struct cgraph_node *);
-void lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder);
-void output_cgraph (cgraph_node_set);
+void lto_cgraph_encoder_delete (lto_cgraph_encoder_t);
+struct varpool_node *lto_varpool_encoder_deref (lto_varpool_encoder_t, int);
+int lto_varpool_encoder_lookup (lto_varpool_encoder_t, struct varpool_node *);
+lto_varpool_encoder_t lto_varpool_encoder_new (void);
+int lto_varpool_encoder_encode (lto_varpool_encoder_t, struct varpool_node *);
+void lto_varpool_encoder_delete (lto_varpool_encoder_t);
+bool lto_varpool_encoder_encode_initializer_p (lto_varpool_encoder_t,
+					       struct varpool_node *);
+void output_cgraph (cgraph_node_set, varpool_node_set);
 void input_cgraph (void);
-void output_varpool (varpool_node_set);
-void input_varpool (void);
+bool referenced_from_other_partition_p (struct ipa_ref_list *,
+				        cgraph_node_set,
+				        varpool_node_set vset);
 
 
 /* In lto-symtab.c.  */


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