diff options
author | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-01-15 18:13:52 +0000 |
---|---|---|
committer | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-01-15 18:13:52 +0000 |
commit | 92802c6fb22841547067e577a9820d25ccfefd15 (patch) | |
tree | e0f2de4b26fbea16dedfb92ad4e491726101c7f8 /gcc/ree.c | |
parent | b69fc80ac37d8117944c7c56786c47fb6f5b2f5b (diff) | |
download | gcc-92802c6fb22841547067e577a9820d25ccfefd15.tar.gz |
PR tree-optimization/59747
* ree.c (find_and_remove_re): Properly handle case where a second
eliminated extension requires widening a copy created for elimination
of a prior extension.
(combine_set_extension): Ensure that the number of hard regs needed
for a destination register does not change when we widen it.
PR tree-optimization/59747
* gcc.c-torture/execute/pr59747.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@206638 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ree.c')
-rw-r--r-- | gcc/ree.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/gcc/ree.c b/gcc/ree.c index 63cc8cc7c32..19d821ce05a 100644 --- a/gcc/ree.c +++ b/gcc/ree.c @@ -297,6 +297,12 @@ combine_set_extension (ext_cand *cand, rtx curr_insn, rtx *orig_set) else new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (*orig_set))); + /* We're going to be widening the result of DEF_INSN, ensure that doing so + doesn't change the number of hard registers needed for the result. */ + if (HARD_REGNO_NREGS (REGNO (new_reg), cand->mode) + != HARD_REGNO_NREGS (REGNO (orig_src), GET_MODE (SET_DEST (*orig_set)))) + return false; + /* Merge constants by directly moving the constant into the register under some conditions. Recall that RTL constants are sign-extended. */ if (GET_CODE (orig_src) == CONST_INT @@ -1017,11 +1023,20 @@ find_and_remove_re (void) for (unsigned int i = 0; i < reinsn_copy_list.length (); i += 2) { rtx curr_insn = reinsn_copy_list[i]; + rtx def_insn = reinsn_copy_list[i + 1]; + + /* Use the mode of the destination of the defining insn + for the mode of the copy. This is necessary if the + defining insn was used to eliminate a second extension + that was wider than the first. */ + rtx sub_rtx = *get_sub_rtx (def_insn); rtx pat = PATTERN (curr_insn); - rtx new_reg = gen_rtx_REG (GET_MODE (SET_DEST (pat)), + rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)), REGNO (XEXP (SET_SRC (pat), 0))); - rtx set = gen_rtx_SET (VOIDmode, new_reg, SET_DEST (pat)); - emit_insn_after (set, reinsn_copy_list[i + 1]); + rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)), + REGNO (SET_DEST (pat))); + rtx set = gen_rtx_SET (VOIDmode, new_dst, new_src); + emit_insn_after (set, def_insn); } /* Delete all useless extensions here in one sweep. */ |