aboutsummaryrefslogtreecommitdiff
path: root/gcc/reload1.c
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>2013-10-30 13:21:27 -0600
committerJeff Law <law@gcc.gnu.org>2013-10-30 13:21:27 -0600
commit46088939523a187d0545f8faffdf1e44e75f9948 (patch)
tree9730e61d0cbc4fe7f623500a10ded2df4bce0b1a /gcc/reload1.c
parentc5028d807fd315cfeb2f1d44e5ffb1c6ca470aff (diff)
downloadgcc-46088939523a187d0545f8faffdf1e44e75f9948.zip
gcc-46088939523a187d0545f8faffdf1e44e75f9948.tar.gz
gcc-46088939523a187d0545f8faffdf1e44e75f9948.tar.bz2
re PR rtl-optimization/58369 (ICE in subreg_get_info when compiling boost for m68k-linux)
PR rtl-optimization/58369 * reload1.c (compute_reload_subreg_offset): New function. (choose_reload_regs): Use it to pass endian-correct offset to subreg_regno_offset. * PR rtl-optimization/58369 * g++.dg/torture/pr58369.C: New test. From-SVN: r204224
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r--gcc/reload1.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c
index d56c554..b62b047 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -6371,6 +6371,37 @@ replaced_subreg (rtx x)
}
#endif
+/* Compute the offset to pass to subreg_regno_offset, for a pseudo of
+ mode OUTERMODE that is available in a hard reg of mode INNERMODE.
+ SUBREG is non-NULL if the pseudo is a subreg whose reg is a pseudo,
+ otherwise it is NULL. */
+
+static int
+compute_reload_subreg_offset (enum machine_mode outermode,
+ rtx subreg,
+ enum machine_mode innermode)
+{
+ int outer_offset;
+ enum machine_mode middlemode;
+
+ if (!subreg)
+ return subreg_lowpart_offset (outermode, innermode);
+
+ outer_offset = SUBREG_BYTE (subreg);
+ middlemode = GET_MODE (SUBREG_REG (subreg));
+
+ /* If SUBREG is paradoxical then return the normal lowpart offset
+ for OUTERMODE and INNERMODE. Our caller has already checked
+ that OUTERMODE fits in INNERMODE. */
+ if (outer_offset == 0
+ && GET_MODE_SIZE (outermode) > GET_MODE_SIZE (middlemode))
+ return subreg_lowpart_offset (outermode, innermode);
+
+ /* SUBREG is normal, but may not be lowpart; return OUTER_OFFSET
+ plus the normal lowpart offset for MIDDLEMODE and INNERMODE. */
+ return outer_offset + subreg_lowpart_offset (middlemode, innermode);
+}
+
/* Assign hard reg targets for the pseudo-registers we must reload
into hard regs for this insn.
Also output the instructions to copy them in and out of the hard regs.
@@ -6508,6 +6539,7 @@ choose_reload_regs (struct insn_chain *chain)
int byte = 0;
int regno = -1;
enum machine_mode mode = VOIDmode;
+ rtx subreg = NULL_RTX;
if (rld[r].in == 0)
;
@@ -6528,7 +6560,10 @@ choose_reload_regs (struct insn_chain *chain)
if (regno < FIRST_PSEUDO_REGISTER)
regno = subreg_regno (rld[r].in_reg);
else
- byte = SUBREG_BYTE (rld[r].in_reg);
+ {
+ subreg = rld[r].in_reg;
+ byte = SUBREG_BYTE (subreg);
+ }
mode = GET_MODE (rld[r].in_reg);
}
#ifdef AUTO_INC_DEC
@@ -6566,6 +6601,9 @@ choose_reload_regs (struct insn_chain *chain)
rtx last_reg = reg_last_reload_reg[regno];
i = REGNO (last_reg);
+ byte = compute_reload_subreg_offset (mode,
+ subreg,
+ GET_MODE (last_reg));
i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
last_class = REGNO_REG_CLASS (i);