+Thu May 17 16:59:41 CEST 2001 Jan Hubicka <jh@suse.cz>
+
+ * simplify-rtx.c (simplify_subreg): Break out from ...
+ * combine.c (combine_splify_rtx) ... here and ...
+ * recog.c (validate_replace_rtx_1): ... here;
+ * rtl.h (subreg_lowpart_parts_p, simplify_subreg): Declare.
+ * emit-rtl.c (subreg_lowpart_parts_p): Break out from ...
+ (subreg_lowpart_p): ... here.
+
2001-05-17 Bernd Schmidt <bernds@redhat.com>
* stmt.c (expand_asm_operands): For inout operands, make sure
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 (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (SUBREG_REG (x));
- 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 (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_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_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
else
abort ();
}
+/* Return 1 iff (SUBREG:outermode (OP:innermode) byte)
+ refers to the least significant part of its containing reg. */
+
+int
+subreg_lowpart_parts_p (outermode, innermode, byte)
+ enum machine_mode outermode, innermode;
+ unsigned int byte;
+{
+ unsigned int offset = 0;
+ int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
+
+ if (difference > 0)
+ {
+ if (WORDS_BIG_ENDIAN)
+ offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ offset += difference % UNITS_PER_WORD;
+ }
+
+ return byte == offset;
+}
/* Return 1 iff X, assumed to be a SUBREG,
refers to the least significant part of its containing reg.
else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
return 0;
- if (difference > 0)
- {
- if (WORDS_BIG_ENDIAN)
- offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
- if (BYTES_BIG_ENDIAN)
- offset += difference % UNITS_PER_WORD;
- }
-
- return SUBREG_BYTE (x) == offset;
+ return subreg_lowpart_parts_p (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
}
\f
/* In case we are replacing by constant, attempt to simplify it to
non-SUBREG expression. We can't do this later, since the information
about inner mode may be lost. */
- if (CONSTANT_P (to) && rtx_equal_p (SUBREG_REG (x), from))
+ if (rtx_equal_p (SUBREG_REG (x), from))
{
- int offset, part;
- unsigned HOST_WIDE_INT val;
-
- /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
- since we are saying that the high bits don't matter. */
- if (GET_MODE (to) == VOIDmode
- && (GET_MODE_SIZE (GET_MODE (x))
- >= GET_MODE_SIZE (GET_MODE (from))))
+ rtx temp;
+ temp = simplify_subreg (GET_MODE (x), to, GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
+ if (temp)
{
- rtx new = gen_lowpart_if_possible (GET_MODE (x), to);
- if (new)
- {
- validate_change (object, loc, new, 1);
- return;
- }
- }
-
- offset = SUBREG_BYTE (x) * BITS_PER_UNIT;
- switch (GET_CODE (to))
- {
- case CONST_DOUBLE:
- if (GET_MODE (to) != VOIDmode)
- break;
-
- part = offset >= HOST_BITS_PER_WIDE_INT;
- if ((BITS_PER_WORD > HOST_BITS_PER_WIDE_INT
- && BYTES_BIG_ENDIAN)
- || (BITS_PER_WORD <= HOST_BITS_PER_WIDE_INT
- && WORDS_BIG_ENDIAN))
- part = !part;
- val = part ? CONST_DOUBLE_HIGH (to) : CONST_DOUBLE_LOW (to);
- offset %= HOST_BITS_PER_WIDE_INT;
-
- /* FALLTHROUGH */
- case CONST_INT:
- if (GET_CODE (to) == CONST_INT)
- val = INTVAL (to);
-
- {
- /* Avoid creating bogus SUBREGs */
- enum machine_mode mode = GET_MODE (x);
- enum machine_mode inner_mode = GET_MODE (from);
-
- /* We've already picked the word we want from a double, so
- pretend this is actually an integer. */
- if (GET_CODE (to) == CONST_DOUBLE)
- inner_mode = SImode;
-
- if (GET_MODE_CLASS (mode) != MODE_INT)
- {
- /* Substitute in something that we know won't be
- recognized. */
- to = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
- validate_change (object, loc, to, 1);
- return;
- }
-
- if (BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
- {
- if (WORDS_BIG_ENDIAN)
- offset = GET_MODE_BITSIZE (inner_mode)
- - GET_MODE_BITSIZE (mode) - offset;
- if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
- offset = offset + BITS_PER_WORD - GET_MODE_BITSIZE (mode)
- - 2 * (offset % BITS_PER_WORD);
- }
-
- if (offset >= HOST_BITS_PER_WIDE_INT)
- to = ((HOST_WIDE_INT) val < 0) ? constm1_rtx : const0_rtx;
- else
- {
- val >>= offset;
- if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
- val = trunc_int_for_mode (val, mode);
- to = GEN_INT (val);
- }
-
- validate_change (object, loc, to, 1);
- return;
- }
-
- default:
- break;
+ validate_change (object, loc, temp, 1);
+ return;
}
- }
-
- /* Changing mode twice with SUBREG => just change it once,
- or not at all if changing back to starting mode. */
- if (GET_CODE (to) == SUBREG
- && rtx_equal_p (SUBREG_REG (x), from))
- {
- if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))
- && SUBREG_BYTE (x) == 0 && SUBREG_BYTE (to) == 0)
+ /* Avoid creating of invalid SUBREGS. */
+ if (GET_MODE (from) == VOIDmode)
{
- validate_change (object, loc, SUBREG_REG (to), 1);
+ /* Substitute in something that we know won't be
+ recognized. */
+ to = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ validate_change (object, loc, to, 1);
return;
}
-
- /* Make sure the 2 byte counts added together are an even unit
- of x's mode, and combine them if so. Otherwise we run
- into problems with something like:
- (subreg:HI (subreg:QI (SI:55) 3) 0)
- we end up with an odd offset into a HI which is invalid. */
-
- if (SUBREG_BYTE (to) % GET_MODE_SIZE (GET_MODE (x)) == 0)
- validate_change (object, loc,
- gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to),
- SUBREG_BYTE(x) + SUBREG_BYTE (to)),
- 1);
- else
- validate_change (object, loc, to, 1);
-
- return;
- }
-
- /* If we have a SUBREG of a register that we are replacing and we are
- replacing it with a MEM, make a new MEM and try replacing the
- SUBREG with it. Don't do this if the MEM has a mode-dependent address
- or if we would be widening it. */
-
- if (GET_CODE (from) == REG
- && GET_CODE (to) == MEM
- && rtx_equal_p (SUBREG_REG (x), from)
- && ! mode_dependent_address_p (XEXP (to, 0))
- && ! MEM_VOLATILE_P (to)
- && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))
- {
- int offset = SUBREG_BYTE (x);
- enum machine_mode mode = GET_MODE (x);
- rtx new;
-
- new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
- MEM_COPY_ATTRIBUTES (new, to);
- validate_change (object, loc, new, 1);
- return;
- }
+ }
break;
case ZERO_EXTRACT:
extern rtx operand_subword_force PARAMS ((rtx, unsigned int,
enum machine_mode));
extern int subreg_lowpart_p PARAMS ((rtx));
+extern int subreg_lowpart_parts_p PARAMS ((enum machine_mode,
+ enum machine_mode,
+ unsigned int));
extern rtx make_safe_from PARAMS ((rtx, rtx));
extern rtx convert_memory_address PARAMS ((enum machine_mode, rtx));
extern rtx get_insns PARAMS ((void));
enum machine_mode,
enum machine_mode,
rtx, rtx));
+extern rtx simplify_subreg PARAMS ((enum machine_mode,
+ rtx,
+ enum machine_mode,
+ unsigned int));
extern rtx simplify_replace_rtx PARAMS ((rtx, rtx, rtx));
extern rtx simplify_rtx PARAMS ((rtx));
return 0;
}
+/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
+ Return 0 if no simplifications is possible. */
+rtx
+simplify_subreg (outermode, op, innermode, byte)
+ rtx op;
+ unsigned int byte;
+ enum machine_mode outermode, innermode;
+{
+ /* Little bit of sanity checking. */
+ if (innermode == VOIDmode || outermode == VOIDmode
+ || innermode == BLKmode || outermode == BLKmode)
+ abort ();
+
+ if (GET_MODE (op) != innermode
+ && GET_MODE (op) != VOIDmode)
+ abort ();
+
+ if (byte % GET_MODE_SIZE (outermode)
+ || byte >= GET_MODE_SIZE (innermode))
+ abort ();
+
+ /* Attempt to simplify constant to non-SUBREG expression. */
+ if (CONSTANT_P (op))
+ {
+ int offset, part;
+ unsigned HOST_WIDE_INT val;
+
+ /* ??? This code is partly redundant with code bellow, but can handle
+ the subregs of floats and similar corner cases.
+ Later it we should move all simplification code here and rewrite
+ GEN_LOWPART_IF_POSSIBLE, GEN_HIGHPART, OPERAND_SUBWORD and friends
+ using SIMPLIFY_SUBREG. */
+ if (subreg_lowpart_parts_p (outermode, innermode, byte))
+ {
+ rtx new = gen_lowpart_if_possible (outermode, op);
+ if (new)
+ return new;
+ }
+
+ /* Similar comment as above apply here. */
+ if (GET_MODE_SIZE (outermode) == UNITS_PER_WORD
+ && GET_MODE_SIZE (innermode) > UNITS_PER_WORD
+ && GET_MODE_CLASS (outermode) == MODE_INT)
+ {
+ rtx new = operand_subword (op,
+ (byte / UNITS_PER_WORD),
+ 0, innermode);
+ if (new)
+ return new;
+ }
+
+ offset = byte * BITS_PER_UNIT;
+ switch (GET_CODE (op))
+ {
+ case CONST_DOUBLE:
+ if (GET_MODE (op) != VOIDmode)
+ break;
+
+ /* We can't handle this case yet. */
+ if (GET_MODE_BITSIZE (outermode) >= HOST_BITS_PER_WIDE_INT)
+ return NULL;
+
+ part = offset >= HOST_BITS_PER_WIDE_INT;
+ if ((BITS_PER_WORD > HOST_BITS_PER_WIDE_INT
+ && BYTES_BIG_ENDIAN)
+ || (BITS_PER_WORD <= HOST_BITS_PER_WIDE_INT
+ && WORDS_BIG_ENDIAN))
+ part = !part;
+ val = part ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op);
+ offset %= HOST_BITS_PER_WIDE_INT;
+
+ /* We've already picked the word we want from a double, so
+ pretend this is actually an integer. */
+ innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
+
+ /* FALLTHROUGH */
+ case CONST_INT:
+ if (GET_CODE (op) == CONST_INT)
+ val = INTVAL (op);
+
+ /* We don't handle synthetizing of non-integral constants yet. */
+ if (GET_MODE_CLASS (outermode) != MODE_INT)
+ return NULL;
+
+ if (BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
+ {
+ if (WORDS_BIG_ENDIAN)
+ offset = (GET_MODE_BITSIZE (innermode)
+ - GET_MODE_BITSIZE (outermode) - offset);
+ if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (outermode) < UNITS_PER_WORD)
+ offset = (offset + BITS_PER_WORD - GET_MODE_BITSIZE (outermode)
+ - 2 * (offset % BITS_PER_WORD));
+ }
+
+ if (offset >= HOST_BITS_PER_WIDE_INT)
+ return ((HOST_WIDE_INT) val < 0) ? constm1_rtx : const0_rtx;
+ else
+ {
+ val >>= offset;
+ if (GET_MODE_BITSIZE (outermode) < HOST_BITS_PER_WIDE_INT)
+ val = trunc_int_for_mode (val, outermode);
+ return GEN_INT (val);
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Changing mode twice with SUBREG => just change it once,
+ or not at all if changing back op starting mode. */
+ if (GET_CODE (op) == SUBREG)
+ {
+ enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
+ unsigned int final_offset = byte + SUBREG_BYTE (op);
+ rtx new;
+
+ if (outermode == innermostmode
+ && byte == 0 && SUBREG_BYTE (op) == 0)
+ return SUBREG_REG (op);
+
+ if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+ && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (outermode)
+ && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (innermostmode))
+ {
+ /* Inner SUBREG is paradoxical, outer is not. On big endian
+ we have to special case this. */
+ if (SUBREG_BYTE (op))
+ abort(); /* Can a paradoxical subreg have nonzero offset? */
+ if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+ final_offset = (byte - GET_MODE_SIZE (innermode)
+ + GET_MODE_SIZE (innermostmode));
+ else if (WORDS_BIG_ENDIAN)
+ final_offset = ((final_offset % UNITS_PER_WORD)
+ + ((byte - GET_MODE_SIZE (innermode)
+ + GET_MODE_SIZE (innermostmode))
+ * UNITS_PER_WORD) / UNITS_PER_WORD);
+ else
+ final_offset = (((final_offset * UNITS_PER_WORD)
+ / UNITS_PER_WORD)
+ + ((byte - GET_MODE_SIZE (innermode)
+ + GET_MODE_SIZE (innermostmode))
+ % UNITS_PER_WORD));
+ }
+
+ /* Recurse for futher possible simplifications. */
+ new = simplify_subreg (outermode, op, GET_MODE (op),
+ final_offset);
+ if (new)
+ return new;
+ return gen_rtx_SUBREG (outermode, op, final_offset);
+ }
+
+ /* 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 simplification. If the hard register is the stack,
+ frame, or argument pointer, leave this as a SUBREG. */
+
+ if (REG_P (op) == REG
+ && REGNO (op) < FIRST_PSEUDO_REGISTER
+ && REGNO (op) != FRAME_POINTER_REGNUM
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ && REGNO (op) != HARD_FRAME_POINTER_REGNUM
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && REGNO (op) != ARG_POINTER_REGNUM
+#endif
+ && REGNO (op) != STACK_POINTER_REGNUM)
+ {
+ int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte),
+ 0);
+
+ if (HARD_REGNO_MODE_OK (final_regno, outermode))
+ return gen_rtx_REG (outermode, final_regno);
+ }
+
+ /* If we have a SUBREG of a register that we are replacing and we are
+ replacing it with a MEM, make a new MEM and try replacing the
+ SUBREG with it. Don't do this if the MEM has a mode-dependent address
+ or if we would be widening it. */
+
+ if (GET_CODE (op) == MEM
+ && ! mode_dependent_address_p (XEXP (op, 0))
+ && ! MEM_VOLATILE_P (op)
+ && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
+ {
+ rtx new;
+
+ new = gen_rtx_MEM (outermode, plus_constant (XEXP (op, 0), byte));
+ MEM_COPY_ATTRIBUTES (new, op);
+ return new;
+ }
+ return NULL_RTX;
+}
/* Simplify X, an rtx expression.
Return the simplified expression or NULL if no simplifications