diff options
author | amonakov <amonakov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-01-14 10:28:47 +0000 |
---|---|---|
committer | amonakov <amonakov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-01-14 10:28:47 +0000 |
commit | 93919afc48209d7787b7a99a5c89c7a3768c034b (patch) | |
tree | 58d8950f43c2356fc70a2c8f766cbde3b179e266 /gcc | |
parent | 28abb7ee5500ae6ca0959a7cce3dc46b760adb2a (diff) | |
download | gcc-93919afc48209d7787b7a99a5c89c7a3768c034b.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155890 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/sel-sched-ir.c | 80 | ||||
-rw-r--r-- | gcc/sel-sched-ir.h | 4 | ||||
-rw-r--r-- | gcc/sel-sched.c | 18 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 |
5 files changed, 99 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b4ebd0b20a3..fda47c64143 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c index e864eb40c7a..ad1dcb212de 100644 --- a/gcc/sel-sched-ir.c +++ b/gcc/sel-sched-ir.c @@ -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. */ diff --git a/gcc/sel-sched-ir.h b/gcc/sel-sched-ir.h index 1950a65e77f..db2989b6111 100644 --- a/gcc/sel-sched-ir.h +++ b/gcc/sel-sched-ir.h @@ -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); diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index 27c0f21ea3b..4ca8ab22f85 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a407fb72536..855b25673f8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> |