Commit 3d09ba95 by Richard Sandiford Committed by Richard Sandiford

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  <richard.sandiford@linaro.org>
	    Alan Hayward  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

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 <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>

From-SVN: r251644
parent d8c40eff
2017-09-04 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
* 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 <amonakov@ispras.ru> 2017-09-04 Alexander Monakov <amonakov@ispras.ru>
PR rtl-optimization/57448 PR rtl-optimization/57448
......
...@@ -1005,6 +1005,33 @@ byte_lowpart_offset (machine_mode outer_mode, ...@@ -1005,6 +1005,33 @@ byte_lowpart_offset (machine_mode outer_mode,
else else
return subreg_lowpart_offset (outer_mode, inner_mode); 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. /* Generate a REG rtx for a new pseudo register of mode MODE.
This pseudo is assigned the next sequential register number. */ This pseudo is assigned the next sequential register number. */
......
...@@ -727,29 +727,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -727,29 +727,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
while (GET_CODE (op0) == SUBREG) while (GET_CODE (op0) == SUBREG)
{ {
/* The following line once was done only if WORDS_BIG_ENDIAN, bitnum += subreg_memory_offset (op0) * BITS_PER_UNIT;
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;
op0 = SUBREG_REG (op0); op0 = SUBREG_REG (op0);
} }
......
...@@ -3541,30 +3541,12 @@ emit_move_ccmode (machine_mode mode, rtx x, rtx y) ...@@ -3541,30 +3541,12 @@ emit_move_ccmode (machine_mode mode, rtx x, rtx y)
static bool static bool
undefined_operand_subword_p (const_rtx op, int i) undefined_operand_subword_p (const_rtx op, int i)
{ {
machine_mode innermode, innermostmode;
int offset;
if (GET_CODE (op) != SUBREG) if (GET_CODE (op) != SUBREG)
return false; return false;
innermode = GET_MODE (op); machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
innermostmode = GET_MODE (SUBREG_REG (op)); HOST_WIDE_INT offset = i * UNITS_PER_WORD + subreg_memory_offset (op);
offset = i * UNITS_PER_WORD + SUBREG_BYTE (op); return (offset >= GET_MODE_SIZE (innermostmode)
/* The SUBREG_BYTE represents offset, as if the value were stored in || offset <= -UNITS_PER_WORD);
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;
} }
/* A subroutine of emit_move_insn_1. Generate a move from Y into X. /* A subroutine of emit_move_insn_1. Generate a move from Y into X.
......
...@@ -2888,6 +2888,8 @@ subreg_highpart_offset (machine_mode outermode, machine_mode innermode) ...@@ -2888,6 +2888,8 @@ subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
} }
extern int byte_lowpart_offset (machine_mode, machine_mode); 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 make_safe_from (rtx, rtx);
extern rtx convert_memory_address_addr_space_1 (scalar_int_mode, rtx, extern rtx convert_memory_address_addr_space_1 (scalar_int_mode, rtx,
addr_space_t, bool, bool); addr_space_t, bool, bool);
......
...@@ -6069,34 +6069,18 @@ simplify_subreg (machine_mode outermode, rtx op, ...@@ -6069,34 +6069,18 @@ simplify_subreg (machine_mode outermode, rtx op,
if (GET_CODE (op) == SUBREG) if (GET_CODE (op) == SUBREG)
{ {
machine_mode innermostmode = GET_MODE (SUBREG_REG (op)); machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
int final_offset = byte + SUBREG_BYTE (op);
rtx newx; rtx newx;
if (outermode == innermostmode if (outermode == innermostmode
&& byte == 0 && SUBREG_BYTE (op) == 0) && byte == 0 && SUBREG_BYTE (op) == 0)
return SUBREG_REG (op); return SUBREG_REG (op);
/* The SUBREG_BYTE represents offset, as if the value were stored /* Work out the memory offset of the final OUTERMODE value relative
in memory. Irritating exception is paradoxical subreg, where to the inner value of OP. */
we define SUBREG_BYTE to be 0. On big endian machines, this HOST_WIDE_INT mem_offset = subreg_memory_offset (outermode,
value should be negative. For a moment, undo this exception. */ innermode, byte);
if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) HOST_WIDE_INT op_mem_offset = subreg_memory_offset (op);
{ HOST_WIDE_INT final_offset = mem_offset + op_mem_offset;
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;
}
/* See whether resulting subreg will be paradoxical. */ /* See whether resulting subreg will be paradoxical. */
if (!paradoxical_subreg_p (outermode, innermostmode)) if (!paradoxical_subreg_p (outermode, innermostmode))
...@@ -6111,19 +6095,12 @@ simplify_subreg (machine_mode outermode, rtx op, ...@@ -6111,19 +6095,12 @@ simplify_subreg (machine_mode outermode, rtx op,
} }
else else
{ {
int offset = 0; HOST_WIDE_INT required_offset
int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode)); = subreg_memory_offset (outermode, innermostmode, 0);
if (final_offset != required_offset)
/* 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
return NULL_RTX; return NULL_RTX;
/* Paradoxical subregs always have byte offset 0. */
final_offset = 0;
} }
/* Recurse for further possible simplifications. */ /* Recurse for further possible simplifications. */
...@@ -6164,22 +6141,9 @@ simplify_subreg (machine_mode outermode, rtx op, ...@@ -6164,22 +6141,9 @@ simplify_subreg (machine_mode outermode, rtx op,
final_regno = simplify_subreg_regno (regno, innermode, byte, outermode); final_regno = simplify_subreg_regno (regno, innermode, byte, outermode);
if (HARD_REGISTER_NUM_P (final_regno)) if (HARD_REGISTER_NUM_P (final_regno))
{ {
rtx x; rtx x = gen_rtx_REG_offset (op, outermode, final_regno,
int final_offset = byte; subreg_memory_offset (outermode,
innermode, 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);
/* Propagate original regno. We don't have any way to specify /* Propagate original regno. We don't have any way to specify
the offset inside original regno, so do so only for lowpart. the offset inside original regno, so do so only for lowpart.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment