Commit b59ab570 by Alexander Monakov

re PR middle-end/42245 (ICE in verify_backedges for 197.parser with sel-sched)

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
parent 0666ff4e
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> 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 * sel-sched.c (try_replace_dest_reg): When chosen register
and original register is the same, do not bail out early, but and original register is the same, do not bail out early, but
still check all original insns for validity of replacing destination still check all original insns for validity of replacing destination
......
...@@ -3503,9 +3503,36 @@ verify_backedges (void) ...@@ -3503,9 +3503,36 @@ verify_backedges (void)
/* Functions to work with control flow. */ /* 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. */ /* Tidy the possibly empty block BB. */
bool static bool
maybe_tidy_empty_bb (basic_block bb) maybe_tidy_empty_bb (basic_block bb, bool recompute_toporder_p)
{ {
basic_block succ_bb, pred_bb; basic_block succ_bb, pred_bb;
edge e; edge e;
...@@ -3552,7 +3579,7 @@ maybe_tidy_empty_bb (basic_block bb) ...@@ -3552,7 +3579,7 @@ maybe_tidy_empty_bb (basic_block bb)
if (!(e->flags & EDGE_FALLTHRU)) 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; rescan_p = true;
break; break;
} }
...@@ -3572,6 +3599,9 @@ maybe_tidy_empty_bb (basic_block bb) ...@@ -3572,6 +3599,9 @@ maybe_tidy_empty_bb (basic_block bb)
remove_empty_bb (bb, true); remove_empty_bb (bb, true);
} }
if (recompute_toporder_p)
sel_recompute_toporder ();
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
verify_backedges (); verify_backedges ();
#endif #endif
...@@ -3589,7 +3619,7 @@ tidy_control_flow (basic_block xbb, bool full_tidying) ...@@ -3589,7 +3619,7 @@ tidy_control_flow (basic_block xbb, bool full_tidying)
insn_t first, last; insn_t first, last;
/* First check whether XBB is empty. */ /* First check whether XBB is empty. */
changed = maybe_tidy_empty_bb (xbb); changed = maybe_tidy_empty_bb (xbb, false);
if (changed || !full_tidying) if (changed || !full_tidying)
return changed; return changed;
...@@ -3640,22 +3670,45 @@ tidy_control_flow (basic_block xbb, bool full_tidying) ...@@ -3640,22 +3670,45 @@ tidy_control_flow (basic_block xbb, bool full_tidying)
/* Also this jump is not at the scheduling boundary. */ /* Also this jump is not at the scheduling boundary. */
&& !IN_CURRENT_FENCE_P (BB_END (xbb->prev_bb))) && !IN_CURRENT_FENCE_P (BB_END (xbb->prev_bb)))
{ {
bool recompute_toporder_p;
/* Clear data structures of jump - jump itself will be removed /* Clear data structures of jump - jump itself will be removed
by sel_redirect_edge_and_branch. */ by sel_redirect_edge_and_branch. */
clear_expr (INSN_EXPR (BB_END (xbb->prev_bb))); 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); gcc_assert (EDGE_SUCC (xbb->prev_bb, 0)->flags & EDGE_FALLTHRU);
/* It can turn out that after removing unused jump, basic block /* It can turn out that after removing unused jump, basic block
that contained that jump, becomes empty too. In such case that contained that jump, becomes empty too. In such case
remove it too. */ remove it too. */
if (sel_bb_empty_p (xbb->prev_bb)) 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; 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, /* 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. do not delete insn's data, because it will be later re-emitted.
Return true if we have removed some blocks afterwards. */ Return true if we have removed some blocks afterwards. */
...@@ -5355,8 +5408,9 @@ sel_redirect_edge_and_branch_force (edge e, basic_block to) ...@@ -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); sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP);
} }
/* A wrapper for redirect_edge_and_branch. */ /* A wrapper for redirect_edge_and_branch. Return TRUE if blocks connected by
void redirected edge are in reverse topological order. */
bool
sel_redirect_edge_and_branch (edge e, basic_block to) sel_redirect_edge_and_branch (edge e, basic_block to)
{ {
bool latch_edge_p; bool latch_edge_p;
...@@ -5364,6 +5418,7 @@ sel_redirect_edge_and_branch (edge e, basic_block to) ...@@ -5364,6 +5418,7 @@ sel_redirect_edge_and_branch (edge e, basic_block to)
int prev_max_uid; int prev_max_uid;
rtx jump; rtx jump;
edge redirected; edge redirected;
bool recompute_toporder_p = false;
latch_edge_p = (pipelining_p latch_edge_p = (pipelining_p
&& current_loop_nest && current_loop_nest
...@@ -5383,9 +5438,18 @@ sel_redirect_edge_and_branch (edge e, basic_block to) ...@@ -5383,9 +5438,18 @@ sel_redirect_edge_and_branch (edge e, basic_block to)
gcc_assert (loop_latch_edge (current_loop_nest)); 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); jump = find_new_jump (src, NULL, prev_max_uid);
if (jump) if (jump)
sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP); 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. */ /* This variable holds the cfg hooks used by the selective scheduler. */
......
...@@ -1613,11 +1613,11 @@ extern bool tidy_control_flow (basic_block, bool); ...@@ -1613,11 +1613,11 @@ extern bool tidy_control_flow (basic_block, bool);
extern void free_bb_note_pool (void); extern void free_bb_note_pool (void);
extern void sel_remove_empty_bb (basic_block, bool, bool); 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_split_edge (edge);
extern basic_block sel_create_recovery_block (insn_t); extern basic_block sel_create_recovery_block (insn_t);
extern void sel_merge_blocks (basic_block, basic_block); 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_redirect_edge_and_branch_force (edge, basic_block);
extern void sel_init_pipelining (void); extern void sel_init_pipelining (void);
extern void sel_finish_pipelining (void); extern void sel_finish_pipelining (void);
......
...@@ -6765,24 +6765,6 @@ setup_current_loop_nest (int rgn) ...@@ -6765,24 +6765,6 @@ setup_current_loop_nest (int rgn)
gcc_assert (LOOP_MARKED_FOR_PIPELINING_P (current_loop_nest)); 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. */ /* Compute instruction priorities for current region. */
static void static void
sel_compute_priorities (int rgn) sel_compute_priorities (int rgn)
......
2010-01-14 Alexander Monakov <amonakov@ispras.ru> 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. * gcc.dg/pr42249.c: New.
2010-01-14 Jakub Jelinek <jakub@redhat.com> 2010-01-14 Jakub Jelinek <jakub@redhat.com>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment