Commit bb51e270 by Roger Sayle Committed by Roger Sayle

rtlanal.c (subreg_lsb_1): New function split out from subreg_lsb.


	* rtlanal.c (subreg_lsb_1): New function split out from subreg_lsb.
	(subreg_lsb): Change to call new subreg_lsb_1 helper function.
	* rtl.h (subreg_lsb_1): Prototype here.
	* simplify-rtx.c (simplify_subreg): Optimize subregs of zero and
	sign extensions.

Co-Authored-By: Paolo Bonzini <bonzini@gnu.org>

From-SVN: r76352
parent 9c49953c
2004-01-22 Roger Sayle <roger@eyesopen.com>
Paolo Bonzini <bonzini@gnu.org>
* rtlanal.c (subreg_lsb_1): New function split out from subreg_lsb.
(subreg_lsb): Change to call new subreg_lsb_1 helper function.
* rtl.h (subreg_lsb_1): Prototype here.
* simplify-rtx.c (simplify_subreg): Optimize subregs of zero and
sign extensions.
2004-01-22 Kazu Hirata <kazu@cs.umass.edu>
* doc/tm.texi (CASE_VECTOR_PC_RELATIVE): Mention that the
......
......@@ -1065,6 +1065,8 @@ enum label_kind
/* in rtlanal.c */
extern unsigned int subreg_lsb (rtx);
extern unsigned int subreg_lsb_1 (enum machine_mode, enum machine_mode,
unsigned int);
extern unsigned int subreg_regno_offset (unsigned int, enum machine_mode,
unsigned int, enum machine_mode);
extern bool subreg_offset_representable_p (unsigned int, enum machine_mode,
......
......@@ -3187,48 +3187,59 @@ loc_mentioned_in_p (rtx *loc, rtx in)
return 0;
}
/* Given a subreg X, return the bit offset where the subreg begins
(counting from the least significant bit of the reg). */
/* Helper function for subreg_lsb. Given a subreg's OUTER_MODE, INNER_MODE,
and SUBREG_BYTE, return the bit offset where the subreg begins
(counting from the least significant bit of the operand). */
unsigned int
subreg_lsb (rtx x)
subreg_lsb_1 (enum machine_mode outer_mode,
enum machine_mode inner_mode,
unsigned int subreg_byte)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
enum machine_mode mode = GET_MODE (x);
unsigned int bitpos;
unsigned int byte;
unsigned int word;
/* A paradoxical subreg begins at bit position 0. */
if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (inner_mode))
if (GET_MODE_BITSIZE (outer_mode) > GET_MODE_BITSIZE (inner_mode))
return 0;
if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
/* If the subreg crosses a word boundary ensure that
it also begins and ends on a word boundary. */
if ((SUBREG_BYTE (x) % UNITS_PER_WORD
+ GET_MODE_SIZE (mode)) > UNITS_PER_WORD
&& (SUBREG_BYTE (x) % UNITS_PER_WORD
|| GET_MODE_SIZE (mode) % UNITS_PER_WORD))
if ((subreg_byte % UNITS_PER_WORD
+ GET_MODE_SIZE (outer_mode)) > UNITS_PER_WORD
&& (subreg_byte % UNITS_PER_WORD
|| GET_MODE_SIZE (outer_mode) % UNITS_PER_WORD))
abort ();
if (WORDS_BIG_ENDIAN)
word = (GET_MODE_SIZE (inner_mode)
- (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) / UNITS_PER_WORD;
- (subreg_byte + GET_MODE_SIZE (outer_mode))) / UNITS_PER_WORD;
else
word = SUBREG_BYTE (x) / UNITS_PER_WORD;
word = subreg_byte / UNITS_PER_WORD;
bitpos = word * BITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
byte = (GET_MODE_SIZE (inner_mode)
- (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) % UNITS_PER_WORD;
- (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
else
byte = SUBREG_BYTE (x) % UNITS_PER_WORD;
byte = subreg_byte % UNITS_PER_WORD;
bitpos += byte * BITS_PER_UNIT;
return bitpos;
}
/* Given a subreg X, return the bit offset where the subreg begins
(counting from the least significant bit of the reg). */
unsigned int
subreg_lsb (rtx x)
{
return subreg_lsb_1 (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
}
/* This function returns the regno offset of a subreg expression.
xregno - A regno of an inner hard subreg_reg (or what will become one).
xmode - The mode of xregno.
......
......@@ -3379,10 +3379,45 @@ simplify_subreg (enum machine_mode outermode, rtx op,
res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
if (res)
return res;
/* We can at least simplify it by referring directly to the relevant part. */
/* We can at least simplify it by referring directly to the
relevant part. */
return gen_rtx_SUBREG (outermode, part, final_offset);
}
/* Optimize SUBREG truncations of zero and sign extended values. */
if ((GET_CODE (op) == ZERO_EXTEND
|| GET_CODE (op) == SIGN_EXTEND)
&& GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
{
unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
/* If we're requesting the lowpart of a zero or sign extension,
there are three possibilities. If the outermode is the same
as the origmode, we can omit both the extension and the subreg.
If the outermode is not larger than the origmode, we can apply
the truncation without the extension. Finally, if the outermode
is larger than the origmode, but both are integer modes, we
can just extend to the appropriate mode. */
if (bitpos == 0)
{
enum machine_mode origmode = GET_MODE (XEXP (op, 0));
if (outermode == origmode)
return XEXP (op, 0);
if (GET_MODE_BITSIZE (outermode) <= GET_MODE_BITSIZE (origmode))
return simplify_gen_subreg (outermode, XEXP (op, 0),
origmode, byte);
if (SCALAR_INT_MODE_P (outermode))
return simplify_gen_unary (GET_CODE (op), outermode,
XEXP (op, 0), origmode);
}
/* A SUBREG resulting from a zero extension may fold to zero if
it extracts higher bits that the ZERO_EXTEND's source bits. */
if (GET_CODE (op) == ZERO_EXTEND
&& bitpos >= GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))))
return CONST0_RTX (outermode);
}
return NULL_RTX;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment