diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2010-11-16 22:13:52 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2010-11-16 22:13:52 +0000 |
commit | 885c9b5d3a53c531fca622b4a3b0ef03df92daed (patch) | |
tree | d3ce62c6785fad984002bec2dbfc693e299f8950 /gcc/ifcvt.c | |
parent | 2b12962772d3b0e85d860609f32bfb28515d5ba9 (diff) | |
download | gcc-885c9b5d3a53c531fca622b4a3b0ef03df92daed.zip gcc-885c9b5d3a53c531fca622b4a3b0ef03df92daed.tar.gz gcc-885c9b5d3a53c531fca622b4a3b0ef03df92daed.tar.bz2 |
re PR rtl-optimization/46315 (-O2 -fno-strict-overflow causes wrong code generation)
PR rtl-optimization/46315
* rtl.h (remove_reg_equal_equiv_notes_for_regno): Declare.
* rtlanal.c (remove_reg_equal_equiv_notes_for_regno): New function
extracted from...
* dce.c (delete_corresponding_reg_eq_notes): ...here. Rename into...
(remove_reg_equal_equiv_notes_for_defs): ...this.
(delete_unmarked_insns): Adjust to above renaming.
* ifcvt.c (dead_or_predicable): Remove REG_EQUAL and REG_EQUIV notes
referring to registers set in the insns being moved, if any.
* df-core.c (df_ref_dump): New function extracted from...
(df_refs_chain_dump): ...here. Call it.
(df_regs_chain_dump): Likewise.
* df-problems.c (df_chain_dump): Print 'e' for uses in notes.
* df-scan.c (df_scan_start_dump): Likewise. Fix long line.
From-SVN: r166827
Diffstat (limited to 'gcc/ifcvt.c')
-rw-r--r-- | gcc/ifcvt.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 58ee90c..c91bbbf 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -3998,6 +3998,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, basic_block other_bb, basic_block new_dest, int reversep) { rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX; + bitmap merge_set = NULL, merge_set_noclobber = NULL; /* Number of pending changes. */ int n_validated_changes = 0; @@ -4086,6 +4087,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, earliest = jump; } #endif + /* Try the NCE path if the CE path did not result in any changes. */ if (n_validated_changes == 0) { @@ -4094,9 +4096,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, that any registers modified are dead at the branch site. */ rtx insn, cond, prev; - bitmap merge_set, merge_set_noclobber, test_live, test_set; - unsigned i, fail = 0; - bitmap_iterator bi; + bitmap test_live, test_set; + bool intersect = false; /* Check for no calls or trapping operations. */ for (insn = head; ; insn = NEXT_INSN (insn)) @@ -4138,12 +4139,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, merge_set = BITMAP_ALLOC (®_obstack); merge_set_noclobber = BITMAP_ALLOC (®_obstack); - test_live = BITMAP_ALLOC (®_obstack); - test_set = BITMAP_ALLOC (®_obstack); - /* ??? bb->local_set is only valid during calculate_global_regs_live, - so we must recompute usage for MERGE_BB. Not so bad, I suppose, - since we've already asserted that MERGE_BB is small. */ /* If we allocated new pseudos (e.g. in the conditional move expander called from noce_emit_cmove), we must resize the array first. */ @@ -4164,17 +4160,22 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, if (! reload_completed && targetm.small_register_classes_for_mode_p (VOIDmode)) { + unsigned i; + bitmap_iterator bi; + EXECUTE_IF_SET_IN_BITMAP (merge_set_noclobber, 0, i, bi) { if (i < FIRST_PSEUDO_REGISTER && ! fixed_regs[i] && ! global_regs[i]) - fail = 1; + goto fail; } } /* For TEST, we're interested in a range of insns, not a whole block. Moreover, we're interested in the insns live from OTHER_BB. */ + test_live = BITMAP_ALLOC (®_obstack); + test_set = BITMAP_ALLOC (®_obstack); /* The loop below takes the set of live registers after JUMP, and calculates the live set before EARLIEST. */ @@ -4195,23 +4196,21 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, /* We can perform the transformation if MERGE_SET_NOCLOBBER & TEST_SET and - MERGE_SET & TEST_LIVE) + MERGE_SET & TEST_LIVE and TEST_SET & DF_LIVE_IN (merge_bb) are empty. */ - if (bitmap_intersect_p (test_set, merge_set_noclobber) - || bitmap_intersect_p (test_live, merge_set) + if (bitmap_intersect_p (merge_set_noclobber, test_set) + || bitmap_intersect_p (merge_set, test_live) || bitmap_intersect_p (test_set, df_get_live_in (merge_bb))) - fail = 1; + intersect = true; - BITMAP_FREE (merge_set_noclobber); - BITMAP_FREE (merge_set); BITMAP_FREE (test_live); BITMAP_FREE (test_set); - if (fail) - return FALSE; + if (intersect) + goto fail; } no_body: @@ -4261,8 +4260,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, if (end == BB_END (merge_bb)) BB_END (merge_bb) = PREV_INSN (head); - /* PR 21767: When moving insns above a conditional branch, REG_EQUAL - notes might become invalid. */ + /* PR 21767: when moving insns above a conditional branch, the REG_EQUAL + notes being moved might become invalid. */ insn = head; do { @@ -4279,6 +4278,20 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, remove_note (insn, note); } while (insn != end && (insn = NEXT_INSN (insn))); + /* PR46315: when moving insns above a conditional branch, the REG_EQUAL + notes referring to the registers being set might become invalid. */ + if (merge_set) + { + unsigned i; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (merge_set_noclobber, 0, i, bi) + remove_reg_equal_equiv_notes_for_regno (i); + + BITMAP_FREE (merge_set); + BITMAP_FREE (merge_set_noclobber); + } + reorder_insns (head, end, PREV_INSN (earliest)); } @@ -4295,6 +4308,12 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, cancel: cancel_changes (0); + fail: + if (merge_set) + { + BITMAP_FREE (merge_set); + BITMAP_FREE (merge_set_noclobber); + } return FALSE; } |