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]

Fix for ipa-cp and ipa-pure-const for recursive functions


Hi,
there is bug in cgraph_create_virtual_clone wrt self recursive
functions.  The function takes as argument list of edges to redirect;
it first produces the clone and later redirect the edges.  Problem is
that by clonning the edges are duplicates and thus calls in the clone
itself are not updated.

While writting testcase I also run into bug in ipa-pure-const that do
consider self recursive functions as const (and later we remove them in
DCE) because self recursive functions are not forming SCC components.

Fixed both, both problems are demonstrated by testcase attached.

Bootstrapped/regtested x86_64-linux, but with additional patches in
tree, so I am retesting now and will commit if it passes.

Honza
	* cgraph.c (cgraph_clone_node): Add redirect_callers parameter.
	(cgraph_create_virtual_clone): Just pass redirect_callers
	around.
	* cgraph.h (cgraph_clone_node): Update prototype.
	* ipa-pure-const.c (self_recursive_p): New function.
	(propagate): Use it.
	* ipa-inline.c (cgraph_clone_inlined_nodes,
	* cgraph_decide_recursive_inlining): Update.
	* gcc.dg/tree-ssa/ipa-cp-1.c: New testcase.
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 152276)
--- cgraph.c	(working copy)
*************** cgraph_clone_edge (struct cgraph_edge *e
*** 1656,1666 ****
     by node.  */
  struct cgraph_node *
  cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
! 		   int loop_nest, bool update_original)
  {
    struct cgraph_node *new_node = cgraph_create_node ();
    struct cgraph_edge *e;
    gcov_type count_scale;
  
    new_node->decl = n->decl;
    new_node->origin = n->origin;
--- 1656,1668 ----
     by node.  */
  struct cgraph_node *
  cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
! 		   int loop_nest, bool update_original,
! 		   VEC(cgraph_edge_p,heap) *redirect_callers)
  {
    struct cgraph_node *new_node = cgraph_create_node ();
    struct cgraph_edge *e;
    gcov_type count_scale;
+   unsigned i;
  
    new_node->decl = n->decl;
    new_node->origin = n->origin;
*************** cgraph_clone_node (struct cgraph_node *n
*** 1691,1696 ****
--- 1693,1706 ----
  	n->count = 0;
      }
  
+   for (i = 0; VEC_iterate (cgraph_edge_p, redirect_callers, i, e); i++)
+     {
+       /* Redirect calls to the old version node to point to its new
+ 	 version.  */
+       cgraph_redirect_edge_callee (e, new_node);
+     }
+ 
+ 
    for (e = n->callees;e; e=e->next_callee)
      cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
  		       update_original);
*************** cgraph_create_virtual_clone (struct cgra
*** 1744,1751 ****
    struct cgraph_node *new_node = NULL;
    tree new_decl;
    struct cgraph_node key, **slot;
-   unsigned i;
-   struct cgraph_edge *e;
  
    gcc_assert  (tree_versionable_function_p (old_decl));
  
--- 1754,1759 ----
*************** cgraph_create_virtual_clone (struct cgra
*** 1762,1768 ****
    SET_DECL_RTL (new_decl, NULL);
  
    new_node = cgraph_clone_node (old_node, old_node->count,
!   				CGRAPH_FREQ_BASE, 0, false);
    new_node->decl = new_decl;
    /* Update the properties.
       Make clone visible only within this translation unit.  Make sure
--- 1770,1777 ----
    SET_DECL_RTL (new_decl, NULL);
  
    new_node = cgraph_clone_node (old_node, old_node->count,
! 				CGRAPH_FREQ_BASE, 0, false,
! 				redirect_callers);
    new_node->decl = new_decl;
    /* Update the properties.
       Make clone visible only within this translation unit.  Make sure
*************** cgraph_create_virtual_clone (struct cgra
*** 1821,1833 ****
        gcc_assert (!*aslot);
        *aslot = new_node;
      }
!    for (i = 0; VEC_iterate (cgraph_edge_p, redirect_callers, i, e); i++)
!      {
!        /* Redirect calls to the old version node to point to its new
! 	  version.  */
!        cgraph_redirect_edge_callee (e, new_node);
!      }
!   
    return new_node;
  }
  
