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]

Symbol table 13/many: reachability code rewrite


Hi,
this is second part of cleanup of the callgraph/varpool reachability code.

As I wrote in previous email, the callgraph was originally written with
reachability code built in. This code was used by non-unit-at-a-time (to drop
unnecesary inline functoins), the unit-a-a-time cgraph builder and by pass
removing unreachable functions.

It was implemented as a queue of functions known to be needed that was
processed by those consumers, plus by the needed flag (removed in previous
patch) for functions that are trivially needed and reachable flag for
functions that are needed by reachablity analysis.

Similarly varpool code had reachability built in, but the variables was not
removed (it broke drwarf2out), just they was not output when unreachable.
This was done after functions was output and later this reachability code
was re-used for removal of unreferenced variables, too.

This all was interlacing with cgraph construction code because we did not track
all references via ipa-ref like we do now.

This patch removes the shared reachability code and replaces it by 3
independent implementations. The motivation is that the 3 cases are different
enough to not motivate code reuse for something as simple as an queue +
walk of ipa-references, callees and same comdat group lists.

1) at cgraph/varpool construction time in cgraphbuild.c.  This code is bit
   complicated by fact that new nodes are being discovered and finalized on the
   process (such as local statics of functions that are not visible before
   function containing them is lowered, or by openMP expansion).

   The code is now also mre contained (see all the varpool_mark_needed_node
   calls that has been removed).  Because of non-unit-at-a-time we
   used to decide that variables are needed at many different places, in
   order to bring them into output file as early as possible.

   Now we discover most of the stuff by walking the IL as we build cgraph
   and reference lists.  There is still feedback from cgraph_finalize,
   varpool_finalize and cgraph_add_new_function for functions/vars appearing
   during the process.  Not as interwinded as before though.
   It is made simple by fact that we have only those references and
   calls that are needed and thus function is reachable if it has some
   referneces to it.

   Newly we now remove unreferenced varpool nodes that should save some memory.
   We should also destroy their DECL_INITIAL pointer, but I am still affraid
   of dwarf2out breaking, so I will try that inrementally.
2) unreachable nodes removal in ipa.c. This is just usual rechability walk,
   but it has some extra complication to deal with extern inlines (that stay
   in code for a while but past inlining their bodies are removed even if
   they are reachable), virtual functions (that also stay for a while to
   allow devirtualization via type based mechanizm or external constructors)
   and it also has to deal with virtual clones (i.e. we can not remove 
   original function of the clone prior materialization) and inline clones
   (when offline version of function is no longer needed, the clone
   tree needs to be reshaped).
3) final pass in varpool that looks what vars are still needed after
   all functions was expanded.  This is done by DECL_RLT_SET_P test that
   is bit kludgy, but works well.
   For example, in combine.c we still remove some of __FUNCTION__ vars because
   some of aborts are proven to be unnecesary. 

There are a lot of subsequent cleanups left on the table, I tried to separate
this into a lot smaller patch than this one, but it has significant snowballing
effect.  Most irritating part is the wrapup_global_declarations logic that once
was there to avoid unreferences static vars to be output but it completely
pointless now.  Probably should be moved into cgraph construction stage.

Other problem is that we are creaing new symbols from realy random places, like
DECL_ASSEMBLER_NAME langhook callback from C++ FE that creates extra name aliases...

The code is now also more picky on variable being finalized in order to be output.
This uncovers latent bug in C++ FE where explicit instantiations are sometimes
not finalized at all.

Regtested/bootstrapped x86_64-linux and also tested with LTO Mozilla.
Will commit it tonight.

Honza


	* lto-symtab.c (lto_varpool_replace_node): Do not merge needed flags.
	* cgraphbuild.c (record_reference, record_type_list, mark_address,
	mark_load, mark_store): Do not mark varpool nodes as needed.
	* cgraph.c (cgraph_new_nodes): Remove.
	(cgraph_create_function_alias): Do not mark nodes as reachable.
	(cgraph_add_thunk): Likewise.
	(cgraph_mark_reachable_node): Do not manage the queue.
	* cgraph.h (cgraph_node): Remove next_needed.
	(varpool_nodes_queue): Remove next_needed and prev_needed.
	(x_cgraph_nodes_queue, x_cgraph_nodes_queue, cgraph_new_nodes): Remove.
	(cgraph_new_nodes): Declare.
	(x_varpool_nodes_queue, varpool_nodes_queue); Remove.
	(varpool_analyze_pending_decls): Remove.
	(varpool_analyze_node): New.
	(varpool_mark_needed_node): Remove.
	(varpool_first_variable, varpool_next_variable): New inlines.
	(varpool_first_static_initializer, varpool_next_static_initializer): Update.
	(FOR_EACH_STATIC_VARIABLE): Remove unused walker.
	(varpool_first_defined_variable): New inline.
	(varpool_next_defined_variable): New inline
	(FOR_EACH_VARIABLE): Reimplement.
	(FOR_EACH_DEFINED_VARIABLE): Reimplement.
	* toplev.c (wrapup_global_declaration_2): Use analyzed instead of
	needed flag.
	* cgraphunit.c (cgraph_new_nodes): Declare here.
	(enqueue_node): New function.
	(cgraph_process_new_functions): update for new
	node set; when constructing cgraph enqueue node for processing.
	(cgraph_add_new_function): Use new node set.
	(process_function_and_variable_attributes): Do not set varpool needed
	flags.
	(referred_to_p): New function.
	(varpool_finalize_decl): Move here from varpool.c; enqueue needed node
	when varpool is in construction.
	(cgraph_analyze_functions): Rewrite.
	(cgraph_expand_all_functions): Update.
	(cgraph_output_in_order): Do not analyze pending decls; do not set needed flags.
	(cgraph_optimize): Do not analyze pending decls.
	* lto-cgraph.c (input_varpool_node): Clear analyzed flag for objects in other
	partition; do not mark node as needed.
	* dwarf2out.c (reference_to_unused): Use analyzed flag.
	(premark_types_used_by_global_vars_helper): Likewise.
	* ipa.c (process_references): Do not call varpool_mark_needed_node.
	(cgraph_remove_unreachable_nodes): Do not rely on varpool and
	cgrpah queues.
	(function_and_variable_visibility): Do not mark node as needed.
	(whole_program_function_and_variable_visibility): Likewise.
	* Makefile.in (gt-varpool.h): No longer needed.
	* passes.c (execute_one_pass, execute_ipa_pass_list): Update.
	(ipa_write_summaries): Do not use needed flag.
	* varpool.c: Do not include gt-varpool.h
	(x_varpool_nodes_queue, x_varpool_last_needed_node,
	x_varpool_last_needed_node, x_varpool_first_unanalyzed_node,
	x_varpool_first_unanalyzed_node, varpool_assembled_nodes_queue):
	Remove.
	(varpool_remove_node): Do not update the lists.
	(dump_varpool_node): Do not dump needed flag.
	(varpool_enqueue_needed_node): Remove.
	(varpool_mark_needed_node): Remove.
	(varpool_reset_queue): Remove.
	(varpool_finalize_decl): Move to cgraphunit.c
	(varpool_analyze_node): New functions based on former
	varpool_analyze_pending_decls.
	(varpool_analyze_pending_decls): Remove.
	(varpool_assemble_decl): Do not update the lists.
	(enqueue_node): New function.
	(varpool_remove_unreferenced_decls): Rewrite.
	(varpool_empty_needed_queue): Remove.
	(add_new_static_var): Do not mark node as needed.
	(varpool_create_variable_alias): Handle expansion state
	creation.
	* except.c (output_ttype): Do not mark node as needed.
	* varasm.c (mark_decl_referenced): Do not use mark_needed_node.
	* tree-profile.c (init_ic_make_global_vars, init_ic_make_global_vars):
	Likewise.
	* tree-switch-conversion.c (build_one_array): Likewise.

	* class.c (build_utf8_ref): Do not mark varpool node as needed.

	* gcc-interface/utils.c (gnat_write_global_declarations): Do not mark
	needed node.

	* lto-partition.c (partition_varpool_node_p): Do not use needed flag.

	* decl2.c (maybe_make_one_only): Mark keyed COMDATs as USED so they
	gets finalized.
Index: lto-symtab.c
===================================================================
*** lto-symtab.c	(revision 186624)
--- lto-symtab.c	(working copy)
*************** static void
*** 262,273 ****
  lto_varpool_replace_node (struct varpool_node *vnode,
  			  struct varpool_node *prevailing_node)
  {
-   /* Merge node flags.  */
-   if (vnode->needed)
-     {
-       gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
-       varpool_mark_needed_node (prevailing_node);
-     }
    gcc_assert (!vnode->finalized || prevailing_node->finalized);
    gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
  
--- 262,267 ----
Index: cgraphbuild.c
===================================================================
*** cgraphbuild.c	(revision 186623)
--- cgraphbuild.c	(working copy)
*************** record_reference (tree *tp, int *walk_su
*** 87,93 ****
  	  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);
  	  ipa_record_reference ((symtab_node)ctx->varpool_node,
  				(symtab_node)vnode,
  				IPA_REF_ADDR, NULL);
--- 87,92 ----
*************** record_type_list (struct cgraph_node *no
*** 130,136 ****
  	  if (TREE_CODE (type) == VAR_DECL)
  	    {
  	      struct varpool_node *vnode = varpool_node (type);
- 	      varpool_mark_needed_node (vnode);
  	      ipa_record_reference ((symtab_node)node,
  				    (symtab_node)vnode,
  				    IPA_REF_ADDR, NULL);
--- 129,134 ----
*************** mark_address (gimple stmt, tree addr, vo
*** 245,251 ****
  
        if (lang_hooks.callgraph.analyze_expr)
  	lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
-       varpool_mark_needed_node (vnode);
        ipa_record_reference ((symtab_node)data,
  			    (symtab_node)vnode,
  			    IPA_REF_ADDR, stmt);
--- 243,248 ----
*************** mark_load (gimple stmt, tree t, void *da
*** 278,284 ****
  
        if (lang_hooks.callgraph.analyze_expr)
  	lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
-       varpool_mark_needed_node (vnode);
        ipa_record_reference ((symtab_node)data,
  			    (symtab_node)vnode,
  			    IPA_REF_LOAD, stmt);
--- 275,280 ----
*************** mark_store (gimple stmt, tree t, void *d
*** 300,306 ****
  
        if (lang_hooks.callgraph.analyze_expr)
  	lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
-       varpool_mark_needed_node (vnode);
        ipa_record_reference ((symtab_node)data,
  			    (symtab_node)vnode,
  			    IPA_REF_STORE, stmt);
--- 296,301 ----
Index: java/class.c
===================================================================
*** java/class.c	(revision 186624)
--- java/class.c	(working copy)
*************** build_utf8_ref (tree name)
*** 1001,1007 ****
    DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (ctype);
    pushdecl (decl);
    rest_of_decl_compilation (decl, global_bindings_p (), 0);
-   varpool_mark_needed_node (varpool_node (decl));
    ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
    IDENTIFIER_UTF8_REF (name) = ref;
    return ref;
--- 1001,1006 ----
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 186624)
--- cgraph.c	(working copy)
*************** static inline void cgraph_edge_remove_ca
*** 123,133 ****
  symtab_node x_cgraph_nodes_queue;
  #define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue)
  
- /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
-    secondary queue used during optimization to accommodate passes that
-    may generate new functions that need to be optimized and expanded.  */
- struct cgraph_node *cgraph_new_nodes;
- 
  /* Number of nodes in existence.  */
  int cgraph_n_nodes;
  
--- 123,128 ----
*************** int cgraph_edge_max_uid;
*** 141,147 ****
  bool cgraph_global_info_ready = false;
  
  /* What state callgraph is in right now.  */
! enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION;
  
  /* Set when the cgraph is fully build and the basic flags are computed.  */
  bool cgraph_function_flags_ready = false;
--- 136,142 ----
  bool cgraph_global_info_ready = false;
  
  /* What state callgraph is in right now.  */
! enum cgraph_state cgraph_state = CGRAPH_STATE_PARSING;
  
  /* Set when the cgraph is fully build and the basic flags are computed.  */
  bool cgraph_function_flags_ready = false;
*************** cgraph_create_function_alias (tree alias
*** 499,509 ****
    alias_node->thunk.alias = decl;
    alias_node->local.finalized = true;
    alias_node->alias = 1;
- 
-   if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias))
-       || (DECL_VIRTUAL_P (alias)
- 	  && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias))))
-     cgraph_mark_reachable_node (alias_node);
    return alias_node;
  }
  
--- 494,499 ----
*************** cgraph_same_body_alias (struct cgraph_no
*** 539,545 ****
  
  struct cgraph_node *
  cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
! 		  tree alias, tree decl,
  		  bool this_adjusting,
  		  HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value,
  		  tree virtual_offset,
--- 529,535 ----
  
  struct cgraph_node *
  cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
! 		  tree alias, tree decl ATTRIBUTE_UNUSED,
  		  bool this_adjusting,
  		  HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value,
  		  tree virtual_offset,
*************** cgraph_add_thunk (struct cgraph_node *de
*** 569,582 ****
    node->thunk.thunk_p = true;
    node->local.finalized = true;
  
-   if (cgraph_decide_is_function_needed (node, decl))
-     cgraph_mark_reachable_node (node);
- 
-   if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
-       || (DECL_VIRTUAL_P (decl)
- 	  && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
-     cgraph_mark_reachable_node (node);
- 
    return node;
  }
  
--- 559,564 ----
*************** cgraph_mark_reachable_node (struct cgrap
*** 1508,1516 ****
        else
          notice_global_symbol (node->symbol.decl);
        node->reachable = 1;
- 
-       node->next_needed = cgraph_nodes_queue;
-       x_cgraph_nodes_queue = (symtab_node)node;
      }
  }
  
--- 1490,1495 ----
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 186624)
--- cgraph.h	(working copy)
*************** struct GTY(()) cgraph_node {
*** 215,224 ****
    struct cgraph_node *
      GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h")))
      next_nested;
-   /* Pointer to the next function in cgraph_nodes_queue.  */
-   struct cgraph_node *
-     GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h")))
-     next_needed;
    /* Pointer to the next clone.  */
    struct cgraph_node *next_sibling_clone;
    struct cgraph_node *prev_sibling_clone;
--- 215,220 ----
*************** struct GTY(()) varpool_node {
*** 419,431 ****
    struct symtab_node_base symbol;
    /* For aliases points to declaration DECL is alias of.  */
    tree alias_of;
-   /* Pointer to the next function in varpool_nodes_queue.  */
-   struct varpool_node *
-     GTY ((nested_ptr (union symtab_node_def, "(struct varpool_node *)(%h)", "(symtab_node)%h")))
-     next_needed;
-   struct varpool_node *
-     GTY ((nested_ptr (union symtab_node_def, "(struct varpool_node *)(%h)", "(symtab_node)%h")))
-     prev_needed;
  
    /* Set when function must be output - it is externally visible
       or its address is taken.  */
--- 415,420 ----
*************** extern GTY(()) int cgraph_edge_max_uid;
*** 471,476 ****
--- 460,467 ----
  extern bool cgraph_global_info_ready;
  enum cgraph_state
  {
+   /* Frontend is parsing and finalizing functions.  */
+   CGRAPH_STATE_PARSING,
    /* Callgraph is being constructed.  It is safe to add new functions.  */
    CGRAPH_STATE_CONSTRUCTION,
    /* Callgraph is built and IPA passes are being run.  */
*************** enum cgraph_state
*** 484,492 ****
  };
  extern enum cgraph_state cgraph_state;
  extern bool cgraph_function_flags_ready;
! extern GTY(()) symtab_node x_cgraph_nodes_queue;
! #define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue)
! extern GTY(()) struct cgraph_node *cgraph_new_nodes;
  
  extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
  extern GTY(()) int symtab_order;
--- 475,481 ----
  };
  extern enum cgraph_state cgraph_state;
  extern bool cgraph_function_flags_ready;
! extern cgraph_node_set cgraph_new_nodes;
  
  extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
  extern GTY(()) int symtab_order;
*************** bool cgraph_maybe_hot_edge_p (struct cgr
*** 687,695 ****
  bool cgraph_optimize_for_size_p (struct cgraph_node *);
  
  /* In varpool.c  */
- extern GTY(()) symtab_node x_varpool_nodes_queue;
- #define varpool_nodes_queue ((struct varpool_node *)x_varpool_nodes_queue)
- 
  struct varpool_node *varpool_node (tree);
  struct varpool_node *varpool_node_for_asm (tree asmname);
  void varpool_mark_needed_node (struct varpool_node *);
--- 676,681 ----
*************** void varpool_remove_node (struct varpool
*** 709,717 ****
  void varpool_finalize_named_section_flags (struct varpool_node *node);
  bool varpool_assemble_pending_decls (void);
  bool varpool_assemble_decl (struct varpool_node *node);
! bool varpool_analyze_pending_decls (void);
  void varpool_remove_unreferenced_decls (void);
- void varpool_empty_needed_queue (void);
  struct varpool_node * varpool_extra_name_alias (tree, tree);
  struct varpool_node * varpool_create_variable_alias (tree, tree);
  void varpool_reset_queue (void);
--- 695,702 ----
  void varpool_finalize_named_section_flags (struct varpool_node *node);
  bool varpool_assemble_pending_decls (void);
  bool varpool_assemble_decl (struct varpool_node *node);
! void varpool_analyze_node (struct varpool_node *);
  void varpool_remove_unreferenced_decls (void);
  struct varpool_node * varpool_extra_name_alias (tree, tree);
  struct varpool_node * varpool_create_variable_alias (tree, tree);
  void varpool_reset_queue (void);
*************** varpool_node_name(struct varpool_node *n
*** 799,814 ****
  #define FOR_EACH_SYMBOL(node) \
     for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next)
  
  /* Return first reachable static variable with initializer.  */
  static inline struct varpool_node *
  varpool_first_static_initializer (void)
  {
!   struct varpool_node *node;
!   for (node = varpool_nodes_queue; node; node = node->next_needed)
      {
!       gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
!       if (DECL_INITIAL (node->symbol.decl))
! 	return node;
      }
    return NULL;
  }
--- 784,831 ----
  #define FOR_EACH_SYMBOL(node) \
     for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next)
  
+ 
+ /* Return first variable.  */
+ static inline struct varpool_node *
+ varpool_first_variable (void)
+ {
+   symtab_node node;
+   for (node = symtab_nodes; node; node = node->symbol.next)
+     {
+       if (symtab_variable_p (node))
+ 	return varpool (node);
+     }
+   return NULL;
+ }
+ 
+ /* Return next variable after NODE.  */
+ static inline struct varpool_node *
+ varpool_next_variable (struct varpool_node *node)
+ {
+   symtab_node node1 = (symtab_node) node->symbol.next;
+   for (; node1; node1 = node1->symbol.next)
+     {
+       if (symtab_variable_p (node1))
+ 	return varpool (node1);
+     }
+   return NULL;
+ }
+ /* Walk all variables.  */
+ #define FOR_EACH_VARIABLE(node) \
+    for ((node) = varpool_first_variable (); \
+         (node); \
+ 	(node) = varpool_next_variable ((node)))
+ 
  /* Return first reachable static variable with initializer.  */
  static inline struct varpool_node *
  varpool_first_static_initializer (void)
  {
!   symtab_node node;
!   for (node = symtab_nodes; node; node = node->symbol.next)
      {
!       if (symtab_variable_p (node)
! 	  && DECL_INITIAL (node->symbol.decl))
! 	return varpool (node);
      }
    return NULL;
  }
*************** varpool_first_static_initializer (void)
*** 817,872 ****
  static inline struct varpool_node *
  varpool_next_static_initializer (struct varpool_node *node)
  {
!   for (node = node->next_needed; node; node = node->next_needed)
      {
!       gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
!       if (DECL_INITIAL (node->symbol.decl))
! 	return node;
      }
    return NULL;
  }
  
- /* Walk all reachable static variables.  */
- #define FOR_EACH_STATIC_VARIABLE(node) \
-    for ((node) = varpool_nodes_queue; (node); (node) = (node)->next_needed)
  /* Walk all static variables with initializer set.  */
  #define FOR_EACH_STATIC_INITIALIZER(node) \
     for ((node) = varpool_first_static_initializer (); (node); \
          (node) = varpool_next_static_initializer (node))
  
! /* Return first variable.  */
  static inline struct varpool_node *
! varpool_first_variable (void)
  {
    symtab_node node;
    for (node = symtab_nodes; node; node = node->symbol.next)
      {
!       if (symtab_variable_p (node))
  	return varpool (node);
      }
    return NULL;
  }
  
! /* Return next variable after NODE.  */
  static inline struct varpool_node *
! varpool_next_variable (struct varpool_node *node)
  {
    symtab_node node1 = (symtab_node) node->symbol.next;
    for (; node1; node1 = node1->symbol.next)
      {
!       if (symtab_variable_p (node1))
  	return varpool (node1);
      }
    return NULL;
  }
- /* Walk all variables.  */
- #define FOR_EACH_VARIABLE(node) \
-    for ((node) = varpool_first_variable (); \
-         (node); \
- 	(node) = varpool_next_variable ((node)))
  /* Walk all variables with definitions in current unit.  */
  #define FOR_EACH_DEFINED_VARIABLE(node) \
!    for ((node) = varpool_nodes_queue; (node); (node) = (node)->next_needed)
  
  /* Return first function with body defined.  */
  static inline struct cgraph_node *
--- 834,883 ----
  static inline struct varpool_node *
  varpool_next_static_initializer (struct varpool_node *node)
  {
!   symtab_node node1 = (symtab_node) node->symbol.next;
!   for (; node1; node1 = node1->symbol.next)
      {
!       if (symtab_variable_p (node1)
! 	  && DECL_INITIAL (node1->symbol.decl))
! 	return varpool (node1);
      }
    return NULL;
  }
  
  /* Walk all static variables with initializer set.  */
  #define FOR_EACH_STATIC_INITIALIZER(node) \
     for ((node) = varpool_first_static_initializer (); (node); \
          (node) = varpool_next_static_initializer (node))
  
! /* Return first reachable static variable with initializer.  */
  static inline struct varpool_node *
! varpool_first_defined_variable (void)
  {
    symtab_node node;
    for (node = symtab_nodes; node; node = node->symbol.next)
      {
!       if (symtab_variable_p (node) && varpool (node)->analyzed)
  	return varpool (node);
      }
    return NULL;
  }
  
! /* Return next reachable static variable with initializer after NODE.  */
  static inline struct varpool_node *
! varpool_next_defined_variable (struct varpool_node *node)
  {
    symtab_node node1 = (symtab_node) node->symbol.next;
    for (; node1; node1 = node1->symbol.next)
      {
!       if (symtab_variable_p (node1) && varpool (node1)->analyzed)
  	return varpool (node1);
      }
    return NULL;
  }
  /* Walk all variables with definitions in current unit.  */
  #define FOR_EACH_DEFINED_VARIABLE(node) \
!    for ((node) = varpool_first_defined_variable (); (node); \
!         (node) = varpool_next_defined_variable (node))
  
  /* Return first function with body defined.  */
  static inline struct cgraph_node *
Index: toplev.c
===================================================================
*** toplev.c	(revision 186623)
--- toplev.c	(working copy)
*************** wrapup_global_declaration_2 (tree decl)
*** 413,419 ****
  	       && (TREE_USED (decl)
  		   || TREE_USED (DECL_ASSEMBLER_NAME (decl))))
  	/* needed */;
!       else if (node && node->needed)
  	/* needed */;
        else if (DECL_COMDAT (decl))
  	needed = false;
--- 413,419 ----
  	       && (TREE_USED (decl)
  		   || TREE_USED (DECL_ASSEMBLER_NAME (decl))))
  	/* needed */;
