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 10/many: Remove "needed" flag from callgraph nodes and fix several latent problems


Hi,
this patch is first of bigger cleanups I have in queue after symtab changes.

The main purpose of the patch is to remove "needed" flag from cgraph nodes.
Long time ago, when cgraph code was written, it was simple datastructure to
compute reachablity and inlinng decisions on.

We still did function-at-a-time by default and I introduced optional
unit-at-a-time mode.  Main pain of cgraph change back then was to keep compiler
behaviour as close as possible to non-unit-at-a-time since a lot of code and
testsuite did rely on it (by toplevel asm statements and other mess).

The code simply waited for frontend to finalize function and then it decided
whether function needs to be output immediately and set "needed" flag if that
was true.

At cgraph construction time then other functions was brought to the callgraph
when they become reachable.

This scheme worked well until we started to do fancier stuff, like whole
program, LTO and other optimization.  Now the main problem of "needed" flag is
that it makes function opaque to the optimizations, but it completely lose
track on why this is the case.

We used to do a lot of tricks at frontend side to mark things as needed
because things happened behind cgraph back.
Moreover varpool datastructure has needed flag, but with different meaning.
In this case it simulate use of "reachable" flag of callgraph and there
is separate "force output" flag that does similar thing as "needed".
The reason is that originally force output logic was done by
simple TREE_SYMBOL_REFERENCED set and due to lack of tree-ssa we was
tracking what variables should be output by checking what symbol names
landed the assembly file during RTL optimization.

Almost decade later we are hopefully ready for cleaner approach.  This patch
is first of series of patches where I want to remove all reachability analysis
related stuff from cgraph/varpool nodes and make it local to the cgraph
construction code, reachability code and perobably drop the final
variable reacability pass.

This patch commonize force_output flag to symbol table and update those few
places where we still need to make function/variable opaque to optimizations
to use it.

There are several latent bugs related to this logic. That is

 1) C++ FE is marking things as force output per ABI decisions.  This is
    unnecesarily conservative, because with LTO support we still can take
    such symbols away (consider force output comdat hidden function, there
    are 2000 of them in Mozilla)

    I plan to handle this incrementally by adding specialized flag for
    this reason (force_output_by_abi)
 2) Java for whatever reason still set flag TREE_SYMBOL_REFERENCED to
    make cgraph output alias targets.  This is not neccesary for years, so
    I dropped this.

 3) varasm.c still set targets of aliases as needed.  This is a bug where
    I apparently did not merge all patches intended for 4.6.  We do have
    about 700 functions in Mozilla unnecesarily needed since mozilla
    internally uses useless attributes at boundaries of former shared
    libraries all linked into libxul.
    Fixed thus.

 4) Fixing 3) uncovered fact that weakrefs are not handled correctly
    in all cases (in particular in case where destination of weakref
    is defined locally).  Fixed thus, in ipa.c and varpool.c
    There is still room for cleanups/improvements here; weakrefs are
    external declarations and as such they are not optimized very well.
    In fact weakrefs are not visible from any other unit and if the
    target is defined locally they binds to it as if they were static
    aliases.  We probably could promote them to these in visibility
    pass and get rid of some of the anoying special cases.

 5) Cgraph building code did not know that when alias is reachable,
    it means that its target is reachable, too.

The patch disturbs some of ages old code WRT aliases and logic how and
when functions are output. 

I've bootstrapped/regtested x86_64-linux (with all languages and LTO with
default languages), i686-linux and in earlier version hp-pa. I also tested that
Mozilla still builds with the patch as well as kernel and on earlier version I
tested webkit, cromium and partial build of open-office.

I plan to commit this today and watch for fallout at weekend.

Honza

	* lto-symtab.c (lto_cgraph_replace_node): Merge needed instead of force flags.
	* cgraph.c (cgraph_add_thunk): Use mark_reachable_node.
	(cgraph_remove_node): Update.
	(cgraph_mark_needed_node): Remove.
	(cgraph_mark_force_output_node): New.
	(dump_cgraph_node): Do not dump needed flag.
	(cgraph_node_cannot_be_local_p_1): Update.
	(cgraph_can_remove_if_no_direct_calls_and_refs): Update.
	* cgraph.h (symtab_node_base): Add force_output flag.
	(cgraph_node): Remove needed flag.
	(varpool_node): Remove force_output flag.
	(cgraph_mark_needed_node): Remove.
	(cgraph_mark_force_output_node): New.
	(cgraph_only_called_directly_or_aliased_p,
	varpool_can_remove_if_no_refs, varpool_all_refs_explicit_p): Update.
	* ipa-cp.c (ipcp_generate_summary): Remove out of date assert.
	* cgraphunit.c (cgraph_decide_is_function_needed): rewrite.
	(cgraph_add_new_function); Update.
	(cgraph_mark_if_needed); Update.
	(verify_cgraph_node): Update.
	(cgraph_analyze_function): Alias target is reachable.
	(process_function_and_variable_attributes): Update: externally_visible
	flag makes function reachable.
	(cgraph_analyze_functions): Update dumping.
	* lto-cgraph.c (lto_output_node, lto_output_varpool_node,
	input_overwrite_node, input_varpool_node): Update streaming.
	* lto-streamer-out.c (produce_symtab): Use force_output.
	* ipa.c (process_references): Weakrefs must be processed.
	(cgraph_remove_unreachable_nodes): Likewise; update for new
	force_output flag.
	(varpool_externally_visible_p); Weakrefs are externally visible
	even if they are not.
	(function_and_variable_visibility): Update; when processing alias
	pair force the targets to be output.
	(whole_program_function_and_variable_visility): Use mark_reachable_node.
	* trans-mem.c (ipa_tm_mark_needed_node): Remove
	(ipa_tm_mark_force_output_node): New function.
	(ipa_tm_create_version_alias, ipa_tm_create_version): Update.
	* gimple-fold.c (can_refer_decl_in_current_unit_p): Be lax about aliases.
	* varasm.c (mark_decl_referenced): Update.
	(find_decl_and_mark_needed): Remove.
	(find_decl): New function.
	(weak_finish, finish_aliases_1, assemble_alias): Update; do not mark
	alias targets as needed.
	(dump_tm_clone_pairs): Update.
	* tree-inline.c (copy_bb): Update check.
	* symtab.c (dump_symtab_base): Dump force_output.
	* tree-ssa-structalias.c (ipa_pta_execute): Use force_output.
	* passes.c (execute_todo): Fix dumping.
	* varpool.c (decide_is_variable_needed, varpool_finalize_decl): Update.
	(varpool_analyze_pending_decls): Alias target is reachable.
	(varpool_create_variable_alias): Finalize weakrefs.

	* class.c (make_local_function_alias): Do not mark symbol referenced.

	* objc-acct.c (mark_referenced_methods); Use
	cgraph_mark_force_output_node.

	* gcc-interface/utils.c (gnat_write_global_declarations): Update for new
	force_output placement.

	* lto/lto-partition.c (partition_cgraph_node_p): Use force_output.
	
