aboutsummaryrefslogtreecommitdiff
path: root/gcc/rtlanal.c
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2013-09-25 18:31:13 +0000
committerYvan Roux <yroux@gcc.gnu.org>2013-09-25 18:31:13 +0000
commit3936bafc7ec961feba2d7db8ac0f65eef344bf7d (patch)
tree2dd965841fb730d3c88ceea762be625b15791fcb /gcc/rtlanal.c
parentb86f6e9e46f47fca000ba531689e4e64ae7366ef (diff)
downloadgcc-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.c36
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)