diff mbox

PR middle-end/51737

Message ID 20120322143609.GA24576@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka March 22, 2012, 2:36 p.m. UTC
Hi,
this patch fixes (now latent) problem where save_inline_function_body blows up when
self recursive call is removed during the body duplication.

The problem reproduce on 4.6, where I will commit the patch after short stay
in mainline. The reason why the bug is latent on 4.7 seems to be the fact
that the code is much less optimized after early optimizations.  I am looking
into it.

Honza

Bootstrapped/regtested x86_64-linux, comitted.
	PR middle-end/51737
	* cgraph.c (cgraph_remove_node_and_inline_clones): Add FORBIDDEN_NODE
	parameter.
	* cgraph.h (cgraph_remove_node_and_inline_clones): Update prototype.
	* ipa-inline-transform.c (save_inline_function_body): Remove copied clone
	if needed.
	* tree-inline.c (delete_unreachable_blocks_update_callgraph): Update.

	PR middle-end/51737
	* g++.dg/torture/pr51737.C: New testcase
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 185605)
--- cgraph.c	(working copy)
*************** cgraph_add_to_same_comdat_group (struct 
*** 1639,1657 ****
      }
  }
  
! /* Remove the node from cgraph.  */
  
! void
! cgraph_remove_node_and_inline_clones (struct cgraph_node *node)
  {
    struct cgraph_edge *e, *next;
    for (e = node->callees; e; e = next)
      {
        next = e->next_callee;
        if (!e->inline_failed)
!         cgraph_remove_node_and_inline_clones (e->callee);
      }
    cgraph_remove_node (node);
  }
  
  /* Notify finalize_compilation_unit that given node is reachable.  */
--- 1639,1665 ----
      }
  }
  
! /* Remove the node from cgraph and all inline clones inlined into it.
!    Skip however removal of FORBIDDEN_NODE and return true if it needs to be
!    removed.  This allows to call the function from outer loop walking clone
!    tree.  */
  
! bool
! cgraph_remove_node_and_inline_clones (struct cgraph_node *node, struct cgraph_node *forbidden_node){
    struct cgraph_edge *e, *next;
+   bool found = false;
+ 
+   if (node == forbidden_node)
+     return true;
    for (e = node->callees; e; e = next)
      {
        next = e->next_callee;
        if (!e->inline_failed)
!         found |= cgraph_remove_node_and_inline_clones (e->callee, forbidden_node);
      }
    cgraph_remove_node (node);
+   return found;
  }
  
  /* Notify finalize_compilation_unit that given node is reachable.  */
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 185605)
--- cgraph.h	(working copy)
*************** void cgraph_insert_node_to_hashtable (st
*** 478,484 ****
  void cgraph_remove_edge (struct cgraph_edge *);
  void cgraph_remove_node (struct cgraph_node *);
  void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *);
! void cgraph_remove_node_and_inline_clones (struct cgraph_node *);
  void cgraph_release_function_body (struct cgraph_node *);
  void cgraph_node_remove_callees (struct cgraph_node *node);
  struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
--- 478,484 ----
  void cgraph_remove_edge (struct cgraph_edge *);
  void cgraph_remove_node (struct cgraph_node *);
  void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *);
! bool cgraph_remove_node_and_inline_clones (struct cgraph_node *, struct cgraph_node *);
  void cgraph_release_function_body (struct cgraph_node *);
  void cgraph_node_remove_callees (struct cgraph_node *node);
  struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
Index: ipa-inline-transform.c
===================================================================
*** ipa-inline-transform.c	(revision 185605)
--- ipa-inline-transform.c	(working copy)
*************** save_inline_function_body (struct cgraph
*** 336,343 ****
              first_clone->ipa_transforms_to_apply);
    first_clone->ipa_transforms_to_apply = NULL;
  
  #ifdef ENABLE_CHECKING
!   verify_cgraph_node (first_clone);
  #endif
    return first_clone;
  }
--- 336,354 ----
              first_clone->ipa_transforms_to_apply);
    first_clone->ipa_transforms_to_apply = NULL;
  
+   /* When doing recursive inlining, the clone may become unnecessary.
+      This is possible i.e. in the case when the recursive function is proved to be
+      non-throwing and the recursion happens only in the EH landing pad.
+      We can not remove the clone until we are done with saving the body.
+      Remove it now.  */
+   if (!first_clone->callers)
+     {
+       cgraph_remove_node_and_inline_clones (first_clone, NULL);
+       first_clone = NULL;
+     }
  #ifdef ENABLE_CHECKING
!   else
!     verify_cgraph_node (first_clone);
  #endif
    return first_clone;
  }
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 185605)
--- tree-inline.c	(working copy)
*************** delete_unreachable_blocks_update_callgra
*** 4955,4961 ****
  	        if ((e = cgraph_edge (id->dst_node, gsi_stmt (bsi))) != NULL)
  		  {
  		    if (!e->inline_failed)
! 		      cgraph_remove_node_and_inline_clones (e->callee);
  		    else
  	              cgraph_remove_edge (e);
  		  }
--- 4955,4961 ----
  	        if ((e = cgraph_edge (id->dst_node, gsi_stmt (bsi))) != NULL)
  		  {
  		    if (!e->inline_failed)
! 		      cgraph_remove_node_and_inline_clones (e->callee, id->dst_node);
  		    else
  	              cgraph_remove_edge (e);
  		  }
*************** delete_unreachable_blocks_update_callgra
*** 4965,4972 ****
  		    {
  	              if ((e = cgraph_edge (node, gsi_stmt (bsi))) != NULL)
  			{
! 		          if (!e->inline_failed)
! 		            cgraph_remove_node_and_inline_clones (e->callee);
  			  else
  	                    cgraph_remove_edge (e);
  			}
--- 4965,4972 ----
  		    {
  	              if ((e = cgraph_edge (node, gsi_stmt (bsi))) != NULL)
  			{
! 		          if (!e->inline_failed)
! 		            cgraph_remove_node_and_inline_clones (e->callee, id->dst_node);
  			  else
  	                    cgraph_remove_edge (e);
  			}
diff mbox

Patch

Index: testsuite/g++.dg/torture/pr51737.C
===================================================================
--- testsuite/g++.dg/torture/pr51737.C	(revision 0)
+++ testsuite/g++.dg/torture/pr51737.C	(revision 0)
@@ -0,0 +1,30 @@ 
+// { dg-do compile }
+template<class T> class intrusive_ptr {
+public:
+    ~intrusive_ptr() { intrusive_ptr_release( px ); }
+    T * px;
+};
+template <typename T>     struct intrusive_base     {
+    friend void intrusive_ptr_release(T* ptr) { delete ptr; }
+};
+struct section_info;
+struct file_info : intrusive_base<file_info> {
+    intrusive_ptr<file_info> parent;
+    intrusive_ptr<section_info> switched_section;
+};
+struct section_info : intrusive_base<section_info> {
+    intrusive_ptr<section_info> parent;
+};
+struct id_state {
+    void * start_file(void);
+};
+void * id_state::start_file(void) {
+    intrusive_ptr<file_info> parent;
+}
+struct id_generation_data : intrusive_base<id_generation_data> {
+    void child_length() const {}
+};
+void generate_id(id_generation_data& generation_data)
+{
+  generation_data.child_length();
+}