/* 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);
}
}
i2dest = SET_DEST (temp);
i2dest_killed = dead_or_set_p (i2, i2dest);
+ /* Replace the source in I2 with the new constant and make the
+ resulting insn the new pattern for I3. Then skip to where we
+ validate the pattern. Everything was set up above. */
SUBST (SET_SRC (temp),
immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
newpat = PATTERN (i2);
+
+ /* The dest of I3 has been replaced with the dest of I2. */
+ changed_i3_dest = 1;
goto validate_replacement;
}
}
}
}
- /* We come here when we are replacing a destination in I2 with the
- destination of I3. */
validate_replacement:
/* Note which hard regs this insn has as inputs. */
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 ();
if (GET_CODE (XEXP (x, 0)) == CONST
|| GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
{
+ enum machine_mode address_mode
+ = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
+
SUBST (XEXP (x, 0),
- gen_rtx_LO_SUM (Pmode,
- gen_rtx_HIGH (Pmode, XEXP (x, 0)),
+ gen_rtx_LO_SUM (address_mode,
+ gen_rtx_HIGH (address_mode, XEXP (x, 0)),
XEXP (x, 0)));
return &XEXP (XEXP (x, 0), 0);
}
it will not remain in the result. */
if (GET_CODE (XEXP (x, 0)) == PLUS
&& CONST_INT_P (XEXP (XEXP (x, 0), 1))
- && ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
+ && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x)))
{
rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
&& NONJUMP_INSN_P (NEXT_INSN (seq))
&& GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
&& SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
- && memory_address_p (GET_MODE (x),
- SET_SRC (PATTERN (NEXT_INSN (seq)))))
+ && memory_address_addr_space_p
+ (GET_MODE (x), SET_SRC (PATTERN (NEXT_INSN (seq))),
+ MEM_ADDR_SPACE (x)))
{
rtx src1 = SET_SRC (PATTERN (seq));
rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq)));
/* If we have a PLUS whose first operand is complex, try computing it
separately by making a split there. */
if (GET_CODE (XEXP (x, 0)) == PLUS
- && ! memory_address_p (GET_MODE (x), XEXP (x, 0))
+ && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x))
&& ! OBJECT_P (XEXP (XEXP (x, 0), 0))
&& ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
&& OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
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,
{
int zero_extended;
+ /* If this is a test for negative, we can make an explicit
+ test of the sign bit. Test this first so we can use
+ a paradoxical subreg to extend OP0. */
+
+ if (op1 == const0_rtx && (code == LT || code == GE)
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ {
+ op0 = simplify_gen_binary (AND, tmode,
+ gen_lowpart (tmode, op0),
+ GEN_INT ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode)
+ - 1)));
+ code = (code == LT) ? NE : EQ;
+ break;
+ }
+
/* If the only nonzero bits in OP0 and OP1 are those in the
narrower mode and this is an equality or unsigned comparison,
we can use the wider mode. Similarly for sign-extended
XEXP (op0, 0)),
gen_lowpart (tmode,
XEXP (op0, 1)));
-
- op0 = gen_lowpart (tmode, op0);
- if (zero_extended && CONST_INT_P (op1))
- op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
- op1 = gen_lowpart (tmode, op1);
- break;
- }
-
- /* If this is a test for negative, we can make an explicit
- test of the sign bit. */
-
- if (op1 == const0_rtx && (code == LT || code == GE)
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- {
- op0 = simplify_gen_binary (AND, tmode,
- gen_lowpart (tmode, op0),
- GEN_INT ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (mode)
- - 1)));
- code = (code == LT) ? NE : EQ;
- break;
+ else
+ {
+ if (zero_extended)
+ {
+ op0 = simplify_gen_unary (ZERO_EXTEND, tmode, op0, mode);
+ op1 = simplify_gen_unary (ZERO_EXTEND, tmode, op1, mode);
+ }
+ else
+ {
+ op0 = simplify_gen_unary (SIGN_EXTEND, tmode, op0, mode);
+ op1 = simplify_gen_unary (SIGN_EXTEND, tmode, op1, mode);
+ }
+ break;
+ }
}
}