diff options
author | Yvan Roux <yvan.roux@linaro.org> | 2013-09-25 18:31:13 +0000 |
---|---|---|
committer | Yvan Roux <yroux@gcc.gnu.org> | 2013-09-25 18:31:13 +0000 |
commit | 3936bafc7ec961feba2d7db8ac0f65eef344bf7d (patch) | |
tree | 2dd965841fb730d3c88ceea762be625b15791fcb /gcc/rtlanal.c | |
parent | b86f6e9e46f47fca000ba531689e4e64ae7366ef (diff) | |
download | gcc-3936bafc7ec961feba2d7db8ac0f65eef344bf7d.zip gcc-3936bafc7ec961feba2d7db8ac0f65eef344bf7d.tar.gz gcc-3936bafc7ec961feba2d7db8ac0f65eef344bf7d.tar.bz2 |
rtlanal.c (lsb_bitfield_op_p): New predicate for bitfield operations from the least significant bit.
2013-09-25 Yvan Roux <yvan.roux@linaro.org>
Vladimir Makarov <vmakarov@redhat.com>
* rtlanal.c (lsb_bitfield_op_p): New predicate for bitfield operations
from the least significant bit.
(strip_address_mutations): Add bitfield operations handling.
(must_be_index_p): Add shifting and rotate operations handling.
(set_address_base): Use must_be_base_p predicate.
(set_address_index):Use must_be_index_p predicate.
Co-Authored-By: Vladimir Makarov <vmakarov@redhat.com>
From-SVN: r202914
Diffstat (limited to 'gcc/rtlanal.c')
-rw-r--r-- | gcc/rtlanal.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 554a44c..24cbcd2 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -5467,12 +5467,29 @@ split_double (rtx value, rtx *first, rtx *second) } } +/* Return true if X is a sign_extract or zero_extract from the least + significant bit. */ + +static bool +lsb_bitfield_op_p (rtx x) +{ + if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS) + { + enum machine_mode mode = GET_MODE (XEXP (x, 0)); + unsigned HOST_WIDE_INT len = INTVAL (XEXP (x, 1)); + HOST_WIDE_INT pos = INTVAL (XEXP (x, 2)); + + return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0)); + } + return false; +} + /* Strip outer address "mutations" from LOC and return a pointer to the inner value. If OUTER_CODE is nonnull, store the code of the innermost stripped expression there. "Mutations" either convert between modes or apply some kind of - alignment. */ + extension, truncation or alignment. */ rtx * strip_address_mutations (rtx *loc, enum rtx_code *outer_code) @@ -5484,6 +5501,10 @@ strip_address_mutations (rtx *loc, enum rtx_code *outer_code) /* Things like SIGN_EXTEND, ZERO_EXTEND and TRUNCATE can be used to convert between pointer sizes. */ loc = &XEXP (*loc, 0); + else if (lsb_bitfield_op_p (*loc)) + /* A [SIGN|ZERO]_EXTRACT from the least significant bit effectively + acts as a combined truncation and extension. */ + loc = &XEXP (*loc, 0); else if (code == AND && CONST_INT_P (XEXP (*loc, 1))) /* (and ... (const_int -X)) is used to align to X bytes. */ loc = &XEXP (*loc, 0); @@ -5513,7 +5534,13 @@ must_be_base_p (rtx x) static bool must_be_index_p (rtx x) { - return GET_CODE (x) == MULT || GET_CODE (x) == ASHIFT; + return (GET_CODE (x) == MULT + || GET_CODE (x) == ASHIFT + /* Needed by ARM targets. */ + || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == LSHIFTRT + || GET_CODE (x) == ROTATE + || GET_CODE (x) == ROTATERT); } /* Set the segment part of address INFO to LOC, given that INNER is the @@ -5535,7 +5562,7 @@ set_address_segment (struct address_info *info, rtx *loc, rtx *inner) static void set_address_base (struct address_info *info, rtx *loc, rtx *inner) { - if (GET_CODE (*inner) == LO_SUM) + if (must_be_base_p (*inner)) inner = strip_address_mutations (&XEXP (*inner, 0)); gcc_checking_assert (REG_P (*inner) || MEM_P (*inner) @@ -5552,8 +5579,7 @@ set_address_base (struct address_info *info, rtx *loc, rtx *inner) static void set_address_index (struct address_info *info, rtx *loc, rtx *inner) { - if ((GET_CODE (*inner) == MULT || GET_CODE (*inner) == ASHIFT) - && CONSTANT_P (XEXP (*inner, 1))) + if (must_be_index_p (*inner) && CONSTANT_P (XEXP (*inner, 1))) inner = strip_address_mutations (&XEXP (*inner, 0)); gcc_checking_assert (REG_P (*inner) || MEM_P (*inner) |