/* Subroutine of try_combine. Determine whether the combine replacement
patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
insn_rtx_cost that the original instruction sequence I1, I2, I3 and
- undobuf.other_insn. Note that I1 and/or NEWI2PAT may be NULL_RTX.
+ undobuf.other_insn. Note that I1 and/or NEWI2PAT may be NULL_RTX.
NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX. This
function returns false, if the costs of all instructions can be
estimated, and the replacements are more expensive than the original
register and establishing log links when def is encountered.
Note that we do not clear next_use array in order to save time,
so we have to test whether the use is in the same basic block as def.
-
+
There are a few cases below when we do not consider the definition or
usage -- these are taken from original flow.c did. Don't ask me why it is
done this way; I don't know and if it works, I don't want to know. */
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
{
- rtx reg = DECL_INCOMING_RTL (arg);
+ rtx x, reg = DECL_INCOMING_RTL (arg);
int uns1, uns3;
enum machine_mode mode1, mode2, mode3, mode4;
mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
- /* The mode and signedness of the argument as it is actually passed,
+ /* The mode and signedness of the argument as it is actually passed,
after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions. */
mode3 = promote_function_mode (DECL_ARG_TYPE (arg), mode2, &uns3,
TREE_TYPE (cfun->decl), 0);
/* The mode of the register in which the argument is being passed. */
mode4 = GET_MODE (reg);
- /* Eliminate sign extensions in the callee when possible. Only
- do this when:
- (a) a mode promotion has occurred;
- (b) the mode of the register is the same as the mode of
- the argument as it is passed; and
- (c) the signedness does not change across any of the promotions; and
- (d) when no language-level promotions (which we cannot guarantee
- will have been done by an external caller) are necessary,
- unless we know that this function is only ever called from
- the current compilation unit -- all of whose call sites will
- do the mode1 --> mode2 promotion. */
- if (mode1 != mode3
- && mode3 == mode4
- && uns1 == uns3
- && (mode1 == mode2 || strictly_local))
- {
- /* Record that the value was promoted from mode1 to mode3,
- so that any sign extension at the head of the current
- function may be eliminated. */
- rtx x;
- x = gen_rtx_CLOBBER (mode1, const0_rtx);
- x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
- record_value_for_reg (reg, first, x);
- }
+ /* Eliminate sign extensions in the callee when:
+ (a) A mode promotion has occurred; */
+ if (mode1 == mode3)
+ continue;
+ /* (b) The mode of the register is the same as the mode of
+ the argument as it is passed; */
+ if (mode3 != mode4)
+ continue;
+ /* (c) There's no language level extension; */
+ if (mode1 == mode2)
+ ;
+ /* (c.1) All callers are from the current compilation unit. If that's
+ the case we don't have to rely on an ABI, we only have to know
+ what we're generating right now, and we know that we will do the
+ mode1 to mode2 promotion with the given sign. */
+ else if (!strictly_local)
+ continue;
+ /* (c.2) The combination of the two promotions is useful. This is
+ true when the signs match, or if the first promotion is unsigned.
+ In the later case, (sign_extend (zero_extend x)) is the same as
+ (zero_extend (zero_extend x)), so make sure to force UNS3 true. */
+ else if (uns1)
+ uns3 = true;
+ else if (uns3)
+ continue;
+
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
}
}
if (newi2pat && new_i2_notes)
distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
-
+
if (new_i3_notes)
distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
}
df_insn_rescan (i3);
}
-
+
/* Set new_direct_jump_p if a new return or simple jump instruction
has been created. Adjust the CFG accordingly. */
*new_direct_jump_p = 1;
update_cfg_for_uncondjump (i3);
}
-
+
combine_successes++;
undo_commit ();
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), 0));
+ /* We can truncate a constant value and return it. */
+ if (CONST_INT_P (XEXP (x, 0)))
+ return gen_int_mode (INTVAL (XEXP (x, 0)), mode);
+
/* Similarly to what we do in simplify-rtx.c, a truncate of a register
whose value is a comparison can be replaced with a subreg if
STORE_FLAG_VALUE permits. */
}
/* Try simplify a*(b/c) as (a*b)/c. */
- if (FLOAT_MODE_P (mode) && flag_associative_math
+ if (FLOAT_MODE_P (mode) && flag_associative_math
&& GET_CODE (XEXP (x, 0)) == DIV)
{
rtx tem = simplify_binary_operation (MULT, mode,
tem = make_compound_operation (SUBREG_REG (x), in_code);
{
- rtx simplified;
- simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
- SUBREG_BYTE (x));
+ rtx simplified = simplify_subreg (mode, tem, GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
if (simplified)
tem = simplified;
if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
&& subreg_lowpart_p (x))
{
rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
if (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
&& ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
return -1;
- if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
+ if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
{
gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
notes = alloc_reg_note (REG_UNUSED,