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


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

Re: IPA-ref infrastructure and WPA partitioning


On Thu, 6 May 2010, Jan Hubicka wrote:

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

Ok.

Thanks,
Richard.

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

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex


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