--- 1830,1836 ----
        gcc_assert (!*aslot);
        *aslot = new_node;
      }
! 
    return new_node;
  }
  
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 152276)
--- cgraph.h	(working copy)
*************** struct cgraph_edge * cgraph_clone_edge (
*** 409,415 ****
  					struct cgraph_node *,
  					gimple, gcov_type, int, int, bool);
  struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int,
! 					int, bool);
  
  void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
  
--- 409,415 ----
  					struct cgraph_node *,
  					gimple, gcov_type, int, int, bool);
  struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int,
! 					int, bool, VEC(cgraph_edge_p,heap) *);
  
  void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
  
Index: testsuite/gcc.dg/tree-ssa/ipa-cp-1.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/ipa-cp-1.c	(revision 0)
--- testsuite/gcc.dg/tree-ssa/ipa-cp-1.c	(revision 0)
***************
*** 0 ****
--- 1,14 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -fdump-tree-optimized -fno-inline" } */
+ int
+ very_long_function(int a)
+ {
+   return very_long_function (a)/4;
+ }
+ main()
+ {
+   very_long_function (1);
+ }
+ /* One appereance for dump, one self recursive call and one call from main.  */
+ /* { dg-final { scan-tree-dump-times "very_long_function.clone.0 \\(\\)" 3 "optimized"} } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: ipa-pure-const.c
===================================================================
*** ipa-pure-const.c	(revision 152276)
--- ipa-pure-const.c	(working copy)
*************** ignore_edge (struct cgraph_edge *e)
*** 688,693 ****
--- 688,705 ----
    return (!e->can_throw_external);
  }
  
+ /* Return true if NODE is self recursive function.  */
+ 
+ static bool
+ self_recursive_p (struct cgraph_node *node)
+ {
+   struct cgraph_edge *e;
+   for (e = node->callees; e; e = e->next_callee)
+     if (e->callee == node)
+       return true;
+   return false;
+ }
+ 
  /* Produce the global information by preforming a transitive closure
     on the local information that was produced by generate_summary.
     Note that there is no function_transform pass since this only
*************** propagate (void)
*** 776,781 ****
--- 788,795 ----
  	  if (w_l->state_previously_known != IPA_NEITHER
  	      && this_state > w_l->state_previously_known)
              this_state = w_l->state_previously_known;
+ 	  if (!this_looping && self_recursive_p (w))
+ 	    this_looping = true;
  	  if (!w_l->looping_previously_known)
  	    this_looping = false;
  
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 152276)
--- ipa-inline.c	(working copy)
*************** cgraph_clone_inlined_nodes (struct cgrap
*** 238,244 ****
  	{
  	  struct cgraph_node *n;
  	  n = cgraph_clone_node (e->callee, e->count, e->frequency, e->loop_nest, 
! 				 update_original);
  	  cgraph_redirect_edge_callee (e, n);
  	}
      }
--- 238,244 ----
  	{
  	  struct cgraph_node *n;
  	  n = cgraph_clone_node (e->callee, e->count, e->frequency, e->loop_nest, 
! 				 update_original, NULL);
  	  cgraph_redirect_edge_callee (e, n);
  	}
      }
*************** cgraph_decide_recursive_inlining (struct
*** 723,729 ****
  	     cgraph_node_name (node));
  
    /* We need original clone to copy around.  */
!   master_clone = cgraph_clone_node (node, node->count, CGRAPH_FREQ_BASE, 1, false);
    master_clone->needed = true;
    for (e = master_clone->callees; e; e = e->next_callee)
      if (!e->inline_failed)
--- 723,730 ----
  	     cgraph_node_name (node));
  
    /* We need original clone to copy around.  */
!   master_clone = cgraph_clone_node (node, node->count, CGRAPH_FREQ_BASE, 1,
!   				    false, NULL);
    master_clone->needed = true;
    for (e = master_clone->callees; e; e = e->next_callee)
      if (!e->inline_failed)


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