diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 95a314f..0032cb1 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -5442,7 +5442,7 @@ split_double (rtx value, rtx *first, rtx *second) 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) @@ -5454,6 +5454,16 @@ 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 (GET_RTX_CLASS (code) == RTX_BITFIELD_OPS) + { + /* Bitfield operations [SIGN|ZERO]_EXTRACT can be used too. */ + enum machine_mode mode = GET_MODE(*loc); + unsigned HOST_WIDE_INT len = INTVAL (XEXP (*loc, 1)); + HOST_WIDE_INT pos = INTVAL (XEXP (*loc, 2)); + + if (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0)) + 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); @@ -5470,6 +5480,18 @@ strip_address_mutations (rtx *loc, enum rtx_code *outer_code) } } +/* Return true if X is a shifting operation. */ + +static bool +shift_code_p (rtx x) +{ + return (GET_CODE (x) == ASHIFT + || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == LSHIFTRT + || GET_CODE (x) == ROTATE + || GET_CODE (x) == ROTATERT); +} + /* Return true if X must be a base rather than an index. */ static bool @@ -5483,7 +5505,7 @@ 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 || shift_code_p (x); } /* Set the segment part of address INFO to LOC, given that INNER is the @@ -5522,7 +5544,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) + if ((GET_CODE (*inner) == MULT || shift_code_p (*inner)) && CONSTANT_P (XEXP (*inner, 1))) inner = strip_address_mutations (&XEXP (*inner, 0)); gcc_checking_assert (REG_P (*inner)