aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/ree.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/ree.c')
-rw-r--r--gcc-4.9/gcc/ree.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/gcc-4.9/gcc/ree.c b/gcc-4.9/gcc/ree.c
index fcde9a0f3..435c16696 100644
--- a/gcc-4.9/gcc/ree.c
+++ b/gcc-4.9/gcc/ree.c
@@ -507,6 +507,8 @@ struct ATTRIBUTE_PACKED ext_modified
/* Kind of modification of the insn. */
ENUM_BITFIELD(ext_modified_kind) kind : 2;
+ unsigned int do_not_reextend : 1;
+
/* True if the insn is scheduled to be deleted. */
unsigned int deleted : 1;
};
@@ -712,8 +714,10 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
register than the source operand, then additional restrictions
are needed. Note we have to handle cases where we have nested
extensions in the source operand. */
- if (REGNO (SET_DEST (PATTERN (cand->insn)))
- != REGNO (get_extended_src_reg (SET_SRC (PATTERN (cand->insn)))))
+ bool copy_needed
+ = (REGNO (SET_DEST (PATTERN (cand->insn)))
+ != REGNO (get_extended_src_reg (SET_SRC (PATTERN (cand->insn)))));
+ if (copy_needed)
{
/* In theory we could handle more than one reaching def, it
just makes the code to update the insn stream more complex. */
@@ -722,7 +726,7 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
/* We require the candidate not already be modified. It may,
for example have been changed from a (sign_extend (reg))
- into (zero_extend (sign_extend (reg)).
+ into (zero_extend (sign_extend (reg))).
Handling that case shouldn't be terribly difficult, but the code
here and the code to emit copies would need auditing. Until
@@ -777,6 +781,34 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
|| reg_set_between_p (SET_DEST (PATTERN (cand->insn)),
def_insn, cand->insn))
return false;
+
+ /* We must be able to copy between the two registers. Generate,
+ recognize and verify constraints of the copy. Also fail if this
+ generated more than one insn.
+
+ This generates garbage since we throw away the insn when we're
+ done, only to recreate it later if this test was successful.
+
+ Make sure to get the mode from the extension (cand->insn). This
+ is different than in the code to emit the copy as we have not
+ modified the defining insn yet. */
+ start_sequence ();
+ rtx pat = PATTERN (cand->insn);
+ rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (pat)),
+ REGNO (XEXP (SET_SRC (pat), 0)));
+ rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (pat)),
+ REGNO (SET_DEST (pat)));
+ emit_move_insn (new_dst, new_src);
+
+ rtx insn = get_insns();
+ end_sequence ();
+ if (NEXT_INSN (insn))
+ return false;
+ if (recog_memoized (insn) == -1)
+ return false;
+ extract_insn (insn);
+ if (!constrain_operands (1))
+ return false;
}
@@ -843,11 +875,15 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
fprintf (dump_file, "All merges were successful.\n");
FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
- if (state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE)
- state->modified[INSN_UID (def_insn)].kind
- = (cand->code == ZERO_EXTEND
- ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT);
+ {
+ ext_modified *modified = &state->modified[INSN_UID (def_insn)];
+ if (modified->kind == EXT_MODIFIED_NONE)
+ modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT
+ : EXT_MODIFIED_SEXT);
+ if (copy_needed)
+ modified->do_not_reextend = 1;
+ }
return true;
}
else
@@ -1087,6 +1123,9 @@ find_and_remove_re (void)
static unsigned int
rest_of_handle_ree (void)
{
+ if (df_check_ud_du_memory_usage ())
+ return 0;
+
timevar_push (TV_REE);
find_and_remove_re ();
timevar_pop (TV_REE);