mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-09 10:27:10 +08:00
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
This commit is contained in:
parent
5d7ef82a5d
commit
eea50aa0ab
@ -1,3 +1,12 @@
|
||||
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
|
||||
|
162
gcc/combine.c
162
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 (op0_mode == VOIDmode)
|
||||
op0_mode = GET_MODE (SUBREG_REG (x));
|
||||
|
||||
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 (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
|
||||
|
@ -1278,6 +1278,27 @@ gen_highpart (mode, x)
|
||||
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.
|
||||
@ -1296,15 +1317,8 @@ subreg_lowpart_p (x)
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
151
gcc/recog.c
151
gcc/recog.c
@ -579,145 +579,26 @@ validate_replace_rtx_1 (loc, from, to, object)
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
validate_change (object, loc, SUBREG_REG (to), 1);
|
||||
validate_change (object, loc, temp, 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;
|
||||
}
|
||||
/* Avoid creating of invalid SUBREGS. */
|
||||
if (GET_MODE (from) == VOIDmode)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ZERO_EXTRACT:
|
||||
|
@ -1198,6 +1198,9 @@ extern rtx constant_subword PARAMS ((rtx, int,
|
||||
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));
|
||||
@ -1324,6 +1327,10 @@ extern rtx simplify_gen_relational PARAMS ((enum rtx_code,
|
||||
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));
|
||||
|
||||
|
@ -2186,6 +2186,200 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user