H.J. Lu wrote: > > 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.
> > since subreg_regno_offset only works on hard registers. Hmm, OK. That look like another latent bug in the original code ... > + if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode) > + reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg)); (As an aside, this is wrong; it's already wrong in the place where you copied it from. This should now use reload_adjust_reg_for_mode just like subst_reload does.) > + > + 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. This doesn't seem correct either, it completely ignores the SUBREG_BYTE of the original SUBREG ... Also, I don't quite see why this should have anything special for Pmode / ptr_mode. It seems simplest to just use simplify_gen_subreg here. Can you try the following version? 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. Use reload_adjust_reg_for_mode. 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) *** 6411,6446 **** if (reloadreg && r->where == loc) { if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode) ! reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg)); 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); ! } } } --- 6360,6378 ---- if (reloadreg && r->where == loc) { if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode) ! reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode); return reloadreg; } ! else if (reloadreg && GET_CODE (*loc) == SUBREG ! && r->where == &SUBREG_REG (*loc)) { ! if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode) ! reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode); ! return simplify_gen_subreg (GET_MODE (*loc), reloadreg, ! GET_MODE (SUBREG_REG (*loc)), ! SUBREG_BYTE (*loc)); } } -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE ulrich.weig...@de.ibm.com