#include "function.h"
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
isn't mentioned in any SETs in NEWPAT that are field assignments. */
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
- 0, NULL_PTR))
+ 0, (rtx*)0))
{
undo_all ();
return 0;
rtvec old = XVEC (newpat, 0);
total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
- bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
- sizeof (old->elem[0]) * old->num_elem);
+ memcpy (XVEC (newpat, 0)->elem, &old->elem[0],
+ sizeof (old->elem[0]) * old->num_elem);
}
else
{
be written as a ZERO_EXTEND. */
if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
- XEXP (*split, 0)));
+ SUBREG_REG (*split)));
#endif
newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
&& GET_CODE (XEXP (SET_SRC (x), 0)) == REG
&& (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
&& GET_CODE (SET_DEST (x)) == REG
- && (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0
+ && (split = find_single_use (SET_DEST (x), insn, (rtx*)0)) != 0
&& (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
&& XEXP (*split, 0) == SET_DEST (x)
&& XEXP (*split, 1) == const0_rtx)
}
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
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 endian_offset = 0;
- /* 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);
-
- if (BYTES_BIG_ENDIAN)
- {
- if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
- endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (mode);
- if (GET_MODE_SIZE (GET_MODE (inner)) < UNITS_PER_WORD)
- endian_offset -= (UNITS_PER_WORD
- - GET_MODE_SIZE (GET_MODE (inner)));
- }
- /* 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),
- (SUBREG_WORD (x) * UNITS_PER_WORD
- + endian_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)
- {
- if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x)))
- && SUBREG_WORD (x) == 0 && SUBREG_WORD (SUBREG_REG (x)) == 0)
- return SUBREG_REG (SUBREG_REG (x));
-
- SUBST_INT (SUBREG_WORD (x),
- SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x)));
- 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)
- {
- if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x),
- mode))
- return gen_rtx_REG (mode,
- REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
- 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 (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_WORD (x),
- 0, op0_mode);
- if (temp)
- return temp;
- }
+ if (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (SUBREG_REG (x));
- /* 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_WORD (x) == 0
- : (SUBREG_WORD (x)
- == ((GET_MODE_SIZE (op0_mode)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD)))
- && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
- && (! WORDS_BIG_ENDIAN
- || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
+ && subreg_lowpart_parts_p (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_WORD (x) != 0))
- return operand_subword (SUBREG_REG (x), SUBREG_WORD (x), 0, 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
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
- && SUBREG_WORD (src) == 0
+ && SUBREG_BYTE (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
&& GET_CODE (SUBREG_REG (src)) == MEM)
{
SUBST (SET_SRC (x),
gen_rtx (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
- GET_MODE (src), XEXP (src, 0)));
+ GET_MODE (src), SUBREG_REG (src)));
src = SET_SRC (x);
}
if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
&& GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
{
+ int byte_offset = SUBREG_BYTE (XEXP (SET_DEST (x), 0));
+
inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
- pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
+ pos = GEN_INT (BITS_PER_WORD * (byte_offset / UNITS_PER_WORD));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
/* We can't call gen_lowpart_for_combine here since we always want
a SUBREG and it would sometimes return a new hard register. */
if (tmode != inner_mode)
- new = gen_rtx_SUBREG (tmode, inner,
- (WORDS_BIG_ENDIAN
- && (GET_MODE_SIZE (inner_mode)
- > UNITS_PER_WORD)
- ? (((GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode))
- / UNITS_PER_WORD)
- - pos / BITS_PER_WORD)
- : pos / BITS_PER_WORD));
- else
- new = inner;
- }
+ {
+ int final_word = pos / BITS_PER_WORD;
+
+ if (WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+ final_word = ((GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode))
+ / UNITS_PER_WORD) - final_word;
+
+ final_word *= UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN &&
+ GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
+ final_word += (GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
+
+ new = gen_rtx_SUBREG (tmode, inner, final_word);
+ }
+ else
+ new = inner;
+ }
else
new = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
|| 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_WORD (x) != 0))
+ && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
{
- true0 = operand_subword (true0, SUBREG_WORD (x), 0,
+ true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
GET_MODE (SUBREG_REG (x)));
- false0 = operand_subword (false0, SUBREG_WORD (x), 0,
+ 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);
case SUBREG:
/* Non-paradoxical SUBREGs distributes over all operations, provided
- the inner modes and word numbers are the same, this is an extraction
+ the inner modes and byte offsets are the same, this is an extraction
of a low-order part, we don't convert an fp operation to int or
vice versa, and we would not be converting a single-word
operation into a multi-word operation. The latter test is not
We produce the result slightly differently in this case. */
if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (rhs))
- || SUBREG_WORD (lhs) != SUBREG_WORD (rhs)
+ || SUBREG_BYTE (lhs) != SUBREG_BYTE (rhs)
|| ! subreg_lowpart_p (lhs)
|| (GET_MODE_CLASS (GET_MODE (lhs))
!= GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
include an explicit SUBREG or we may simplify it further in combine. */
else
{
- int word = 0;
+ int offset = 0;
- if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
- word = ((GET_MODE_SIZE (GET_MODE (x))
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD);
- return gen_rtx_SUBREG (mode, x, word);
+ 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);
}
}
\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
&& (code != GT && code != LT && code != GE && code != LE))
|| (GET_CODE (op0) == ASHIFTRT
&& (code != GTU && code != LTU
- && code != GEU && code != GEU)))
+ && code != GEU && code != LEU)))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) >= 0
&& INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
/* 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
that accesses one word of a multi-word item, some
piece of everything register in the expression is used by
this insn, so remove any old death. */
+ /* ??? So why do we test for equality of the sizes? */
if (GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART
break;
case REG_EH_REGION:
+ /* These notes must remain with the call or trapping instruction. */
+ if (GET_CODE (i3) == CALL_INSN)
+ place = i3;
+ else if (i2 && GET_CODE (i2) == CALL_INSN)
+ place = i2;
+ else if (flag_non_call_exceptions)
+ {
+ if (may_trap_p (i3))
+ place = i3;
+ else if (i2 && may_trap_p (i2))
+ place = i2;
+ /* ??? Otherwise assume we've combined things such that we
+ can now prove that the instructions can't trap. Drop the
+ note in this case. */
+ }
+ else
+ abort ();
+ break;
+
case REG_EH_RETHROW:
case REG_NORETURN:
/* These notes must remain with the call. It should not be