Index: lto-symtab.c
===================================================================
*** lto-symtab.c	(revision 186597)
--- lto-symtab.c	(working copy)
*************** lto_cgraph_replace_node (struct cgraph_n
*** 223,230 ****
      }
  
    /* Merge node flags.  */
!   if (node->needed)
!     cgraph_mark_needed_node (prevailing_node);
    if (node->reachable)
      cgraph_mark_reachable_node (prevailing_node);
    if (node->symbol.address_taken)
--- 223,230 ----
      }
  
    /* Merge node flags.  */
!   if (node->symbol.force_output)
!     cgraph_mark_force_output_node (prevailing_node);
    if (node->reachable)
      cgraph_mark_reachable_node (prevailing_node);
    if (node->symbol.address_taken)
Index: java/class.c
===================================================================
*** java/class.c	(revision 186597)
--- java/class.c	(working copy)
*************** make_local_function_alias (tree method)
*** 1407,1413 ****
    DECL_INITIAL (alias) = error_mark_node;
    TREE_ADDRESSABLE (alias) = 1;
    TREE_USED (alias) = 1;
-   TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
    if (!flag_syntax_only)
      assemble_alias (alias, DECL_ASSEMBLER_NAME (method));
    return alias;
--- 1407,1412 ----
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 186597)
--- cgraph.c	(working copy)
*************** cgraph_add_thunk (struct cgraph_node *de
*** 570,576 ****
    node->local.finalized = true;
  
    if (cgraph_decide_is_function_needed (node, decl))
!     cgraph_mark_needed_node (node);
  
    if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
        || (DECL_VIRTUAL_P (decl)
--- 570,576 ----
    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)
*************** cgraph_remove_node (struct cgraph_node *
*** 1362,1368 ****
  
    /* Incremental inlining access removed nodes stored in the postorder list.
       */
!   node->needed = node->reachable = false;
    for (n = node->nested; n; n = n->next_nested)
      n->origin = NULL;
    node->nested = NULL;
--- 1362,1368 ----
  
    /* Incremental inlining access removed nodes stored in the postorder list.
       */
!   node->symbol.force_output = node->reachable = false;
    for (n = node->nested; n; n = n->next_nested)
      n->origin = NULL;
    node->nested = NULL;
*************** cgraph_mark_reachable_node (struct cgrap
*** 1518,1526 ****
     external means.  */
  
  void
! cgraph_mark_needed_node (struct cgraph_node *node)
  {
!   node->needed = 1;
    gcc_assert (!node->global.inlined_to);
    cgraph_mark_reachable_node (node);
  }
--- 1518,1526 ----
     external means.  */
  
  void
! cgraph_mark_force_output_node (struct cgraph_node *node)
  {
!   node->symbol.force_output = 1;
    gcc_assert (!node->global.inlined_to);
    cgraph_mark_reachable_node (node);
  }
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1642,1649 ****
  	     (HOST_WIDEST_INT)node->count);
    if (node->origin)
      fprintf (f, " nested in: %s", cgraph_node_asm_name (node->origin));
-   if (node->needed)
-     fprintf (f, " needed");
    else if (node->reachable)
      fprintf (f, " reachable");
    if (gimple_has_body_p (node->symbol.decl))
--- 1642,1647 ----
*************** static bool
*** 2134,2140 ****
  cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node,
  				 void *data ATTRIBUTE_UNUSED)
  {
!   return !(!node->needed
  	   && ((DECL_COMDAT (node->symbol.decl)
  		&& !node->symbol.same_comdat_group)
  	       || !node->symbol.externally_visible));
--- 2132,2138 ----
  cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node,
  				 void *data ATTRIBUTE_UNUSED)
  {
!   return !(!node->symbol.force_output
  	   && ((DECL_COMDAT (node->symbol.decl)
  		&& !node->symbol.same_comdat_group)
  	       || !node->symbol.externally_visible));
*************** cgraph_can_remove_if_no_direct_calls_and
*** 2570,2576 ****
    if (DECL_EXTERNAL (node->symbol.decl))
      return true;
    /* When function is needed, we can not remove it.  */
!   if (node->needed || node->symbol.used_from_other_partition)
      return false;
    if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)
        || DECL_STATIC_DESTRUCTOR (node->symbol.decl))
--- 2568,2574 ----
    if (DECL_EXTERNAL (node->symbol.decl))
      return true;
    /* When function is needed, we can not remove it.  */
!   if (node->symbol.force_output || node->symbol.used_from_other_partition)
      return false;
    if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)
        || DECL_STATIC_DESTRUCTOR (node->symbol.decl))
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 186597)
--- cgraph.h	(working copy)
*************** struct GTY(()) symtab_node_base
*** 77,82 ****
--- 77,85 ----
    unsigned in_other_partition : 1;
    /* Set when function is visible by other units.  */
    unsigned externally_visible : 1;
+   /* Needed variables might become dead by optimization.  This flag
+      forces the variable to be output even if it appears dead otherwise.  */
+   unsigned force_output : 1;
  };
  
  enum availability
*************** struct GTY(()) cgraph_node {
*** 246,257 ****
    /* Unique id of the node.  */
    int uid;
  
-   /* Set when function must be output for some reason.  The primary
-      use of this flag is to mark functions needed to be output for
-      non-standard reason.  Functions that are externally visible
-      or reachable from functions needed to be output are marked
-      by specialized flags.  */
-   unsigned needed : 1;
    /* Set when decl is an abstract function pointed to by the
       ABSTRACT_DECL_ORIGIN of a reachable function.  */
    unsigned abstract_and_needed : 1;
--- 249,254 ----
*************** struct GTY(()) varpool_node {
*** 433,441 ****
    /* Set when function must be output - it is externally visible
       or its address is taken.  */
    unsigned needed : 1;
-   /* Needed variables might become dead by optimization.  This flag
-      forces the variable to be output even if it appears dead otherwise.  */
-   unsigned force_output : 1;
    /* Set once the variable has been instantiated and its callee
       lists created.  */
    unsigned analyzed : 1;
--- 430,435 ----
*************** void cgraph_mark_if_needed (tree);
*** 610,616 ****
  void cgraph_analyze_function (struct cgraph_node *);
  void cgraph_finalize_compilation_unit (void);
  void cgraph_optimize (void);
! void cgraph_mark_needed_node (struct cgraph_node *);
  void cgraph_mark_address_taken_node (struct cgraph_node *);
  void cgraph_mark_reachable_node (struct cgraph_node *);
  bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason);
--- 604,610 ----
  void cgraph_analyze_function (struct cgraph_node *);
  void cgraph_finalize_compilation_unit (void);
  void cgraph_optimize (void);
! void cgraph_mark_force_output_node (struct cgraph_node *);
  void cgraph_mark_address_taken_node (struct cgraph_node *);
  void cgraph_mark_reachable_node (struct cgraph_node *);
  bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason);
