if (!outcome)
return false;
+ /* If cand->insn has been already modified, update cand->mode to a wider
+ mode if possible, or punt. */
+ if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
+ {
+ enum machine_mode mode;
+ rtx set;
+
+ if (state->modified[INSN_UID (cand->insn)].kind
+ != (cand->code == ZERO_EXTEND
+ ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT)
+ || state->modified[INSN_UID (cand->insn)].mode != cand->mode
+ || (set = single_set (cand->insn)) == NULL_RTX)
+ return false;
+ mode = GET_MODE (SET_DEST (set));
+ gcc_assert (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (cand->mode));
+ cand->mode = mode;
+ }
+
merge_successful = true;
/* Go through the defs vector and try to merge all the definitions
static void
add_removable_extension (const_rtx expr, rtx insn,
VEC (ext_cand, heap) **insn_list,
- ext_cand **def_map)
+ unsigned *def_map)
{
enum rtx_code code;
enum machine_mode mode;
+ unsigned int idx;
rtx src, dest;
/* We are looking for SET (REG N) (ANY_EXTEND (REG N)). */
/* Second, make sure the reaching definitions don't feed another and
different extension. FIXME: this obviously can be improved. */
for (def = defs; def; def = def->next)
- if ((cand = def_map[INSN_UID(DF_REF_INSN (def->ref))])
+ if ((idx = def_map[INSN_UID(DF_REF_INSN (def->ref))])
+ && (cand = VEC_index (ext_cand, *insn_list, idx - 1))
&& (cand->code != code || cand->mode != mode))
{
if (dump_file)
cand->code = code;
cand->mode = mode;
cand->insn = insn;
+ idx = VEC_length (ext_cand, *insn_list);
for (def = defs; def; def = def->next)
- def_map[INSN_UID(DF_REF_INSN (def->ref))] = cand;
+ def_map[INSN_UID(DF_REF_INSN (def->ref))] = idx;
}
}
VEC (ext_cand, heap) *insn_list = NULL;
basic_block bb;
rtx insn, set;
- ext_cand **def_map = XCNEWVEC (ext_cand *, max_insn_uid);
+ unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
FOR_EACH_BB (bb)
FOR_BB_INSNS (bb, insn)