diff options
author | Jeff Law <law@gcc.gnu.org> | 2013-10-30 13:21:27 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2013-10-30 13:21:27 -0600 |
commit | 46088939523a187d0545f8faffdf1e44e75f9948 (patch) | |
tree | 9730e61d0cbc4fe7f623500a10ded2df4bce0b1a /gcc/reload1.c | |
parent | c5028d807fd315cfeb2f1d44e5ffb1c6ca470aff (diff) | |
download | gcc-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.c | 40 |
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); |