public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code
@ 2020-02-06 14:52 Richard Biener
  2020-02-06 21:24 ` Martin Sebor
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Biener @ 2020-02-06 14:52 UTC (permalink / raw)
  To: gcc-patches; +Cc: law

The inliner folds stmts delayed, the following arranges things so
to not fold stmts that are obviously not reachable to avoid warnings
from those code regions.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

OK?

Thanks,
Richard.

2020-02-06  Richard Biener  <rguenther@suse.de>

	PR middle-end/93519
	* tree-inline.c (fold_marked_statements): Do a PRE walk,
	skipping unreachable regions.
	(optimize_inline_calls): Skip folding stmts when we didn't
	inline.

	* gcc.dg/Wrestrict-21.c: New testcase.
---
 gcc/testsuite/gcc.dg/Wrestrict-21.c |  18 +++
 gcc/tree-inline.c                   | 195 ++++++++++++++++------------
 2 files changed, 133 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wrestrict-21.c

diff --git a/gcc/testsuite/gcc.dg/Wrestrict-21.c b/gcc/testsuite/gcc.dg/Wrestrict-21.c
new file mode 100644
index 00000000000..e300663758e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-21.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wrestrict" } */
+
+static char *
+str_numth(char *dest, char *num, int type)
+{
+  if (dest != num)
+    __builtin_strcpy(dest, num); /* { dg-bogus "is the same" } */
+  __builtin_strcat(dest, "foo");
+  return dest;
+}
+
+void
+DCH_to_char(char *in, char *out, int collid)
+{
+  char *s = out;
+  str_numth(s, s, 42);
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 5b0050a53d2..19154bb843e 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5261,86 +5261,118 @@ static void
 fold_marked_statements (int first, hash_set<gimple *> *statements)
 {
   auto_bitmap to_purge;
-  for (; first < last_basic_block_for_fn (cfun); first++)
-    if (BASIC_BLOCK_FOR_FN (cfun, first))
-      {
-        gimple_stmt_iterator gsi;
 
-	for (gsi = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
-	     !gsi_end_p (gsi);
-	     gsi_next (&gsi))
-	  if (statements->contains (gsi_stmt (gsi)))
-	    {
-	      gimple *old_stmt = gsi_stmt (gsi);
-	      tree old_decl
-		= is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
+  auto_vec<edge_iterator, 20> stack (n_basic_blocks_for_fn (cfun) + 2);
+  auto_sbitmap visited (last_basic_block_for_fn (cfun));
+  bitmap_clear (visited);
+
+  stack.quick_push (ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs));
+  while (!stack.is_empty ())
+    {
+      /* Look at the edge on the top of the stack.  */
+      edge_iterator ei = stack.last ();
+      basic_block dest = ei_edge (ei)->dest;
+      edge known_taken;
+
+      if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
+	  && !bitmap_bit_p (visited, dest->index)
+	  /* Avoid walking unreachable edges, the iteration scheme
+	     using edge iterators doesn't allow to not push them so
+	     ignore them here instead (FIXME: use an edge flag at least?).  */
+	  && !((known_taken = find_taken_edge (ei_edge (ei)->src, NULL_TREE))
+	       && known_taken != ei_edge (ei)))
+	{
+	  bitmap_set_bit (visited, dest->index);
 
-	      if (old_decl && fndecl_built_in_p (old_decl))
-		{
-		  /* Folding builtins can create multiple instructions,
-		     we need to look at all of them.  */
-		  gimple_stmt_iterator i2 = gsi;
-		  gsi_prev (&i2);
-		  if (fold_stmt (&gsi))
-		    {
-		      gimple *new_stmt;
-		      /* If a builtin at the end of a bb folded into nothing,
-			 the following loop won't work.  */
-		      if (gsi_end_p (gsi))
-			{
-			  cgraph_update_edges_for_call_stmt (old_stmt,
-							     old_decl, NULL);
-			  break;
-			}
-		      if (gsi_end_p (i2))
-			i2 = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
-		      else
-			gsi_next (&i2);
-		      while (1)
-			{
-			  new_stmt = gsi_stmt (i2);
-			  update_stmt (new_stmt);
-			  cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
-							     new_stmt);
+	  if (dest->index >= first)
+	    for (gimple_stmt_iterator gsi = gsi_start_bb (dest);
+		 !gsi_end_p (gsi); gsi_next (&gsi))
+	      {
+		if (!statements->contains (gsi_stmt (gsi)))
+		  continue;
 
-			  if (new_stmt == gsi_stmt (gsi))
-			    {
-			      /* It is okay to check only for the very last
-				 of these statements.  If it is a throwing
-				 statement nothing will change.  If it isn't
-				 this can remove EH edges.  If that weren't
-				 correct then because some intermediate stmts
-				 throw, but not the last one.  That would mean
-				 we'd have to split the block, which we can't
-				 here and we'd loose anyway.  And as builtins
-				 probably never throw, this all
-				 is mood anyway.  */
-			      if (maybe_clean_or_replace_eh_stmt (old_stmt,
-								  new_stmt))
-				bitmap_set_bit (to_purge, first);
-			      break;
-			    }
+		gimple *old_stmt = gsi_stmt (gsi);
+		tree old_decl = (is_gimple_call (old_stmt)
+				 ? gimple_call_fndecl (old_stmt) : 0);
+		if (old_decl && fndecl_built_in_p (old_decl))
+		  {
+		    /* Folding builtins can create multiple instructions,
+		       we need to look at all of them.  */
+		    gimple_stmt_iterator i2 = gsi;
+		    gsi_prev (&i2);
+		    if (fold_stmt (&gsi))
+		      {
+			gimple *new_stmt;
+			/* If a builtin at the end of a bb folded into nothing,
+			   the following loop won't work.  */
+			if (gsi_end_p (gsi))
+			  {
+			    cgraph_update_edges_for_call_stmt (old_stmt,
+							       old_decl, NULL);
+			    break;
+			  }
+			if (gsi_end_p (i2))
+			  i2 = gsi_start_bb (dest);
+			else
 			  gsi_next (&i2);
-			}
-		    }
-		}
-	      else if (fold_stmt (&gsi))
-		{
-		  /* Re-read the statement from GSI as fold_stmt() may
-		     have changed it.  */
-		  gimple *new_stmt = gsi_stmt (gsi);
-		  update_stmt (new_stmt);
-
-		  if (is_gimple_call (old_stmt)
-		      || is_gimple_call (new_stmt))
-		    cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
-						       new_stmt);
-
-		  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
-		    bitmap_set_bit (to_purge, first);
-		}
-	    }
-      }
+			while (1)
+			  {
+			    new_stmt = gsi_stmt (i2);
+			    update_stmt (new_stmt);
+			    cgraph_update_edges_for_call_stmt (old_stmt,
+							       old_decl,
+							       new_stmt);
+
+			    if (new_stmt == gsi_stmt (gsi))
+			      {
+				/* It is okay to check only for the very last
+				   of these statements.  If it is a throwing
+				   statement nothing will change.  If it isn't
+				   this can remove EH edges.  If that weren't
+				   correct then because some intermediate stmts
+				   throw, but not the last one.  That would mean
+				   we'd have to split the block, which we can't
+				   here and we'd loose anyway.  And as builtins
+				   probably never throw, this all
+				   is mood anyway.  */
+				if (maybe_clean_or_replace_eh_stmt (old_stmt,
+								    new_stmt))
+				  bitmap_set_bit (to_purge, dest->index);
+				break;
+			      }
+			    gsi_next (&i2);
+			  }
+		      }
+		  }
+		else if (fold_stmt (&gsi))
+		  {
+		    /* Re-read the statement from GSI as fold_stmt() may
+		       have changed it.  */
+		    gimple *new_stmt = gsi_stmt (gsi);
+		    update_stmt (new_stmt);
+
+		    if (is_gimple_call (old_stmt)
+			|| is_gimple_call (new_stmt))
+		      cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+							 new_stmt);
+
+		    if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
+		      bitmap_set_bit (to_purge, dest->index);
+		  }
+	      }
+
+	  if (EDGE_COUNT (dest->succs) > 0)
+	    stack.quick_push (ei_start (dest->succs));
+	}
+      else
+	{
+	  if (!ei_one_before_end_p (ei))
+	    ei_next (&stack.last ());
+	  else
+	    stack.pop ();
+	}
+    }
+
   gimple_purge_all_dead_eh_edges (to_purge);
 }
 
@@ -5404,6 +5436,13 @@ optimize_inline_calls (tree fn)
 	gcc_assert (e->inline_failed);
     }
 
+  /* If we didn't inline into the function there is nothing to do.  */
+  if (!inlined_p)
+    {
+      delete id.statements_to_fold;
+      return 0;
+    }
+
   /* Fold queued statements.  */
   update_max_bb_count ();
   fold_marked_statements (last, id.statements_to_fold);
@@ -5426,10 +5465,6 @@ optimize_inline_calls (tree fn)
 
   gcc_assert (!id.debug_stmts.exists ());
 
-  /* If we didn't inline into the function there is nothing to do.  */
-  if (!inlined_p)
-    return 0;
-
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (fn);
 
-- 
2.23.0

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code
  2020-02-06 14:52 [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code Richard Biener
@ 2020-02-06 21:24 ` Martin Sebor
  2020-02-07 11:56   ` Richard Biener
  0 siblings, 1 reply; 3+ messages in thread
From: Martin Sebor @ 2020-02-06 21:24 UTC (permalink / raw)
  To: Richard Biener, gcc-patches; +Cc: law

On 2/6/20 7:52 AM, Richard Biener wrote:
> The inliner folds stmts delayed, the following arranges things so
> to not fold stmts that are obviously not reachable to avoid warnings
> from those code regions.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu.

It fixes the reported problem so it works for me.

The tests I submitted with my patch fail a number of cases because
along with strcpy it also deferred folding overlapping mempcpy calls.
That was not strictly part of the regression so I'm okay with deferring
it until GCC 11.  I will resubmit an updated patch to defer the folding
then.

Thanks
Martin

> OK?
> 
> Thanks,
> Richard.
> 
> 2020-02-06  Richard Biener  <rguenther@suse.de>
> 
> 	PR middle-end/93519
> 	* tree-inline.c (fold_marked_statements): Do a PRE walk,
> 	skipping unreachable regions.
> 	(optimize_inline_calls): Skip folding stmts when we didn't
> 	inline.
> 
> 	* gcc.dg/Wrestrict-21.c: New testcase.
> ---
>   gcc/testsuite/gcc.dg/Wrestrict-21.c |  18 +++
>   gcc/tree-inline.c                   | 195 ++++++++++++++++------------
>   2 files changed, 133 insertions(+), 80 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.dg/Wrestrict-21.c
> 
> diff --git a/gcc/testsuite/gcc.dg/Wrestrict-21.c b/gcc/testsuite/gcc.dg/Wrestrict-21.c
> new file mode 100644
> index 00000000000..e300663758e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wrestrict-21.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wrestrict" } */
> +
> +static char *
> +str_numth(char *dest, char *num, int type)
> +{
> +  if (dest != num)
> +    __builtin_strcpy(dest, num); /* { dg-bogus "is the same" } */
> +  __builtin_strcat(dest, "foo");
> +  return dest;
> +}
> +
> +void
> +DCH_to_char(char *in, char *out, int collid)
> +{
> +  char *s = out;
> +  str_numth(s, s, 42);
> +}
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index 5b0050a53d2..19154bb843e 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -5261,86 +5261,118 @@ static void
>   fold_marked_statements (int first, hash_set<gimple *> *statements)
>   {
>     auto_bitmap to_purge;
> -  for (; first < last_basic_block_for_fn (cfun); first++)
> -    if (BASIC_BLOCK_FOR_FN (cfun, first))
> -      {
> -        gimple_stmt_iterator gsi;
>   
> -	for (gsi = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
> -	     !gsi_end_p (gsi);
> -	     gsi_next (&gsi))
> -	  if (statements->contains (gsi_stmt (gsi)))
> -	    {
> -	      gimple *old_stmt = gsi_stmt (gsi);
> -	      tree old_decl
> -		= is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
> +  auto_vec<edge_iterator, 20> stack (n_basic_blocks_for_fn (cfun) + 2);
> +  auto_sbitmap visited (last_basic_block_for_fn (cfun));
> +  bitmap_clear (visited);
> +
> +  stack.quick_push (ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs));
> +  while (!stack.is_empty ())
> +    {
> +      /* Look at the edge on the top of the stack.  */
> +      edge_iterator ei = stack.last ();
> +      basic_block dest = ei_edge (ei)->dest;
> +      edge known_taken;
> +
> +      if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
> +	  && !bitmap_bit_p (visited, dest->index)
> +	  /* Avoid walking unreachable edges, the iteration scheme
> +	     using edge iterators doesn't allow to not push them so
> +	     ignore them here instead (FIXME: use an edge flag at least?).  */
> +	  && !((known_taken = find_taken_edge (ei_edge (ei)->src, NULL_TREE))
> +	       && known_taken != ei_edge (ei)))
> +	{
> +	  bitmap_set_bit (visited, dest->index);
>   
> -	      if (old_decl && fndecl_built_in_p (old_decl))
> -		{
> -		  /* Folding builtins can create multiple instructions,
> -		     we need to look at all of them.  */
> -		  gimple_stmt_iterator i2 = gsi;
> -		  gsi_prev (&i2);
> -		  if (fold_stmt (&gsi))
> -		    {
> -		      gimple *new_stmt;
> -		      /* If a builtin at the end of a bb folded into nothing,
> -			 the following loop won't work.  */
> -		      if (gsi_end_p (gsi))
> -			{
> -			  cgraph_update_edges_for_call_stmt (old_stmt,
> -							     old_decl, NULL);
> -			  break;
> -			}
> -		      if (gsi_end_p (i2))
> -			i2 = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
> -		      else
> -			gsi_next (&i2);
> -		      while (1)
> -			{
> -			  new_stmt = gsi_stmt (i2);
> -			  update_stmt (new_stmt);
> -			  cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
> -							     new_stmt);
> +	  if (dest->index >= first)
> +	    for (gimple_stmt_iterator gsi = gsi_start_bb (dest);
> +		 !gsi_end_p (gsi); gsi_next (&gsi))
> +	      {
> +		if (!statements->contains (gsi_stmt (gsi)))
> +		  continue;
>   
> -			  if (new_stmt == gsi_stmt (gsi))
> -			    {
> -			      /* It is okay to check only for the very last
> -				 of these statements.  If it is a throwing
> -				 statement nothing will change.  If it isn't
> -				 this can remove EH edges.  If that weren't
> -				 correct then because some intermediate stmts
> -				 throw, but not the last one.  That would mean
> -				 we'd have to split the block, which we can't
> -				 here and we'd loose anyway.  And as builtins
> -				 probably never throw, this all
> -				 is mood anyway.  */
> -			      if (maybe_clean_or_replace_eh_stmt (old_stmt,
> -								  new_stmt))
> -				bitmap_set_bit (to_purge, first);
> -			      break;
> -			    }
> +		gimple *old_stmt = gsi_stmt (gsi);
> +		tree old_decl = (is_gimple_call (old_stmt)
> +				 ? gimple_call_fndecl (old_stmt) : 0);
> +		if (old_decl && fndecl_built_in_p (old_decl))
> +		  {
> +		    /* Folding builtins can create multiple instructions,
> +		       we need to look at all of them.  */
> +		    gimple_stmt_iterator i2 = gsi;
> +		    gsi_prev (&i2);
> +		    if (fold_stmt (&gsi))
> +		      {
> +			gimple *new_stmt;
> +			/* If a builtin at the end of a bb folded into nothing,
> +			   the following loop won't work.  */
> +			if (gsi_end_p (gsi))
> +			  {
> +			    cgraph_update_edges_for_call_stmt (old_stmt,
> +							       old_decl, NULL);
> +			    break;
> +			  }
> +			if (gsi_end_p (i2))
> +			  i2 = gsi_start_bb (dest);
> +			else
>   			  gsi_next (&i2);
> -			}
> -		    }
> -		}
> -	      else if (fold_stmt (&gsi))
> -		{
> -		  /* Re-read the statement from GSI as fold_stmt() may
> -		     have changed it.  */
> -		  gimple *new_stmt = gsi_stmt (gsi);
> -		  update_stmt (new_stmt);
> -
> -		  if (is_gimple_call (old_stmt)
> -		      || is_gimple_call (new_stmt))
> -		    cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
> -						       new_stmt);
> -
> -		  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
> -		    bitmap_set_bit (to_purge, first);
> -		}
> -	    }
> -      }
> +			while (1)
> +			  {
> +			    new_stmt = gsi_stmt (i2);
> +			    update_stmt (new_stmt);
> +			    cgraph_update_edges_for_call_stmt (old_stmt,
> +							       old_decl,
> +							       new_stmt);
> +
> +			    if (new_stmt == gsi_stmt (gsi))
> +			      {
> +				/* It is okay to check only for the very last
> +				   of these statements.  If it is a throwing
> +				   statement nothing will change.  If it isn't
> +				   this can remove EH edges.  If that weren't
> +				   correct then because some intermediate stmts
> +				   throw, but not the last one.  That would mean
> +				   we'd have to split the block, which we can't
> +				   here and we'd loose anyway.  And as builtins
> +				   probably never throw, this all
> +				   is mood anyway.  */
> +				if (maybe_clean_or_replace_eh_stmt (old_stmt,
> +								    new_stmt))
> +				  bitmap_set_bit (to_purge, dest->index);
> +				break;
> +			      }
> +			    gsi_next (&i2);
> +			  }
> +		      }
> +		  }
> +		else if (fold_stmt (&gsi))
> +		  {
> +		    /* Re-read the statement from GSI as fold_stmt() may
> +		       have changed it.  */
> +		    gimple *new_stmt = gsi_stmt (gsi);
> +		    update_stmt (new_stmt);
> +
> +		    if (is_gimple_call (old_stmt)
> +			|| is_gimple_call (new_stmt))
> +		      cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
> +							 new_stmt);
> +
> +		    if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
> +		      bitmap_set_bit (to_purge, dest->index);
> +		  }
> +	      }
> +
> +	  if (EDGE_COUNT (dest->succs) > 0)
> +	    stack.quick_push (ei_start (dest->succs));
> +	}
> +      else
> +	{
> +	  if (!ei_one_before_end_p (ei))
> +	    ei_next (&stack.last ());
> +	  else
> +	    stack.pop ();
> +	}
> +    }
> +
>     gimple_purge_all_dead_eh_edges (to_purge);
>   }
>   
> @@ -5404,6 +5436,13 @@ optimize_inline_calls (tree fn)
>   	gcc_assert (e->inline_failed);
>       }
>   
> +  /* If we didn't inline into the function there is nothing to do.  */
> +  if (!inlined_p)
> +    {
> +      delete id.statements_to_fold;
> +      return 0;
> +    }
> +
>     /* Fold queued statements.  */
>     update_max_bb_count ();
>     fold_marked_statements (last, id.statements_to_fold);
> @@ -5426,10 +5465,6 @@ optimize_inline_calls (tree fn)
>   
>     gcc_assert (!id.debug_stmts.exists ());
>   
> -  /* If we didn't inline into the function there is nothing to do.  */
> -  if (!inlined_p)
> -    return 0;
> -
>     /* Renumber the lexical scoping (non-code) blocks consecutively.  */
>     number_blocks (fn);
>   
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code
  2020-02-06 21:24 ` Martin Sebor
