From: Richard Sandiford Date: Mon, 4 Sep 2017 10:48:40 +0000 (+0000) Subject: Add subreg_memory_offset helper functions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3d09ba95c150d9676f9a2585fb61315e86fa644a;p=gcc.git Add subreg_memory_offset helper functions This patch adds routines for converting a SUBREG_BYTE offset into a memory address offset. The two only differ for paradoxical subregs, where SUBREG_BYTE is always 0 but the memory address offset can be negative. 2017-09-04 Richard Sandiford Alan Hayward David Sherwood gcc/ * rtl.h (subreg_memory_offset): Declare. * emit-rtl.c (subreg_memory_offset): New function. * expmed.c (store_bit_field_1): Use it. * expr.c (undefined_operand_subword_p): Likewise. * simplify-rtx.c (simplify_subreg): Likewise. Co-Authored-By: Alan Hayward Co-Authored-By: David Sherwood From-SVN: r251644 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5102356fcd4..5d468c9493d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2017-09-04 Richard Sandiford + Alan Hayward + David Sherwood + + * rtl.h (subreg_memory_offset): Declare. + * emit-rtl.c (subreg_memory_offset): New function. + * expmed.c (store_bit_field_1): Use it. + * expr.c (undefined_operand_subword_p): Likewise. + * simplify-rtx.c (simplify_subreg): Likewise. + 2017-09-04 Alexander Monakov PR rtl-optimization/57448 diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 3954648027c..ac6637d60a6 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1005,6 +1005,33 @@ byte_lowpart_offset (machine_mode outer_mode, else return subreg_lowpart_offset (outer_mode, inner_mode); } + +/* Return the offset of (subreg:OUTER_MODE (mem:INNER_MODE X) OFFSET) + from address X. For paradoxical big-endian subregs this is a + negative value, otherwise it's the same as OFFSET. */ + +int +subreg_memory_offset (machine_mode outer_mode, machine_mode inner_mode, + unsigned int offset) +{ + if (paradoxical_subreg_p (outer_mode, inner_mode)) + { + gcc_assert (offset == 0); + return -subreg_lowpart_offset (inner_mode, outer_mode); + } + return offset; +} + +/* As above, but return the offset that existing subreg X would have + if SUBREG_REG (X) were stored in memory. The only significant thing + about the current SUBREG_REG is its mode. */ + +int +subreg_memory_offset (const_rtx x) +{ + return subreg_memory_offset (GET_MODE (x), GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x)); +} /* Generate a REG rtx for a new pseudo register of mode MODE. This pseudo is assigned the next sequential register number. */ diff --git a/gcc/expmed.c b/gcc/expmed.c index ff9eb5b2c71..f82bfc75627 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -727,29 +727,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, while (GET_CODE (op0) == SUBREG) { - /* The following line once was done only if WORDS_BIG_ENDIAN, - but I think that is a mistake. WORDS_BIG_ENDIAN is - meaningful at a much higher level; when structures are copied - between memory and regs, the higher-numbered regs - always get higher addresses. */ - int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))); - int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0)); - int byte_offset = 0; - - /* Paradoxical subregs need special handling on big-endian machines. */ - if (paradoxical_subreg_p (op0)) - { - int difference = inner_mode_size - outer_mode_size; - - if (WORDS_BIG_ENDIAN) - byte_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - byte_offset += difference % UNITS_PER_WORD; - } - else - byte_offset = SUBREG_BYTE (op0); - - bitnum += byte_offset * BITS_PER_UNIT; + bitnum += subreg_memory_offset (op0) * BITS_PER_UNIT; op0 = SUBREG_REG (op0); } diff --git a/gcc/expr.c b/gcc/expr.c index c14deedae5f..e912e683bb0 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -3541,30 +3541,12 @@ emit_move_ccmode (machine_mode mode, rtx x, rtx y) static bool undefined_operand_subword_p (const_rtx op, int i) { - machine_mode innermode, innermostmode; - int offset; if (GET_CODE (op) != SUBREG) return false; - innermode = GET_MODE (op); - innermostmode = GET_MODE (SUBREG_REG (op)); - offset = i * UNITS_PER_WORD + SUBREG_BYTE (op); - /* The SUBREG_BYTE represents offset, as if the value were stored in - memory, except for a paradoxical subreg where we define - SUBREG_BYTE to be 0; undo this exception as in - simplify_subreg. */ - if (SUBREG_BYTE (op) == 0 - && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode)) - { - int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode)); - if (WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - } - if (offset >= GET_MODE_SIZE (innermostmode) - || offset <= -GET_MODE_SIZE (word_mode)) - return true; - return false; + machine_mode innermostmode = GET_MODE (SUBREG_REG (op)); + HOST_WIDE_INT offset = i * UNITS_PER_WORD + subreg_memory_offset (op); + return (offset >= GET_MODE_SIZE (innermostmode) + || offset <= -UNITS_PER_WORD); } /* A subroutine of emit_move_insn_1. Generate a move from Y into X. diff --git a/gcc/rtl.h b/gcc/rtl.h index 36d42542171..e1e664b32ff 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2888,6 +2888,8 @@ subreg_highpart_offset (machine_mode outermode, machine_mode innermode) } extern int byte_lowpart_offset (machine_mode, machine_mode); +extern int subreg_memory_offset (machine_mode, machine_mode, unsigned int); +extern int subreg_memory_offset (const_rtx); extern rtx make_safe_from (rtx, rtx); extern rtx convert_memory_address_addr_space_1 (scalar_int_mode, rtx, addr_space_t, bool, bool); diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 6f4398e06ff..97a06528271 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -6069,34 +6069,18 @@ simplify_subreg (machine_mode outermode, rtx op, if (GET_CODE (op) == SUBREG) { machine_mode innermostmode = GET_MODE (SUBREG_REG (op)); - int final_offset = byte + SUBREG_BYTE (op); rtx newx; if (outermode == innermostmode && byte == 0 && SUBREG_BYTE (op) == 0) return SUBREG_REG (op); - /* The SUBREG_BYTE represents offset, as if the value were stored - in memory. Irritating exception is paradoxical subreg, where - we define SUBREG_BYTE to be 0. On big endian machines, this - value should be negative. For a moment, undo this exception. */ - if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) - { - int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); - if (WORDS_BIG_ENDIAN) - final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - final_offset += difference % UNITS_PER_WORD; - } - if (SUBREG_BYTE (op) == 0 - && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode)) - { - int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode)); - if (WORDS_BIG_ENDIAN) - final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - final_offset += difference % UNITS_PER_WORD; - } + /* Work out the memory offset of the final OUTERMODE value relative + to the inner value of OP. */ + HOST_WIDE_INT mem_offset = subreg_memory_offset (outermode, + innermode, byte); + HOST_WIDE_INT op_mem_offset = subreg_memory_offset (op); + HOST_WIDE_INT final_offset = mem_offset + op_mem_offset; /* See whether resulting subreg will be paradoxical. */ if (!paradoxical_subreg_p (outermode, innermostmode)) @@ -6111,19 +6095,12 @@ simplify_subreg (machine_mode outermode, rtx op, } else { - int offset = 0; - int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode)); - - /* In paradoxical subreg, see if we are still looking on lower part. - If so, our SUBREG_BYTE will be 0. */ - if (WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - if (offset == final_offset) - final_offset = 0; - else + HOST_WIDE_INT required_offset + = subreg_memory_offset (outermode, innermostmode, 0); + if (final_offset != required_offset) return NULL_RTX; + /* Paradoxical subregs always have byte offset 0. */ + final_offset = 0; } /* Recurse for further possible simplifications. */ @@ -6164,22 +6141,9 @@ simplify_subreg (machine_mode outermode, rtx op, final_regno = simplify_subreg_regno (regno, innermode, byte, outermode); if (HARD_REGISTER_NUM_P (final_regno)) { - rtx x; - int final_offset = byte; - - /* Adjust offset for paradoxical subregs. */ - if (byte == 0 - && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) - { - int difference = (GET_MODE_SIZE (innermode) - - GET_MODE_SIZE (outermode)); - if (WORDS_BIG_ENDIAN) - final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - final_offset += difference % UNITS_PER_WORD; - } - - x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset); + rtx x = gen_rtx_REG_offset (op, outermode, final_regno, + subreg_memory_offset (outermode, + innermode, byte)); /* Propagate original regno. We don't have any way to specify the offset inside original regno, so do so only for lowpart.