*************** static inline bool
*** 1118,1124 ****
  cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node)
  {
    gcc_assert (!node->global.inlined_to);
!   return (!node->needed && !node->symbol.address_taken
  	  && !node->symbol.used_from_other_partition
  	  && !DECL_STATIC_CONSTRUCTOR (node->symbol.decl)
  	  && !DECL_STATIC_DESTRUCTOR (node->symbol.decl)
--- 1112,1118 ----
  cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node)
  {
    gcc_assert (!node->global.inlined_to);
!   return (!node->symbol.force_output && !node->symbol.address_taken
  	  && !node->symbol.used_from_other_partition
  	  && !DECL_STATIC_CONSTRUCTOR (node->symbol.decl)
  	  && !DECL_STATIC_DESTRUCTOR (node->symbol.decl)
*************** cgraph_only_called_directly_or_aliased_p
*** 1131,1139 ****
  static inline bool
  varpool_can_remove_if_no_refs (struct varpool_node *node)
  {
!   return (!node->force_output && !node->symbol.used_from_other_partition
    	  && (DECL_COMDAT (node->symbol.decl)
! 	  || !node->symbol.externally_visible));
  }
  
  /* Return true when all references to VNODE must be visible in ipa_ref_list.
--- 1125,1134 ----
  static inline bool
  varpool_can_remove_if_no_refs (struct varpool_node *node)
  {
!   return (!node->symbol.force_output && !node->symbol.used_from_other_partition
    	  && (DECL_COMDAT (node->symbol.decl)
! 	  || !node->symbol.externally_visible
! 	  || DECL_EXTERNAL (node->symbol.decl)));
  }
  
  /* Return true when all references to VNODE must be visible in ipa_ref_list.
*************** varpool_all_refs_explicit_p (struct varp
*** 1147,1153 ****
    return (vnode->analyzed
  	  && !vnode->symbol.externally_visible
  	  && !vnode->symbol.used_from_other_partition
! 	  && !vnode->force_output);
  }
  
  /* Constant pool accessor function.  */
--- 1142,1148 ----
    return (vnode->analyzed
  	  && !vnode->symbol.externally_visible
  	  && !vnode->symbol.used_from_other_partition
! 	  && !vnode->symbol.force_output);
  }
  
  /* Constant pool accessor function.  */
Index: ipa-cp.c
===================================================================
*** ipa-cp.c	(revision 186597)
--- ipa-cp.c	(working copy)
*************** ipcp_generate_summary (void)
*** 2494,2501 ****
  
    FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
        {
- 	/* Unreachable nodes should have been eliminated before ipcp.  */
- 	gcc_assert (node->needed || node->reachable);
  	node->local.versionable
  	  = tree_versionable_function_p (node->symbol.decl);
  	ipa_analyze_node (node);
--- 2494,2499 ----
Index: objc/objc-act.c
===================================================================
*** objc/objc-act.c	(revision 186597)
--- objc/objc-act.c	(working copy)
*************** mark_referenced_methods (void)
*** 4625,4631 ****
        chain = CLASS_CLS_METHODS (impent->imp_context);
        while (chain)
  	{
! 	  cgraph_mark_needed_node (
  			   cgraph_get_create_node (METHOD_DEFINITION (chain)));
  	  chain = DECL_CHAIN (chain);
  	}
--- 4625,4631 ----
        chain = CLASS_CLS_METHODS (impent->imp_context);
        while (chain)
  	{
! 	  cgraph_mark_force_output_node (
  			   cgraph_get_create_node (METHOD_DEFINITION (chain)));
  	  chain = DECL_CHAIN (chain);
  	}
*************** mark_referenced_methods (void)
*** 4633,4639 ****
        chain = CLASS_NST_METHODS (impent->imp_context);
        while (chain)
  	{
! 	  cgraph_mark_needed_node (
  			   cgraph_get_create_node (METHOD_DEFINITION (chain)));
  	  chain = DECL_CHAIN (chain);
  	}
--- 4633,4639 ----
        chain = CLASS_NST_METHODS (impent->imp_context);
        while (chain)
  	{
! 	  cgraph_mark_force_output_node (
  			   cgraph_get_create_node (METHOD_DEFINITION (chain)));
  	  chain = DECL_CHAIN (chain);
  	}
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 186597)
--- cgraphunit.c	(working copy)
*************** FILE *cgraph_dump_file;
*** 156,211 ****
  /* Used for vtable lookup in thunk adjusting.  */
  static GTY (()) tree vtable_entry_type;
  
! /* Determine if function DECL is needed.  That is, visible to something
!    either outside this translation unit, something magic in the system
!    configury.  */
  
  bool
  cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
  {
    /* If the user told us it is used, then it must be so.  */
!   if (node->symbol.externally_visible)
      return true;
  
!   /* ??? If the assembler name is set by hand, it is possible to assemble
!      the name later after finalizing the function and the fact is noticed
!      in assemble_name then.  This is arguably a bug.  */
!   if (DECL_ASSEMBLER_NAME_SET_P (decl)
!       && (!node->thunk.thunk_p && !node->same_body_alias)
!       && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
!     return true;
  
-   /* With -fkeep-inline-functions we are keeping all inline functions except
-      for extern inline ones.  */
-   if (flag_keep_inline_functions
-       && DECL_DECLARED_INLINE_P (decl)
-       && !DECL_EXTERNAL (decl)
-       && !DECL_DISREGARD_INLINE_LIMITS (decl))
-      return true;
  
!   /* If we decided it was needed before, but at the time we didn't have
!      the body of the function available, then it's still needed.  We have
!      to go back and re-check its dependencies now.  */
!   if (node->needed)
!     return true;
  
    /* Externally visible functions must be output.  The exception is
!      COMDAT functions that must be output only when they are needed.
  
!      When not optimizing, also output the static functions. (see
!      PR24561), but don't do so for always_inline functions, functions
!      declared inline and nested functions.  These were optimized out
!      in the original implementation and it is unclear whether we want
!      to change the behavior here.  */
!   if (((TREE_PUBLIC (decl)
! 	|| (!optimize
! 	    && !node->same_body_alias
! 	    && !DECL_DISREGARD_INLINE_LIMITS (decl)
! 	    && !DECL_DECLARED_INLINE_P (decl)
! 	    && !(DECL_CONTEXT (decl)
! 		 && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)))
!        && !flag_whole_program
!        && !flag_lto)
        && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
      return true;
  
--- 156,191 ----
  /* Used for vtable lookup in thunk adjusting.  */
  static GTY (()) tree vtable_entry_type;
  
! /* Determine if function DECL is trivially needed and should stay in the
!    compilation unit.  This is used at the symbol table construction time
!    and differs from later logic removing unnecesary functions that can
!    take into account results of analysis, whole program info etc.  */
  
  bool
  cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
  {
    /* If the user told us it is used, then it must be so.  */
!   if (node->symbol.force_output)
      return true;
  
!   /* Double check that no one output the function into assembly file
!      early.  */
!   gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
! 	               || (node->thunk.thunk_p || node->same_body_alias)
! 	               ||  !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
  
  
!   /* Keep constructors, destructors and virtual functions.  */
!   if (DECL_STATIC_CONSTRUCTOR (decl)
!       || DECL_STATIC_DESTRUCTOR (decl)
!       || (DECL_VIRTUAL_P (decl)
! 	  && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
!      return true;
  
    /* Externally visible functions must be output.  The exception is
!      COMDAT functions that must be output only when they are needed.  */
  
!   if (TREE_PUBLIC (decl)
        && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
      return true;
  
*************** cgraph_finalize_function (tree decl, boo
*** 337,358 ****
    node->local.finalized = true;
    node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
  
!   if (cgraph_decide_is_function_needed (node, decl))
!     cgraph_mark_needed_node (node);
  
!   /* Since we reclaim unreachable nodes at the end of every language
!      level unit, we need to be conservative about possible entry points
!      there.  */
!   if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
!       || DECL_STATIC_CONSTRUCTOR (decl)
!       || DECL_STATIC_DESTRUCTOR (decl)
!       /* COMDAT virtual functions may be referenced by vtable from
! 	 other compilation unit.  Still we want to devirtualize calls
! 	 to those so we need to analyze them.
! 	 FIXME: We should introduce may edges for this purpose and update
! 	 their handling in unreachable function removal and inliner too.  */
!       || (DECL_VIRTUAL_P (decl)
! 	  && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
      cgraph_mark_reachable_node (node);
  
    /* If we've not yet emitted decl, tell the debug info about it.  */
--- 317,345 ----
    node->local.finalized = true;
    node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
  
!   /* With -fkeep-inline-functions we are keeping all inline functions except
!      for extern inline ones.  */
!   if (flag_keep_inline_functions
!       && DECL_DECLARED_INLINE_P (decl)
!       && !DECL_EXTERNAL (decl)
!       && !DECL_DISREGARD_INLINE_LIMITS (decl))
!     node->symbol.force_output = 1;
  
!   /* When not optimizing, also output the static functions. (see
!      PR24561), but don't do so for always_inline functions, functions
!      declared inline and nested functions.  These were optimized out
!      in the original implementation and it is unclear whether we want
!      to change the behavior here.  */
!   if ((!optimize
!        && !node->same_body_alias
!        && !DECL_DISREGARD_INLINE_LIMITS (decl)
!        && !DECL_DECLARED_INLINE_P (decl)
!        && !(DECL_CONTEXT (decl)
! 	    && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL))
!       && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
!     node->symbol.force_output = 1;
! 
!   if (cgraph_decide_is_function_needed (node, decl))
      cgraph_mark_reachable_node (node);
  
    /* If we've not yet emitted decl, tell the debug info about it.  */
*************** cgraph_add_new_function (tree fndecl, bo
*** 402,408 ****
  	node = cgraph_get_create_node (fndecl);
  	node->local.local = false;
  	node->local.finalized = true;
! 	node->reachable = node->needed = true;
  	if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION)
  	  {
  	    push_cfun (DECL_STRUCT_FUNCTION (fndecl));
--- 389,395 ----
  	node = cgraph_get_create_node (fndecl);
  	node->local.local = false;
  	node->local.finalized = true;
! 	node->reachable = node->symbol.force_output = true;
  	if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION)
  	  {
  	    push_cfun (DECL_STRUCT_FUNCTION (fndecl));
*************** cgraph_mark_if_needed (tree decl)
*** 462,468 ****
  {
    struct cgraph_node *node = cgraph_get_node (decl);
    if (node->local.finalized && cgraph_decide_is_function_needed (node, decl))
!     cgraph_mark_needed_node (node);
  }
  
  /* Return TRUE if NODE2 is equivalent to NODE or its clone.  */
--- 449,455 ----
  {
    struct cgraph_node *node = cgraph_get_node (decl);
    if (node->local.finalized && cgraph_decide_is_function_needed (node, decl))
!     cgraph_mark_reachable_node (node);
  }
  
  /* Return TRUE if NODE2 is equivalent to NODE or its clone.  */
*************** verify_cgraph_node (struct cgraph_node *
*** 601,609 ****
        error ("inline clone with address taken");
        error_found = true;
      }
!   if (node->global.inlined_to && node->needed)
      {
!       error ("inline clone is needed");
        error_found = true;
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
--- 588,596 ----
        error ("inline clone with address taken");
        error_found = true;
      }
!   if (node->global.inlined_to && node->symbol.force_output)
      {
!       error ("inline clone is forced to output");
        error_found = true;
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
*************** cgraph_analyze_function (struct cgraph_n
*** 901,906 ****
--- 888,894 ----
        if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
          ipa_record_reference ((symtab_node)node, (symtab_node)tgt,
  			      IPA_REF_ALIAS, NULL);
+       cgraph_mark_reachable_node (tgt);
        if (node->same_body_alias)
  	{ 
  	  DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (node->thunk.alias);
*************** cgraph_analyze_function (struct cgraph_n
*** 940,946 ****
        if (node->symbol.address_taken)
  	cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node));
        if (cgraph_decide_is_function_needed (node, node->symbol.decl))
! 	cgraph_mark_needed_node (node);
      }
    else if (node->thunk.thunk_p)
      {
--- 928,934 ----
        if (node->symbol.address_taken)
  	cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node));
        if (cgraph_decide_is_function_needed (node, node->symbol.decl))
! 	cgraph_mark_reachable_node (node);
      }
    else if (node->thunk.thunk_p)
      {
*************** process_function_and_variable_attributes
*** 1061,1073 ****
      {
        tree decl = node->symbol.decl;
        if (DECL_PRESERVE_P (decl))
! 	cgraph_mark_needed_node (node);
        if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
  	  && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))
  	  && TREE_PUBLIC (node->symbol.decl))
  	{
  	  if (node->local.finalized)
! 	    cgraph_mark_needed_node (node);
  	}
        else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
  	{
--- 1049,1061 ----
      {
        tree decl = node->symbol.decl;
        if (DECL_PRESERVE_P (decl))
! 	cgraph_mark_force_output_node (node);
        if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
  	  && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))
  	  && TREE_PUBLIC (node->symbol.decl))
  	{
  	  if (node->local.finalized)
! 	    cgraph_mark_reachable_node (node);
  	}
        else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
  	{
*************** process_function_and_variable_attributes
*** 1076,1082 ****
  			"%<externally_visible%>"
  			" attribute have effect only on public objects");
  	  else if (node->local.finalized)
! 	     cgraph_mark_needed_node (node);
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
  	  && (node->local.finalized && !node->alias))
--- 1064,1070 ----
  			"%<externally_visible%>"
  			" attribute have effect only on public objects");
  	  else if (node->local.finalized)
! 	    cgraph_mark_reachable_node (node);
  	}
        if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
  	  && (node->local.finalized && !node->alias))
*************** process_function_and_variable_attributes
*** 1104,1110 ****
        tree decl = vnode->symbol.decl;
        if (DECL_PRESERVE_P (decl))
  	{
! 	  vnode->force_output = true;
  	  if (vnode->finalized)
  	    varpool_mark_needed_node (vnode);
  	}
--- 1092,1098 ----
        tree decl = vnode->symbol.decl;
        if (DECL_PRESERVE_P (decl))
  	{
! 	  vnode->symbol.force_output = true;
  	  if (vnode->finalized)
  	    varpool_mark_needed_node (vnode);
  	}
*************** cgraph_analyze_functions (void)
*** 1165,1171 ****
        fprintf (cgraph_dump_file, "Initial entry points:");
        for (node = cgraph_first_function (); node != first_analyzed;
  	   node = cgraph_next_function (node))
! 	if (node->needed)
  	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
        fprintf (cgraph_dump_file, "\n");
      }
--- 1153,1159 ----
        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_analyze_functions (void)
*** 1241,1247 ****
        fprintf (cgraph_dump_file, "Unit entry points:");
        for (node = cgraph_first_function (); node != first_analyzed;
  	   node = cgraph_next_function (node))
! 	if (node->needed)
  	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
        fprintf (cgraph_dump_file, "\n\nInitial ");
        dump_symtab (cgraph_dump_file);
--- 1229,1235 ----
        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);
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c	(revision 186597)
--- lto-cgraph.c	(working copy)
*************** lto_output_node (struct lto_simple_outpu
*** 503,509 ****
    bp_pack_value (&bp, node->local.versionable, 1);
    bp_pack_value (&bp, node->local.can_change_signature, 1);
    bp_pack_value (&bp, node->local.redefined_extern_inline, 1);
!   bp_pack_value (&bp, node->needed, 1);
    bp_pack_value (&bp, node->symbol.address_taken, 1);
    bp_pack_value (&bp, node->abstract_and_needed, 1);
    bp_pack_value (&bp, tag == LTO_cgraph_analyzed_node
--- 503,509 ----
    bp_pack_value (&bp, node->local.versionable, 1);
    bp_pack_value (&bp, node->local.can_change_signature, 1);
    bp_pack_value (&bp, node->local.redefined_extern_inline, 1);
!   bp_pack_value (&bp, node->symbol.force_output, 1);
    bp_pack_value (&bp, node->symbol.address_taken, 1);
    bp_pack_value (&bp, node->abstract_and_needed, 1);
    bp_pack_value (&bp, tag == LTO_cgraph_analyzed_node
*************** lto_output_varpool_node (struct lto_simp
*** 566,572 ****
    lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->symbol.decl);
    bp = bitpack_create (ob->main_stream);
    bp_pack_value (&bp, node->symbol.externally_visible, 1);
!   bp_pack_value (&bp, node->force_output, 1);
    bp_pack_value (&bp, node->finalized, 1);
    bp_pack_value (&bp, node->alias, 1);
    bp_pack_value (&bp, node->alias_of != NULL, 1);
--- 566,572 ----
    lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->symbol.decl);
    bp = bitpack_create (ob->main_stream);
    bp_pack_value (&bp, node->symbol.externally_visible, 1);
!   bp_pack_value (&bp, node->symbol.force_output, 1);
    bp_pack_value (&bp, node->finalized, 1);
    bp_pack_value (&bp, node->alias, 1);
    bp_pack_value (&bp, node->alias_of != NULL, 1);
*************** input_overwrite_node (struct lto_file_de
*** 911,917 ****
    node->local.versionable = bp_unpack_value (bp, 1);
    node->local.can_change_signature = bp_unpack_value (bp, 1);
    node->local.redefined_extern_inline = bp_unpack_value (bp, 1);
!   node->needed = bp_unpack_value (bp, 1);
    node->symbol.address_taken = bp_unpack_value (bp, 1);
    node->abstract_and_needed = bp_unpack_value (bp, 1);
    node->symbol.used_from_other_partition = bp_unpack_value (bp, 1);
--- 911,917 ----
    node->local.versionable = bp_unpack_value (bp, 1);
    node->local.can_change_signature = bp_unpack_value (bp, 1);
    node->local.redefined_extern_inline = bp_unpack_value (bp, 1);
!   node->symbol.force_output = bp_unpack_value (bp, 1);
    node->symbol.address_taken = bp_unpack_value (bp, 1);
    node->abstract_and_needed = bp_unpack_value (bp, 1);
    node->symbol.used_from_other_partition = bp_unpack_value (bp, 1);
*************** input_varpool_node (struct lto_file_decl
*** 1075,1081 ****
  
    bp = streamer_read_bitpack (ib);
    node->symbol.externally_visible = bp_unpack_value (&bp, 1);
!   node->force_output = bp_unpack_value (&bp, 1);
    node->finalized = bp_unpack_value (&bp, 1);
    node->alias = bp_unpack_value (&bp, 1);
    non_null_aliasof = bp_unpack_value (&bp, 1);
--- 1075,1081 ----
  
    bp = streamer_read_bitpack (ib);
    node->symbol.externally_visible = bp_unpack_value (&bp, 1);
!   node->symbol.force_output = bp_unpack_value (&bp, 1);
    node->finalized = bp_unpack_value (&bp, 1);
    node->alias = bp_unpack_value (&bp, 1);
    non_null_aliasof = bp_unpack_value (&bp, 1);
Index: lto-streamer-out.c
===================================================================
*** lto-streamer-out.c	(revision 186597)
--- lto-streamer-out.c	(working copy)
*************** produce_symtab (struct output_block *ob,
*** 1456,1462 ****
  	 in the LTO symbol table to prevent linker from forcing them
  	 into the output. */
        if (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->force_output
  	  && vnode->finalized 
  	  && DECL_VIRTUAL_P (vnode->symbol.decl))
  	continue;
--- 1456,1462 ----
  	 in the LTO symbol table to prevent linker from forcing them
  	 into the output. */
        if (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->symbol.force_output
  	  && vnode->finalized 
  	  && DECL_VIRTUAL_P (vnode->symbol.decl))
  	continue;
*************** produce_symtab (struct output_block *ob,
*** 1470,1476 ****
        if (!DECL_EXTERNAL (vnode->symbol.decl))
  	continue;
        if (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->force_output
  	  && vnode->finalized 
  	  && DECL_VIRTUAL_P (vnode->symbol.decl))
  	continue;
--- 1470,1476 ----
        if (!DECL_EXTERNAL (vnode->symbol.decl))
  	continue;
        if (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->symbol.force_output
  	  && vnode->finalized 
  	  && DECL_VIRTUAL_P (vnode->symbol.decl))
  	continue;
Index: ada/gcc-interface/utils.c
===================================================================
*** ada/gcc-interface/utils.c	(revision 186597)
--- ada/gcc-interface/utils.c	(working copy)
*************** gnat_write_global_declarations (void)
*** 4859,4865 ****
        TREE_STATIC (dummy_global) = 1;
        TREE_ASM_WRITTEN (dummy_global) = 1;
        node = varpool_node (dummy_global);
!       node->force_output = 1;
        varpool_mark_needed_node (node);
  
        while (!VEC_empty (tree, types_used_by_cur_var_decl))
--- 4859,4865 ----
        TREE_STATIC (dummy_global) = 1;
        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))
Index: ipa.c
===================================================================
*** ipa.c	(revision 186597)
--- ipa.c	(working copy)
*************** process_references (struct ipa_ref_list 
*** 97,102 ****
--- 97,103 ----
  	  if (!node->reachable
  	      && node->analyzed
  	      && (!DECL_EXTERNAL (node->symbol.decl)
+ 		  || node->alias
  	          || before_inlining_p))
  	    node->reachable = true;
  	  enqueue_cgraph_node (node, first);
*************** cgraph_remove_unreachable_nodes (bool be
*** 214,220 ****
      {
        vnode->next_needed = NULL;
        vnode->prev_needed = NULL;
!       if ((vnode->analyzed || vnode->force_output)
  	  && !varpool_can_remove_if_no_refs (vnode))
  	{
  	  vnode->needed = false;
--- 215,221 ----
      {
        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;
*************** cgraph_remove_unreachable_nodes (bool be
*** 254,259 ****
--- 255,261 ----
  		      && node->analyzed
  		      && (!e->inline_failed
  			  || !DECL_EXTERNAL (e->callee->symbol.decl)
+ 			  || node->alias
  			  || before_inlining_p))
  		    e->callee->reachable = true;
  		  enqueue_cgraph_node (e->callee, &first);
*************** cgraph_externally_visible_p (struct cgra
*** 659,664 ****
--- 661,672 ----
  bool
  varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
  {
+   /* Do not touch weakrefs; while they are not externally visible,
+      dropping their DECL_EXTERNAL flags confuse most
+      of code handling them.  */
+   if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl))
+     return true;
+ 
    if (!DECL_COMDAT (vnode->symbol.decl) && !TREE_PUBLIC (vnode->symbol.decl))
      return false;
  
*************** varpool_externally_visible_p (struct var
*** 700,706 ****
       is faster for dynamic linking.  Also this match logic hidding vtables
       from LTO symbol tables.  */
    if ((in_lto_p || flag_whole_program)
!       && !vnode->force_output
        && DECL_COMDAT (vnode->symbol.decl) && DECL_VIRTUAL_P (vnode->symbol.decl))
      return false;
  
--- 708,714 ----
       is faster for dynamic linking.  Also this match logic hidding vtables
       from LTO symbol tables.  */
    if ((in_lto_p || flag_whole_program)
!       && !vnode->symbol.force_output
        && DECL_COMDAT (vnode->symbol.decl) && DECL_VIRTUAL_P (vnode->symbol.decl))
      return false;
  
*************** function_and_variable_visibility (bool w
*** 776,783 ****
          {
  	  if (!node->analyzed)
  	    continue;
! 	  cgraph_mark_needed_node (node);
! 	  gcc_assert (node->needed);
  	  pointer_set_insert (aliased_nodes, node);
  	  if (dump_file)
  	    fprintf (dump_file, "  node %s/%i",
--- 784,790 ----
          {
  	  if (!node->analyzed)
  	    continue;
! 	  cgraph_mark_force_output_node (node);
  	  pointer_set_insert (aliased_nodes, node);
  	  if (dump_file)
  	    fprintf (dump_file, "  node %s/%i",
*************** function_and_variable_visibility (bool w
*** 786,791 ****
--- 793,799 ----
        else if ((vnode = varpool_node_for_asm (p->target)) != NULL
  	       && !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);
*************** function_and_variable_visibility (bool w
*** 813,821 ****
        /* Frontends and alias code marks nodes as needed before parsing is finished.
  	 We may end up marking as node external nodes where this flag is meaningless
  	 strip it.  */
!       if (node->needed
  	  && (DECL_EXTERNAL (node->symbol.decl) || !node->analyzed))
! 	node->needed = 0;
  
        /* C++ FE on lack of COMDAT support create local COMDAT functions
  	 (that ought to be shared but can not due to object format
--- 821,829 ----
        /* Frontends and alias code marks nodes as needed before parsing is finished.
  	 We may end up marking as node external nodes where this flag is meaningless
  	 strip it.  */
!       if (node->symbol.force_output
  	  && (DECL_EXTERNAL (node->symbol.decl) || !node->analyzed))
! 	node->symbol.force_output = 0;
  
        /* C++ FE on lack of COMDAT support create local COMDAT functions
  	 (that ought to be shared but can not due to object format
*************** whole_program_function_and_variable_visi
*** 1017,1023 ****
    FOR_EACH_DEFINED_FUNCTION (node)
      if ((node->symbol.externally_visible && !DECL_COMDAT (node->symbol.decl))
          && node->local.finalized)
!       cgraph_mark_needed_node (node);
    FOR_EACH_DEFINED_VARIABLE (vnode)
      if (vnode->symbol.externally_visible && !DECL_COMDAT (vnode->symbol.decl))
        varpool_mark_needed_node (vnode);
--- 1025,1031 ----
    FOR_EACH_DEFINED_FUNCTION (node)
      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);
Index: trans-mem.c
===================================================================
*** trans-mem.c	(revision 186597)
--- trans-mem.c	(working copy)
*************** tm_mangle (tree old_asm_id)
*** 4267,4275 ****
  }
  
  static inline void
! ipa_tm_mark_needed_node (struct cgraph_node *node)
  {
!   cgraph_mark_needed_node (node);
    /* ??? function_and_variable_visibility will reset
       the needed bit, without actually checking.  */
    node->analyzed = 1;
--- 4267,4275 ----
  }
  
  static inline void
! ipa_tm_mark_force_output_node (struct cgraph_node *node)
  {
!   cgraph_mark_force_output_node (node);
    /* ??? function_and_variable_visibility will reset
       the needed bit, without actually checking.  */
    node->analyzed = 1;
*************** ipa_tm_create_version_alias (struct cgra
*** 4328,4335 ****
  
    record_tm_clone_pair (old_decl, new_decl);
  
!   if (info->old_node->needed)
!     ipa_tm_mark_needed_node (new_node);
    return false;
  }
  
--- 4328,4335 ----
  
    record_tm_clone_pair (old_decl, new_decl);
  
!   if (info->old_node->symbol.force_output)
!     ipa_tm_mark_force_output_node (new_node);
    return false;
  }
  
*************** ipa_tm_create_version (struct cgraph_nod
*** 4381,4388 ****
    record_tm_clone_pair (old_decl, new_decl);
  
    cgraph_call_function_insertion_hooks (new_node);
!   if (old_node->needed)
!     ipa_tm_mark_needed_node (new_node);
  
    /* Do the same thing, but for any aliases of the original node.  */
    {
--- 4381,4388 ----
    record_tm_clone_pair (old_decl, new_decl);
  
    cgraph_call_function_insertion_hooks (new_node);
!   if (old_node->symbol.force_output)
!     ipa_tm_mark_force_output_node (new_node);
  
    /* Do the same thing, but for any aliases of the original node.  */
    {
Index: gimple-fold.c
===================================================================
*** gimple-fold.c	(revision 186597)
--- gimple-fold.c	(working copy)
*************** can_refer_decl_in_current_unit_p (tree d
*** 70,75 ****
--- 70,76 ----
  	 flags incorrectly.  Those variables should never
  	 be finalized.  */
        gcc_checking_assert (!(vnode = varpool_get_node (decl))
+ 			   || vnode->alias
  			   || !vnode->finalized);
        return false;
      }
Index: lto/lto-partition.c
===================================================================
*** lto/lto-partition.c	(revision 186597)
--- lto/lto-partition.c	(working copy)
*************** partition_cgraph_node_p (struct cgraph_n
*** 269,274 ****
--- 269,275 ----
    /* Extern inlines and comdat are always only in partitions they are needed.  */
    if (DECL_EXTERNAL (node->symbol.decl)
        || (DECL_COMDAT (node->symbol.decl)
+ 	  && !node->symbol.force_output
  	  && !cgraph_used_from_object_file_p (node)))
      return false;
    if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
*************** partition_varpool_node_p (struct varpool
*** 287,293 ****
    /* Constant pool and comdat are always only in partitions they are needed.  */
    if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
        || (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->force_output
  	  && !varpool_used_from_object_file_p (vnode)))
      return false;
    if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
--- 288,294 ----
    /* Constant pool and comdat are always only in partitions they are needed.  */
    if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)
        || (DECL_COMDAT (vnode->symbol.decl)
! 	  && !vnode->symbol.force_output
  	  && !varpool_used_from_object_file_p (vnode)))
      return false;
    if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl)))
Index: varasm.c
===================================================================
*** varasm.c	(revision 186597)
--- varasm.c	(working copy)
*************** mark_decl_referenced (tree decl)
*** 2249,2255 ****
        struct cgraph_node *node = cgraph_get_create_node (decl);
        if (!DECL_EXTERNAL (decl)
  	  && !node->local.finalized)
! 	cgraph_mark_needed_node (node);
      }
    else if (TREE_CODE (decl) == VAR_DECL)
      {
--- 2249,2255 ----
        struct cgraph_node *node = cgraph_get_create_node (decl);
        if (!DECL_EXTERNAL (decl)
  	  && !node->local.finalized)
! 	cgraph_mark_force_output_node (node);
      }
    else if (TREE_CODE (decl) == VAR_DECL)
      {
*************** mark_decl_referenced (tree decl)
*** 2257,2263 ****
        varpool_mark_needed_node (node);
        /* C++ frontend use mark_decl_references to force COMDAT variables
           to be output that might appear dead otherwise.  */
!       node->force_output = true;
      }
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
--- 2257,2263 ----
        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;
      }
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
*************** weak_finish_1 (tree decl)
*** 5271,5283 ****
  #endif
  }
  
  /* This TREE_LIST contains weakref targets.  */
  
  static GTY(()) tree weakref_targets;
  
- /* Forward declaration.  */
- static tree find_decl_and_mark_needed (tree decl, tree target);
- 
  /* Emit any pending weak declarations.  */
  
  void
--- 5271,5290 ----
  #endif
  }
  
+ /* Fiven an assembly name, find the decl it is associated with.  */
+ static tree
+ find_decl (tree target)
+ {
+   symtab_node node = symtab_node_for_asm (target);
+   if (node)
+     return node->symbol.decl;
+   return NULL_TREE;
+ }
+ 
  /* This TREE_LIST contains weakref targets.  */
  
  static GTY(()) tree weakref_targets;
  
  /* Emit any pending weak declarations.  */
  
  void
*************** weak_finish (void)
*** 5303,5309 ****
  # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
  	  ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
  # else
! 	  tree decl = find_decl_and_mark_needed (alias_decl, target);
  
  	  if (! decl)
  	    {
--- 5310,5316 ----
  # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
  	  ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
  # else
! 	  tree decl = find_decl (target);
  
  	  if (! decl)
  	    {
*************** globalize_decl (tree decl)
*** 5406,5448 ****
  
  VEC(alias_pair,gc) *alias_pairs;
  
- /* Given an assembly name, find the decl it is associated with.  At the
-    same time, mark it needed for cgraph.  */
- 
- static tree
- find_decl_and_mark_needed (tree decl, tree target)
- {
-   struct cgraph_node *fnode = NULL;
-   struct varpool_node *vnode = NULL;
- 
-   if (TREE_CODE (decl) == FUNCTION_DECL)
-     {
-       fnode = cgraph_node_for_asm (target);
-       if (fnode == NULL)
- 	vnode = varpool_node_for_asm (target);
-     }
-   else
-     {
-       vnode = varpool_node_for_asm (target);
-       if (vnode == NULL)
- 	fnode = cgraph_node_for_asm (target);
-     }
- 
-   if (fnode)
-     {
-       cgraph_mark_needed_node (fnode);
-       return fnode->symbol.decl;
-     }
-   else if (vnode)
-     {
-       varpool_mark_needed_node (vnode);
-       vnode->force_output = 1;
-       return vnode->symbol.decl;
-     }
-   else
-     return NULL_TREE;
- }
- 
  /* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
     or ASM_OUTPUT_DEF_FROM_DECLS.  The function defines the symbol whose
     tree node is DECL to have the value of the tree node TARGET.  */
--- 5413,5418 ----
*************** finish_aliases_1 (void)
*** 5748,5754 ****
      {
        tree target_decl;
  
!       target_decl = find_decl_and_mark_needed (p->decl, p->target);
        if (target_decl == NULL)
  	{
  	  if (symbol_alias_set_contains (defined, p->target))
--- 5718,5724 ----
      {
        tree target_decl;
  
!       target_decl = find_decl (p->target);
        if (target_decl == NULL)
  	{
  	  if (symbol_alias_set_contains (defined, p->target))
*************** assemble_alias (tree decl, tree target)
*** 5854,5860 ****
    /* If the target has already been emitted, we don't have to queue the
       alias.  This saves a tad of memory.  */
    if (cgraph_global_info_ready)
!     target_decl = find_decl_and_mark_needed (decl, target);
    else
      target_decl= NULL;
    if (target_decl && TREE_ASM_WRITTEN (target_decl))
--- 5824,5830 ----
    /* If the target has already been emitted, we don't have to queue the
       alias.  This saves a tad of memory.  */
    if (cgraph_global_info_ready)
!     target_decl = find_decl (target);
    else
      target_decl= NULL;
    if (target_decl && TREE_ASM_WRITTEN (target_decl))
*************** dump_tm_clone_pairs (VEC(tm_alias_pair,h
*** 5960,5971 ****
  	 TM_GETTMCLONE.  If neither of these are true, we didn't generate
  	 a clone, and we didn't call it indirectly... no sense keeping it
  	 in the clone table.  */
!       if (!dst_n || !dst_n->needed)
  	continue;
  
        /* This covers the case where we have optimized the original
  	 function away, and only access the transactional clone.  */
!       if (!src_n || !src_n->needed)
  	continue;
  
        if (!switched)
--- 5930,5941 ----
  	 TM_GETTMCLONE.  If neither of these are true, we didn't generate
  	 a clone, and we didn't call it indirectly... no sense keeping it
  	 in the clone table.  */
!       if (!dst_n || !dst_n->symbol.address_taken)
  	continue;
  
        /* This covers the case where we have optimized the original
  	 function away, and only access the transactional clone.  */
!       if (!src_n || !src_n->symbol.address_taken)
  	continue;
  
        if (!switched)
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 186597)
--- tree-inline.c	(working copy)
*************** copy_bb (copy_body_data *id, basic_block
*** 1755,1761 ****
  		     producing dead clone (for further cloning).  In all
  		     other cases we hit a bug (incorrect node sharing is the
  		     most common reason for missing edges).  */
! 		  gcc_assert (dest->needed || !dest->analyzed
  			      || dest->symbol.address_taken
  		  	      || !id->src_node->analyzed
  			      || !id->dst_node->analyzed);
--- 1755,1761 ----
  		     producing dead clone (for further cloning).  In all
  		     other cases we hit a bug (incorrect node sharing is the
  		     most common reason for missing edges).  */
! 		  gcc_assert (!dest->analyzed
  			      || dest->symbol.address_taken
  		  	      || !id->src_node->analyzed
  			      || !id->dst_node->analyzed);
Index: symtab.c
===================================================================
*** symtab.c	(revision 186619)
--- symtab.c	(working copy)
*************** dump_symtab_base (FILE *f, symtab_node n
*** 378,383 ****
--- 378,385 ----
      fprintf (f, " in_other_partition");
    if (node->symbol.used_from_other_partition)
      fprintf (f, " used_from_other_partition");
+   if (node->symbol.force_output)
+     fprintf (f, " force_output");
    if (node->symbol.resolution != LDPR_UNKNOWN)
      fprintf (f, " %s",
   	     ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]);
Index: tree-ssa-structalias.c
===================================================================
*** tree-ssa-structalias.c	(revision 186597)
--- tree-ssa-structalias.c	(working copy)
*************** ipa_pta_execute (void)
*** 6928,6934 ****
  	 constraints for parameters.  */
        if (node->symbol.used_from_other_partition
  	  || node->symbol.externally_visible
! 	  || node->needed)
  	{
  	  intra_create_variable_infos ();
  
--- 6928,6934 ----
  	 constraints for parameters.  */
        if (node->symbol.used_from_other_partition
  	  || node->symbol.externally_visible
! 	  || node->symbol.force_output)
  	{
  	  intra_create_variable_infos ();
  
Index: passes.c
===================================================================
*** passes.c	(revision 186597)
--- passes.c	(working copy)
*************** execute_todo (unsigned int flags)
*** 1865,1871 ****
    if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl)
      {
        gcc_assert (!cfun);
!       dump_cgraph (dump_file);
        /* Flush the file.  If verification fails, we won't be able to
  	 close the file before aborting.  */
        fflush (dump_file);
--- 1865,1871 ----
    if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl)
      {
        gcc_assert (!cfun);
!       dump_symtab (dump_file);
        /* Flush the file.  If verification fails, we won't be able to
  	 close the file before aborting.  */
        fflush (dump_file);
Index: varpool.c
===================================================================
*** varpool.c	(revision 186597)
--- varpool.c	(working copy)
*************** bool
*** 214,220 ****
  decide_is_variable_needed (struct varpool_node *node, tree decl)
  {
    /* If the user told us it is used, then it must be so.  */
!   if (node->force_output)
      return true;
  
    gcc_assert (!DECL_EXTERNAL (decl));
--- 214,220 ----
  decide_is_variable_needed (struct varpool_node *node, tree decl)
  {
    /* If the user told us it is used, then it must be so.  */
!   if (node->symbol.force_output)
      return true;
  
    gcc_assert (!DECL_EXTERNAL (decl));
*************** varpool_finalize_decl (tree decl)
*** 298,304 ****
  	 optimizing and when not doing toplevel reoder.  */
        || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
  	  && !DECL_ARTIFICIAL (node->symbol.decl)))
!     node->force_output = true;
  
    if (decide_is_variable_needed (node, decl))
      varpool_mark_needed_node (node);
--- 298,304 ----
  	 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);
*************** varpool_analyze_pending_decls (void)
*** 410,415 ****
--- 410,416 ----
  		    }
  		}
  	    }
+    	  varpool_mark_needed_node (tgt);
  	}
        else if (DECL_INITIAL (decl))
  	record_references_in_initializer (decl, analyzed);
*************** varpool_create_variable_alias (tree alia
*** 621,628 ****
    gcc_assert (TREE_CODE (alias) == VAR_DECL);
    alias_node = varpool_node (alias);
    alias_node->alias = 1;
!   if (!DECL_EXTERNAL (alias))
!     alias_node->finalized = 1;
    alias_node->alias_of = decl;
    if ((!DECL_EXTERNAL (alias)
         && decide_is_variable_needed (alias_node, alias))
--- 622,628 ----
    gcc_assert (TREE_CODE (alias) == VAR_DECL);
    alias_node = varpool_node (alias);
    alias_node->alias = 1;
!   alias_node->finalized = 1;
    alias_node->alias_of = decl;
    if ((!DECL_EXTERNAL (alias)
         && decide_is_variable_needed (alias_node, alias))


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