!       else if (node && node->analyzed)
  	/* needed */;
        else if (DECL_COMDAT (decl))
  	needed = false;
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 186624)
--- cgraphunit.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 145,150 ****
--- 145,155 ----
  #include "except.h"
  #include "regset.h"     /* FIXME: For reg_obstack.  */
  
+ /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
+    secondary queue used during optimization to accommodate passes that
+    may generate new functions that need to be optimized and expanded.  */
+ cgraph_node_set cgraph_new_nodes;
+ 
  static void cgraph_expand_all_functions (void);
  static void cgraph_mark_functions_to_output (void);
  static void cgraph_expand_function (struct cgraph_node *);
*************** cgraph_decide_is_function_needed (struct
*** 192,197 ****
--- 197,219 ----
    return false;
  }
  
+ /* Head of the queue of nodes to be processed while building callgraph */
+ 
+ static symtab_node first = (symtab_node)(void *)1;
+ 
+ /* Add NODE to queue starting at FIRST. 
+    The queue is linked via AUX pointers and terminated by pointer to 1.  */
+ 
+ static void
+ enqueue_node (symtab_node node)
+ {
+   if (node->symbol.aux)
+     return;
+   gcc_checking_assert (first);
+   node->symbol.aux = first;
+   first = node;
+ }
+ 
  /* Process CGRAPH_NEW_FUNCTIONS and perform actions necessary to add these
     functions into callgraph in a way so they look like ordinary reachable
     functions inserted into callgraph already at construction time.  */
*************** cgraph_process_new_functions (void)
*** 202,227 ****
    bool output = false;
    tree fndecl;
    struct cgraph_node *node;
  
!   varpool_analyze_pending_decls ();
    /*  Note that this queue may grow as its being processed, as the new
        functions may generate new ones.  */
!   while (cgraph_new_nodes)
      {
!       node = cgraph_new_nodes;
        fndecl = node->symbol.decl;
-       cgraph_new_nodes = cgraph_new_nodes->next_needed;
        switch (cgraph_state)
  	{
  	case CGRAPH_STATE_CONSTRUCTION:
  	  /* At construction time we just need to finalize function and move
  	     it into reachable functions list.  */
  
- 	  node->next_needed = NULL;
  	  cgraph_finalize_function (fndecl, false);
- 	  cgraph_mark_reachable_node (node);
  	  output = true;
            cgraph_call_function_insertion_hooks (node);
  	  break;
  
  	case CGRAPH_STATE_IPA:
--- 224,249 ----
    bool output = false;
    tree fndecl;
    struct cgraph_node *node;
+   cgraph_node_set_iterator csi;
  
!   if (!cgraph_new_nodes)
!     return false;
    /*  Note that this queue may grow as its being processed, as the new
        functions may generate new ones.  */
!   for (csi = csi_start (cgraph_new_nodes); !csi_end_p (csi); csi_next (&csi))
      {
!       node = csi_node (csi);
        fndecl = node->symbol.decl;
        switch (cgraph_state)
  	{
  	case CGRAPH_STATE_CONSTRUCTION:
  	  /* At construction time we just need to finalize function and move
  	     it into reachable functions list.  */
  
  	  cgraph_finalize_function (fndecl, false);
  	  output = true;
            cgraph_call_function_insertion_hooks (node);
+ 	  enqueue_node ((symtab_node) node);
  	  break;
  
  	case CGRAPH_STATE_IPA:
*************** cgraph_process_new_functions (void)
*** 262,269 ****
  	  gcc_unreachable ();
  	  break;
  	}
-       varpool_analyze_pending_decls ();
      }
    return output;
  }
  
--- 284,292 ----
  	  gcc_unreachable ();
  	  break;
  	}
      }
+   free_cgraph_node_set (cgraph_new_nodes);
+   cgraph_new_nodes = NULL;
    return output;
  }
  
*************** cgraph_add_new_function (tree fndecl, bo
*** 375,384 ****
        case CGRAPH_STATE_CONSTRUCTION:
  	/* Just enqueue function to be processed at nearest occurrence.  */
  	node = cgraph_create_node (fndecl);
- 	node->next_needed = cgraph_new_nodes;
  	if (lowered)
  	  node->lowered = true;
! 	cgraph_new_nodes = node;
          break;
  
        case CGRAPH_STATE_IPA:
--- 398,408 ----
        case CGRAPH_STATE_CONSTRUCTION:
  	/* Just enqueue function to be processed at nearest occurrence.  */
  	node = cgraph_create_node (fndecl);
  	if (lowered)
  	  node->lowered = true;
! 	if (!cgraph_new_nodes)
! 	  cgraph_new_nodes = cgraph_node_set_new ();
! 	cgraph_node_set_add (cgraph_new_nodes, node);
          break;
  
        case CGRAPH_STATE_IPA:
*************** cgraph_add_new_function (tree fndecl, bo
*** 406,413 ****
  	  }
  	if (lowered)
  	  node->lowered = true;
! 	node->next_needed = cgraph_new_nodes;
! 	cgraph_new_nodes = node;
          break;
  
        case CGRAPH_STATE_FINISHED:
--- 430,438 ----
  	  }
  	if (lowered)
  	  node->lowered = true;
! 	if (!cgraph_new_nodes)
! 	  cgraph_new_nodes = cgraph_node_set_new ();
! 	cgraph_node_set_add (cgraph_new_nodes, node);
          break;
  
        case CGRAPH_STATE_FINISHED:
*************** process_function_and_variable_attributes
*** 1091,1116 ****
      {
        tree decl = vnode->symbol.decl;
        if (DECL_PRESERVE_P (decl))
! 	{
! 	  vnode->symbol.force_output = true;
! 	  if (vnode->finalized)
! 	    varpool_mark_needed_node (vnode);
! 	}
!       if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
! 	  && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))
! 	  && TREE_PUBLIC (vnode->symbol.decl))
! 	{
! 	  if (vnode->finalized)
! 	    varpool_mark_needed_node (vnode);
! 	}
        else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
  	{
  	  if (! TREE_PUBLIC (vnode->symbol.decl))
  	    warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes,
  			"%<externally_visible%>"
  			" attribute have effect only on public objects");
- 	  else if (vnode->finalized)
- 	    varpool_mark_needed_node (vnode);
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
  	  && vnode->finalized
--- 1116,1128 ----
      {
        tree decl = vnode->symbol.decl;
        if (DECL_PRESERVE_P (decl))
! 	vnode->symbol.force_output = true;
        else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
  	{
  	  if (! TREE_PUBLIC (vnode->symbol.decl))
  	    warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes,
  			"%<externally_visible%>"
  			" attribute have effect only on public objects");
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
  	  && vnode->finalized
*************** process_function_and_variable_attributes
*** 1127,1136 ****
      }
  }
  
! /* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively
!    each reachable functions) and build cgraph.
!    The function can be called multiple times after inserting new nodes
!    into beginning of queue.  Just the new part of queue is re-scanned then.  */
  
  static void
  cgraph_analyze_functions (void)
--- 1139,1192 ----
      }
  }
  
! /* Return true when there are references to NODE.  */
! 
! static bool
! referred_to_p (symtab_node node)
! {
!   int i;
!   struct ipa_ref *ref;
! 
!   for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref);
!        i++)
!     return true;
!   if (symtab_function_p (node) && cgraph (node)->callers)
!     return true;
!   return false;
! }
! 
! /* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
!    middle end to output the variable to asm file, if needed or externally
!    visible.  */
! 
! void
! varpool_finalize_decl (tree decl)
! {
!   struct varpool_node *node = varpool_node (decl);
! 
!   gcc_assert (TREE_STATIC (decl));
! 
!   if (node->finalized)
!     return;
!   notice_global_symbol (decl);
!   node->finalized = true;
!   if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
!       /* Traditionally we do not eliminate static variables when not
! 	 optimizing and when not doing toplevel reoder.  */
!       || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
! 	  && !DECL_ARTIFICIAL (node->symbol.decl)))
!     node->symbol.force_output = true;
! 
!   if (cgraph_state == CGRAPH_STATE_CONSTRUCTION
!       && (decide_is_variable_needed (node, decl)
! 	  || referred_to_p ((symtab_node)node)))
!     enqueue_node ((symtab_node)node);
!   if (cgraph_state >= CGRAPH_STATE_IPA_SSA)
!     varpool_analyze_node (node);
! }
! 
! /* Discover all functions and variables that are trivially needed, analyze
!    them as well as all functions and variables referred by them  */
  
  static void
  cgraph_analyze_functions (void)
*************** cgraph_analyze_functions (void)
*** 1138,1277 ****
    /* Keep track of already processed nodes when called multiple times for
       intermodule optimization.  */
    static struct cgraph_node *first_analyzed;
!   struct cgraph_node *first_processed = first_analyzed;
    static struct varpool_node *first_analyzed_var;
!   struct cgraph_node *node, *next;
  
    bitmap_obstack_initialize (NULL);
!   process_function_and_variable_attributes (first_processed,
! 					    first_analyzed_var);
!   first_processed = cgraph_first_function ();
!   first_analyzed_var = varpool_first_variable ();
!   varpool_analyze_pending_decls ();
!   if (cgraph_dump_file)
      {
!       fprintf (cgraph_dump_file, "Initial entry points:");
!       for (node = cgraph_first_function (); node != first_analyzed;
! 	   node = cgraph_next_function (node))
! 	if (cgraph_decide_is_function_needed (node, node->symbol.decl))
! 	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
!       fprintf (cgraph_dump_file, "\n");
!     }
!   cgraph_process_new_functions ();
  
!   /* Propagate reachability flag and lower representation of all reachable
!      functions.  In the future, lowering will introduce new functions and
!      new entry points on the way (by template instantiation and virtual
!      method table generation for instance).  */
!   while (cgraph_nodes_queue)
!     {
!       struct cgraph_edge *edge;
!       tree decl = cgraph_nodes_queue->symbol.decl;
! 
!       node = cgraph_nodes_queue;
!       x_cgraph_nodes_queue = (symtab_node)cgraph_nodes_queue->next_needed;
!       node->next_needed = NULL;
! 
!       /* ??? It is possible to create extern inline function and later using
! 	 weak alias attribute to kill its body. See
! 	 gcc.c-torture/compile/20011119-1.c  */
!       if (!DECL_STRUCT_FUNCTION (decl)
! 	  && (!node->alias || !node->thunk.alias)
! 	  && !node->thunk.thunk_p)
! 	{
! 	  cgraph_reset_node (node);
!           node->local.redefined_extern_inline = true;
! 	  continue;
  	}
  
!       if (!node->analyzed)
! 	cgraph_analyze_function (node);
  
!       for (edge = node->callees; edge; edge = edge->next_callee)
! 	if (!edge->callee->reachable)
! 	  cgraph_mark_reachable_node (edge->callee);
!       for (edge = node->callers; edge; edge = edge->next_caller)
! 	if (!edge->caller->reachable && edge->caller->thunk.thunk_p)
! 	  cgraph_mark_reachable_node (edge->caller);
! 
!       if (node->symbol.same_comdat_group)
! 	{
! 	  for (next = cgraph (node->symbol.same_comdat_group);
! 	       next != node;
! 	       next = cgraph (next->symbol.same_comdat_group))
! 	    cgraph_mark_reachable_node (next);
! 	}
! 
!       /* If decl is a clone of an abstract function, mark that abstract
! 	 function so that we don't release its body. The DECL_INITIAL() of that
! 	 abstract function declaration will be later needed to output debug
! 	 info.  */
!       if (DECL_ABSTRACT_ORIGIN (decl))
! 	{
! 	  struct cgraph_node *origin_node;
! 	  origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
! 	  origin_node->abstract_and_needed = true;
! 	}
! 
!       /* We finalize local static variables during constructing callgraph
!          edges.  Process their attributes too.  */
!       process_function_and_variable_attributes (first_processed,
! 						first_analyzed_var);
!       first_processed = cgraph_first_function ();
!       first_analyzed_var = varpool_first_variable ();
!       varpool_analyze_pending_decls ();
!       cgraph_process_new_functions ();
      }
  
    /* Collect entry points to the unit.  */
    if (cgraph_dump_file)
      {
-       fprintf (cgraph_dump_file, "Unit entry points:");
-       for (node = cgraph_first_function (); node != first_analyzed;
- 	   node = cgraph_next_function (node))
- 	if (cgraph_decide_is_function_needed (node, node->symbol.decl))
- 	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
        fprintf (cgraph_dump_file, "\n\nInitial ");
        dump_symtab (cgraph_dump_file);
      }
  
    if (cgraph_dump_file)
!     fprintf (cgraph_dump_file, "\nReclaiming functions:");
  
!   for (node = cgraph_first_function (); node != first_analyzed;
!        node = next)
      {
!       tree decl = node->symbol.decl;
!       next = cgraph_next_function (node);
! 
!       if (node->local.finalized && !gimple_has_body_p (decl)
! 	  && (!node->alias || !node->thunk.alias)
! 	  && !node->thunk.thunk_p)
! 	cgraph_reset_node (node);
! 
!       if (!node->reachable
! 	  && (gimple_has_body_p (decl) || node->thunk.thunk_p
! 	      || (node->alias && node->thunk.alias)))
  	{
  	  if (cgraph_dump_file)
! 	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
! 	  cgraph_remove_node (node);
  	  continue;
  	}
!       else
! 	node->next_needed = NULL;
!       gcc_assert (!node->local.finalized || node->thunk.thunk_p
! 		  || node->alias
! 		  || gimple_has_body_p (decl));
!       gcc_assert (node->analyzed == node->local.finalized);
      }
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\n\nReclaimed ");
        dump_symtab (cgraph_dump_file);
      }
    bitmap_obstack_release (NULL);
-   first_analyzed = cgraph_first_function ();
    ggc_collect ();
  }
  
--- 1194,1369 ----
    /* Keep track of already processed nodes when called multiple times for
       intermodule optimization.  */
    static struct cgraph_node *first_analyzed;
!   struct cgraph_node *first_handled = first_analyzed;
    static struct varpool_node *first_analyzed_var;
!   struct varpool_node *first_handled_var = first_analyzed_var;
! 
!   symtab_node node, next;
!   int i;
!   struct ipa_ref *ref;
!   bool changed = true;
  
    bitmap_obstack_initialize (NULL);
!   cgraph_state = CGRAPH_STATE_CONSTRUCTION;
! 
!   /* Analysis adds static variables that in turn adds references to new functions.
!      So we need to iterate the process until it stabilize.  */
!   while (changed)
      {
!       changed = false;
!       process_function_and_variable_attributes (first_analyzed,
! 						first_analyzed_var);
  
!       /* First identify the trivially needed symbols.  */
!       for (node = symtab_nodes;
! 	   node != (symtab_node)first_analyzed
! 	   && node != (symtab_node)first_analyzed_var; node = node->symbol.next)
! 	{
! 	  if ((symtab_function_p (node)
! 	       && cgraph (node)->local.finalized
! 	       && cgraph_decide_is_function_needed (cgraph (node), node->symbol.decl))
! 	      || (symtab_variable_p (node)
! 		  && varpool (node)->finalized
! 		  && !DECL_EXTERNAL (node->symbol.decl)
! 		  && decide_is_variable_needed (varpool (node), node->symbol.decl)))
! 	    {
! 	      enqueue_node (node);
! 	      if (!changed && cgraph_dump_file)
! 		fprintf (cgraph_dump_file, "Trivially needed symbols:");
! 	      changed = true;
! 	      if (cgraph_dump_file)
! 		fprintf (cgraph_dump_file, " %s", symtab_node_asm_name (node));
! 	    }
! 	  if (node == (symtab_node)first_analyzed
! 	      || node == (symtab_node)first_analyzed_var)
! 	    break;
  	}
+       cgraph_process_new_functions ();
+       first_analyzed_var = varpool_first_variable ();
+       first_analyzed = cgraph_first_function ();
  
!       if (changed && dump_file)
! 	fprintf (cgraph_dump_file, "\n");
  
!       /* Lower representation, build callgraph edges and references for all trivially
!          needed symbols and all symbols referred by them.  */
!       while (first != (symtab_node)(void *)1)
! 	{
! 	  changed = true;
! 	  node = first;
! 	  first = (symtab_node)first->symbol.aux;
! 	  if (symtab_function_p (node) && cgraph (node)->local.finalized)
! 	    {
! 	      struct cgraph_edge *edge;
! 	      struct cgraph_node *cnode;
! 	      tree decl;
! 
! 	      cnode = cgraph (node);
! 	      decl = cnode->symbol.decl;
! 
! 	      /* ??? It is possible to create extern inline function and later using
! 		 weak alias attribute to kill its body. See
! 		 gcc.c-torture/compile/20011119-1.c  */
! 	      if (!DECL_STRUCT_FUNCTION (decl)
! 		  && (!cnode->alias || !cnode->thunk.alias)
! 		  && !cnode->thunk.thunk_p)
! 		{
! 		  cgraph_reset_node (cnode);
! 		  cnode->local.redefined_extern_inline = true;
! 		  continue;
! 		}
! 
! 	      if (!cnode->analyzed)
! 		cgraph_analyze_function (cnode);
! 
! 	      for (edge = cnode->callees; edge; edge = edge->next_callee)
! 		{
! 		  cgraph_mark_reachable_node (edge->callee);
! 		  if (edge->callee->local.finalized)
! 		    enqueue_node ((symtab_node)edge->callee);
! 		}
! 
! 	      /* If decl is a clone of an abstract function, mark that abstract
! 		 function so that we don't release its body. The DECL_INITIAL() of that
! 		 abstract function declaration will be later needed to output debug
! 		 info.  */
! 	      if (DECL_ABSTRACT_ORIGIN (decl))
! 		{
! 		  struct cgraph_node *origin_node;
! 		  origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
! 		  origin_node->abstract_and_needed = true;
! 		}
! 
! 	    }
! 	  else if (symtab_variable_p (node)
! 		   && varpool (node)->finalized)
! 	    {
! 	      varpool_analyze_node (varpool (node));
! 	    }
! 
! 	  if (node->symbol.same_comdat_group)
! 	    {
! 	      symtab_node next;
! 	      for (next = node->symbol.same_comdat_group;
! 		   next != node;
! 		   next = next->symbol.same_comdat_group)
! 		enqueue_node (next);
! 	    }
! 	  for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
! 	    if ((symtab_function_p (ref->referred) && cgraph (ref->referred)->local.finalized)
! 		|| (symtab_variable_p (ref->referred) && varpool (ref->referred)->finalized))
! 	      enqueue_node (ref->referred);
!           cgraph_process_new_functions ();
! 	}
      }
  
    /* Collect entry points to the unit.  */
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\n\nInitial ");
        dump_symtab (cgraph_dump_file);
      }
  
    if (cgraph_dump_file)
