Add more subreg offset helpers
Provide versions of subreg_lowpart_offset and subreg_highpart_offset that work on mode sizes rather than modes. Also provide a routine that converts an lsb position to a subreg offset. The intent (in combination with later patches) is to move the handling of the BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN case into just two places, so that for other combinations we don't have to split offsets into words and subwords. gcc/ 2016-11-15 Richard Sandiford <richard.sandiford@arm.com> Alan Hayward <alan.hayward@arm.com> David Sherwood <david.sherwood@arm.com> * rtl.h (subreg_size_offset_from_lsb): Declare. (subreg_offset_from_lsb): New function. (subreg_size_lowpart_offset): Declare. (subreg_lowpart_offset): Turn into an inline function. (subreg_size_highpart_offset): Declare. (subreg_highpart_offset): Turn into an inline function. * emit-rtl.c (subreg_size_lowpart_offset): New function. (subreg_size_highpart_offset): Likewise * rtlanal.c (subreg_size_offset_from_lsb): Likewise. Co-Authored-By: Alan Hayward <alan.hayward@arm.com> Co-Authored-By: David Sherwood <david.sherwood@arm.com> From-SVN: r242755
This commit is contained in:
parent
cbb88345e1
commit
33951763a8
@ -1,3 +1,17 @@
|
||||
2016-11-23 Richard Sandiford <richard.sandiford@arm.com>
|
||||
Alan Hayward <alan.hayward@arm.com>
|
||||
David Sherwood <david.sherwood@arm.com>
|
||||
|
||||
* rtl.h (subreg_size_offset_from_lsb): Declare.
|
||||
(subreg_offset_from_lsb): New function.
|
||||
(subreg_size_lowpart_offset): Declare.
|
||||
(subreg_lowpart_offset): Turn into an inline function.
|
||||
(subreg_size_highpart_offset): Declare.
|
||||
(subreg_highpart_offset): Turn into an inline function.
|
||||
* emit-rtl.c (subreg_size_lowpart_offset): New function.
|
||||
(subreg_size_highpart_offset): Likewise
|
||||
* rtlanal.c (subreg_size_offset_from_lsb): Likewise.
|
||||
|
||||
2016-11-23 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/78482
|
||||
|
@ -1478,44 +1478,41 @@ gen_highpart_mode (machine_mode outermode, machine_mode innermode, rtx exp)
|
||||
subreg_highpart_offset (outermode, innermode));
|
||||
}
|
||||
|
||||
/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */
|
||||
/* Return the SUBREG_BYTE for a lowpart subreg whose outer mode has
|
||||
OUTER_BYTES bytes and whose inner mode has INNER_BYTES bytes. */
|
||||
|
||||
unsigned int
|
||||
subreg_lowpart_offset (machine_mode outermode, machine_mode innermode)
|
||||
subreg_size_lowpart_offset (unsigned int outer_bytes, unsigned int inner_bytes)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
|
||||
if (outer_bytes > inner_bytes)
|
||||
/* Paradoxical subregs always have a SUBREG_BYTE of 0. */
|
||||
return 0;
|
||||
|
||||
if (difference > 0)
|
||||
{
|
||||
if (WORDS_BIG_ENDIAN)
|
||||
offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
offset += difference % UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
return offset;
|
||||
if (BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN)
|
||||
return inner_bytes - outer_bytes;
|
||||
else if (!BYTES_BIG_ENDIAN && !WORDS_BIG_ENDIAN)
|
||||
return 0;
|
||||
else
|
||||
return subreg_size_offset_from_lsb (outer_bytes, inner_bytes, 0);
|
||||
}
|
||||
|
||||
/* Return offset in bytes to get OUTERMODE high part
|
||||
of the value in mode INNERMODE stored in memory in target format. */
|
||||
/* Return the SUBREG_BYTE for a highpart subreg whose outer mode has
|
||||
OUTER_BYTES bytes and whose inner mode has INNER_BYTES bytes. */
|
||||
|
||||
unsigned int
|
||||
subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
|
||||
subreg_size_highpart_offset (unsigned int outer_bytes,
|
||||
unsigned int inner_bytes)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
|
||||
gcc_assert (inner_bytes >= outer_bytes);
|
||||
|
||||
gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode));
|
||||
|
||||
if (difference > 0)
|
||||
{
|
||||
if (! WORDS_BIG_ENDIAN)
|
||||
offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
|
||||
if (! BYTES_BIG_ENDIAN)
|
||||
offset += difference % UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
return offset;
|
||||
if (BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN)
|
||||
return 0;
|
||||
else if (!BYTES_BIG_ENDIAN && !WORDS_BIG_ENDIAN)
|
||||
return inner_bytes - outer_bytes;
|
||||
else
|
||||
return subreg_size_offset_from_lsb (outer_bytes, inner_bytes,
|
||||
(inner_bytes - outer_bytes)
|
||||
* BITS_PER_UNIT);
|
||||
}
|
||||
|
||||
/* Return 1 iff X, assumed to be a SUBREG,
|
||||
|
44
gcc/rtl.h
44
gcc/rtl.h
@ -2178,6 +2178,24 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
|
||||
extern unsigned int subreg_lsb (const_rtx);
|
||||
extern unsigned int subreg_lsb_1 (machine_mode, machine_mode,
|
||||
unsigned int);
|
||||
extern unsigned int subreg_size_offset_from_lsb (unsigned int, unsigned int,
|
||||
unsigned int);
|
||||
|
||||
/* Return the subreg byte offset for a subreg whose outer mode is
|
||||
OUTER_MODE, whose inner mode is INNER_MODE, and where there are
|
||||
LSB_SHIFT *bits* between the lsb of the outer value and the lsb of
|
||||
the inner value. This is the inverse of subreg_lsb_1 (which converts
|
||||
byte offsets to bit shifts). */
|
||||
|
||||
inline unsigned int
|
||||
subreg_offset_from_lsb (machine_mode outer_mode,
|
||||
machine_mode inner_mode,
|
||||
unsigned int lsb_shift)
|
||||
{
|
||||
return subreg_size_offset_from_lsb (GET_MODE_SIZE (outer_mode),
|
||||
GET_MODE_SIZE (inner_mode), lsb_shift);
|
||||
}
|
||||
|
||||
extern unsigned int subreg_regno_offset (unsigned int, machine_mode,
|
||||
unsigned int, machine_mode);
|
||||
extern bool subreg_offset_representable_p (unsigned int, machine_mode,
|
||||
@ -2764,10 +2782,28 @@ extern rtx operand_subword (rtx, unsigned int, int, machine_mode);
|
||||
extern rtx operand_subword_force (rtx, unsigned int, machine_mode);
|
||||
extern bool paradoxical_subreg_p (const_rtx);
|
||||
extern int subreg_lowpart_p (const_rtx);
|
||||
extern unsigned int subreg_lowpart_offset (machine_mode,
|
||||
machine_mode);
|
||||
extern unsigned int subreg_highpart_offset (machine_mode,
|
||||
machine_mode);
|
||||
extern unsigned int subreg_size_lowpart_offset (unsigned int, unsigned int);
|
||||
|
||||
/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */
|
||||
|
||||
inline unsigned int
|
||||
subreg_lowpart_offset (machine_mode outermode, machine_mode innermode)
|
||||
{
|
||||
return subreg_size_lowpart_offset (GET_MODE_SIZE (outermode),
|
||||
GET_MODE_SIZE (innermode));
|
||||
}
|
||||
|
||||
extern unsigned int subreg_size_highpart_offset (unsigned int, unsigned int);
|
||||
|
||||
/* Return the SUBREG_BYTE for an OUTERMODE highpart of an INNERMODE value. */
|
||||
|
||||
inline unsigned int
|
||||
subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
|
||||
{
|
||||
return subreg_size_highpart_offset (GET_MODE_SIZE (outermode),
|
||||
GET_MODE_SIZE (innermode));
|
||||
}
|
||||
|
||||
extern int byte_lowpart_offset (machine_mode, machine_mode);
|
||||
extern rtx make_safe_from (rtx, rtx);
|
||||
extern rtx convert_memory_address_addr_space_1 (machine_mode, rtx,
|
||||
|
@ -3528,6 +3528,42 @@ subreg_lsb (const_rtx x)
|
||||
SUBREG_BYTE (x));
|
||||
}
|
||||
|
||||
/* Return the subreg byte offset for a subreg whose outer value has
|
||||
OUTER_BYTES bytes, whose inner value has INNER_BYTES bytes, and where
|
||||
there are LSB_SHIFT *bits* between the lsb of the outer value and the
|
||||
lsb of the inner value. This is the inverse of the calculation
|
||||
performed by subreg_lsb_1 (which converts byte offsets to bit shifts). */
|
||||
|
||||
unsigned int
|
||||
subreg_size_offset_from_lsb (unsigned int outer_bytes,
|
||||
unsigned int inner_bytes,
|
||||
unsigned int lsb_shift)
|
||||
{
|
||||
/* A paradoxical subreg begins at bit position 0. */
|
||||
if (outer_bytes > inner_bytes)
|
||||
{
|
||||
gcc_checking_assert (lsb_shift == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gcc_assert (lsb_shift % BITS_PER_UNIT == 0);
|
||||
unsigned int lower_bytes = lsb_shift / BITS_PER_UNIT;
|
||||
unsigned int upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
|
||||
if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
|
||||
return upper_bytes;
|
||||
else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
|
||||
return lower_bytes;
|
||||
else
|
||||
{
|
||||
unsigned int lower_word_part = lower_bytes & -UNITS_PER_WORD;
|
||||
unsigned int upper_word_part = upper_bytes & -UNITS_PER_WORD;
|
||||
if (WORDS_BIG_ENDIAN)
|
||||
return upper_word_part + (lower_bytes - lower_word_part);
|
||||
else
|
||||
return lower_word_part + (upper_bytes - upper_word_part);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in information about a subreg of a hard register.
|
||||
xregno - A regno of an inner hard subreg_reg (or what will become one).
|
||||
xmode - The mode of xregno.
|
||||
|
Loading…
Reference in New Issue
Block a user