@ 2020-02-07 11:56   ` Richard Biener
  0 siblings, 0 replies; 3+ messages in thread
From: Richard Biener @ 2020-02-07 11:56 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches, law

On Thu, 6 Feb 2020, Martin Sebor wrote:

> On 2/6/20 7:52 AM, Richard Biener wrote:
> > The inliner folds stmts delayed, the following arranges things so
> > to not fold stmts that are obviously not reachable to avoid warnings
> > from those code regions.
> > 
> > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> 
> It fixes the reported problem so it works for me.
> 
> The tests I submitted with my patch fail a number of cases because
> along with strcpy it also deferred folding overlapping mempcpy calls.
> That was not strictly part of the regression so I'm okay with deferring
> it until GCC 11.  I will resubmit an updated patch to defer the folding
> then.

The following is what I have applied, fixing the quadraticness with
switch stmt edges, trading it with possible re-allocation of the
worker stack.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Richard.

From ed41d9926a45d5ebc50d3721dde564cabd36f861 Mon Sep 17 00:00:00 2001
From: Richard Biener <rguenther@suse.de>
Date: Thu, 6 Feb 2020 15:49:57 +0100
Subject: [PATCH] middle-end/93519 - avoid folding stmts in obviously
 unreachable code

The inliner folds stmts delayed, the following arranges things so
to not fold stmts that are obviously not reachable to avoid warnings
from those code regions.

2020-02-06  Richard Biener  <rguenther@suse.de>

	PR middle-end/93519
	* tree-inline.c (fold_marked_statements): Do a PRE walk,
	skipping unreachable regions.
	(optimize_inline_calls): Skip folding stmts when we didn't
	inline.

	* gcc.dg/Wrestrict-21.c: New testcase.

diff --git a/gcc/testsuite/gcc.dg/Wrestrict-21.c b/gcc/testsuite/gcc.dg/Wrestrict-21.c
new file mode 100644
index 00000000000..e300663758e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-21.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wrestrict" } */
+
+static char *
+str_numth(char *dest, char *num, int type)
+{
+  if (dest != num)
+    __builtin_strcpy(dest, num); /* { dg-bogus "is the same" } */
+  __builtin_strcat(dest, "foo");
+  return dest;
+}
+
+void
+DCH_to_char(char *in, char *out, int collid)
+{
+  char *s = out;
+  str_numth(s, s, 42);
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 5b0050a53d2..23941dade55 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5261,86 +5261,117 @@ static void
 fold_marked_statements (int first, hash_set<gimple *> *statements)
 {
   auto_bitmap to_purge;
-  for (; first < last_basic_block_for_fn (cfun); first++)
-    if (BASIC_BLOCK_FOR_FN (cfun, first))
-      {
-        gimple_stmt_iterator gsi;
 
-	for (gsi = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
-	     !gsi_end_p (gsi);
-	     gsi_next (&gsi))
-	  if (statements->contains (gsi_stmt (gsi)))
-	    {
-	      gimple *old_stmt = gsi_stmt (gsi);
-	      tree old_decl
-		= is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
+  auto_vec<edge, 20> stack (n_basic_blocks_for_fn (cfun) + 2);
+  auto_sbitmap visited (last_basic_block_for_fn (cfun));
+  bitmap_clear (visited);
 
-	      if (old_decl && fndecl_built_in_p (old_decl))
-		{
-		  /* Folding builtins can create multiple instructions,
-		     we need to look at all of them.  */
-		  gimple_stmt_iterator i2 = gsi;
-		  gsi_prev (&i2);
-		  if (fold_stmt (&gsi))
-		    {
-		      gimple *new_stmt;
-		      /* If a builtin at the end of a bb folded into nothing,
-			 the following loop won't work.  */
-		      if (gsi_end_p (gsi))
-			{
-			  cgraph_update_edges_for_call_stmt (old_stmt,
-							     old_decl, NULL);
-			  break;
-			}
-		      if (gsi_end_p (i2))
-			i2 = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
-		      else
+  stack.quick_push (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+  while (!stack.is_empty ())
+    {
+      /* Look at the edge on the top of the stack.  */
+      edge e = stack.pop ();
+      basic_block dest = e->dest;
+
+      if (dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
+	  || bitmap_bit_p (visited, dest->index))
+	continue;
+
+      bitmap_set_bit (visited, dest->index);
+
+      if (dest->index >= first)
+	for (gimple_stmt_iterator gsi = gsi_start_bb (dest);
+	     !gsi_end_p (gsi); gsi_next (&gsi))
+	  {
+	    if (!statements->contains (gsi_stmt (gsi)))
+	      continue;
+
+	    gimple *old_stmt = gsi_stmt (gsi);
+	    tree old_decl = (is_gimple_call (old_stmt)
+			     ? gimple_call_fndecl (old_stmt) : 0);
+	    if (old_decl && fndecl_built_in_p (old_decl))
+	      {
+		/* Folding builtins can create multiple instructions,
+		   we need to look at all of them.  */
+		gimple_stmt_iterator i2 = gsi;
+		gsi_prev (&i2);
+		if (fold_stmt (&gsi))
+		  {
+		    gimple *new_stmt;
+		    /* If a builtin at the end of a bb folded into nothing,
+		       the following loop won't work.  */
+		    if (gsi_end_p (gsi))
+		      {
+			cgraph_update_edges_for_call_stmt (old_stmt,
+							   old_decl, NULL);
+			break;
+		      }
+		    if (gsi_end_p (i2))
+		      i2 = gsi_start_bb (dest);
+		    else
+		      gsi_next (&i2);
+		    while (1)
+		      {
+			new_stmt = gsi_stmt (i2);
+			update_stmt (new_stmt);
+			cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+							   new_stmt);
+
+			if (new_stmt == gsi_stmt (gsi))
+			  {
+			    /* It is okay to check only for the very last
+			       of these statements.  If it is a throwing
+			       statement nothing will change.  If it isn't
+			       this can remove EH edges.  If that weren't
+			       correct then because some intermediate stmts
+			       throw, but not the last one.  That would mean
+			       we'd have to split the block, which we can't
+			       here and we'd loose anyway.  And as builtins
+			       probably never throw, this all
+			       is mood anyway.  */
+			    if (maybe_clean_or_replace_eh_stmt (old_stmt,
+								new_stmt))
+			      bitmap_set_bit (to_purge, dest->index);
+			    break;
+			  }
 			gsi_next (&i2);
-		      while (1)
-			{
-			  new_stmt = gsi_stmt (i2);
-			  update_stmt (new_stmt);
-			  cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
-							     new_stmt);
+		      }
+		  }
+	      }
+	    else if (fold_stmt (&gsi))
+	      {
+		/* Re-read the statement from GSI as fold_stmt() may
+		   have changed it.  */
+		gimple *new_stmt = gsi_stmt (gsi);
+		update_stmt (new_stmt);
+
+		if (is_gimple_call (old_stmt)
+		    || is_gimple_call (new_stmt))
+		  cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+						     new_stmt);
+
+		if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
+		  bitmap_set_bit (to_purge, dest->index);
+	      }
+	  }
 
-			  if (new_stmt == gsi_stmt (gsi))
-			    {
-			      /* It is okay to check only for the very last
-				 of these statements.  If it is a throwing
-				 statement nothing will change.  If it isn't
-				 this can remove EH edges.  If that weren't
-				 correct then because some intermediate stmts
-				 throw, but not the last one.  That would mean
-				 we'd have to split the block, which we can't
-				 here and we'd loose anyway.  And as builtins
-				 probably never throw, this all
-				 is mood anyway.  */
-			      if (maybe_clean_or_replace_eh_stmt (old_stmt,
-								  new_stmt))
-				bitmap_set_bit (to_purge, first);
-			      break;
-			    }
-			  gsi_next (&i2);
-			}
-		    }
-		}
-	      else if (fold_stmt (&gsi))
-		{
-		  /* Re-read the statement from GSI as fold_stmt() may
-		     have changed it.  */
-		  gimple *new_stmt = gsi_stmt (gsi);
-		  update_stmt (new_stmt);
-
-		  if (is_gimple_call (old_stmt)
-		      || is_gimple_call (new_stmt))
-		    cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
-						       new_stmt);
-
-		  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
-		    bitmap_set_bit (to_purge, first);
-		}
+      if (EDGE_COUNT (dest->succs) > 0)
+	{
+	  /* Avoid warnings emitted from folding statements that
+	     became unreachable because of inlined function parameter
+	     propagation.  */
+	  e = find_taken_edge (dest, NULL_TREE);
+	  if (e)
+	    stack.quick_push (e);
+	  else
+	    {
+	      edge_iterator ei;
+	      FOR_EACH_EDGE (e, ei, dest->succs)
+		stack.safe_push (e);
 	    }
-      }
+	}
+    }
+
   gimple_purge_all_dead_eh_edges (to_purge);
 }
 
@@ -5404,6 +5435,13 @@ optimize_inline_calls (tree fn)
 	gcc_assert (e->inline_failed);
     }
 
+  /* If we didn't inline into the function there is nothing to do.  */
+  if (!inlined_p)
+    {
+      delete id.statements_to_fold;
+      return 0;
+    }
+
   /* Fold queued statements.  */
   update_max_bb_count ();
   fold_marked_statements (last, id.statements_to_fold);
@@ -5426,10 +5464,6 @@ optimize_inline_calls (tree fn)
 
   gcc_assert (!id.debug_stmts.exists ());
 
-  /* If we didn't inline into the function there is nothing to do.  */
-  if (!inlined_p)
-    return 0;
-
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (fn);
 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-02-07 11:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06 14:52 [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code Richard Biener
2020-02-06 21:24 ` Martin Sebor
2020-02-07 11:56   ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).