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]

[pretty-ipa] IPA clones reorg


Hi,
this patch changes datastructure of handling cgraph clones from flat list
assuming that all clones are equal and are inline clones to a tree of clones.
The trees will allow implementing IPA-CP clonning so we can have constant
propagation clone done by IPA-CP and later inliner derrive inline clones from
it.  This is not implemented yet by the patch and will need more infrastructure
in passmanager, compilation driver and also few places still assume that tree
has depth 2.

Bootstrapped/regtested x86_64-linux, commiting to pretty-ipa

Honza

	* cgraph.c (cgraph_remove_node): Handle clones tree.
	(cgraph_clone_node): Create clone tree.
	(cgraph_function_body_availability): Fixup comment.
	* cgraph.h (cgraph_node): Add clone tree.
	* cgraphunit.c (verify_cgraph_node): Verify clone tree.
	(cgraph_preserve_function_body_p): Use clone tree.
	(save_inline_function_body): Redirect clone tree to new copy.
	* ipa.c (cgraph_remove_unreachable_nodes): Check clone childs.
	* tree-inline.c (copy_bb): Likewise.
	* ipa-struct-reorg.c (do_reorg_1): Likewise.
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 141945)
--- cgraph.c	(working copy)
*************** cgraph_remove_node (struct cgraph_node *
*** 975,988 ****
    slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
    if (*slot == node)
      {
!       if (node->next_clone)
!       {
! 	struct cgraph_node *new_node = node->next_clone;
! 	struct cgraph_node *n;
! 
! 	*slot = new_node;
! 	node->next_clone->prev_clone = NULL;
!       }
        else
  	{
  	  htab_clear_slot (cgraph_hash, slot);
--- 975,1006 ----
    slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
    if (*slot == node)
      {
!       gcc_assert (!node->clone_of);
!       gcc_assert (!node->next_sibling_clone);
!       if (node->clones)
! 	{
! 	  struct cgraph_node *new_node = node->clones;
! 	  struct cgraph_node *n;
! 
! 	  *slot = new_node;
! 	  if (new_node->next_sibling_clone)
! 	    {
! 	      n = new_node->next_sibling_clone;
! 	      while (n->next_sibling_clone)
! 		{
! 		  n->clone_of = new_node;
! 		  n = n->next_sibling_clone;
! 		}
! 	      n->clone_of = new_node;
! 	      if (new_node->clones)
! 	        new_node->clones->prev_sibling_clone = n;
! 	      n->next_sibling_clone = new_node->clones;
! 	      new_node->clones = new_node->next_sibling_clone;
! 	      new_node->next_sibling_clone->prev_sibling_clone = NULL;
! 	      new_node->next_sibling_clone = NULL;
! 	    }
! 	  new_node->clone_of = NULL;
! 	}
        else
  	{
  	  htab_clear_slot (cgraph_hash, slot);
*************** cgraph_remove_node (struct cgraph_node *
*** 991,999 ****
      }
    else
      {
!       node->prev_clone->next_clone = node->next_clone;
!       if (node->next_clone)
! 	node->next_clone->prev_clone = node->prev_clone;
      }
  
    /* While all the clones are removed after being proceeded, the function
--- 1009,1032 ----
      }
    else
      {
!       gcc_assert (node->clone_of);
!       if (node->prev_sibling_clone)
!         node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
!       else if (node->clone_of)
!         node->clone_of->clones = node->next_sibling_clone;
!       if (node->next_sibling_clone)
!         node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
!       if (node->clones)
! 	{
! 	  struct cgraph_node *n;
! 	  for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone)
! 	    n->clone_of = node->clone_of;
! 	  n->clone_of = node->clone_of;
! 	  n->next_sibling_clone = node->clone_of->clones;
! 	  if (node->clone_of->clones)
! 	    node->clone_of->clones->prev_sibling_clone = n;
! 	  node->clone_of->clones = node->clones;
! 	}
      }
  
    /* While all the clones are removed after being proceeded, the function
*************** cgraph_remove_node (struct cgraph_node *
*** 1003,1009 ****
    if (!kill_body && *slot)
      {
        struct cgraph_node *n = (struct cgraph_node *) *slot;
!       if (!n->next_clone && !n->global.inlined_to
  	  && (cgraph_global_info_ready
  	      && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl))))
  	kill_body = true;
--- 1036,1042 ----
    if (!kill_body && *slot)
      {
        struct cgraph_node *n = (struct cgraph_node *) *slot;
!       if (!n->clones && !n->clone_of && !n->global.inlined_to
  	  && (cgraph_global_info_ready
  	      && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl))))
  	kill_body = true;
*************** cgraph_clone_node (struct cgraph_node *n
*** 1364,1374 ****
      cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
  		       update_original);
  
!   new_node->next_clone = n->next_clone;
!   new_node->prev_clone = n;
!   n->next_clone = new_node;
!   if (new_node->next_clone)
!     new_node->next_clone->prev_clone = new_node;
  
    cgraph_call_node_duplication_hooks (n, new_node);
    return new_node;
--- 1397,1407 ----
      cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
  		       update_original);
  
!   new_node->next_sibling_clone = n->clones;
!   if (n->clones)
!     n->clones->prev_sibling_clone = new_node;
!   n->clones = new_node;
!   new_node->clone_of = n;
  
    cgraph_call_node_duplication_hooks (n, new_node);
    return new_node;
*************** cgraph_function_body_availability (struc
*** 1414,1425 ****
  
       ??? Does the C++ one definition rule allow us to always return
       AVAIL_AVAILABLE here?  That would be good reason to preserve this
!      hook Similarly deal with extern inline functions - this is again
!      necessary to get C++ shared functions having keyed templates
!      right and in the C extension documentation we probably should
!      document the requirement of both versions of function (extern
!      inline and offline) having same side effect characteristics as
!      good optimization is what this optimization is about.  */
  
    else if (!(*targetm.binds_local_p) (node->decl)
  	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
--- 1447,1453 ----
  
       ??? Does the C++ one definition rule allow us to always return
       AVAIL_AVAILABLE here?  That would be good reason to preserve this
!      bit.  */
  
    else if (!(*targetm.binds_local_p) (node->decl)
  	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 141945)
--- cgraph.h	(working copy)
*************** struct cgraph_node GTY((chain_next ("%h.
*** 147,154 ****
    /* Pointer to the next function in cgraph_nodes_queue.  */
    struct cgraph_node *next_needed;
    /* Pointer to the next clone.  */
!   struct cgraph_node *next_clone;
!   struct cgraph_node *prev_clone;
    /* For functions with many calls sites it holds map from call expression
       to the edge to speed up cgraph_edge function.  */
    htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
--- 147,156 ----
    /* Pointer to the next function in cgraph_nodes_queue.  */
    struct cgraph_node *next_needed;
    /* Pointer to the next clone.  */
!   struct cgraph_node *next_sibling_clone;
!   struct cgraph_node *prev_sibling_clone;
!   struct cgraph_node *clones;
!   struct cgraph_node *clone_of;
    /* For functions with many calls sites it holds map from call expression
       to the edge to speed up cgraph_edge function.  */
    htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 141945)
--- cgraphunit.c	(working copy)
*************** void
*** 553,559 ****
  verify_cgraph_node (struct cgraph_node *node)
  {
    struct cgraph_edge *e;
-   struct cgraph_node *main_clone;
    struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl);
    struct function *saved_cfun = cfun;
    basic_block this_block;
--- 553,558 ----
*************** verify_cgraph_node (struct cgraph_node *
*** 628,643 ****
        error_found = true;
      }
  
-   for (main_clone = cgraph_node (node->decl); main_clone;
-        main_clone = main_clone->next_clone)
-     if (main_clone == node)
-       break;
    if (!cgraph_node (node->decl))
      {
        error ("node not found in cgraph_hash");
        error_found = true;
      }
  
    if (node->analyzed
        && !TREE_ASM_WRITTEN (node->decl)
        && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
--- 627,678 ----
        error_found = true;
      }
  
    if (!cgraph_node (node->decl))
      {
        error ("node not found in cgraph_hash");
        error_found = true;
      }
  
+   if (node->clone_of)
+     {
+       struct cgraph_node *n;
+       for (n = node->clone_of->clones; n; n = n->next_sibling_clone)
+         if (n == node)
+ 	  break;
+       if (!n)
+ 	{
+ 	  error ("node has wrong clone_of");
+ 	  error_found = true;
+ 	}
+     }
+   if (node->clones)
+     {
+       struct cgraph_node *n;
+       for (n = node->clones; n; n = n->next_sibling_clone)
+         if (n->clone_of != node)
+ 	  break;
+       if (n)
+ 	{
+ 	  error ("node has wrong clone list");
+ 	  error_found = true;
+ 	}
+     }
+   if ((node->prev_sibling_clone || node->next_sibling_clone) && !node->clone_of)
+     {
+        error ("node is in clone list but it is not clone");
+        error_found = true;
+     }
+   if (!node->prev_sibling_clone && node->clone_of && node->clone_of->clones != node)
+     {
+       error ("node has wrong prev_clone pointer");
+       error_found = true;
+     }
+   if (node->prev_sibling_clone && node->prev_sibling_clone->next_sibling_clone != node)
+     {
+       error ("double linked list of clones corrupted");
+       error_found = true;
+     }
+ 
    if (node->analyzed
        && !TREE_ASM_WRITTEN (node->decl)
        && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
*************** cgraph_preserve_function_body_p (tree de
*** 1214,1222 ****
  
    gcc_assert (cgraph_global_info_ready);
    /* Look if there is any clone around.  */
!   for (node = cgraph_node (decl); node; node = node->next_clone)
!     if (node->global.inlined_to)
!       return true;
    return false;
  }
  
--- 1249,1257 ----
  
    gcc_assert (cgraph_global_info_ready);
    /* Look if there is any clone around.  */
!   node = cgraph_node (decl);
!   if (node->clones)
!     return true;
    return false;
  }
  
*************** cgraph_function_versioning (struct cgrap
*** 1558,1576 ****
  struct cgraph_node *
  save_inline_function_body (struct cgraph_node *node)
  {
!   struct cgraph_node *first_clone;
  
    gcc_assert (node == cgraph_node (node->decl));
  
    cgraph_lower_function (node);
  
!   first_clone = node->next_clone;
  
    first_clone->decl = copy_node (node->decl);
-   node->next_clone = NULL;
-   first_clone->prev_clone = NULL;
    cgraph_insert_node_to_hashtable (first_clone);
    gcc_assert (first_clone == cgraph_node (first_clone->decl));
  
    /* Copy the OLD_VERSION_NODE function tree to the new version.  */
    tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL);
--- 1593,1624 ----
  struct cgraph_node *
  save_inline_function_body (struct cgraph_node *node)
  {
!   struct cgraph_node *first_clone, *n;
  
    gcc_assert (node == cgraph_node (node->decl));
  
    cgraph_lower_function (node);
  
!   first_clone = node->clones;
  
    first_clone->decl = copy_node (node->decl);
    cgraph_insert_node_to_hashtable (first_clone);
    gcc_assert (first_clone == cgraph_node (first_clone->decl));
+   if (first_clone->next_sibling_clone)
+     {
+       for (n = first_clone->next_sibling_clone; n->next_sibling_clone; n = n->next_sibling_clone)
+         n->clone_of = first_clone;
+       n->clone_of = first_clone;
+       n->next_sibling_clone = first_clone->clones;
+       if (first_clone->clones)
+         first_clone->clones->prev_sibling_clone = n;
+       first_clone->clones = first_clone->next_sibling_clone;
+       first_clone->next_sibling_clone->prev_sibling_clone = NULL;
+       first_clone->next_sibling_clone = NULL;
+       gcc_assert (!first_clone->prev_sibling_clone);
+     }
+   first_clone->clone_of = NULL;
+   node->clones = NULL;
  
    /* Copy the OLD_VERSION_NODE function tree to the new version.  */
    tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL);
*************** save_inline_function_body (struct cgraph
*** 1580,1586 ****
    TREE_PUBLIC (first_clone->decl) = 0;
    DECL_COMDAT (first_clone->decl) = 0;
  
!   for (node = first_clone->next_clone; node; node = node->next_clone)
      node->decl = first_clone->decl;
  #ifdef ENABLE_CHECKING
    verify_cgraph_node (first_clone);
--- 1628,1634 ----
    TREE_PUBLIC (first_clone->decl) = 0;
    DECL_COMDAT (first_clone->decl) = 0;
  
!   for (node = first_clone->clones; node; node = node->next_sibling_clone)
      node->decl = first_clone->decl;
  #ifdef ENABLE_CHECKING
    verify_cgraph_node (first_clone);
Index: ipa.c
===================================================================
*** ipa.c	(revision 141945)
--- ipa.c	(working copy)
*************** cgraph_remove_unreachable_nodes (bool be
*** 174,181 ****
  		{
  		  struct cgraph_node *clone;
  
! 		  for (clone = node->next_clone; clone;
! 		       clone = clone->next_clone)
  		    if (clone->aux)
  		      break;
  		  if (!clone)
--- 174,181 ----
  		{
  		  struct cgraph_node *clone;
  
! 		  for (clone = node->clones; clone;
! 		       clone = clone->next_sibling_clone)
  		    if (clone->aux)
  		      break;
  		  if (!clone)
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 141945)
--- tree-inline.c	(working copy)
*************** copy_bb (copy_body_data *id, basic_block
*** 1392,1400 ****
  		break;
  
  	      case CB_CGE_MOVE_CLONES:
! 		for (node = id->dst_node->next_clone;
  		    node;
! 		    node = node->next_clone)
  		  {
  		    edge = cgraph_edge (node, orig_stmt);
  			  if (edge)
--- 1392,1400 ----
  		break;
  
  	      case CB_CGE_MOVE_CLONES:
! 		for (node = id->dst_node->clones;
  		    node;
! 		    node = node->next_sibling_clone)
  		  {
  		    edge = cgraph_edge (node, orig_stmt);
  			  if (edge)
Index: ipa-struct-reorg.c
===================================================================
*** ipa-struct-reorg.c	(revision 141945)
--- ipa-struct-reorg.c	(working copy)
*************** do_reorg_1 (void)
*** 3632,3638 ****
    bitmap_obstack_initialize (NULL);
  
    for (node = cgraph_nodes; node; node = node->next)
!     if (node->analyzed && node->decl && !node->next_clone)
        {
  	push_cfun (DECL_STRUCT_FUNCTION (node->decl));
  	current_function_decl = node->decl;
--- 3632,3638 ----
    bitmap_obstack_initialize (NULL);
  
    for (node = cgraph_nodes; node; node = node->next)
!     if (node->analyzed && node->decl)
        {
  	push_cfun (DECL_STRUCT_FUNCTION (node->decl));
  	current_function_decl = node->decl;
*************** collect_data_accesses (void)
*** 3800,3807 ****
  	{
  	  struct function *func = DECL_STRUCT_FUNCTION (c_node->decl);
  
! 	  if (!c_node->next_clone)
! 	    collect_accesses_in_func (func);
  	  exclude_alloc_and_field_accs (c_node);
  	}
      }
--- 3800,3806 ----
  	{
  	  struct function *func = DECL_STRUCT_FUNCTION (c_node->decl);
  
! 	  collect_accesses_in_func (func);
  	  exclude_alloc_and_field_accs (c_node);
  	}
      }


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