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))
+ if (subreg_lowpart_offset (outermode, innermode) == byte)
{
rtx new = gen_lowpart_if_possible (outermode, op);
if (new)
&& GET_MODE_SIZE (innermode) > UNITS_PER_WORD
&& GET_MODE_CLASS (outermode) == MODE_INT)
{
- rtx new = operand_subword (op,
- (byte / UNITS_PER_WORD),
- 0, innermode);
+ rtx new = constant_subword (op,
+ (byte / UNITS_PER_WORD),
+ innermode);
if (new)
return new;
}
if (GET_CODE (op) == SUBREG)
{
enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
- unsigned int final_offset = byte + SUBREG_BYTE (op);
+ 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))
+ /* The SUBREG_BYTE represents offset, as if the value were stored
+ in memory. Irritating exception is paradoxical subreg, where
+ we define SUBREG_BYTE to be 0. On big endian machines, this
+ value should be negative. For a moment, undo this exception. */
+ if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
{
- /* 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);
+ int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
+ if (WORDS_BIG_ENDIAN)
+ final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ final_offset += difference % UNITS_PER_WORD;
+ }
+ if (SUBREG_BYTE (op) == 0
+ && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
+ {
+ int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
+ if (WORDS_BIG_ENDIAN)
+ final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ final_offset += difference % UNITS_PER_WORD;
+ }
+
+ /* See whether resulting subreg will be paradoxical. */
+ if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode))
+ {
+ /* In nonparadoxical subregs we can't handle negative offsets. */
+ if (final_offset < 0)
+ return NULL_RTX;
+ /* Bail out in case resulting subreg would be incorrect. */
+ if (final_offset % GET_MODE_SIZE (outermode)
+ || final_offset >= GET_MODE_SIZE (innermostmode))
+ return NULL;
+ }
+ else
+ {
+ int offset = 0;
+ int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
+
+ /* In paradoxical subreg, see if we are still looking on lower part.
+ If so, our SUBREG_BYTE will be 0. */
+ if (WORDS_BIG_ENDIAN)
+ offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ offset += difference % UNITS_PER_WORD;
+ if (offset == final_offset)
+ final_offset = 0;
else
- final_offset = (((final_offset * UNITS_PER_WORD)
- / UNITS_PER_WORD)
- + ((byte - GET_MODE_SIZE (innermode)
- + GET_MODE_SIZE (innermostmode))
- % UNITS_PER_WORD));
+ return NULL;
}
- /* Bail out in case resulting subreg would be incorrect. */
- if (final_offset % GET_MODE_SIZE (outermode)
- || final_offset >= GET_MODE_SIZE (innermostmode))
- return NULL;
/* Recurse for futher possible simplifications. */
new = simplify_subreg (outermode, SUBREG_REG (op),
GET_MODE (SUBREG_REG (op)),
frame, or argument pointer, leave this as a SUBREG. */
if (REG_P (op)
+ && (! REG_FUNCTION_VALUE_P (op)
+ || ! rtx_equal_function_value_matters)
+#ifdef CLASS_CANNOT_CHANGE_MODE
+ && ! (CLASS_CANNOT_CHANGE_MODE_P (outermode, innermode)
+ && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
+ REGNO (op))))
+#endif
&& REGNO (op) < FIRST_PSEUDO_REGISTER
- && REGNO (op) != FRAME_POINTER_REGNUM
+ && ((reload_completed && !frame_pointer_needed)
+ || (REGNO (op) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && REGNO (op) != HARD_FRAME_POINTER_REGNUM
+ && REGNO (op) != HARD_FRAME_POINTER_REGNUM
#endif
+ ))
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& REGNO (op) != ARG_POINTER_REGNUM
#endif
int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte),
0);
- if (HARD_REGNO_MODE_OK (final_regno, outermode))
+ /* ??? We do allow it if the current REG is not valid for
+ its mode. This is a kludge to work around how float/complex
+ arguments are passed on 32-bit Sparc and should be fixed. */
+ if (HARD_REGNO_MODE_OK (final_regno, outermode)
+ || ! HARD_REGNO_MODE_OK (REGNO (op), innermode))
return gen_rtx_REG (outermode, final_regno);
}
if (GET_CODE (op) == MEM
&& ! mode_dependent_address_p (XEXP (op, 0))
- && ! MEM_VOLATILE_P (op)
+ /* Allow splitting of volatile memory references in case we don't
+ have instruction to move the whole thing. */
+ && (! MEM_VOLATILE_P (op)
+ || (mov_optab->handlers[(int) innermode].insn_code
+ == CODE_FOR_nothing))
&& GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
{
rtx new;
of real and imaginary part. */
if (GET_CODE (op) == CONCAT)
{
- int is_realpart = byte < GET_MODE_UNIT_SIZE (innermode) / 2;
+ int is_realpart = byte < GET_MODE_UNIT_SIZE (innermode);
rtx part = is_realpart ? XEXP (op, 0) : XEXP (op, 1);
unsigned int final_offset;
- final_offset = byte % (GET_MODE_UNIT_SIZE (innermode) / 2);
+ final_offset = byte % (GET_MODE_UNIT_SIZE (innermode));
return simplify_subreg (outermode, part, GET_MODE (part), final_offset);
}