On Tue, Jun 28, 2011 at 7:47 AM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Tue, Jun 28, 2011 at 7:24 AM, Ulrich Weigand <uweig...@de.ibm.com> wrote: >> H.J. Lu wrote: >>> > find_replacement never checks subreg: >>> > >>> > Breakpoint 3, find_replacement (loc=3D0x7ffff068ab00) >>> > =A0 =A0at /export/gnu/import/git/gcc-x32/gcc/reload.c:6411 >>> > 6411 =A0 =A0 =A0 =A0 =A0if (reloadreg && r->where =3D=3D loc) >>> > (reg:DI 0 ax) >>> > (reg/v/f:DI 182 [ b ]) >>> > (gdb) call debug_rtx (*loc) >>> > (subreg:SI (reg/v/f:DI 182 [ b ]) 0) >>> > (gdb) >>> > >>> >>> This seems to work. Does it make any senses? >> >> Ah, I see. This was supposed to be handled via the SUBREG_LOC >> member of the replacement struct. Unfortunately, it turns out >> that this is no longer reliably set these days ... >> >> At first I was concerned that this might also cause problems at >> the other location where replacements are processed, subst_reloads. >> However, it turns out that code in subst_reloads is dead these days >> anyway, as the reloadreg is *always* a REG, and never a SUBREG. >> >> Once that code (and similar code in find_replacement that tries >> to handle SUBREG reloadregs) is removed, the only remaining user >> of the SUBREG_LOC field is actually find_replacement. But here >> we're doing a recursive descent through an RTL anyway, so we >> always know we're replacing inside a SUBREG. >> >> This makes the whole SUBREG_LOC field obsolete. >> >> The patch below implements those changes (untested so far). >> Can you verify that this works for you as well? >> >> Thanks, >> Ulrich >> >> >> ChangeLog: >> >> * reload.c (struct replacement): Remove SUBREG_LOC member. >> (push_reload): Do not set it. >> (push_replacement): Likewise. >> (subst_reload): Remove dead code. >> (copy_replacements): Remove assertion. >> (copy_replacements_1): Do not handle SUBREG_LOC. >> (move_replacements): Likewise. >> (find_replacement): Remove dead code. Detect subregs via >> recursive descent instead of via SUBREG_LOC. >> >> Index: gcc/reload.c >> =================================================================== >> *** gcc/reload.c (revision 175580) >> --- gcc/reload.c (working copy) >> *************** static int replace_reloads; >> *** 158,165 **** >> struct replacement >> { >> rtx *where; /* Location to store in */ >> - rtx *subreg_loc; /* Location of SUBREG if WHERE is inside >> - a SUBREG; 0 otherwise. */ >> int what; /* which reload this is for */ >> enum machine_mode mode; /* mode it must have */ >> }; >> --- 158,163 ---- >> *************** push_reload (rtx in, rtx out, rtx *inloc >> *** 1496,1502 **** >> { >> struct replacement *r = &replacements[n_replacements++]; >> r->what = i; >> - r->subreg_loc = in_subreg_loc; >> r->where = inloc; >> r->mode = inmode; >> } >> --- 1494,1499 ---- >> *************** push_reload (rtx in, rtx out, rtx *inloc >> *** 1505,1511 **** >> struct replacement *r = &replacements[n_replacements++]; >> r->what = i; >> r->where = outloc; >> - r->subreg_loc = out_subreg_loc; >> r->mode = outmode; >> } >> } >> --- 1502,1507 ---- >> *************** push_replacement (rtx *loc, int reloadnu >> *** 1634,1640 **** >> struct replacement *r = &replacements[n_replacements++]; >> r->what = reloadnum; >> r->where = loc; >> - r->subreg_loc = 0; >> r->mode = mode; >> } >> } >> --- 1630,1635 ---- >> *************** subst_reloads (rtx insn) >> *** 6287,6319 **** >> if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode) >> reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode); >> >> ! /* If we are putting this into a SUBREG and RELOADREG is a >> ! SUBREG, we would be making nested SUBREGs, so we have to fix >> ! this up. Note that r->where == &SUBREG_REG (*r->subreg_loc). >> */ >> ! >> ! if (r->subreg_loc != 0 && GET_CODE (reloadreg) == SUBREG) >> ! { >> ! if (GET_MODE (*r->subreg_loc) >> ! == GET_MODE (SUBREG_REG (reloadreg))) >> ! *r->subreg_loc = SUBREG_REG (reloadreg); >> ! else >> ! { >> ! int final_offset = >> ! SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg); >> ! >> ! /* When working with SUBREGs the rule is that the byte >> ! offset must be a multiple of the SUBREG's mode. */ >> ! final_offset = (final_offset / >> ! GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); >> ! final_offset = (final_offset * >> ! GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); >> ! >> ! *r->where = SUBREG_REG (reloadreg); >> ! SUBREG_BYTE (*r->subreg_loc) = final_offset; >> ! } >> ! } >> ! else >> ! *r->where = reloadreg; >> } >> /* If reload got no reg and isn't optional, something's wrong. */ >> else >> --- 6282,6288 ---- >> if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode) >> reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode); >> >> ! *r->where = reloadreg; >> } >> /* If reload got no reg and isn't optional, something's wrong. */ >> else >> *************** subst_reloads (rtx insn) >> *** 6327,6336 **** >> void >> copy_replacements (rtx x, rtx y) >> { >> - /* We can't support X being a SUBREG because we might then need to know >> its >> - location if something inside it was replaced. */ >> - gcc_assert (GET_CODE (x) != SUBREG); >> - >> copy_replacements_1 (&x, &y, n_replacements); >> } >> >> --- 6296,6301 ---- >> *************** copy_replacements_1 (rtx *px, rtx *py, i >> *** 6344,6367 **** >> const char *fmt; >> >> for (j = 0; j < orig_replacements; j++) >> ! { >> ! if (replacements[j].subreg_loc == px) >> ! { >> ! r = &replacements[n_replacements++]; >> ! r->where = replacements[j].where; >> ! r->subreg_loc = py; >> ! r->what = replacements[j].what; >> ! r->mode = replacements[j].mode; >> ! } >> ! else if (replacements[j].where == px) >> ! { >> ! r = &replacements[n_replacements++]; >> ! r->where = py; >> ! r->subreg_loc = 0; >> ! r->what = replacements[j].what; >> ! r->mode = replacements[j].mode; >> ! } >> ! } >> >> x = *px; >> y = *py; >> --- 6309,6321 ---- >> const char *fmt; >> >> for (j = 0; j < orig_replacements; j++) >> ! if (replacements[j].where == px) >> ! { >> ! r = &replacements[n_replacements++]; >> ! r->where = py; >> ! r->what = replacements[j].what; >> ! r->mode = replacements[j].mode; >> ! } >> >> x = *px; >> y = *py; >> *************** move_replacements (rtx *x, rtx *y) >> *** 6387,6399 **** >> int i; >> >> for (i = 0; i < n_replacements; i++) >> ! if (replacements[i].subreg_loc == x) >> ! replacements[i].subreg_loc = y; >> ! else if (replacements[i].where == x) >> ! { >> ! replacements[i].where = y; >> ! replacements[i].subreg_loc = 0; >> ! } >> } >> >> /* If LOC was scheduled to be replaced by something, return the replacement. >> --- 6341,6348 ---- >> int i; >> >> for (i = 0; i < n_replacements; i++) >> ! if (replacements[i].where == x) >> ! replacements[i].where = y; >> } >> >> /* If LOC was scheduled to be replaced by something, return the replacement. >> *************** find_replacement (rtx *loc) >> *** 6415,6446 **** >> >> return reloadreg; >> } >> ! else if (reloadreg && r->subreg_loc == loc) >> { >> ! /* RELOADREG must be either a REG or a SUBREG. >> ! >> ! ??? Is it actually still ever a SUBREG? If so, why? */ >> ! >> ! if (REG_P (reloadreg)) >> ! return gen_rtx_REG (GET_MODE (*loc), >> ! (REGNO (reloadreg) + >> ! subreg_regno_offset (REGNO (SUBREG_REG >> (*loc)), >> GET_MODE (SUBREG_REG >> (*loc)), >> SUBREG_BYTE (*loc), >> GET_MODE (*loc)))); >> - else if (GET_MODE (reloadreg) == GET_MODE (*loc)) >> - return reloadreg; >> - else >> - { >> - int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE >> (*loc); >> - >> - /* When working with SUBREGs the rule is that the byte >> - offset must be a multiple of the SUBREG's mode. */ >> - final_offset = (final_offset / GET_MODE_SIZE (GET_MODE >> (*loc))); >> - final_offset = (final_offset * GET_MODE_SIZE (GET_MODE >> (*loc))); >> - return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg), >> - final_offset); >> - } >> } >> } >> >> --- 6364,6378 ---- >> >> return reloadreg; >> } >> ! else if (reloadreg && GET_CODE (*loc) == SUBREG >> ! && r->where == &SUBREG_REG (*loc)) >> { >> ! return gen_rtx_REG (GET_MODE (*loc), >> ! (REGNO (reloadreg) >> ! + subreg_regno_offset (REGNO (SUBREG_REG >> (*loc)), >> GET_MODE (SUBREG_REG >> (*loc)), >> SUBREG_BYTE (*loc), >> GET_MODE (*loc)))); >> } >> } >> >> >> -- >> Dr. Ulrich Weigand >> GNU Toolchain for Linux on System z and Cell BE >> ulrich.weig...@de.ibm.com >> > > it doesn't work; > > allocation.f: In function 'allocation': > allocation.f:1048:0: internal compiler error: in subreg_get_info, at > rtlanal.c:3235 > Please submit a full bug report, > with preprocessed source if appropriate. > See <http://gcc.gnu.org/bugs.html> for instructions. > > (gdb) bt > #0 fancy_abort (file=0xe7d920 "/export/gnu/import/git/gcc-x32/gcc/rtlanal.c", > line=3235, function=0xe7d8c0 "subreg_get_info") > at /export/gnu/import/git/gcc-x32/gcc/diagnostic.c:892 > #1 0x0000000000888c8e in subreg_get_info (xregno=<optimized out>, > xmode=<optimized out>, offset=0, ymode=<optimized out>, > info=<optimized out>) at /export/gnu/import/git/gcc-x32/gcc/rtlanal.c:3235 > #2 0x0000000000888d4c in subreg_regno_offset (xregno=<optimized out>, > xmode=<optimized out>, offset=<optimized out>, ymode=<optimized out>) > at /export/gnu/import/git/gcc-x32/gcc/rtlanal.c:3387 > #3 0x0000000000868546 in find_replacement (loc=0x7ffff063ee80) > at /export/gnu/import/git/gcc-x32/gcc/reload.c:6372 > #4 0x00000000008685b8 in find_replacement (loc=0x7ffff063ba48) > at /export/gnu/import/git/gcc-x32/gcc/reload.c:6385 > #5 0x0000000000877182 in gen_reload (out=0x7ffff062be80, in=0x7ffff063ba40, > opnum=0, type=RELOAD_FOR_OPERAND_ADDRESS) > at /export/gnu/import/git/gcc-x32/gcc/reload1.c:8599 > > since subreg_regno_offset only works on hard registers. >
+ int offset; + + if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode) + reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg)); + + if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) + && GET_MODE_SIZE (Pmode) > GET_MODE_SIZE (ptr_mode)) + { + offset = GET_MODE_SIZE (Pmode) - GET_MODE_SIZE (ptr_mode); + if (! BYTES_BIG_ENDIAN) + offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + else if (! WORDS_BIG_ENDIAN) + offset %= UNITS_PER_WORD; + } + else + offset = 0; + + return gen_rtx_SUBREG (ptr_mode, reloadreg, offset); works for me. -- H.J.