!     fprintf (cgraph_dump_file, "\nRemoving unused symbols:");
  
!   for (node = symtab_nodes;
!        node != (symtab_node)first_handled
!        && node != (symtab_node)first_handled_var; node = next)
      {
!       next = node->symbol.next;
!       if (!node->symbol.aux && !referred_to_p (node))
  	{
  	  if (cgraph_dump_file)
! 	    fprintf (cgraph_dump_file, " %s", symtab_node_name (node));
! 	  symtab_remove_node (node);
  	  continue;
  	}
!       if (symtab_function_p (node))
! 	{
! 	  tree decl = node->symbol.decl;
! 	  struct cgraph_node *cnode = cgraph (node);
! 
! 	  if (cnode->local.finalized && !gimple_has_body_p (decl)
! 	      && (!cnode->alias || !cnode->thunk.alias)
! 	      && !cnode->thunk.thunk_p)
! 	    cgraph_reset_node (cnode);
! 
! 	  gcc_assert (!cnode->local.finalized || cnode->thunk.thunk_p
! 		      || cnode->alias
! 		      || gimple_has_body_p (decl));
! 	  gcc_assert (cnode->analyzed == cnode->local.finalized);
! 	}
!       node->symbol.aux = NULL;
      }
+   first_analyzed = cgraph_first_function ();
+   first_analyzed_var = varpool_first_variable ();
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\n\nReclaimed ");
        dump_symtab (cgraph_dump_file);
      }
    bitmap_obstack_release (NULL);
    ggc_collect ();
  }
  
*************** cgraph_output_in_order (void)
*** 2041,2048 ****
    max = symtab_order;
    nodes = XCNEWVEC (struct cgraph_order_sort, max);
  
-   varpool_analyze_pending_decls ();
- 
    FOR_EACH_DEFINED_FUNCTION (pf)
      {
        if (pf->process && !pf->thunk.thunk_p && !pf->alias)
--- 2133,2138 ----
*************** cgraph_output_in_order (void)
*** 2071,2084 ****
      }
  
    /* In toplevel reorder mode we output all statics; mark them as needed.  */
-   for (i = 0; i < max; ++i)
-     {
-       if (nodes[i].kind == ORDER_VAR)
-         {
- 	  varpool_mark_needed_node (nodes[i].u.v);
- 	}
-     }
-   varpool_empty_needed_queue ();
  
    for (i = 0; i < max; ++i)
      if (nodes[i].kind == ORDER_VAR)
--- 2161,2166 ----
*************** cgraph_optimize (void)
*** 2614,2623 ****
    verify_symtab ();
  #endif
  
-   /* Frontend may output common variables after the unit has been finalized.
-      It is safe to deal with them here as they are always zero initialized.  */
-   varpool_analyze_pending_decls ();
- 
    timevar_push (TV_CGRAPHOPT);
    if (pre_ipa_mem_report)
      {
--- 2696,2701 ----
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 186658)
--- cp/decl2.c	(working copy)
*************** maybe_make_one_only (tree decl)
*** 1677,1682 ****
--- 1677,1683 ----
  	  DECL_COMDAT (decl) = 1;
  	  /* Mark it needed so we don't forget to emit it.  */
  	  mark_decl_referenced (decl);
