aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorRichard Stallman <rms@gnu.org>1992-10-22 13:28:02 +0000
committerRichard Stallman <rms@gnu.org>1992-10-22 13:28:02 +0000
commit94b4b17a338e83a18c8d734faf51de25619604ca (patch)
treed7fb16b9f4a3e9208644fa2586efcdd886b77115 /gcc/combine.c
parent1880be65a8843d5b3df18a63201c7a27bbc0a7e7 (diff)
downloadgcc-94b4b17a338e83a18c8d734faf51de25619604ca.zip
gcc-94b4b17a338e83a18c8d734faf51de25619604ca.tar.gz
gcc-94b4b17a338e83a18c8d734faf51de25619604ca.tar.bz2
(make_extraction): Use is_mode, not inner_mode,
for BYTES_BIG_ENDIAN adjustment to offset for non-bitfield case. Update is_mode when stripping subreg from around a mem. From-SVN: r2556
Diffstat (limited to 'gcc/combine.c')
-rw-r--r--gcc/combine.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index c3f0b49..de46091 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -4536,6 +4536,9 @@ make_extraction (mode, inner, pos, pos_rtx, len,
int unsignedp;
int in_dest, in_compare;
{
+ /* This mode describes the size of the storage area
+ to fetch the overall value from. Within that, we
+ ignore the POS lowest bits, etc. */
enum machine_mode is_mode = GET_MODE (inner);
enum machine_mode inner_mode;
enum machine_mode wanted_mem_mode = byte_mode;
@@ -4547,11 +4550,21 @@ make_extraction (mode, inner, pos, pos_rtx, len,
/* Get some information about INNER and get the innermost object. */
if (GET_CODE (inner) == USE)
+ /* (use:SI (mem:QI foo)) stands for (mem:SI foo). */
/* We don't need to adjust the position because we set up the USE
to pretend that it was a full-word object. */
spans_byte = 1, inner = XEXP (inner, 0);
else if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
- inner = SUBREG_REG (inner);
+ {
+ /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
+ consider just the QI as the memory to extract from.
+ The subreg adds or removes high bits; its mode is
+ irrelevant to the meaning of this extraction,
+ since POS and LEN count from the lsb. */
+ if (GET_CODE (SUBREG_REG (inner)) == MEM)
+ is_mode = GET_MODE (SUBREG_REG (inner));
+ inner = SUBREG_REG (inner);
+ }
inner_mode = GET_MODE (inner);
@@ -4589,8 +4602,6 @@ make_extraction (mode, inner, pos, pos_rtx, len,
|| (! mode_dependent_address_p (XEXP (inner, 0))
&& ! MEM_VOLATILE_P (inner))))))
{
- int offset = pos / BITS_PER_UNIT;
-
/* If INNER is a MEM, make a new MEM that encompasses just the desired
field. If the original and current mode are the same, we need not
adjust the offset. Otherwise, we do if bytes big endian.
@@ -4600,11 +4611,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
if (GET_CODE (inner) == MEM)
{
-#if BYTES_BIG_ENDIAN
- if (inner_mode != tmode)
- offset = (GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode) - offset);
-#endif
+ int offset;
+ /* POS counts from lsb, but make OFFSET count in memory order. */
+ if (BYTES_BIG_ENDIAN)
+ offset = (GET_MODE_BITSIZE (is_mode) - len - pos) / BITS_PER_UNIT;
+ else
+ offset = pos / BITS_PER_UNIT;
new = gen_rtx (MEM, tmode, plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner);