]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/42245 (ICE in verify_backedges for 197.parser with sel-sched)
authorAlexander Monakov <amonakov@gcc.gnu.org>
Thu, 14 Jan 2010 10:28:47 +0000 (13:28 +0300)
committerAlexander Monakov <amonakov@gcc.gnu.org>
Thu, 14 Jan 2010 10:28:47 +0000 (13:28 +0300)
2010-01-14  Andrey Belevantsev  <abel@ispras.ru>
    Alexander Monakov  <amonakov@ispras.ru>

PR middle-end/42245
* sel-sched-ir.c (sel_recompute_toporder): New.  Use it...
(maybe_tidy_empty_bb): ... here.  Make static.  Add new
argument.  Update all callers.
(tidy_control_flow): ... and here.  Recompute topological order
of basic blocks in region if necessary.
(sel_redirect_edge_and_branch): Change return type.  Return true
if topological order might have been invalidated.
(purge_empty_blocks): Export and move from...
* sel-sched.c (purge_empty_blocks): ... here.
* sel-sched-ir.h (sel_redirect_edge_and_branch): Update prototype.
        (maybe_tidy_empty_bb): Delete prototype.
(purge_empty_blocks): Declare.

* gcc.dg/pr42245.c: New.
* gcc.dg/pr42245-2.c: New.

From-SVN: r155890

gcc/ChangeLog
gcc/sel-sched-ir.c
gcc/sel-sched-ir.h
gcc/sel-sched.c
gcc/testsuite/ChangeLog

index b4ebd0b20a3dc420d76efb83d55b29ca39f5d988..fda47c6414388bd3991075c53cad79f07e49a268 100644 (file)
@@ -1,6 +1,23 @@
+2010-01-14  Andrey Belevantsev  <abel@ispras.ru>
+           Alexander Monakov  <amonakov@ispras.ru>
+
+       PR middle-end/42245
+       * sel-sched-ir.c (sel_recompute_toporder): New.  Use it...
+       (maybe_tidy_empty_bb): ... here.  Make static.  Add new
+       argument.  Update all callers.
+       (tidy_control_flow): ... and here.  Recompute topological order
+       of basic blocks in region if necessary.
+       (sel_redirect_edge_and_branch): Change return type.  Return true
+       if topological order might have been invalidated.
+       (purge_empty_blocks): Export and move from...
+       * sel-sched.c (purge_empty_blocks): ... here.
+       * sel-sched-ir.h (sel_redirect_edge_and_branch): Update prototype.
+        (maybe_tidy_empty_bb): Delete prototype.
+       (purge_empty_blocks): Declare.
+
 2010-01-14  Andrey Belevantsev <abel@ispras.ru>
 
-       PR rtl-optimization/42294
+       PR rtl-optimization/42249
        * sel-sched.c (try_replace_dest_reg): When chosen register
        and original register is the same, do not bail out early, but
        still check all original insns for validity of replacing destination
index e864eb40c7a048f7e9fe0bec52eab53e037ba6f2..ad1dcb212de9757e68787d045e9bd2895a6cd526 100644 (file)
@@ -3503,9 +3503,36 @@ verify_backedges (void)
 
 /* Functions to work with control flow.  */
 
+/* Recompute BLOCK_TO_BB and BB_FOR_BLOCK for current region so that blocks
+   are sorted in topological order (it might have been invalidated by
+   redirecting an edge).  */
+static void
+sel_recompute_toporder (void)
+{
+  int i, n, rgn;
+  int *postorder, n_blocks;
+
+  postorder = XALLOCAVEC (int, n_basic_blocks);
+  n_blocks = post_order_compute (postorder, false, false);
+
+  rgn = CONTAINING_RGN (BB_TO_BLOCK (0));
+  for (n = 0, i = n_blocks - 1; i >= 0; i--)
+    if (CONTAINING_RGN (postorder[i]) == rgn)
+      {
+       BLOCK_TO_BB (postorder[i]) = n;
+       BB_TO_BLOCK (n) = postorder[i];
+       n++;
+      }
+
+  /* Assert that we updated info for all blocks.  We may miss some blocks if
+     this function is called when redirecting an edge made a block
+     unreachable, but that block is not deleted yet.  */
+  gcc_assert (n == RGN_NR_BLOCKS (rgn));
+}
+
 /* Tidy the possibly empty block BB.  */
