diff options
author | David Malcolm <dmalcolm@redhat.com> | 2019-01-16 20:13:23 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2019-01-16 20:13:23 +0000 |
commit | 15b93db9ca258710e3abb43e2378ef3601e3a697 (patch) | |
tree | 843768dfbe9461304aa053363cc987e1a4fe8b18 /gcc/combine.c | |
parent | 33b5a38c2dc961e9dd3e28ffd535d81c40d2b7bb (diff) | |
download | gcc-15b93db9ca258710e3abb43e2378ef3601e3a697.zip gcc-15b93db9ca258710e3abb43e2378ef3601e3a697.tar.gz gcc-15b93db9ca258710e3abb43e2378ef3601e3a697.tar.bz2 |
Fix ICE due to "combine" creating unreachable EH blocks (PR target/88861)
PR target/88861 reports an ICE in "ce2" due to an unreachable
basic block.
The block becomes unreachable in "combine" when delete_noop_moves
deletes an insn with a REG_EH_REGION, deleting the EH edge, the
only edge leading to the basic block.
Normally, rest_of_handle_combine would call cleanup_cfg, deleting
unreachable blocks, if combine_instructions returns true, and
combine_instructions does return true for some cases of edge-removal,
but it doesn't for this case, leading to the ICE.
This patch updates delete_noop_moves so that it returns true if
it deletes any edges, and passes that through to combine_instructions,
so that it too will return true if any edges were deleted, ensuring that
cleanup_cfg will be called by rest_of_handle_combine for this case,
deleting the now-unreachable block, and fixing the ICE.
gcc/ChangeLog:
PR target/88861
* combine.c (delete_noop_moves): Convert to "bool" return,
returning true if any edges are eliminated.
(combine_instructions): Also return true if delete_noop_moves
returns true.
gcc/testsuite/ChangeLog:
PR target/88861
* g++.dg/torture/pr88861.C: New test.
From-SVN: r267984
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index e226c7dd..c108f65 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -983,14 +983,17 @@ combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3, } -/* Delete any insns that copy a register to itself. */ +/* Delete any insns that copy a register to itself. + Return true if the CFG was changed. */ -static void +static bool delete_noop_moves (void) { rtx_insn *insn, *next; basic_block bb; + bool edges_deleted = false; + FOR_EACH_BB_FN (bb, cfun) { for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next) @@ -1001,10 +1004,12 @@ delete_noop_moves (void) if (dump_file) fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn)); - delete_insn_and_edges (insn); + edges_deleted |= delete_insn_and_edges (insn); } } } + + return edges_deleted; } @@ -1143,8 +1148,8 @@ insn_a_feeds_b (rtx_insn *a, rtx_insn *b) /* Main entry point for combiner. F is the first insn of the function. NREGS is the first unused pseudo-reg number. - Return nonzero if the combiner has turned an indirect jump - instruction into a direct jump. */ + Return nonzero if the CFG was changed (e.g. if the combiner has + turned an indirect jump instruction into a direct jump). */ static int combine_instructions (rtx_insn *f, unsigned int nregs) { @@ -1529,7 +1534,7 @@ retry: default_rtl_profile (); clear_bb_flags (); new_direct_jump_p |= purge_all_dead_edges (); - delete_noop_moves (); + new_direct_jump_p |= delete_noop_moves (); /* Clean up. */ obstack_free (&insn_link_obstack, NULL); |