+ 	  TREE_USED (decl) = 1;
  	}
      }
  }
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c	(revision 186624)
--- lto-cgraph.c	(working copy)
*************** lto_output_varpool_node (struct lto_simp
*** 571,577 ****
    bp_pack_value (&bp, node->alias, 1);
    bp_pack_value (&bp, node->alias_of != NULL, 1);
    gcc_assert (node->finalized || !node->analyzed);
-   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.  */
--- 571,576 ----
*************** input_varpool_node (struct lto_file_decl
*** 1079,1094 ****
    node->finalized = bp_unpack_value (&bp, 1);
    node->alias = bp_unpack_value (&bp, 1);
    non_null_aliasof = bp_unpack_value (&bp, 1);
-   node->analyzed = node->finalized; 
    node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1);
    node->symbol.in_other_partition = bp_unpack_value (&bp, 1);
    if (node->symbol.in_other_partition)
      {
        DECL_EXTERNAL (node->symbol.decl) = 1;
        TREE_STATIC (node->symbol.decl) = 0;
      }
-   if (node->finalized)
-     varpool_mark_needed_node (node);
    if (non_null_aliasof)
      {
        decl_index = streamer_read_uhwi (ib);
--- 1078,1091 ----
    node->finalized = bp_unpack_value (&bp, 1);
    node->alias = bp_unpack_value (&bp, 1);
    non_null_aliasof = bp_unpack_value (&bp, 1);
    node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1);
    node->symbol.in_other_partition = bp_unpack_value (&bp, 1);
+   node->analyzed = (node->finalized && (!node->alias || !node->symbol.in_other_partition)); 
    if (node->symbol.in_other_partition)
      {
        DECL_EXTERNAL (node->symbol.decl) = 1;
        TREE_STATIC (node->symbol.decl) = 0;
      }
    if (non_null_aliasof)
      {
        decl_index = streamer_read_uhwi (ib);
*************** input_cgraph (void)
*** 1457,1462 ****
--- 1454,1461 ----
    unsigned int j = 0;
    struct cgraph_node *node;
  
+   cgraph_state = CGRAPH_STATE_IPA_SSA;
+ 
    while ((file_data = file_data_vec[j++]))
      {
        const char *data;
Index: dwarf2out.c
===================================================================
*** dwarf2out.c	(revision 186623)
--- dwarf2out.c	(working copy)
*************** reference_to_unused (tree * tp, int * wa
*** 14572,14578 ****
    else if (TREE_CODE (*tp) == VAR_DECL)
      {
        struct varpool_node *node = varpool_get_node (*tp);
!       if (!node || !node->needed)
  	return *tp;
      }
    else if (TREE_CODE (*tp) == FUNCTION_DECL
--- 14572,14578 ----
    else if (TREE_CODE (*tp) == VAR_DECL)
      {
        struct varpool_node *node = varpool_get_node (*tp);
!       if (!node || !node->analyzed)
  	return *tp;
      }
    else if (TREE_CODE (*tp) == FUNCTION_DECL
*************** premark_types_used_by_global_vars_helper
*** 17057,17063 ****
        /* Ask cgraph if the global variable really is to be emitted.
           If yes, then we'll keep the DIE of ENTRY->TYPE.  */
        struct varpool_node *node = varpool_get_node (entry->var_decl);
!       if (node && node->needed)
  	{
  	  die->die_perennial_p = 1;
  	  /* Keep the parent DIEs as well.  */
--- 17057,17063 ----
        /* Ask cgraph if the global variable really is to be emitted.
           If yes, then we'll keep the DIE of ENTRY->TYPE.  */
        struct varpool_node *node = varpool_get_node (entry->var_decl);
!       if (node && node->analyzed)
  	{
  	  die->die_perennial_p = 1;
  	  /* Keep the parent DIEs as well.  */
Index: go/gofrontend/gogo-tree.cc
===================================================================
*** go/gofrontend/gogo-tree.cc	(revision 186623)
--- go/gofrontend/gogo-tree.cc	(working copy)
*************** Gogo::write_initialization_function(tree
*** 495,501 ****
    gimplify_function_tree(fndecl);
  
    cgraph_add_new_function(fndecl, false);
-   cgraph_mark_needed_node(cgraph_get_node(fndecl));
  
    current_function_decl = NULL_TREE;
    pop_cfun();
--- 495,500 ----
Index: ada/gcc-interface/utils.c
===================================================================
*** ada/gcc-interface/utils.c	(revision 186624)
--- ada/gcc-interface/utils.c	(working copy)
*************** gnat_write_global_declarations (void)
*** 4860,4866 ****
        TREE_ASM_WRITTEN (dummy_global) = 1;
        node = varpool_node (dummy_global);
        node->symbol.force_output = 1;
-       varpool_mark_needed_node (node);
  
        while (!VEC_empty (tree, types_used_by_cur_var_decl))
  	{
--- 4860,4865 ----
Index: ipa.c
===================================================================
*** ipa.c	(revision 186624)
--- ipa.c	(working copy)
*************** process_references (struct ipa_ref_list 
*** 107,113 ****
  	  struct varpool_node *node = ipa_ref_varpool_node (ref);
  	  if (!node->needed)
  	    {
! 	      varpool_mark_needed_node (node);
  	      enqueue_varpool_node (node, first_varpool);
  	    }
  	}
--- 107,113 ----
  	  struct varpool_node *node = ipa_ref_varpool_node (ref);
  	  if (!node->needed)
  	    {
! 	      node->needed = true;
  	      enqueue_varpool_node (node, first_varpool);
  	    }
  	}
*************** cgraph_remove_unreachable_nodes (bool be
*** 187,193 ****
    FOR_EACH_VARIABLE (vnode)
      gcc_assert (!vnode->symbol.aux);
  #endif
-   varpool_reset_queue ();
    /* Mark functions whose bodies are obviously needed.
       This is mostly when they can be referenced externally.  Inline clones
       are special since their declarations are shared with master clone and thus
--- 187,192 ----
*************** cgraph_remove_unreachable_nodes (bool be
*** 213,225 ****
    /* Mark variables that are obviously needed.  */
    FOR_EACH_VARIABLE (vnode)
      {
-       vnode->next_needed = NULL;
-       vnode->prev_needed = NULL;
        if ((vnode->analyzed || vnode->symbol.force_output)
  	  && !varpool_can_remove_if_no_refs (vnode))
  	{
! 	  vnode->needed = false;
! 	  varpool_mark_needed_node (vnode);
  	  enqueue_varpool_node (vnode, &first_varpool);
  	}
        else
--- 212,221 ----
    /* Mark variables that are obviously needed.  */
    FOR_EACH_VARIABLE (vnode)
      {
        if ((vnode->analyzed || vnode->symbol.force_output)
  	  && !varpool_can_remove_if_no_refs (vnode))
  	{
! 	  vnode->needed = true;
  	  enqueue_varpool_node (vnode, &first_varpool);
  	}
        else
*************** cgraph_remove_unreachable_nodes (bool be
*** 315,321 ****
  		   next = varpool (next->symbol.same_comdat_group))
  		if (!next->needed)
  		  {
! 		    varpool_mark_needed_node (next);
  		    enqueue_varpool_node (next, &first_varpool);
  		  }
  	    }
--- 311,317 ----
  		   next = varpool (next->symbol.same_comdat_group))
  		if (!next->needed)
  		  {
! 		    next->needed = true;
  		    enqueue_varpool_node (next, &first_varpool);
  		  }
  	    }
*************** function_and_variable_visibility (bool w
*** 794,801 ****
  	       && !DECL_EXTERNAL (vnode->symbol.decl))
          {
  	  vnode->symbol.force_output = 1;
- 	  varpool_mark_needed_node (vnode);
- 	  gcc_assert (vnode->needed);
  	  pointer_set_insert (aliased_vnodes, vnode);
  	  if (dump_file)
  	    fprintf (dump_file, "  varpool node %s",
--- 790,795 ----
*************** function_and_variable_visibility (bool w
*** 933,942 ****
      {
        if (!vnode->finalized)
          continue;
!       if (vnode->needed
! 	  && varpool_externally_visible_p
! 	      (vnode, 
! 	       pointer_set_contains (aliased_vnodes, vnode)))
  	vnode->symbol.externally_visible = true;
        else
          vnode->symbol.externally_visible = false;
--- 927,935 ----
      {
        if (!vnode->finalized)
          continue;
!       if (varpool_externally_visible_p
! 	    (vnode, 
! 	     pointer_set_contains (aliased_vnodes, vnode)))
  	vnode->symbol.externally_visible = true;
        else
          vnode->symbol.externally_visible = false;
*************** static unsigned int
*** 1018,1024 ****
  whole_program_function_and_variable_visibility (void)
  {
    struct cgraph_node *node;
-   struct varpool_node *vnode;
  
    function_and_variable_visibility (flag_whole_program);
  
--- 1011,1016 ----
*************** whole_program_function_and_variable_visi
*** 1026,1042 ****
      if ((node->symbol.externally_visible && !DECL_COMDAT (node->symbol.decl))
          && node->local.finalized)
        cgraph_mark_reachable_node (node);
-   FOR_EACH_DEFINED_VARIABLE (vnode)
-     if (vnode->symbol.externally_visible && !DECL_COMDAT (vnode->symbol.decl))
-       varpool_mark_needed_node (vnode);
-   if (dump_file)
-     {
-       fprintf (dump_file, "\nNeeded variables:");
-       FOR_EACH_DEFINED_VARIABLE (vnode)
- 	if (vnode->needed)
- 	  fprintf (dump_file, " %s", varpool_node_name (vnode));
-       fprintf (dump_file, "\n\n");
-     }
    if (optimize)
      ipa_discover_readonly_nonaddressable_vars ();
    return 0;
--- 1018,1023 ----
Index: except.c
===================================================================
*** except.c	(revision 186623)
--- except.c	(working copy)
*************** output_ttype (tree type, int tt_format, 
*** 2814,2821 ****
      value = const0_rtx;
    else
      {
-       struct varpool_node *node;
- 
        /* FIXME lto.  pass_ipa_free_lang_data changes all types to
  	 runtime types so TYPE should already be a runtime type
  	 reference.  When pass_ipa_free_lang data is made a default
--- 2814,2819 ----
*************** output_ttype (tree type, int tt_format, 
*** 2834,2845 ****
  	{
  	  type = TREE_OPERAND (type, 0);
  	  if (TREE_CODE (type) == VAR_DECL)
! 	    {
! 	      node = varpool_node (type);
! 	      if (node)
! 		varpool_mark_needed_node (node);
! 	      is_public = TREE_PUBLIC (type);
! 	    }
  	}
        else
  	gcc_assert (TREE_CODE (type) == INTEGER_CST);
--- 2832,2838 ----
  	{
  	  type = TREE_OPERAND (type, 0);
  	  if (TREE_CODE (type) == VAR_DECL)
! 	    is_public = TREE_PUBLIC (type);
  	}
        else
  	gcc_assert (TREE_CODE (type) == INTEGER_CST);
Index: lto/lto-partition.c
===================================================================
*** lto/lto-partition.c	(revision 186624)
--- lto/lto-partition.c	(working copy)
*************** partition_cgraph_node_p (struct cgraph_n
*** 283,289 ****
  static bool
  partition_varpool_node_p (struct varpool_node *vnode)
  {
!   if (vnode->alias || !vnode->needed)
      return false;
    /* Constant pool and comdat are always only in partitions they are needed.  */
    if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
--- 283,289 ----
  static bool
  partition_varpool_node_p (struct varpool_node *vnode)
  {
!   if (vnode->alias || !vnode->analyzed)
      return false;
    /* Constant pool and comdat are always only in partitions they are needed.  */
    if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
Index: varasm.c
===================================================================
*** varasm.c	(revision 186624)
--- varasm.c	(working copy)
*************** mark_decl_referenced (tree decl)
*** 2254,2260 ****
    else if (TREE_CODE (decl) == VAR_DECL)
      {
        struct varpool_node *node = varpool_node (decl);
-       varpool_mark_needed_node (node);
        /* C++ frontend use mark_decl_references to force COMDAT variables
           to be output that might appear dead otherwise.  */
        node->symbol.force_output = true;
--- 2254,2259 ----
Index: symtab.c
===================================================================
*** symtab.c	(revision 186624)
--- symtab.c	(working copy)
*************** dump_symtab_base (FILE *f, symtab_node n
*** 429,434 ****
--- 429,439 ----
  
    if (node->symbol.address_taken)
      fprintf (f, "  Address is taken.\n");
+   if (node->symbol.aux)
+     {
+       fprintf (f, "  Aux:");
+       dump_addr (f, " @", (void *)node->symbol.aux);
+     }
  
    fprintf (f, "  References: ");
    ipa_dump_references (f, &node->symbol.ref_list);
Index: tree-profile.c
===================================================================
*** tree-profile.c	(revision 186623)
--- tree-profile.c	(working copy)
*************** init_ic_make_global_vars (void)
*** 87,93 ****
        decl_default_tls_model (ic_void_ptr_var);
  
    varpool_finalize_decl (ic_void_ptr_var);
-   varpool_mark_needed_node (varpool_node (ic_void_ptr_var));
  
    gcov_type_ptr = build_pointer_type (get_gcov_type ());
    ic_gcov_type_ptr_var
--- 87,92 ----
*************** init_ic_make_global_vars (void)
*** 103,109 ****
        decl_default_tls_model (ic_gcov_type_ptr_var);
  
    varpool_finalize_decl (ic_gcov_type_ptr_var);
-   varpool_mark_needed_node (varpool_node (ic_gcov_type_ptr_var));
  }
  
  void
--- 102,107 ----
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 186623)
--- Makefile.in	(working copy)
*************** cgraphbuild.o : cgraphbuild.c $(CONFIG_H
*** 2934,2940 ****
  varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \
     $(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \
!    $(TREE_FLOW_H) gt-varpool.h
  ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
     $(TREE_PASS_H) $(TIMEVAR_H) $(GIMPLE_H) $(GGC_H) pointer-set.h \
     $(IPA_UTILS_H)
--- 2934,2940 ----
  varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \
     $(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \
!    $(TREE_FLOW_H) 
  ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
     $(TREE_PASS_H) $(TIMEVAR_H) $(GIMPLE_H) $(GGC_H) pointer-set.h \
     $(IPA_UTILS_H)
*************** GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
*** 3719,3725 ****
    $(srcdir)/tree-scalar-evolution.c \
    $(srcdir)/tree-ssa-operands.h \
    $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \
-   $(srcdir)/varpool.c \
    $(srcdir)/tree-parloops.c \
    $(srcdir)/omp-low.c \
    $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \
--- 3719,3724 ----
Index: tree-switch-conversion.c
===================================================================
*** tree-switch-conversion.c	(revision 186623)
--- tree-switch-conversion.c	(working copy)
*************** build_one_array (gimple swtch, int num, 
*** 625,631 ****
        TREE_CONSTANT (decl) = 1;
        TREE_READONLY (decl) = 1;
        add_referenced_var (decl);
-       varpool_mark_needed_node (varpool_node (decl));
        varpool_finalize_decl (decl);
  
        fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
--- 625,630 ----
Index: passes.c
===================================================================
*** passes.c	(revision 186624)
--- passes.c	(working copy)
*************** ipa_write_summaries (void)
*** 2342,2349 ****
      }
    vset = varpool_node_set_new ();
  
!   FOR_EACH_VARIABLE (vnode)
!     if (vnode->needed && (!vnode->alias || vnode->alias_of))
        varpool_node_set_add (vset, vnode);
  
    ipa_write_summaries_1 (set, vset);
--- 2342,2349 ----
      }
    vset = varpool_node_set_new ();
  
!   FOR_EACH_DEFINED_VARIABLE (vnode)
!     if ((!vnode->alias || vnode->alias_of))
        varpool_node_set_add (vset, vnode);
  
    ipa_write_summaries_1 (set, vset);
Index: varpool.c
===================================================================
*** varpool.c	(revision 186624)
--- varpool.c	(working copy)
***************
*** 1,5 ****
  /* Callgraph handling code.
!    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011
     Free Software Foundation, Inc.
     Contributed by Jan Hubicka
  
--- 1,5 ----
  /* Callgraph handling code.
!    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012
     Free Software Foundation, Inc.
     Contributed by Jan Hubicka
  
*************** along with GCC; see the file COPYING3.  
*** 48,79 ****
      All variables supposed to be output into final file needs to be
      explicitly marked by frontend via VARPOOL_FINALIZE_DECL function.  */
  
- /* Queue of cgraph nodes scheduled to be lowered and output.
-    The queue is maintained via mark_needed_node, linked via node->next_needed
-    pointer.
- 
-    LAST_NEEDED_NODE points to the end of queue, so it can be
-    maintained in forward order.  GTY is needed to make it friendly to
-    PCH.
- 
-    During compilation we construct the queue of needed variables
-    twice: first time it is during cgraph construction, second time it is at the
-    end of compilation in VARPOOL_REMOVE_UNREFERENCED_DECLS so we can avoid
-    optimized out variables being output.
- 
-    Each variable is thus first analyzed and then later possibly output.
-    FIRST_UNANALYZED_NODE points to first node in queue that was not analyzed
-    yet and is moved via VARPOOL_ANALYZE_PENDING_DECLS.  */
- 
- symtab_node x_varpool_nodes_queue;
- static GTY(()) symtab_node x_varpool_last_needed_node;
- #define varpool_last_needed_node ((struct varpool_node *)x_varpool_last_needed_node)
- static GTY(()) symtab_node x_varpool_first_unanalyzed_node;
- #define varpool_first_unanalyzed_node ((struct varpool_node *)x_varpool_first_unanalyzed_node)
- 
- /* Lists all assembled variables to be sent to debugger output later on.  */
- static GTY(()) struct varpool_node *varpool_assembled_nodes_queue;
- 
  /* Return varpool node assigned to DECL.  Create new one when needed.  */
  struct varpool_node *
  varpool_node (tree decl)
--- 48,53 ----
*************** varpool_node (tree decl)
*** 95,118 ****
  void
  varpool_remove_node (struct varpool_node *node)
  {
-   gcc_assert (!varpool_assembled_nodes_queue);
    symtab_unregister_node ((symtab_node)node);
-   if (varpool_first_unanalyzed_node == node)
-     x_varpool_first_unanalyzed_node = (symtab_node)node->next_needed;
-   if (node->next_needed)
-     node->next_needed->prev_needed = node->prev_needed;
-   else if (node->prev_needed)
-     {
-       gcc_assert (varpool_last_needed_node);
-       x_varpool_last_needed_node = (symtab_node)node->prev_needed;
-     }
-   if (node->prev_needed)
-     node->prev_needed->next_needed = node->next_needed;
-   else if (node->next_needed)
-     {
-       gcc_assert (varpool_nodes_queue == node);
-       x_varpool_nodes_queue = (symtab_node)node->next_needed;
-     }
    ggc_free (node);
  }
  
--- 69,75 ----
*************** dump_varpool_node (FILE *f, struct varpo
*** 128,135 ****
    fprintf (f, "  Varpool flags:");
    if (DECL_INITIAL (node->symbol.decl))
      fprintf (f, " initialized");
-   if (node->needed)
-     fprintf (f, " needed");
    if (node->analyzed)
      fprintf (f, " analyzed");
    if (node->finalized)
--- 85,90 ----
*************** varpool_node_for_asm (tree asmname)
*** 168,212 ****
    return NULL;
  }
  
- /* Helper function for finalization code - add node into lists so it will
-    be analyzed and compiled.  */
- static void
- varpool_enqueue_needed_node (struct varpool_node *node)
- {
-   if (varpool_last_needed_node)
-     {
-       varpool_last_needed_node->next_needed = node;
-       node->prev_needed = varpool_last_needed_node;
-     }
-   x_varpool_last_needed_node = (symtab_node)node;
-   node->next_needed = NULL;
-   if (!varpool_nodes_queue)
-     x_varpool_nodes_queue = (symtab_node)node;
-   if (!varpool_first_unanalyzed_node)
-     x_varpool_first_unanalyzed_node = (symtab_node)node;
-   notice_global_symbol (node->symbol.decl);
- }
- 
- /* Notify finalize_compilation_unit that given node is reachable
-    or needed.  */
- void
- varpool_mark_needed_node (struct varpool_node *node)
- {
-   if (!node->needed && node->finalized
-       && !TREE_ASM_WRITTEN (node->symbol.decl))
-     varpool_enqueue_needed_node (node);
-   node->needed = 1;
- }
- 
- /* Reset the queue of needed nodes.  */
- void
- varpool_reset_queue (void)
- {
-   x_varpool_last_needed_node = NULL;
-   x_varpool_nodes_queue = NULL;
-   x_varpool_first_unanalyzed_node = NULL;
- }
- 
  /* Determine if variable DECL is needed.  That is, visible to something
     either outside this translation unit, something magic in the system
     configury */
--- 123,128 ----
*************** const_value_known_p (tree decl)
*** 270,311 ****
    return true;
  }
  
- /* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
-    middle end to output the variable to asm file, if needed or externally
-    visible.  */
- void
- varpool_finalize_decl (tree decl)
- {
-   struct varpool_node *node = varpool_node (decl);
- 
-   gcc_assert (TREE_STATIC (decl));
- 
-   /* The first declaration of a variable that comes through this function
-      decides whether it is global (in C, has external linkage)
-      or local (in C, has internal linkage).  So do nothing more
-      if this function has already run.  */
-   if (node->finalized)
-     {
-       if (cgraph_global_info_ready)
- 	varpool_assemble_pending_decls ();
-       return;
-     }
-   if (node->needed)
-     varpool_enqueue_needed_node (node);
-   node->finalized = true;
-   if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
-       /* Traditionally we do not eliminate static variables when not
- 	 optimizing and when not doing toplevel reoder.  */
-       || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
- 	  && !DECL_ARTIFICIAL (node->symbol.decl)))
-     node->symbol.force_output = true;
- 
-   if (decide_is_variable_needed (node, decl))
-     varpool_mark_needed_node (node);
-   if (cgraph_global_info_ready)
-     varpool_assemble_pending_decls ();
- }
- 
  /* Add the variable DECL to the varpool.
     Unlike varpool_finalize_decl function is intended to be used
     by middle end and allows insertion of new variable at arbitrary point
--- 186,191 ----
*************** cgraph_variable_initializer_availability
*** 338,430 ****
    return AVAIL_AVAILABLE;
  }
  
! /* Walk the decls we marked as necessary and see if they reference new
!    variables or functions and add them into the worklists.  */
! bool
! varpool_analyze_pending_decls (void)
  {
!   bool changed = false;
  
!   timevar_push (TV_VARPOOL);
!   while (varpool_first_unanalyzed_node)
      {
!       struct varpool_node *node = varpool_first_unanalyzed_node, *next;
!       tree decl = node->symbol.decl;
!       bool analyzed = node->analyzed;
! 
!       varpool_first_unanalyzed_node->analyzed = true;
! 
!       x_varpool_first_unanalyzed_node = (symtab_node)varpool_first_unanalyzed_node->next_needed;
! 
!       /* When reading back varpool at LTO time, we re-construct the queue in order
!          to have "needed" list right by inserting all needed nodes into varpool.
! 	 We however don't want to re-analyze already analyzed nodes.  */
!       if (!analyzed)
! 	{
! 	  gcc_assert (!in_lto_p || cgraph_function_flags_ready);
!           /* Compute the alignment early so function body expanders are
! 	     already informed about increased alignment.  */
!           align_variable (decl, 0);
! 	}
!       if (node->alias && node->alias_of)
! 	{
! 	  struct varpool_node *tgt = varpool_node (node->alias_of);
!           struct varpool_node *n;
  
! 	  for (n = tgt; n && n->alias;
! 	       n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
! 	    if (n == node)
! 	      {
! 		error ("variable %q+D part of alias cycle", node->symbol.decl);
! 		node->alias = false;
! 		continue;
! 	      }
! 	  if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
! 	    ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL);
! 	  /* C++ FE sometimes change linkage flags after producing same body aliases.  */
! 	  if (node->extra_name_alias)
  	    {
! 	      DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of);
! 	      TREE_PUBLIC (node->symbol.decl) = TREE_PUBLIC (node->alias_of);
! 	      DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of);
! 	      DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of);
! 	      if (TREE_PUBLIC (node->symbol.decl))
  		{
! 		  DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->alias_of);
! 		  DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->alias_of);
! 		  if (DECL_ONE_ONLY (node->alias_of)
! 		      && !node->symbol.same_comdat_group)
  		    {
! 		      node->symbol.same_comdat_group = (symtab_node)tgt;
! 		      if (!tgt->symbol.same_comdat_group)
! 			tgt->symbol.same_comdat_group = (symtab_node)node;
! 		      else
! 			{
! 			  symtab_node n;
! 			  for (n = tgt->symbol.same_comdat_group;
! 			       n->symbol.same_comdat_group != (symtab_node)tgt;
! 			       n = n->symbol.same_comdat_group)
! 			    ;
! 			  n->symbol.same_comdat_group = (symtab_node)node;
! 			}
  		    }
  		}
  	    }
-    	  varpool_mark_needed_node (tgt);
  	}
-       else if (DECL_INITIAL (decl))
- 	record_references_in_initializer (decl, analyzed);
-       if (node->symbol.same_comdat_group)
- 	{
- 	  for (next = varpool (node->symbol.same_comdat_group);
- 	       next != node;
- 	       next = varpool (next->symbol.same_comdat_group))
- 	    varpool_mark_needed_node (next);
- 	}
-       changed = true;
      }
!   timevar_pop (TV_VARPOOL);
!   return changed;
  }
  
  /* Assemble thunks and aliases asociated to NODE.  */
--- 218,286 ----
    return AVAIL_AVAILABLE;
  }
  
! void
! varpool_analyze_node (struct varpool_node *node)
  {
!   tree decl = node->symbol.decl;
  
!   /* When reading back varpool at LTO time, we re-construct the queue in order
!      to have "needed" list right by inserting all needed nodes into varpool.
!      We however don't want to re-analyze already analyzed nodes.  */
!   if (!node->analyzed)
      {
!       gcc_assert (!in_lto_p || cgraph_function_flags_ready);
!       /* Compute the alignment early so function body expanders are
! 	 already informed about increased alignment.  */
!       align_variable (decl, 0);
!     }
!   if (node->alias && node->alias_of)
!     {
!       struct varpool_node *tgt = varpool_node (node->alias_of);
!       struct varpool_node *n;
  
!       for (n = tgt; n && n->alias;
! 	   n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
! 	if (n == node)
! 	  {
! 	    error ("variable %q+D part of alias cycle", node->symbol.decl);
! 	    node->alias = false;
! 	    continue;
! 	  }
!       if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
! 	ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL);
!       /* C++ FE sometimes change linkage flags after producing same body aliases.  */
!       if (node->extra_name_alias)
! 	{
! 	  DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of);
! 	  TREE_PUBLIC (node->symbol.decl) = TREE_PUBLIC (node->alias_of);
! 	  DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of);
! 	  DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of);
! 	  if (TREE_PUBLIC (node->symbol.decl))
  	    {
! 	      DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->alias_of);
! 	      DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->alias_of);
! 	      if (DECL_ONE_ONLY (node->alias_of)
! 		  && !node->symbol.same_comdat_group)
  		{
! 		  node->symbol.same_comdat_group = (symtab_node)tgt;
! 		  if (!tgt->symbol.same_comdat_group)
! 		    tgt->symbol.same_comdat_group = (symtab_node)node;
! 		  else
  		    {
! 		      symtab_node n;
! 		      for (n = tgt->symbol.same_comdat_group;
! 			   n->symbol.same_comdat_group != (symtab_node)tgt;
! 			   n = n->symbol.same_comdat_group)
! 			;
! 		      n->symbol.same_comdat_group = (symtab_node)node;
  		    }
  		}
  	    }
  	}
      }
!   else if (DECL_INITIAL (decl))
!     record_references_in_initializer (decl, node->analyzed);
!   node->analyzed = true;
  }
  
  /* Assemble thunks and aliases asociated to NODE.  */
*************** varpool_assemble_decl (struct varpool_no
*** 459,469 ****
        assemble_variable (decl, 0, 1, 0);
        if (TREE_ASM_WRITTEN (decl))
  	{
- 	  node->next_needed = varpool_assembled_nodes_queue;
- 	  node->prev_needed = NULL;
- 	  if (varpool_assembled_nodes_queue)
- 	    varpool_assembled_nodes_queue->prev_needed = node;
- 	  varpool_assembled_nodes_queue = node;
  	  node->finalized = 1;
  	  assemble_aliases (node);
  	  return true;
--- 315,320 ----
*************** varpool_assemble_decl (struct varpool_no
*** 473,512 ****
    return false;
  }
  
  /* Optimization of function bodies might've rendered some variables as
!    unnecessary so we want to avoid these from being compiled.
  
-    This is done by pruning the queue and keeping only the variables that
-    really appear needed (ie they are either externally visible or referenced
-    by compiled function). Re-doing the reachability analysis on variables
-    brings back the remaining variables referenced by these.  */
  void
  varpool_remove_unreferenced_decls (void)
  {
!   struct varpool_node *next, *node = varpool_nodes_queue;
! 
!   varpool_reset_queue ();
  
    if (seen_error ())
      return;
  
!   while (node)
      {
-       next = node->next_needed;
-       node->needed = 0;
- 
        if (node->analyzed
  	  && (!varpool_can_remove_if_no_refs (node)
  	      /* We just expanded all function bodies.  See if any of
  		 them needed the variable.  */
  	      || DECL_RTL_SET_P (node->symbol.decl)))
! 	varpool_mark_needed_node (node);
  
!       node = next;
      }
!   /* Make sure we mark alias targets as used targets.  */
!   finish_aliases_1 ();
!   varpool_analyze_pending_decls ();
  }
  
  /* For variables in named sections make sure get_variable_section
--- 324,408 ----
    return false;
  }
  
+ /* Add NODE to queue starting at FIRST. 
+    The queue is linked via AUX pointers and terminated by pointer to 1.  */
+ 
+ static void
+ enqueue_node (struct varpool_node *node, struct varpool_node **first)
+ {
+   if (node->symbol.aux)
+     return;
+   gcc_checking_assert (*first);
+   node->symbol.aux = *first;
+   *first = node;
+ }
+ 
  /* Optimization of function bodies might've rendered some variables as
!    unnecessary so we want to avoid these from being compiled.  Re-do
!    reachability starting from variables that are either externally visible
!    or was referred from the asm output routines.  */
  
  void
  varpool_remove_unreferenced_decls (void)
  {
!   struct varpool_node *next, *node;
!   struct varpool_node *first = (struct varpool_node *)(void *)1;
!   int i;
!   struct ipa_ref *ref;
  
    if (seen_error ())
      return;
  
!   if (cgraph_dump_file)
!     fprintf (cgraph_dump_file, "Trivially needed variables:");
!   finish_aliases_1 ();
!   FOR_EACH_DEFINED_VARIABLE (node)
      {
        if (node->analyzed
  	  && (!varpool_can_remove_if_no_refs (node)
  	      /* We just expanded all function bodies.  See if any of
  		 them needed the variable.  */
  	      || DECL_RTL_SET_P (node->symbol.decl)))
! 	{
! 	  enqueue_node (node, &first);
!           if (cgraph_dump_file)
! 	    fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node));
! 	}
!     }
!   while (first != (struct varpool_node *)(void *)1)
!     {
!       node = first;
!       first = (struct varpool_node *)first->symbol.aux;
  
!       if (node->symbol.same_comdat_group)
! 	{
! 	  symtab_node next;
! 	  for (next = node->symbol.same_comdat_group;
! 	       next != (symtab_node)node;
! 	       next = next->symbol.same_comdat_group)
! 	    if (symtab_variable_p (next)
! 		&& varpool (next)->analyzed)
! 	      enqueue_node (varpool (next), &first);
! 	}
!       for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
! 	if (symtab_variable_p (ref->referred)
! 	    && varpool (ref->referred)->analyzed)
! 	  enqueue_node (varpool (ref->referred), &first);
      }
!   if (cgraph_dump_file)
!     fprintf (cgraph_dump_file, "\nRemoving variables:");
!   for (node = varpool_first_defined_variable (); node; node = next)
!     {
!       next = varpool_next_defined_variable (node);
!       if (!node->symbol.aux)
! 	{
!           if (cgraph_dump_file)
! 	    fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node));
! 	  varpool_remove_node (node);
! 	}
!     }
!   if (cgraph_dump_file)
!     fprintf (cgraph_dump_file, "\n");
  }
  
  /* For variables in named sections make sure get_variable_section
*************** varpool_assemble_pending_decls (void)
*** 537,591 ****
      return false;
  
    timevar_push (TV_VAROUT);
-   /* EH might mark decls as needed during expansion.  This should be safe since
-      we don't create references to new function, but it should not be used
-      elsewhere.  */
-   varpool_analyze_pending_decls ();
  
    FOR_EACH_DEFINED_VARIABLE (node)
      varpool_finalize_named_section_flags (node);
  
!   while (varpool_nodes_queue)
!     {
!       struct varpool_node *node = varpool_nodes_queue;
! 
!       x_varpool_nodes_queue = (symtab_node)(varpool_nodes_queue->next_needed);
!       if (varpool_assemble_decl (node))
! 	changed = true;
!       else
! 	{
! 	  node->prev_needed = NULL;
!           node->next_needed = NULL;
! 	}
!     }
!   /* varpool_nodes_queue is now empty, clear the pointer to the last element
!      in the queue.  */
!   x_varpool_last_needed_node = NULL;
    timevar_pop (TV_VAROUT);
    return changed;
  }
  
- /* Remove all elements from the queue so we can re-use it for debug output.  */
- void
- varpool_empty_needed_queue (void)
- {
-   /* EH might mark decls as needed during expansion.  This should be safe since
-      we don't create references to new function, but it should not be used
-      elsewhere.  */
-   varpool_analyze_pending_decls ();
- 
-   while (varpool_nodes_queue)
-     {
-       struct varpool_node *node = varpool_nodes_queue;
-       x_varpool_nodes_queue = (symtab_node)varpool_nodes_queue->next_needed;
-       node->next_needed = NULL;
-       node->prev_needed = NULL;
-     }
-   /* varpool_nodes_queue is now empty, clear the pointer to the last element
-      in the queue.  */
-   x_varpool_last_needed_node = NULL;
- }
- 
  /* Create a new global variable of type TYPE.  */
  tree
  add_new_static_var (tree type)
--- 433,449 ----
      return false;
  
    timevar_push (TV_VAROUT);
  
    FOR_EACH_DEFINED_VARIABLE (node)
      varpool_finalize_named_section_flags (node);
  
!   FOR_EACH_DEFINED_VARIABLE (node)
!     if (varpool_assemble_decl (node))
!       changed = true;
    timevar_pop (TV_VAROUT);
    return changed;
  }
  
  /* Create a new global variable of type TYPE.  */
  tree
  add_new_static_var (tree type)
*************** add_new_static_var (tree type)
*** 603,609 ****
    lang_hooks.dup_lang_specific_decl (new_decl);
    create_var_ann (new_decl);
    new_node = varpool_node (new_decl);
-   varpool_mark_needed_node (new_node);
    add_referenced_var (new_decl);
    varpool_finalize_decl (new_decl);
  
--- 461,466 ----
*************** varpool_create_variable_alias (tree alia
*** 624,633 ****
    alias_node->alias = 1;
    alias_node->finalized = 1;
    alias_node->alias_of = decl;
!   if ((!DECL_EXTERNAL (alias)
!        && decide_is_variable_needed (alias_node, alias))
!       || alias_node->needed)
!     varpool_mark_needed_node (alias_node);
    return alias_node;
  }
  
--- 481,497 ----
    alias_node->alias = 1;
    alias_node->finalized = 1;
    alias_node->alias_of = decl;
! 
!   /* Extra name alias mechanizm creates aliases really late
!      via DECL_ASSEMBLER_NAME mechanizm.
!      This is unfortunate because they are not going through the
!      standard channels.  Ensure they get output.  */
!   if (cgraph_state >= CGRAPH_STATE_IPA)
!     {
!       varpool_analyze_node (alias_node);
!       if (TREE_PUBLIC (alias))
! 	alias_node->symbol.externally_visible = true;
!     }
    return alias_node;
  }
  
*************** varpool_for_node_and_aliases (struct var
*** 688,691 ****
        }
    return false;
  }
- #include "gt-varpool.h"
--- 552,554 ----


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