-bool
-maybe_tidy_empty_bb (basic_block bb)
+static bool
+maybe_tidy_empty_bb (basic_block bb, bool recompute_toporder_p)
 {
   basic_block succ_bb, pred_bb;
   edge e;
@@ -3552,7 +3579,7 @@ maybe_tidy_empty_bb (basic_block bb)
 
           if (!(e->flags & EDGE_FALLTHRU))
             {
-              sel_redirect_edge_and_branch (e, succ_bb);
+              recompute_toporder_p |= sel_redirect_edge_and_branch (e, succ_bb);
               rescan_p = true;
               break;
             }
@@ -3572,6 +3599,9 @@ maybe_tidy_empty_bb (basic_block bb)
       remove_empty_bb (bb, true);
     }
 
+  if (recompute_toporder_p)
+    sel_recompute_toporder ();
+
 #ifdef ENABLE_CHECKING
   verify_backedges ();
 #endif
@@ -3589,7 +3619,7 @@ tidy_control_flow (basic_block xbb, bool full_tidying)
   insn_t first, last;
 
   /* First check whether XBB is empty.  */
-  changed = maybe_tidy_empty_bb (xbb);
+  changed = maybe_tidy_empty_bb (xbb, false);
   if (changed || !full_tidying)
     return changed;
 
@@ -3640,22 +3670,45 @@ tidy_control_flow (basic_block xbb, bool full_tidying)
       /* Also this jump is not at the scheduling boundary.  */
       && !IN_CURRENT_FENCE_P (BB_END (xbb->prev_bb)))
     {
+      bool recompute_toporder_p;
       /* Clear data structures of jump - jump itself will be removed
          by sel_redirect_edge_and_branch.  */
       clear_expr (INSN_EXPR (BB_END (xbb->prev_bb)));
-      sel_redirect_edge_and_branch (EDGE_SUCC (xbb->prev_bb, 0), xbb);
+      recompute_toporder_p
+        = sel_redirect_edge_and_branch (EDGE_SUCC (xbb->prev_bb, 0), xbb);
+
       gcc_assert (EDGE_SUCC (xbb->prev_bb, 0)->flags & EDGE_FALLTHRU);
 
       /* It can turn out that after removing unused jump, basic block
          that contained that jump, becomes empty too.  In such case
          remove it too.  */
       if (sel_bb_empty_p (xbb->prev_bb))
-        changed = maybe_tidy_empty_bb (xbb->prev_bb);
+        changed = maybe_tidy_empty_bb (xbb->prev_bb, recompute_toporder_p);
+      else if (recompute_toporder_p)
+       sel_recompute_toporder ();
     }
 
   return changed;
 }
 
+/* Purge meaningless empty blocks in the middle of a region.  */
+void
+purge_empty_blocks (void)
+{
+  /* Do not attempt to delete preheader.  */
+  int i = sel_is_loop_preheader_p (BASIC_BLOCK (BB_TO_BLOCK (0))) ? 1 : 0;
+
+  while (i < current_nr_blocks)
+    {
+      basic_block b = BASIC_BLOCK (BB_TO_BLOCK (i));
+
+      if (maybe_tidy_empty_bb (b, false))
+       continue;
+
+      i++;
+    }
+}
+
 /* Rip-off INSN from the insn stream.  When ONLY_DISCONNECT is true,
    do not delete insn's data, because it will be later re-emitted.
    Return true if we have removed some blocks afterwards.  */
@@ -5355,8 +5408,9 @@ sel_redirect_edge_and_branch_force (edge e, basic_block to)
     sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP);
 }
 
-/* A wrapper for redirect_edge_and_branch.  */
-void
+/* A wrapper for redirect_edge_and_branch.  Return TRUE if blocks connected by
+   redirected edge are in reverse topological order.  */
+bool
 sel_redirect_edge_and_branch (edge e, basic_block to)
 {
   bool latch_edge_p;
@@ -5364,6 +5418,7 @@ sel_redirect_edge_and_branch (edge e, basic_block to)
   int prev_max_uid;
   rtx jump;
   edge redirected;
+  bool recompute_toporder_p = false;
 
   latch_edge_p = (pipelining_p
                   && current_loop_nest
@@ -5383,9 +5438,18 @@ sel_redirect_edge_and_branch (edge e, basic_block to)
       gcc_assert (loop_latch_edge (current_loop_nest));
     }
 
+  /* In rare situations, the topological relation between the blocks connected
+     by the redirected edge can change (see PR42245 for an example).  Update
+     block_to_bb/bb_to_block.  */
+  if (CONTAINING_RGN (e->src->index) == CONTAINING_RGN (to->index)
+      && BLOCK_TO_BB (e->src->index) > BLOCK_TO_BB (to->index))
+    recompute_toporder_p = true;
+
   jump = find_new_jump (src, NULL, prev_max_uid);
   if (jump)
     sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP);
+
+  return recompute_toporder_p;
 }
 
 /* This variable holds the cfg hooks used by the selective scheduler.  */
index 1950a65e77f67a157b921cb145b8d1af1c895e69..db2989b61117fd95ac064957a19f7d2c54295b23 100644 (file)
@@ -1613,11 +1613,11 @@ extern bool tidy_control_flow (basic_block, bool);
 extern void free_bb_note_pool (void);
 
 extern void sel_remove_empty_bb (basic_block, bool, bool);
-extern bool maybe_tidy_empty_bb (basic_block bb);
+extern void purge_empty_blocks (void);
 extern basic_block sel_split_edge (edge);
 extern basic_block sel_create_recovery_block (insn_t);
 extern void sel_merge_blocks (basic_block, basic_block);
-extern void sel_redirect_edge_and_branch (edge, basic_block);
+extern bool sel_redirect_edge_and_branch (edge, basic_block);
 extern void sel_redirect_edge_and_branch_force (edge, basic_block);
 extern void sel_init_pipelining (void);
 extern void sel_finish_pipelining (void);
index 27c0f21ea3b38db9a7fd0db62764e868ea8cda26..4ca8ab22f8586885c39155d1f0e0dfdc33f9db6a 100644 (file)
@@ -6765,24 +6765,6 @@ setup_current_loop_nest (int rgn)
   gcc_assert (LOOP_MARKED_FOR_PIPELINING_P (current_loop_nest));
 }
 
-/* Purge meaningless empty blocks in the middle of a region.  */
-static void
-purge_empty_blocks (void)
-{
-  /* Do not attempt to delete preheader.  */
-  int i = sel_is_loop_preheader_p (BASIC_BLOCK (BB_TO_BLOCK (0))) ? 1 : 0;
-
-  while (i < current_nr_blocks)
-    {
-      basic_block b = BASIC_BLOCK (BB_TO_BLOCK (i));
-
-      if (maybe_tidy_empty_bb (b))
-       continue;
-
-      i++;
-    }
-}
-
 /* Compute instruction priorities for current region.  */
 static void
 sel_compute_priorities (int rgn)
index a407fb72536371fc3ed5fe2aeac94c997fdd342f..855b25673f87bde6a0fa9a0d88a4e1874a44278c 100644 (file)
@@ -1,6 +1,12 @@
 2010-01-14  Alexander Monakov <amonakov@ispras.ru>
 
-        PR rtl-optimization/42294
+       PR middle-end/42245
+       * gcc.dg/pr42245.c: New.
+       * gcc.dg/pr42245-2.c: New.
+
+2010-01-14  Alexander Monakov <amonakov@ispras.ru>
+
+        PR rtl-optimization/42249
         * gcc.dg/pr42249.c: New.
 
 2010-01-14  Jakub Jelinek  <jakub@redhat.com>