diff mbox series

[PR,ipa/88933] Careful CFG cleanup in IPA-CP function transformation

Message ID ri6r2d0vcal.fsf@suse.cz
State New
Headers show
Series [PR,ipa/88933] Careful CFG cleanup in IPA-CP function transformation | expand

Commit Message

Martin Jambor Jan. 25, 2019, 6:10 p.m. UTC
Hi,

the following patch fixes a verification ICE because of mismatching BB
and cgraph_edge counts arising as a consequence of cleaning-up CFG after
IPA-CP transformation, which is currently done as if it was a normal
tree pass, and which IPA passes should not attempt exaclty because of
this reason.

Fixed (hopefully) exactly as I was told by Honza in Bugzilla, by
resorting to calling delete_unreachable_blocks_update_callgraph
instead.  The aforementioned function had to be made public and in the
process was moved to a more suitable file.

Bootstrapped and tested on x86_64-linux.  OK for trunk?

Thanks,

Martin



2019-01-25  Martin Jambor  <mjambor@suse.cz>

	* tree-inline.c: Include tree-cfgcleanup.h.
	(delete_unreachable_blocks_update_callgraph): Move...
	* tree-cfgcleanup.c (delete_unreachable_blocks_update_callgraph):
	...here, make externally visible, make second argument bool, adjust
	all callers.
	* tree-cfgcleanup.c: Include cgraph.h.
	* tree-cfgcleanup.h (delete_unreachable_blocks_update_callgraph):
	Declare.
	* ipa-prop.c: Include tree-cfgcleanup.h.
	(ipcp_transform_function): Call
	delete_unreachable_blocks_update_callgraph instead of cleaning uo CFG.

	testsuite/
	* gfortran.dg/gomp/pr88933.f90: New test.
---
 gcc/ipa-prop.c                             | 10 +--
 gcc/testsuite/gfortran.dg/gomp/pr88933.f90 | 39 +++++++++++
 gcc/tree-cfgcleanup.c                      | 75 +++++++++++++++++++-
 gcc/tree-cfgcleanup.h                      |  2 +
 gcc/tree-inline.c                          | 80 ++--------------------
 5 files changed, 125 insertions(+), 81 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr88933.f90

Comments

Jan Hubicka Jan. 25, 2019, 6:36 p.m. UTC | #1
Dne 2019-01-25 19:10, Martin Jambor napsal:
> Hi,
> 
> the following patch fixes a verification ICE because of mismatching BB
> and cgraph_edge counts arising as a consequence of cleaning-up CFG 
> after
> IPA-CP transformation, which is currently done as if it was a normal
> tree pass, and which IPA passes should not attempt exaclty because of
> this reason.
> 
> Fixed (hopefully) exactly as I was told by Honza in Bugzilla, by
> resorting to calling delete_unreachable_blocks_update_callgraph
> instead.  The aforementioned function had to be made public and in the
> process was moved to a more suitable file.
> 
> Bootstrapped and tested on x86_64-linux.  OK for trunk?

