Cgraph alias reorg 19/14 (inline functions called once through alias)

Jan Hubicka hubicka@ucw.cz
Mon Jun 13 10:51:00 GMT 2011


Hi,
tramp3d and some other benchmarks regressed as a result of switch to new
represnetaiton of same body aliases.  The reason is that inliner doesn't handle
functions with aliases so well as it used to.  The problems are:
1) functions with aliases are not inlined when called once
2) we now have more same comdat groups and inliner never removed offline copy of such functions
3) early inlinining is weaker since topological sort ignore aliases.

This patch fixes 1)

Bootstrapped/regtested x86_64-linux, comitted.

Honza

	* cgraph.c (cgraph_for_node_thunks_and_aliases,
	cgraph_for_node_and_aliases): Fix thinko in recursive walking.
	(nonremovable_p): New function.
	(cgraph_can_remove_if_no_direct_calls_p): New function.
	(used_from_object_file_p): New functoin.
	(cgraph_will_be_removed_from_program_if_no_direct_calls): Look for references
	from aliases.
	* cgraph.h (cgraph_can_remove_if_no_direct_calls_p): Bring offline.
	* ipa-inline.c (check_caller_edge): New function.
	(want_inline_function_called_once_p): Use it; accept aliases called once, too.
	* ipa-inline-analysis.c (do_estimate_growth): Remove FIXME.

Index: cgraph.c
===================================================================
*** cgraph.c	(revision 174958)
--- cgraph.c	(working copy)
*************** cgraph_for_node_thunks_and_aliases (stru
*** 2567,2580 ****
      if (e->caller->thunk.thunk_p
  	&& (include_overwritable
  	    || cgraph_function_body_availability (e->caller)))
!       cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
    for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
      if (ref->use == IPA_REF_ALIAS)
        {
  	struct cgraph_node *alias = ipa_ref_refering_node (ref);
  	if (include_overwritable
  	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
!           cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable);
        }
    return false;
  }
--- 2567,2584 ----
      if (e->caller->thunk.thunk_p
  	&& (include_overwritable
  	    || cgraph_function_body_availability (e->caller)))
!       if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data,
! 					      include_overwritable))
! 	return true;
    for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
      if (ref->use == IPA_REF_ALIAS)
        {
  	struct cgraph_node *alias = ipa_ref_refering_node (ref);
  	if (include_overwritable
  	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
! 	  if (cgraph_for_node_thunks_and_aliases (alias, callback, data,
! 						  include_overwritable))
! 	    return true;
        }
    return false;
  }
*************** cgraph_for_node_and_aliases (struct cgra
*** 2600,2606 ****
  	struct cgraph_node *alias = ipa_ref_refering_node (ref);
  	if (include_overwritable
  	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
!           cgraph_for_node_and_aliases (alias, callback, data, include_overwritable);
        }
    return false;
  }
--- 2604,2612 ----
  	struct cgraph_node *alias = ipa_ref_refering_node (ref);
  	if (include_overwritable
  	    || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
!           if (cgraph_for_node_and_aliases (alias, callback, data,
! 					   include_overwritable))
! 	    return true;
        }
    return false;
  }
*************** cgraph_can_remove_if_no_direct_calls_and
*** 2900,2905 ****
--- 2906,2941 ----
    return true;
  }
  
+ /* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
+ 
+ static bool
+ nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+ {
+   return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
+ }
+ 
+ /* Return true when function NODE and its aliases can be removed from callgraph
+    if all direct calls are eliminated.  */
+ 
+ bool
+ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
+ {
+   /* Extern inlines can always go, we will use the external definition.  */
+   if (DECL_EXTERNAL (node->decl))
+     return true;
+   if (node->address_taken)
+     return false;
+   return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true);
+ }
+ 
+ /* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
+ 
+ static bool
+ used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+ {
+   return cgraph_used_from_object_file_p (node);
+ }
+ 
  /* Return true when function NODE can be expected to be removed
     from program when direct calls in this compilation unit are removed.
  
*************** bool
*** 2918,2924 ****
  cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
  {
    gcc_assert (!node->global.inlined_to);
!   if (cgraph_used_from_object_file_p (node))
      return false;
    if (!in_lto_p && !flag_whole_program)
      return cgraph_only_called_directly_p (node);
--- 2954,2960 ----
  cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
  {
    gcc_assert (!node->global.inlined_to);
!   if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true))
      return false;
    if (!in_lto_p && !flag_whole_program)
      return cgraph_only_called_directly_p (node);
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 174958)
--- cgraph.h	(working copy)
*************** bool cgraph_will_be_removed_from_program
*** 535,540 ****
--- 535,541 ----
    (struct cgraph_node *node);
  bool cgraph_can_remove_if_no_direct_calls_and_refs_p
    (struct cgraph_node *node);
+ bool cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node);
  bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution);
  bool cgraph_used_from_object_file_p (struct cgraph_node *);
  bool varpool_used_from_object_file_p (struct varpool_node *);
*************** cgraph_only_called_directly_or_aliased_p
*** 926,945 ****
     if all direct calls are eliminated.  */
  
  static inline bool
- cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
- {
-   /* Extern inlines can always go, we will use the external definition.  */
-   if (DECL_EXTERNAL (node->decl))
-     return true;
-   return (!node->address_taken
- 	  && cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
- 	  && !ipa_ref_has_aliases_p (&node->ref_list));
- }
- 
- /* Return true when function NODE can be removed from callgraph
-    if all direct calls are eliminated.  */
- 
- static inline bool
  varpool_can_remove_if_no_refs (struct varpool_node *node)
  {
    return (!node->force_output && !node->used_from_other_partition
--- 927,932 ----
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 174958)
--- ipa-inline.c	(working copy)
*************** want_inline_self_recursive_call_p (struc
*** 643,648 ****
--- 643,658 ----
    return want_inline;
  }
  
+ /* Return true when NODE has caller other than EDGE. 
+    Worker for cgraph_for_node_and_aliases.  */
+ 
+ static bool
+ check_caller_edge (struct cgraph_node *node, void *edge)
+ {
+   return (node->callers
+           && node->callers != edge);
+ }
+ 
  
  /* Decide if NODE is called once inlining it would eliminate need
     for the offline copy of function.  */
*************** want_inline_self_recursive_call_p (struc
*** 650,673 ****
  static bool
  want_inline_function_called_once_p (struct cgraph_node *node)
  {
!    if (node->alias)
!      return false;
     /* Already inlined?  */
!    if (node->global.inlined_to)
       return false;
     /* Zero or more then one callers?  */
     if (!node->callers
         || node->callers->next_caller)
       return false;
     /* Recursive call makes no sense to inline.  */
!    if (node->callers->caller == node)
       return false;
     /* External functions are not really in the unit, so inlining
        them when called once would just increase the program size.  */
!    if (DECL_EXTERNAL (node->decl))
       return false;
     /* Offline body must be optimized out.  */
!    if (!cgraph_will_be_removed_from_program_if_no_direct_calls (node))
       return false;
     if (!can_inline_edge_p (node->callers, true))
       return false;
--- 660,685 ----
  static bool
  want_inline_function_called_once_p (struct cgraph_node *node)
  {
!    struct cgraph_node *function = cgraph_function_or_thunk_node (node, NULL);
     /* Already inlined?  */
!    if (function->global.inlined_to)
       return false;
     /* Zero or more then one callers?  */
     if (!node->callers
         || node->callers->next_caller)
       return false;
+    /* Maybe other aliases has more direct calls.  */
+    if (cgraph_for_node_and_aliases (node, check_caller_edge, node->callers, true))
+      return false;
     /* Recursive call makes no sense to inline.  */
!    if (cgraph_edge_recursive_p (node->callers))
       return false;
     /* External functions are not really in the unit, so inlining
        them when called once would just increase the program size.  */
!    if (DECL_EXTERNAL (function->decl))
       return false;
     /* Offline body must be optimized out.  */
!    if (!cgraph_will_be_removed_from_program_if_no_direct_calls (function))
       return false;
     if (!can_inline_edge_p (node->callers, true))
       return false;
Index: ipa-inline-analysis.c
===================================================================
*** ipa-inline-analysis.c	(revision 174958)
--- ipa-inline-analysis.c	(working copy)
*************** do_estimate_growth (struct cgraph_node *
*** 2229,2236 ****
  	  && !cgraph_will_be_removed_from_program_if_no_direct_calls (node))
  	d.growth -= info->size;
        /* COMDAT functions are very often not shared across multiple units since they
! 	 come from various template instantiations.  Take this into account.
!          FIXME: allow also COMDATs with COMDAT aliases.  */
        else  if (DECL_COMDAT (node->decl)
  		&& cgraph_can_remove_if_no_direct_calls_p (node))
  	d.growth -= (info->size
--- 2229,2235 ----
  	  && !cgraph_will_be_removed_from_program_if_no_direct_calls (node))
  	d.growth -= info->size;
        /* COMDAT functions are very often not shared across multiple units since they
! 	 come from various template instantiations.  Take this into account.  */
        else  if (DECL_COMDAT (node->decl)
  		&& cgraph_can_remove_if_no_direct_calls_p (node))
  	d.growth -= (info->size



More information about the Gcc-patches mailing list