Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
- It we are combining three insns and the resulting insn is not recognized,
+ If we are combining three insns and the resulting insn is not recognized,
try splitting it into two insns. If that happens, I2 and I3 are retained
and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2
are pseudo-deleted.
}
else if (fmt[i] == 'e')
{
- if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ /* If this is a register being set, ignore it. */
+ new = XEXP (x, i);
+ if (in_dest
+ && (code == SUBREG || code == STRICT_LOW_PART
+ || code == ZERO_EXTRACT)
+ && i == 0
+ && GET_CODE (new) == REG)
+ ;
+
+ else if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
{
/* In general, don't install a subreg involving two
modes not tieable. It can worsen register
/* If this is a commutative operation, put a constant last and a complex
expression first. We don't need to do this for comparisons here. */
if (GET_RTX_CLASS (code) == 'c'
- && ((CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT)
- || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == 'o'
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')
- || (GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o'
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')))
+ && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
{
temp = XEXP (x, 0);
SUBST (XEXP (x, 0), XEXP (x, 1));
}
if (temp)
- x = temp, code = GET_CODE (temp);
+ x = temp, code = GET_CODE (temp), op0_mode = VOIDmode;
/* First see if we can apply the inverse distributive law. */
if (code == PLUS || code == MINUS
{
x = apply_distributive_law (x);
code = GET_CODE (x);
+ op0_mode = VOIDmode;
}
/* If CODE is an associative operation not otherwise handled, see if we
can associate some operands. This can win if they are constants or
- if they are logically related (i.e. (a & b) & a. */
+ if they are logically related (i.e. (a & b) & a). */
if ((code == PLUS || code == MINUS
|| code == MULT || code == AND || code == IOR || code == XOR
|| code == DIV || code == UDIV
break;
case SUBREG:
- /* (subreg:A (mem:B X) N) becomes a modified MEM unless the SUBREG
- is paradoxical. If we can't do that safely, then it becomes
- something nonsensical so that this combination won't take place. */
-
- if (GET_CODE (SUBREG_REG (x)) == MEM
- && (GET_MODE_SIZE (mode)
- <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
- {
- rtx inner = SUBREG_REG (x);
- int offset = SUBREG_BYTE (x);
- /* Don't change the mode of the MEM
- if that would change the meaning of the address. */
- if (MEM_VOLATILE_P (SUBREG_REG (x))
- || mode_dependent_address_p (XEXP (inner, 0)))
- return gen_rtx_CLOBBER (mode, const0_rtx);
-
- /* Note if the plus_constant doesn't make a valid address
- then this combination won't be accepted. */
- x = gen_rtx_MEM (mode,
- plus_constant (XEXP (inner, 0), offset));
- MEM_COPY_ATTRIBUTES (x, inner);
- return x;
- }
-
- /* If we are in a SET_DEST, these other cases can't apply. */
- if (in_dest)
- return x;
-
- /* Changing mode twice with SUBREG => just change it once,
- or not at all if changing back to starting mode. */
- if (GET_CODE (SUBREG_REG (x)) == SUBREG)
- {
- int final_offset;
- enum machine_mode outer_mode, inner_mode;
-
- /* If the innermost mode is the same as the goal mode,
- and the low word is being referenced in both SUBREGs,
- return the innermost element. */
- if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x))))
- {
- int inner_word = SUBREG_BYTE (SUBREG_REG (x));
- int outer_word = SUBREG_BYTE (x);
-
- inner_word = (inner_word / UNITS_PER_WORD) * UNITS_PER_WORD;
- outer_word = (outer_word / UNITS_PER_WORD) * UNITS_PER_WORD;
- if (inner_word == 0
- && outer_word == 0)
- return SUBREG_REG (SUBREG_REG (x));
- }
-
- outer_mode = GET_MODE (SUBREG_REG (x));
- inner_mode = GET_MODE (SUBREG_REG (SUBREG_REG (x)));
- final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (SUBREG_REG(x));
-
- if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
- && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (mode)
- && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (inner_mode))
- {
- /* Inner SUBREG is paradoxical, outer is not. On big endian
- we have to special case this. */
- if (SUBREG_BYTE (SUBREG_REG (x)))
- abort(); /* Can a paradoxical subreg have nonzero offset? */
- if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
- final_offset = SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
- + GET_MODE_SIZE (inner_mode);
- else if (WORDS_BIG_ENDIAN)
- final_offset = (final_offset % UNITS_PER_WORD)
- + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
- + GET_MODE_SIZE (inner_mode))
- * UNITS_PER_WORD) / UNITS_PER_WORD;
- else
- final_offset = ((final_offset * UNITS_PER_WORD)
- / UNITS_PER_WORD)
- + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
- + GET_MODE_SIZE (inner_mode))
- % UNITS_PER_WORD);
- }
-
- /* The SUBREG rules are that the byte offset must be
- some multiple of the toplevel SUBREG's mode. */
- final_offset = (final_offset / GET_MODE_SIZE (mode));
- final_offset = (final_offset * GET_MODE_SIZE (mode));
-
- SUBST_INT (SUBREG_BYTE (x), final_offset);
- SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
- }
-
- /* SUBREG of a hard register => just change the register number
- and/or mode. If the hard register is not valid in that mode,
- suppress this combination. If the hard register is the stack,
- frame, or argument pointer, leave this as a SUBREG. */
-
- if (GET_CODE (SUBREG_REG (x)) == REG
- && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
- && REGNO (SUBREG_REG (x)) != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && REGNO (SUBREG_REG (x)) != HARD_FRAME_POINTER_REGNUM
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- && REGNO (SUBREG_REG (x)) != ARG_POINTER_REGNUM
-#endif
- && REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
- {
- int final_regno = subreg_hard_regno (x, 0);
-
- if (HARD_REGNO_MODE_OK (final_regno, mode))
- return gen_rtx_REG (mode, final_regno);
- else
- return gen_rtx_CLOBBER (mode, const0_rtx);
- }
-
- /* For a constant, try to pick up the part we want. Handle a full
- word and low-order part. Only do this if we are narrowing
- the constant; if it is being widened, we have no idea what
- the extra bits will have been set to. */
+ if (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (SUBREG_REG (x));
- if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
- && GET_MODE_SIZE (mode) == UNITS_PER_WORD
- && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
- && GET_MODE_CLASS (mode) == MODE_INT)
- {
- temp = operand_subword (SUBREG_REG (x),
- (SUBREG_BYTE (x) / UNITS_PER_WORD),
- 0, op0_mode);
- if (temp)
- return temp;
- }
-
- /* If we want a subreg of a constant, at offset 0,
- take the low bits. On a little-endian machine, that's
- always valid. On a big-endian machine, it's valid
- only if the constant's mode fits in one word. Note that we
- cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode. */
+ /* simplify_subreg can't use gen_lowpart_for_combine. */
if (CONSTANT_P (SUBREG_REG (x))
- && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
- || ! WORDS_BIG_ENDIAN)
- ? SUBREG_BYTE (x) == 0
- : (SUBREG_BYTE (x)
- == (GET_MODE_SIZE (op0_mode) - GET_MODE_SIZE (mode))))
- && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
- && (! WORDS_BIG_ENDIAN
- || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
+ && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x))
return gen_lowpart_for_combine (mode, SUBREG_REG (x));
- /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
- since we are saying that the high bits don't matter. */
- if (CONSTANT_P (SUBREG_REG (x)) && GET_MODE (SUBREG_REG (x)) == VOIDmode
- && GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode))
- {
- if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
- && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) != 0))
- return constant_subword (SUBREG_REG (x),
- SUBREG_BYTE (x) / UNITS_PER_WORD, mode);
- return SUBREG_REG (x);
- }
+ {
+ rtx temp;
+ temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
+ SUBREG_BYTE (x));
+ if (temp)
+ return temp;
+ }
/* Note that we cannot do any narrowing for non-constants since
we might have been counting on using the fact that some bits were
return cond0;
}
- /* If X is a normal SUBREG with both inner and outer modes integral,
- we can narrow both the true and false values of the inner expression,
- if there is a condition. */
- else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
- && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ /* If X is a SUBREG, we can narrow both the true and false values
+ if the inner expression, if there is a condition. */
+ else if (code == SUBREG
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
- if ((GET_CODE (SUBREG_REG (x)) == REG
- || GET_CODE (SUBREG_REG (x)) == MEM
- || CONSTANT_P (SUBREG_REG (x)))
- && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
- && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
- {
- true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
- GET_MODE (SUBREG_REG (x)));
- false0 = operand_subword (false0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
- GET_MODE (SUBREG_REG (x)));
- }
- *ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
- *pfalse
- = force_to_mode (false0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
+ *ptrue = simplify_gen_subreg (mode, true0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+ *pfalse = simplify_gen_subreg (mode, false0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
return cond0;
}
else
{
int offset = 0;
+ rtx res;
- if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
- && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
- {
- int difference = (GET_MODE_SIZE (GET_MODE (x))
- - GET_MODE_SIZE (mode));
- if (WORDS_BIG_ENDIAN)
- offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
- if (BYTES_BIG_ENDIAN)
- offset += difference % UNITS_PER_WORD;
- }
- return gen_rtx_SUBREG (mode, x, offset);
+ offset = subreg_lowpart_offset (mode, GET_MODE (x));
+ res = simplify_gen_subreg (mode, x, GET_MODE (x), offset);
+ if (res)
+ return res;
+ return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
}
}
\f
rtx tem;
if (GET_RTX_CLASS (code) == 'c'
- && (GET_CODE (op0) == CONST_INT
- || (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
+ && swap_commutative_operands_p (op0, op1))
tem = op0, op0 = op1, op1 = tem;
if (GET_RTX_CLASS (code) == '<')
/* Put complex operands first and constants second. */
if (GET_RTX_CLASS (code) == 'c'
- && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
- || (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
- && GET_RTX_CLASS (GET_CODE (op1)) != 'o')
- || (GET_CODE (op0) == SUBREG
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
- && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
+ && swap_commutative_operands_p (op0, op1))
return gen_rtx_fmt_ee (code, mode, op1, op0);
/* If we are turning off bits already known off in OP0, we need not do
/* If the first operand is a constant, swap the operands and adjust the
comparison code appropriately, but don't do this if the second operand
is already a constant integer. */
- if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
+ if (swap_commutative_operands_p (op0, op1))
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
/* Get the constant we are comparing against and turn off all bits
not on in our mode. */
const_op = trunc_int_for_mode (INTVAL (op1), mode);
+ op1 = GEN_INT (const_op);
/* If we are comparing against a constant power of two and the value
being compared can only have that single bit nonzero (e.g., it was