public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFA] [PR tree-optimization/71661] Fix forwarder removal when new loops are exposed
@ 2016-10-05 15:59 Jeff Law
  2016-10-06 10:11 ` Richard Biener
  0 siblings, 1 reply; 3+ messages in thread
From: Jeff Law @ 2016-10-05 15:59 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1559 bytes --]


Removal of forwarder blocks is a two step process.

First we build a worklist of potential forwarder blocks,  Then we 
iterate over that worklist attempting to remove each potential forwarder 
block in the worklist.

The code which builds the worklist is aware that we do not want to 
remove a forwarder that is a loop header and avoids putting such blocks 
into the worklist.

The problem is that removing a forwarder block may turn an irreducible 
region into a natural loop, which of course will have a loop header. 
But that loop header could not be recognized as such during the initial 
building of the worklist.

So as a result if removal of a forwarder block exposes a new loop and 
the header of that newly exposed loop appears to be a forwarder block, 
we may forward through the newly exposed loop header too.  That can 
squash two loops into a single loop, which invalidates the cached 
iteration information and other stuff which can in turn cause incorrect 
code generation (as seen by 71661).

There's two ways to address this problem.  First we could invalidate the 
cached loop info when this situation occurs.  Second, we could avoid 
forwarding through the newly exposed loop header.

The patch takes the latter approach.  Based on the CFG transformations 
for 71661, I think we're better off leaving the newly exposed loop alone 
-- we've exposed a nice simple loop nest, collapsing the nest into a 
single loop with multiple latch edges just seems wrong.

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

Jeff

[-- Attachment #2: P --]
[-- Type: text/plain, Size: 2369 bytes --]

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2b56878..33ee250 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2016-10-05  Jeff Law  <law@redhat.com>
+
+	PR tree-optimization/71661
+	* tree-cfgcleanup.c (remove_forwarder_block): Handle case when removal
+	of a forwarder exposes a new natural loop.
+	(remove_forwarder_block_with_phi): Likewise.
+
 2016-10-05  Martin Sebor  <msebor@redhat.com>
 
 	PR bootstrap/77819
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fa1f310..3bba95d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-10-05  Jeff Law  <law@redhat.com>
+
+        PR tree-optimization/71661
+	* gcc.dg/tree-ssa/pr71661.c: New test.
+
 2016-10-05  Richard Biener  <rguenther@suse.de>
 
 	PR middle-end/77826
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c b/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c
new file mode 100644
index 0000000..c273ea1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fdisable-tree-ethread" } */
+
+extern void exit (int);
+
+int a, b;
+
+void
+fn1 ()
+{
+  unsigned c = 0;
+  int d;
+  b = a;
+  if (a < 0)
+    goto L1;
+  for (; a < 1; a++)
+    d = 0;
+  for (; d < 2; d++)
+    {
+      for (c = 0; c < 3; c++)
+      L1:
+        a = 2;
+    }
+}
+
+int
+main ()
+{
+  fn1 ();
+  exit (0);
+}
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index 6052872..e3cb8ee 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -418,6 +418,11 @@ remove_forwarder_block (basic_block bb)
   if (dest == bb)
     return false;
 
+  /* Removal of forwarders may expose new natural loops and thus
+     a block may turn into a loop header.  */
+  if (current_loops && bb_loop_header_p (bb))
+    return false;
+
   /* If the destination block consists of a nonlocal label or is a
      EH landing pad, do not merge it.  */
   label = first_stmt (dest);
@@ -840,6 +845,11 @@ remove_forwarder_block_with_phi (basic_block bb)
   if (dest == bb)
     return false;
 
+  /* Removal of forwarders may expose new natural loops and thus
+     a block may turn into a loop header.  */
+  if (current_loops && bb_loop_header_p (bb))
+    return false;
+
   /* If the destination block consists of a nonlocal label, do not
      merge it.  */
   label = first_stmt (dest);

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

* Re: [RFA] [PR tree-optimization/71661] Fix forwarder removal when new loops are exposed
  2016-10-05 15:59 [RFA] [PR tree-optimization/71661] Fix forwarder removal when new loops are exposed Jeff Law
@ 2016-10-06 10:11 ` Richard Biener
  2016-10-06 15:38   ` Jeff Law
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Biener @ 2016-10-06 10:11 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

On Wed, Oct 5, 2016 at 5:58 PM, Jeff Law <law@redhat.com> wrote:
>
> Removal of forwarder blocks is a two step process.
>
> First we build a worklist of potential forwarder blocks,  Then we iterate
> over that worklist attempting to remove each potential forwarder block in
> the worklist.
>
> The code which builds the worklist is aware that we do not want to remove a
> forwarder that is a loop header and avoids putting such blocks into the
> worklist.
>
> The problem is that removing a forwarder block may turn an irreducible
> region into a natural loop, which of course will have a loop header. But
> that loop header could not be recognized as such during the initial building
> of the worklist.
>
> So as a result if removal of a forwarder block exposes a new loop and the
> header of that newly exposed loop appears to be a forwarder block, we may
> forward through the newly exposed loop header too.  That can squash two
> loops into a single loop, which invalidates the cached iteration information
> and other stuff which can in turn cause incorrect code generation (as seen
> by 71661).
>
> There's two ways to address this problem.  First we could invalidate the
> cached loop info when this situation occurs.  Second, we could avoid
> forwarding through the newly exposed loop header.
>
> The patch takes the latter approach.  Based on the CFG transformations for
> 71661, I think we're better off leaving the newly exposed loop alone --
> we've exposed a nice simple loop nest, collapsing the nest into a single
> loop with multiple latch edges just seems wrong.
>
> Bootstrapped and regression tested on x86_64-linux.gnu.  OK for the trunk?

The remove_forwarder_block hunk is redundant (I've fixed a similar bug there
by checking in tree_forwarder_block_p).  This function doesn't operate from
a worklist and thus shouldn't have the issue.

The remove_forwarder_block_with_phi hunk is ok.

Thanks,
Richard.

> Jeff
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 2b56878..33ee250 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,10 @@
> +2016-10-05  Jeff Law  <law@redhat.com>
> +
> +       PR tree-optimization/71661
> +       * tree-cfgcleanup.c (remove_forwarder_block): Handle case when
> removal
> +       of a forwarder exposes a new natural loop.
> +       (remove_forwarder_block_with_phi): Likewise.
> +
>  2016-10-05  Martin Sebor  <msebor@redhat.com>
>
>         PR bootstrap/77819
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index fa1f310..3bba95d 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,8 @@
> +2016-10-05  Jeff Law  <law@redhat.com>
> +
> +        PR tree-optimization/71661
> +       * gcc.dg/tree-ssa/pr71661.c: New test.
> +
>  2016-10-05  Richard Biener  <rguenther@suse.de>
>
>         PR middle-end/77826
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c
> new file mode 100644
> index 0000000..c273ea1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71661.c
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-options "-O3 -fdisable-tree-ethread" } */
> +
> +extern void exit (int);
> +
> +int a, b;
> +
> +void
> +fn1 ()
> +{
> +  unsigned c = 0;
> +  int d;
> +  b = a;
> +  if (a < 0)
> +    goto L1;
> +  for (; a < 1; a++)
> +    d = 0;
> +  for (; d < 2; d++)
> +    {
> +      for (c = 0; c < 3; c++)
> +      L1:
> +        a = 2;
> +    }
> +}
> +
> +int
> +main ()
> +{
> +  fn1 ();
> +  exit (0);
> +}
> diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
> index 6052872..e3cb8ee 100644
> --- a/gcc/tree-cfgcleanup.c
> +++ b/gcc/tree-cfgcleanup.c
> @@ -418,6 +418,11 @@ remove_forwarder_block (basic_block bb)
>    if (dest == bb)
>      return false;
>
> +  /* Removal of forwarders may expose new natural loops and thus
> +     a block may turn into a loop header.  */
> +  if (current_loops && bb_loop_header_p (bb))
> +    return false;
> +
>    /* If the destination block consists of a nonlocal label or is a
>       EH landing pad, do not merge it.  */
>    label = first_stmt (dest);
> @@ -840,6 +845,11 @@ remove_forwarder_block_with_phi (basic_block bb)
>    if (dest == bb)
>      return false;
>
> +  /* Removal of forwarders may expose new natural loops and thus
> +     a block may turn into a loop header.  */
> +  if (current_loops && bb_loop_header_p (bb))
> +    return false;
> +
>    /* If the destination block consists of a nonlocal label, do not
>       merge it.  */
>    label = first_stmt (dest);
>

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

* Re: [RFA] [PR tree-optimization/71661] Fix forwarder removal when new loops are exposed
  2016-10-06 10:11 ` Richard Biener
@ 2016-10-06 15:38   ` Jeff Law
  0 siblings, 0 replies; 3+ messages in thread
From: Jeff Law @ 2016-10-06 15:38 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On 10/06/2016 04:11 AM, Richard Biener wrote:
>
> The remove_forwarder_block hunk is redundant (I've fixed a similar bug there
> by checking in tree_forwarder_block_p).  This function doesn't operate from
> a worklist and thus shouldn't have the issue.
Agreed.  I hadn't really looked closely at remove_forwarder_block, but 
it has the same check for newly exposed infinite loops so my patch added 
the check for new loop headers in both places.  But I agree it isn't 
necessary here when I look at how remove_forwarder_block is used.


>
> The remove_forwarder_block_with_phi hunk is ok.
I'll extract/install just the remove_forwarder_block_with_phi hunk & the 
testcase.

Thanks,
jeff

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

end of thread, other threads:[~2016-10-06 15:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-05 15:59 [RFA] [PR tree-optimization/71661] Fix forwarder removal when new loops are exposed Jeff Law
2016-10-06 10:11 ` Richard Biener
2016-10-06 15:38   ` Jeff Law

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).