OK,
Honza
> 
> Thanks,
> 
> Martin
> 
> 
> 
> 2019-01-25  Martin Jambor  <mjambor@suse.cz>
> 
> 	* tree-inline.c: Include tree-cfgcleanup.h.
> 	(delete_unreachable_blocks_update_callgraph): Move...
> 	* tree-cfgcleanup.c (delete_unreachable_blocks_update_callgraph):
> 	...here, make externally visible, make second argument bool, adjust
> 	all callers.
> 	* tree-cfgcleanup.c: Include cgraph.h.
> 	* tree-cfgcleanup.h (delete_unreachable_blocks_update_callgraph):
> 	Declare.
> 	* ipa-prop.c: Include tree-cfgcleanup.h.
> 	(ipcp_transform_function): Call
> 	delete_unreachable_blocks_update_callgraph instead of cleaning uo CFG.
> 
> 	testsuite/
> 	* gfortran.dg/gomp/pr88933.f90: New test.
> ---
>  gcc/ipa-prop.c                             | 10 +--
>  gcc/testsuite/gfortran.dg/gomp/pr88933.f90 | 39 +++++++++++
>  gcc/tree-cfgcleanup.c                      | 75 +++++++++++++++++++-
>  gcc/tree-cfgcleanup.h                      |  2 +
>  gcc/tree-inline.c                          | 80 ++--------------------
>  5 files changed, 125 insertions(+), 81 deletions(-)
>  create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr88933.f90
> 
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index 40ab130b750..d86c2f3db55 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "dbgcnt.h"
>  #include "domwalk.h"
>  #include "builtins.h"
> +#include "tree-cfgcleanup.h"
> 
>  /* Function summary where the parameter infos are actually stored. */
>  ipa_node_params_t *ipa_node_params_sum = NULL;
> @@ -5173,10 +5174,11 @@ ipcp_transform_function (struct cgraph_node 
> *node)
> 
>    if (!something_changed)
>      return 0;
> -  else if (cfg_changed)
> -    return TODO_update_ssa_only_virtuals | TODO_cleanup_cfg;
> -  else
> -    return TODO_update_ssa_only_virtuals;
> +
> +  if (cfg_changed)
> +    delete_unreachable_blocks_update_callgraph (node, false);
> +
> +  return TODO_update_ssa_only_virtuals;
>  }
> 
>  #include "gt-ipa-prop.h"
> diff --git a/gcc/testsuite/gfortran.dg/gomp/pr88933.f90
> b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90
> new file mode 100644
> index 00000000000..e4f30ae9f3e
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90
> @@ -0,0 +1,39 @@
> +! PR ipa/88933
> +! { dg-do compile }
> +! { dg-options "-O1 -fexceptions -fipa-cp -fnon-call-exceptions
> -fopenmp -fno-inline-functions-called-once" }
> +
> +!$omp parallel
> +!$omp single
> +  call a
> +!$omp end single
> +!$omp end parallel
> +contains
> +  subroutine b (c, d, e, f, g, h, i, j, k, m)
> +    character (*) c
> +    character  d
> +    integer, dimension (m) :: e
> +    integer, dimension (m) :: f
> +    character  g
> +    character  h
> +    real, dimension (:, :, :) :: i
> +    double precision, dimension (:, :, :) :: j
> +    integer, dimension (:, :, :) :: k
> +
> +    integer, dimension (m) :: l
> +!$omp task firstprivate (k) firstprivate (l)
> +    !$omp end task
> +  c = ''
> +  end
> +  subroutine a
> +    character  c
> +    character  d
> +    integer, dimension (7) :: e
> +    integer, dimension (7) :: f
> +    character g
> +    character h
> +    real, dimension (5, 6, 7) :: i
> +    double precision, dimension (6, 6, 7) :: j
> +    integer, dimension (5, 7, 6) :: k
> +    call b (c, d, e, f, g, h, i, j, k, 7)
> +  end
> +end
> diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
> index 2adb3953d6b..f2e8b96ee8e 100644
> --- a/gcc/tree-cfgcleanup.c
> +++ b/gcc/tree-cfgcleanup.c
> @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimple-match.h"
>  #include "gimple-fold.h"
>  #include "tree-ssa-loop-niter.h"
> -
> +#include "cgraph.h"
> 
>  /* The set of blocks in that at least one of the following changes 
> happened:
>     -- the statement at the end of the block was changed
> @@ -1380,3 +1380,76 @@ make_pass_cleanup_cfg_post_optimizing
> (gcc::context *ctxt)
>  }
> 
> 
> +/* Delete all unreachable basic blocks and update callgraph.
> +   Doing so is somewhat nontrivial because we need to update all 
> clones and
> +   remove inline function that become unreachable.  */
> +
> +bool
> +delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node,
> +					    bool update_clones)
> +{
> +  bool changed = false;
> +  basic_block b, next_bb;
> +
> +  find_unreachable_blocks ();
> +
> +  /* Delete all unreachable basic blocks.  */
> +
> +  for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b
> +       != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb)
> +    {
> +      next_bb = b->next_bb;
> +
> +      if (!(b->flags & BB_REACHABLE))
> +	{
> +          gimple_stmt_iterator bsi;
> +
> +          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next 
> (&bsi))
> +	    {
> +	      struct cgraph_edge *e;
> +	      struct cgraph_node *node;
> +
> +	      dst_node->remove_stmt_references (gsi_stmt (bsi));
> +
> +	      if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
> +		  &&(e = dst_node->get_edge (gsi_stmt (bsi))) != NULL)
> +		{
> +		  if (!e->inline_failed)
> +		    e->callee->remove_symbol_and_inline_clones (dst_node);
> +		  else
> +		    e->remove ();
> +		}
> +	      if (update_clones && dst_node->clones)
> +		for (node = dst_node->clones; node != dst_node;)
> +		  {
> +		    node->remove_stmt_references (gsi_stmt (bsi));
> +		    if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
> +			&& (e = node->get_edge (gsi_stmt (bsi))) != NULL)
> +		      {
> +			if (!e->inline_failed)
> +			  e->callee->remove_symbol_and_inline_clones (dst_node);
> +			else
> +			  e->remove ();
> +		      }
> +
> +		    if (node->clones)
> +		      node = node->clones;
> +		    else if (node->next_sibling_clone)
> +		      node = node->next_sibling_clone;
> +		    else
> +		      {
> +			while (node != dst_node && !node->next_sibling_clone)
> +			  node = node->clone_of;
> +			if (node != dst_node)
> +			  node = node->next_sibling_clone;
> +		      }
> +		  }
> +	    }
> +	  delete_basic_block (b);
> +	  changed = true;
> +	}
> +    }
> +
> +  return changed;
> +}
> +
> diff --git a/gcc/tree-cfgcleanup.h b/gcc/tree-cfgcleanup.h
> index e133bbdfbec..bd27505fd5c 100644
> --- a/gcc/tree-cfgcleanup.h
> +++ b/gcc/tree-cfgcleanup.h
> @@ -24,5 +24,7 @@ along with GCC; see the file COPYING3.  If not see
>  extern bitmap cfgcleanup_altered_bbs;
>  extern bool cleanup_tree_cfg (void);
>  extern bool fixup_noreturn_call (gimple *stmt);
> +extern bool delete_unreachable_blocks_update_callgraph (cgraph_node 
> *dst_node,
> +							bool update_clones);
> 
>  #endif /* GCC_TREE_CFGCLEANUP_H */
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index 29f119ade77..d8bed50d78e 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "sreal.h"
> +#include "tree-cfgcleanup.h"
> 
>  /* I'm not real happy about this, but we need to handle gimple and
>     non-gimple trees.  */
> @@ -132,7 +133,6 @@ static tree copy_decl_to_var (tree, copy_body_data 
> *);
>  static tree copy_result_decl_to_var (tree, copy_body_data *);
>  static tree copy_decl_maybe_to_var (tree, copy_body_data *);
>  static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *);
> -static bool delete_unreachable_blocks_update_callgraph (copy_body_data 
> *id);
>  static void insert_init_stmt (copy_body_data *, basic_block, gimple 
> *);
> 
>  /* Insert a tree->tree mapping for ID.  Despite the name suggests
> @@ -5123,7 +5123,8 @@ optimize_inline_calls (tree fn)
>    /* Renumber the lexical scoping (non-code) blocks consecutively.  */
>    number_blocks (fn);
> 
> -  delete_unreachable_blocks_update_callgraph (&id);
> +  delete_unreachable_blocks_update_callgraph (id.dst_node, false);
> +
>    if (flag_checking)
>      id.dst_node->verify ();
> 
> @@ -5707,79 +5708,6 @@ tree_versionable_function_p (tree fndecl)
>  	  && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL);
>  }
> 
> -/* Delete all unreachable basic blocks and update callgraph.
> -   Doing so is somewhat nontrivial because we need to update all 
> clones and
> -   remove inline function that become unreachable.  */
> -
> -static bool
> -delete_unreachable_blocks_update_callgraph (copy_body_data *id)
> -{
> -  bool changed = false;
> -  basic_block b, next_bb;
> -
> -  find_unreachable_blocks ();
> -
> -  /* Delete all unreachable basic blocks.  */
> -
> -  for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b
> -       != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb)
> -    {
> -      next_bb = b->next_bb;
> -
> -      if (!(b->flags & BB_REACHABLE))
> -	{
> -          gimple_stmt_iterator bsi;
> -
> -          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next 
> (&bsi))
> -	    {
> -	      struct cgraph_edge *e;
> -	      struct cgraph_node *node;
> -
> -	      id->dst_node->remove_stmt_references (gsi_stmt (bsi));
> -
> -	      if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
> -		  &&(e = id->dst_node->get_edge (gsi_stmt (bsi))) != NULL)
> -		{
> -		  if (!e->inline_failed)
> -		    e->callee->remove_symbol_and_inline_clones (id->dst_node);
> -		  else
> -		    e->remove ();
> -		}
> -	      if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
> -		  && id->dst_node->clones)
> -		for (node = id->dst_node->clones; node != id->dst_node;)
> -		  {
> -		    node->remove_stmt_references (gsi_stmt (bsi));
> -		    if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
> -			&& (e = node->get_edge (gsi_stmt (bsi))) != NULL)
> -		      {
> -			if (!e->inline_failed)
> -			  e->callee->remove_symbol_and_inline_clones (id->dst_node);
> -			else
> -			  e->remove ();
> -		      }
> -
> -		    if (node->clones)
> -		      node = node->clones;
> -		    else if (node->next_sibling_clone)
> -		      node = node->next_sibling_clone;
> -		    else
> -		      {
> -			while (node != id->dst_node && !node->next_sibling_clone)
> -			  node = node->clone_of;
> -			if (node != id->dst_node)
> -			  node = node->next_sibling_clone;
> -		      }
> -		  }
> -	    }
> -	  delete_basic_block (b);
> -	  changed = true;
> -	}
> -    }
> -
> -  return changed;
> -}
> -
>  /* Update clone info after duplication.  */
> 
>  static void
> @@ -6093,7 +6021,7 @@ tree_function_versioning (tree old_decl, tree 
> new_decl,
>    update_max_bb_count ();
>    fold_marked_statements (0, id.statements_to_fold);
>    delete id.statements_to_fold;
> -  delete_unreachable_blocks_update_callgraph (&id);
> +  delete_unreachable_blocks_update_callgraph (id.dst_node, 
> update_clones);
>    if (id.dst_node->definition)
>      cgraph_edge::rebuild_references ();
>    if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
diff mbox series

Patch

diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 40ab130b750..d86c2f3db55 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -52,6 +52,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "domwalk.h"
 #include "builtins.h"
+#include "tree-cfgcleanup.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -5173,10 +5174,11 @@  ipcp_transform_function (struct cgraph_node *node)
 
   if (!something_changed)
     return 0;
-  else if (cfg_changed)
-    return TODO_update_ssa_only_virtuals | TODO_cleanup_cfg;
-  else
-    return TODO_update_ssa_only_virtuals;
+
+  if (cfg_changed)
+    delete_unreachable_blocks_update_callgraph (node, false);
+
+  return TODO_update_ssa_only_virtuals;
 }
 
 #include "gt-ipa-prop.h"
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90
new file mode 100644
index 00000000000..e4f30ae9f3e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90
@@ -0,0 +1,39 @@ 
+! PR ipa/88933
+! { dg-do compile }
+! { dg-options "-O1 -fexceptions -fipa-cp -fnon-call-exceptions -fopenmp -fno-inline-functions-called-once" }
+
+!$omp parallel  
+!$omp single
+  call a
+!$omp end single
+!$omp end parallel
+contains
+  subroutine b (c, d, e, f, g, h, i, j, k, m)
+    character (*) c
+    character  d
+    integer, dimension (m) :: e
+    integer, dimension (m) :: f
+    character  g
+    character  h
+    real, dimension (:, :, :) :: i
+    double precision, dimension (:, :, :) :: j
+    integer, dimension (:, :, :) :: k
+     
+    integer, dimension (m) :: l
+!$omp task firstprivate (k) firstprivate (l)
+    !$omp end task
+  c = ''
+  end  
+  subroutine a
+    character  c
+    character  d
+    integer, dimension (7) :: e
+    integer, dimension (7) :: f
+    character g
+    character h
+    real, dimension (5, 6, 7) :: i
+    double precision, dimension (6, 6, 7) :: j
+    integer, dimension (5, 7, 6) :: k
+    call b (c, d, e, f, g, h, i, j, k, 7)
+  end  
+end
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index 2adb3953d6b..f2e8b96ee8e 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -43,7 +43,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-match.h"
 #include "gimple-fold.h"
 #include "tree-ssa-loop-niter.h"
