summaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2001-05-17 17:00:35 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2001-05-17 15:00:35 +0000
commiteea50aa0ab1e891b39116177f7f6eaded47ef176 (patch)
tree83f417361746b3974c92d8656cd3a83d068dd204 /gcc/combine.c
parent5d7ef82a5dcfba9ab3d4080fd229449a9b7f2207 (diff)
downloadgcc-eea50aa0ab1e891b39116177f7f6eaded47ef176.tar.gz
simplify-rtx.c (simplify_subreg): Break out from ...
* 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. From-SVN: r42199
Diffstat (limited to 'gcc/combine.c')
-rw-r--r--gcc/combine.c162
1 files changed, 11 insertions, 151 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index a60f92e6eec..53df2f58c86 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3765,161 +3765,21 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
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