int flags = DF_REF_FLAGS (use);
rtx set = single_set (insn);
bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
- int old_cost = rtx_cost (SET_SRC (set), SET, speed);
+ int old_cost = 0;
bool ok;
+ /* forward_propagate_subreg may be operating on an instruction with
+ multiple sets. If so, assume the cost of the new instruction is
+ not greater than the old one. */
+ if (set)
+ old_cost = rtx_cost (SET_SRC (set), SET, speed);
if (dump_file)
{
fprintf (dump_file, "\nIn insn %d, replacing\n ", INSN_UID (insn));
}
else if (DF_REF_TYPE (use) == DF_REF_REG_USE
+ && set
&& rtx_cost (SET_SRC (set), SET, speed) > old_cost)
{
if (dump_file)
return ok;
}
+#ifdef LOAD_EXTEND_OP
+static df_ref
+get_reg_use_in (rtx insn, rtx reg)
+{
+ df_ref *use_vec;
-/* If USE is a paradoxical subreg, see if it can be replaced by a pseudo. */
+ for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
+ {
+ df_ref use = *use_vec;
+
+ if (!DF_REF_IS_ARTIFICIAL (use)
+ && DF_REF_TYPE (use) == DF_REF_REG_USE
+ && DF_REF_REG (use) == reg)
+ return use;
+ }
+ return NULL;
+}
+#endif
+
+/* If USE is a subreg, see if it can be replaced by a pseudo. */
static bool
forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
rtx use_reg = DF_REF_REG (use);
rtx use_insn, src;
- /* Only consider paradoxical subregs... */
+ /* Only consider subregs... */
enum machine_mode use_mode = GET_MODE (use_reg);
if (GET_CODE (use_reg) != SUBREG
- || !REG_P (SET_DEST (def_set))
- || GET_MODE_SIZE (use_mode)
- <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
+ || !REG_P (SET_DEST (def_set)))
return false;
- /* If this is a paradoxical SUBREG, we have no idea what value the
- extra bits would have. However, if the operand is equivalent to
- a SUBREG whose operand is the same as our mode, and all the modes
- are within a word, we can just use the inner operand because
- these SUBREGs just say how to treat the register. */
- use_insn = DF_REF_INSN (use);
- src = SET_SRC (def_set);
- if (GET_CODE (src) == SUBREG
- && REG_P (SUBREG_REG (src))
- && GET_MODE (SUBREG_REG (src)) == use_mode
- && subreg_lowpart_p (src)
- && all_uses_available_at (def_insn, use_insn))
- return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src),
- def_insn, false);
- else
- return false;
+ /* If this is a paradoxical SUBREG... */
+ if (GET_MODE_SIZE (use_mode)
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
+ {
+ /* If this is a paradoxical SUBREG, we have no idea what value the
+ extra bits would have. However, if the operand is equivalent to
+ a SUBREG whose operand is the same as our mode, and all the modes
+ are within a word, we can just use the inner operand because
+ these SUBREGs just say how to treat the register. */
+ use_insn = DF_REF_INSN (use);
+ src = SET_SRC (def_set);
+ if (GET_CODE (src) == SUBREG
+ && REG_P (SUBREG_REG (src))
+ && GET_MODE (SUBREG_REG (src)) == use_mode
+ && subreg_lowpart_p (src)
+ && all_uses_available_at (def_insn, use_insn))
+ return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src),
+ def_insn, false);
+ }
+
+ /* If this is a SUBREG of a ZERO_EXTEND or SIGN_EXTEND, and the SUBREG
+ is the low part of the reg being extended then just use the inner
+ operand. Don't do this if the ZERO_EXTEND or SIGN_EXTEND insn will
+ be removed due to it matching a LOAD_EXTEND_OP load from memory. */
+ else if (subreg_lowpart_p (use_reg))
+ {
+#ifdef LOAD_EXTEND_OP
+ df_ref prev_use, prev_def;
+#endif
+ use_insn = DF_REF_INSN (use);
+ src = SET_SRC (def_set);
+ if ((GET_CODE (src) == ZERO_EXTEND
+ || GET_CODE (src) == SIGN_EXTEND)
+ && REG_P (XEXP (src, 0))
+ && GET_MODE (XEXP (src, 0)) == use_mode
+#ifdef LOAD_EXTEND_OP
+ && !(LOAD_EXTEND_OP (use_mode) == GET_CODE (src)
+ && (prev_use = get_reg_use_in (def_insn, XEXP (src, 0))) != NULL
+ && (prev_def = get_def_for_use (prev_use)) != NULL
+ && !DF_REF_IS_ARTIFICIAL (prev_def)
+ && NONJUMP_INSN_P (DF_REF_INSN (prev_def))
+ && GET_CODE (PATTERN (DF_REF_INSN (prev_def))) == SET
+ && GET_CODE (SET_SRC (PATTERN (DF_REF_INSN (prev_def)))) == MEM
+ && rtx_equal_p (SET_DEST (PATTERN (DF_REF_INSN (prev_def))),
+ XEXP (src, 0)))
+#endif
+ && all_uses_available_at (def_insn, use_insn))
+ return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0),
+ def_insn, false);
+ }
+
+ return false;
}
/* Try to replace USE with SRC (defined in DEF_INSN) in __asm. */