-
+#include "cgraph.h"
 
 /* The set of blocks in that at least one of the following changes happened:
    -- the statement at the end of the block was changed
@@ -1380,3 +1380,76 @@  make_pass_cleanup_cfg_post_optimizing (gcc::context *ctxt)
 }
 
 
+/* Delete all unreachable basic blocks and update callgraph.
+   Doing so is somewhat nontrivial because we need to update all clones and
+   remove inline function that become unreachable.  */
+
+bool
+delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node,
+					    bool update_clones)
+{
+  bool changed = false;
+  basic_block b, next_bb;
+
+  find_unreachable_blocks ();
+
+  /* Delete all unreachable basic blocks.  */
+
+  for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b
+       != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb)
+    {
+      next_bb = b->next_bb;
+
+      if (!(b->flags & BB_REACHABLE))
+	{
+          gimple_stmt_iterator bsi;
+
+          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi))
+	    {
+	      struct cgraph_edge *e;
+	      struct cgraph_node *node;
+
+	      dst_node->remove_stmt_references (gsi_stmt (bsi));
+
+	      if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
+		  &&(e = dst_node->get_edge (gsi_stmt (bsi))) != NULL)
+		{
+		  if (!e->inline_failed)
+		    e->callee->remove_symbol_and_inline_clones (dst_node);
+		  else
+		    e->remove ();
+		}
+	      if (update_clones && dst_node->clones)
+		for (node = dst_node->clones; node != dst_node;)
+		  {
+		    node->remove_stmt_references (gsi_stmt (bsi));
+		    if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
+			&& (e = node->get_edge (gsi_stmt (bsi))) != NULL)
+		      {
+			if (!e->inline_failed)
+			  e->callee->remove_symbol_and_inline_clones (dst_node);
+			else
+			  e->remove ();
+		      }
+
+		    if (node->clones)
+		      node = node->clones;
+		    else if (node->next_sibling_clone)
+		      node = node->next_sibling_clone;
+		    else
+		      {
+			while (node != dst_node && !node->next_sibling_clone)
+			  node = node->clone_of;
+			if (node != dst_node)
+			  node = node->next_sibling_clone;
+		      }
+		  }
+	    }
+	  delete_basic_block (b);
+	  changed = true;
+	}
+    }
+
+  return changed;
+}
+
diff --git a/gcc/tree-cfgcleanup.h b/gcc/tree-cfgcleanup.h
index e133bbdfbec..bd27505fd5c 100644
--- a/gcc/tree-cfgcleanup.h
+++ b/gcc/tree-cfgcleanup.h
@@ -24,5 +24,7 @@  along with GCC; see the file COPYING3.  If not see
 extern bitmap cfgcleanup_altered_bbs;
 extern bool cleanup_tree_cfg (void);
 extern bool fixup_noreturn_call (gimple *stmt);
