reassoc: Fix -fcompare-debug bug in reassociate_bb [PR94329]
authorJakub Jelinek <jakub@redhat.com>
Sat, 28 Mar 2020 09:21:52 +0000 (10:21 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sat, 28 Mar 2020 09:21:52 +0000 (10:21 +0100)
The following testcase FAILs with -fcompare-debug, because reassociate_bb
mishandles the case when the last stmt in a bb has zero uses.  In that case
reassoc_remove_stmt (like gsi_remove) moves the iterator to the next stmt,
i.e. gsi_end_p is true, which means the code sets the iterator back to
gsi_last_bb.  The problem is that the for loop does gsi_prev on that before
handling the next statement, which means the former penultimate stmt, now
last one, is not processed by reassociate_bb.
Now, with -g, if there is at least one debug stmt at the end of the bb,
reassoc_remove_stmt moves the iterator to that following debug stmt and we
just do gsi_prev and continue with the former penultimate non-debug stmt,
now last non-debug stmt.

The following patch fixes that by not doing the gsi_prev in this case; there
are too many continue; cases, so I didn't want to copy over the gsi_prev to
all of them, so this patch uses a bool for that instead.  The second
gsi_end_p check isn't needed anymore, because when we don't do the
undesirable gsi_prev after gsi = gsi_last_bb, the loop !gsi_end_p (gsi)
condition will catch the removal of the very last stmt from a bb.

2020-03-28  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/94329
* tree-ssa-reassoc.c (reassociate_bb): When calling reassoc_remove_stmt
on the last stmt in a bb, make sure gsi_prev isn't done immediately
after gsi_last_bb.

* gfortran.dg/pr94329.f90: New test.

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/pr94329.f90 [new file with mode: 0644]
gcc/tree-ssa-reassoc.c

index 3bfe5ff8f69ae5e7eab3a13bb867532ed562ee1a..52c296c00ae0e19159a196c373f9970db04c96d7 100644 (file)
@@ -1,3 +1,10 @@
+2020-03-28  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/94329
+       * tree-ssa-reassoc.c (reassociate_bb): When calling reassoc_remove_stmt
+       on the last stmt in a bb, make sure gsi_prev isn't done immediately
+       after gsi_last_bb.
+
 2020-03-27  Alan Modra  <amodra@gmail.com>
 
        PR target/94145
index 7876b57deebfd9dd47c2d27a8931c7f373d36eb4..3e51175368cc435172184a962a8785a615c1ac39 100644 (file)
@@ -1,3 +1,8 @@
+2020-03-28  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/94329
+       * gfortran.dg/pr94329.f90: New test.
+
 2020-03-27  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/94339
diff --git a/gcc/testsuite/gfortran.dg/pr94329.f90 b/gcc/testsuite/gfortran.dg/pr94329.f90
new file mode 100644 (file)
index 0000000..9efcf4b
--- /dev/null
@@ -0,0 +1,12 @@
+! PR tree-optimization/94329
+! { dg-do compile }
+! { dg-options "-O1 -fno-tree-loop-optimize -fwrapv -fcompare-debug" }
+
+subroutine pr94329 (s, t)
+  real :: s, t(:,:)
+  do i = 1,3
+    do j = 1,3
+      s = t(i,j)
+    end do
+  end do
+end
index 14f9550b094327b052463b0b1e7a0f8a8c67e9be..ec1c033a2cff990a6a4a67f74dfc2147e8eafecb 100644 (file)
@@ -6224,8 +6224,11 @@ reassociate_bb (basic_block bb)
   if (stmt && !gimple_visited_p (stmt))
     cfg_cleanup_needed |= maybe_optimize_range_tests (stmt);
 
-  for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+  bool do_prev = false;
+  for (gsi = gsi_last_bb (bb);
+       !gsi_end_p (gsi); do_prev ? gsi_prev (&gsi) : (void) 0)
     {
+      do_prev = true;
       stmt = gsi_stmt (gsi);
 
       if (is_gimple_assign (stmt)
@@ -6246,15 +6249,12 @@ reassociate_bb (basic_block bb)
                  release_defs (stmt);
                  /* We might end up removing the last stmt above which
                     places the iterator to the end of the sequence.
-                    Reset it to the last stmt in this case which might
-                    be the end of the sequence as well if we removed
-                    the last statement of the sequence.  In which case
-                    we need to bail out.  */
+                    Reset it to the last stmt in this case and make sure
+                    we don't do gsi_prev in that case.  */
                  if (gsi_end_p (gsi))
                    {
                      gsi = gsi_last_bb (bb);
-                     if (gsi_end_p (gsi))
-                       break;
+                     do_prev = false;
                    }
                }
              continue;