diff options
author | Richard Henderson <rth@redhat.com> | 2014-06-22 12:32:57 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2014-06-22 12:32:57 -0700 |
commit | 08281ce0fb9870da71ad27f4a06ff0091d227e43 (patch) | |
tree | 367808896d5be5fd32976d88ee4cb10130d107b6 | |
parent | 37317a1fc012ba4208a01d337864c579c55d3a3d (diff) | |
download | gcc-08281ce0fb9870da71ad27f4a06ff0091d227e43.zip gcc-08281ce0fb9870da71ad27f4a06ff0091d227e43.tar.gz gcc-08281ce0fb9870da71ad27f4a06ff0091d227e43.tar.bz2 |
re PR bootstrap/61565 (ICE building libjava/interpret.cc)
PR target/61565
* compare-elim.c (struct comparison): Add eh_note.
(find_comparison_dom_walker::before_dom_children): Don't eliminate
a redundant comparison in a different EH region. Purge EH edges if
necessary.
From-SVN: r211881
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/compare-elim.c | 75 |
2 files changed, 58 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5bc7bfc..bc72a7f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2014-06-22 Richard Henderson <rth@redhat.com> + + PR target/61565 + * compare-elim.c (struct comparison): Add eh_note. + (find_comparison_dom_walker::before_dom_children): Don't eliminate + a redundant comparison in a different EH region. Purge EH edges if + necessary. + 2014-06-22 Segher Boessenkool <segher@kernel.crashing.org> * config/rs6000/rs6000.md (maybe_var_shift): New define_attr. diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c index 2fbb75b..4ecdd48 100644 --- a/gcc/compare-elim.c +++ b/gcc/compare-elim.c @@ -100,6 +100,9 @@ struct comparison constants. */ rtx in_a, in_b; + /* The REG_EH_REGION of the comparison. */ + rtx eh_note; + /* Information about how this comparison is used. */ struct comparison_use uses[MAX_CMP_USE]; @@ -262,6 +265,7 @@ find_comparison_dom_walker::before_dom_children (basic_block bb) struct comparison *last_cmp; rtx insn, next, last_clobber; bool last_cmp_valid; + bool need_purge = false; bitmap killed; killed = BITMAP_ALLOC (NULL); @@ -303,44 +307,60 @@ find_comparison_dom_walker::before_dom_children (basic_block bb) if (src) { enum machine_mode src_mode = GET_MODE (src); + rtx eh_note = NULL; - /* Eliminate a compare that's redundant with the previous. */ - if (last_cmp_valid - && rtx_equal_p (last_cmp->in_a, XEXP (src, 0)) - && rtx_equal_p (last_cmp->in_b, XEXP (src, 1))) - { - rtx flags, x; - enum machine_mode new_mode - = targetm.cc_modes_compatible (last_cmp->orig_mode, src_mode); + if (flag_non_call_exceptions) + eh_note = find_reg_note (insn, REG_EH_REGION, NULL); - /* New mode is incompatible with the previous compare mode. */ - if (new_mode == VOIDmode) - continue; + if (!last_cmp_valid) + goto dont_delete; - if (new_mode != last_cmp->orig_mode) - { - flags = gen_rtx_REG (src_mode, targetm.flags_regnum); + /* Take care that it's in the same EH region. */ + if (flag_non_call_exceptions + && !rtx_equal_p (eh_note, last_cmp->eh_note)) + goto dont_delete; - /* Generate new comparison for substitution. */ - x = gen_rtx_COMPARE (new_mode, XEXP (src, 0), XEXP (src, 1)); - x = gen_rtx_SET (VOIDmode, flags, x); + /* Make sure the compare is redundant with the previous. */ + if (!rtx_equal_p (last_cmp->in_a, XEXP (src, 0)) + || !rtx_equal_p (last_cmp->in_b, XEXP (src, 1))) + goto dont_delete; - if (!validate_change (last_cmp->insn, - &PATTERN (last_cmp->insn), x, false)) - continue; + /* New mode must be compatible with the previous compare mode. */ + { + enum machine_mode new_mode + = targetm.cc_modes_compatible (last_cmp->orig_mode, src_mode); + if (new_mode == VOIDmode) + goto dont_delete; - last_cmp->orig_mode = new_mode; - } + if (new_mode != last_cmp->orig_mode) + { + rtx x, flags = gen_rtx_REG (src_mode, targetm.flags_regnum); - delete_insn (insn); - continue; - } + /* Generate new comparison for substitution. */ + x = gen_rtx_COMPARE (new_mode, XEXP (src, 0), XEXP (src, 1)); + x = gen_rtx_SET (VOIDmode, flags, x); + if (!validate_change (last_cmp->insn, + &PATTERN (last_cmp->insn), x, false)) + goto dont_delete; + + last_cmp->orig_mode = new_mode; + } + } + + /* All tests and substitutions succeeded! */ + if (eh_note) + need_purge = true; + delete_insn (insn); + continue; + + dont_delete: last_cmp = XCNEW (struct comparison); last_cmp->insn = insn; last_cmp->prev_clobber = last_clobber; last_cmp->in_a = XEXP (src, 0); last_cmp->in_b = XEXP (src, 1); + last_cmp->eh_note = eh_note; last_cmp->orig_mode = src_mode; all_compares.safe_push (last_cmp); @@ -404,6 +424,11 @@ find_comparison_dom_walker::before_dom_children (basic_block bb) } } } + + /* If we deleted a compare with a REG_EH_REGION note, we may need to + remove EH edges. */ + if (need_purge) + purge_dead_edges (bb); } /* Find all comparisons in the function. */ |