+extern bool delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node,
+							bool update_clones);
 
 #endif /* GCC_TREE_CFGCLEANUP_H */
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 29f119ade77..d8bed50d78e 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -60,6 +60,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "sreal.h"
+#include "tree-cfgcleanup.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
@@ -132,7 +133,6 @@  static tree copy_decl_to_var (tree, copy_body_data *);
 static tree copy_result_decl_to_var (tree, copy_body_data *);
 static tree copy_decl_maybe_to_var (tree, copy_body_data *);
 static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *);
-static bool delete_unreachable_blocks_update_callgraph (copy_body_data *id);
 static void insert_init_stmt (copy_body_data *, basic_block, gimple *);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
@@ -5123,7 +5123,8 @@  optimize_inline_calls (tree fn)
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (fn);
 
-  delete_unreachable_blocks_update_callgraph (&id);
+  delete_unreachable_blocks_update_callgraph (id.dst_node, false);
+
   if (flag_checking)
     id.dst_node->verify ();
 
@@ -5707,79 +5708,6 @@  tree_versionable_function_p (tree fndecl)
 	  && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL);
 }
 
-/* Delete all unreachable basic blocks and update callgraph.
-   Doing so is somewhat nontrivial because we need to update all clones and
-   remove inline function that become unreachable.  */
-
-static bool
-delete_unreachable_blocks_update_callgraph (copy_body_data *id)
-{
-  bool changed = false;
-  basic_block b, next_bb;
-
-  find_unreachable_blocks ();
-
-  /* Delete all unreachable basic blocks.  */
-
-  for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b
-       != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb)
-    {
-      next_bb = b->next_bb;
-
-      if (!(b->flags & BB_REACHABLE))
-	{
-          gimple_stmt_iterator bsi;
-
-          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi))
-	    {
-	      struct cgraph_edge *e;
-	      struct cgraph_node *node;
-
-	      id->dst_node->remove_stmt_references (gsi_stmt (bsi));
-
-	      if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
-		  &&(e = id->dst_node->get_edge (gsi_stmt (bsi))) != NULL)
-		{
-		  if (!e->inline_failed)
-		    e->callee->remove_symbol_and_inline_clones (id->dst_node);
-		  else
-		    e->remove ();
-		}
-	      if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
-		  && id->dst_node->clones)
-		for (node = id->dst_node->clones; node != id->dst_node;)
-		  {
-		    node->remove_stmt_references (gsi_stmt (bsi));
-		    if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL
-			&& (e = node->get_edge (gsi_stmt (bsi))) != NULL)
-		      {
-			if (!e->inline_failed)
-			  e->callee->remove_symbol_and_inline_clones (id->dst_node);
-			else
-			  e->remove ();
-		      }
-
-		    if (node->clones)
-		      node = node->clones;
-		    else if (node->next_sibling_clone)
-		      node = node->next_sibling_clone;
-		    else
-		      {
-			while (node != id->dst_node && !node->next_sibling_clone)
-			  node = node->clone_of;
-			if (node != id->dst_node)
-			  node = node->next_sibling_clone;
-		      }
-		  }
-	    }
-	  delete_basic_block (b);
-	  changed = true;
-	}
-    }
-
-  return changed;
-}
-
 /* Update clone info after duplication.  */
 
 static void
@@ -6093,7 +6021,7 @@  tree_function_versioning (tree old_decl, tree new_decl,
   update_max_bb_count ();
   fold_marked_statements (0, id.statements_to_fold);
   delete id.statements_to_fold;
-  delete_unreachable_blocks_update_callgraph (&id);
+  delete_unreachable_blocks_update_callgraph (id.dst_node, update_clones);
   if (id.dst_node->definition)
     cgraph_edge::rebuild_references ();
   if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))