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

Richard Guenther richard.guenther@gmail.com
Sun May 2 14:18:00 GMT 2010


On Sun, May 2, 2010 at 3:30 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
> 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.

If we now have an interface that transparently handles varpool nodes
and cgraph nodes, why not go the way and make them derived from a
common base?  Like

union ipa_obj {
  ipa_obj_base base;
  cgraph_node node;
  varpool_node vnode;
};

ipa_obj_base {
  enum ipa_obj_kind kind;
};

struct cgraph_node {
  ipa_obj_base base;
  ...
};

struct varpool_node {
  ipa_obj_base base;
  ...
};

?  That at least would simplify the odd interfaces taking two pairs
of cgraph/varpool nodes considerably.

Overall I like the idea - thanks for implementing it.  But ...

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

... they can also be fixed upfront, correct?  We already have quite a number
of regressions due to your previous changes and I'd rather not add to them.

I will have a more detailed look at the patch tomorrow.

Thanks,
Richard.

> 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.  */
>



More information about the Gcc-patches mailing list