- /* 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 (GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (from)) > UNITS_PER_WORD
- && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
- {
- rtx temp = operand_subword (to, SUBREG_WORD (x),
- 0, GET_MODE (from));
- if (temp)
- {
- validate_change (object, loc, temp, 1);
- return;
- }
- }
- if (subreg_lowpart_p (x))
- {
- rtx new = gen_lowpart_if_possible (GET_MODE (x), to);
- if (new)
- {
- validate_change (object, loc, new, 1);
- return;
- }
- }
-
- /* 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)))
- {
- validate_change (object, loc, to, 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_WORD (x) == 0 && SUBREG_WORD (to) == 0)
- {
- validate_change (object, loc, SUBREG_REG (to), 1);
- return;
- }
-
- validate_change (object, loc,
- gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to),
- SUBREG_WORD (x) + SUBREG_WORD (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_WORD (x) * UNITS_PER_WORD;
- enum machine_mode mode = GET_MODE (x);
- rtx new;
-
- if (BYTES_BIG_ENDIAN)
- offset += (MIN (UNITS_PER_WORD,
- GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-
- new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
- MEM_COPY_ATTRIBUTES (new, to);
- validate_change (object, loc, new, 1);
- return;
- }