diff options
author | Roger Sayle <roger@eyesopen.com> | 2004-01-22 12:44:54 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2004-01-22 12:44:54 +0000 |
commit | bb51e27026e8f068ad191b7200f51439aaa292af (patch) | |
tree | 3c307eaa8d9217b307aed75ea2e9ba109fafafb0 /gcc | |
parent | 9c49953c15b1071a2a44135143b463a15b40687a (diff) | |
download | gcc-bb51e27026e8f068ad191b7200f51439aaa292af.zip gcc-bb51e27026e8f068ad191b7200f51439aaa292af.tar.gz gcc-bb51e27026e8f068ad191b7200f51439aaa292af.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/rtl.h | 2 | ||||
-rw-r--r-- | gcc/rtlanal.c | 39 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 37 |
4 files changed, 72 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eeee09e..22c095a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +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, diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 44a6c6c..4dda178 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -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. diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 7272424..5ba6882 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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; } |