------- Comment #6 from matz at suse dot de 2006-03-25 21:10 ------- The sequence of what happens is a bit involved, and breaks a very old invariant in reload.c which doesn't seem to hold anyway since a long time, as there is already much code handling this non-holding, namely that subreg's of MEM only happen for paradoxical subregs, except on WORD_REGISTER_OPERATIONS machines. OTOH there is also other code in reload*.c which still seem to rely on this invariant (like this asserting code here), or tries to make sure it's true (e.g. in eliminate_regs_1).
So, what happens is this: * pseudo 64 doesn't get a hardreg, and we are faced with (subreg:QI (reg:SI 64)) in some operand * the first time through the reload loop, reg_equiv_memory_loc[64] is still zero, hence no elimination is run on it, and no stackslot is created for it yet. * first time in calculate_needs_all_insns() it does an eliminate_regs call on the insn in question. As reg_equiv_memory_loc[64] is not yet filled in it goes down until eliminate_regs_1((reg:SI 64)), which then allocates the stack-slot for pseudo 64 in alter_reg. [this already is strange design, that stackslots are created sort of by accident in random order by trying to eliminate other regs] * now reg_equiv_memory_loc[64] _is_ set up to that new stack slot. But we are still deep down in the calculate_needs_all_insns() activation, not in the outer reload loop. Hence reg_equiv_mem[64] or reg_equiv_address[64] are not yet filled (they are normally setup from reg_equiv_memory_loc[64] just before the whole insn scanning). * now the insn in question is scanned further, and eventually goes into find_reloads(), which, before scanning constraints, tries to reload operand addresses. When it sees a SUBREG in an operand (as here), it uses find_reloads_toplev on that one. * find_reloads_toplev tries to handle SUBREGs sensible, i.e. tries to avoid creating (subreg (mem ...)), but can only do that if either reg_equiv_address[regno] or reg_equiv_mem[regno] are set up. See above for why this normally, but not here, is the case. * So it happily creates the problematic (subreg:QI (mem:SI stackslot)) which is stored into recog_data.operand[i] in find_reloads, so that further on we see that subreg-mem as operand (for this run in find_reloads). * Further down the road it checks constraints, which all are fine, but then comes optional reloads. * find_reloads tries to be nice to reload inheritance and creates an optional reload for each MEM operand (or subreg thereof), i.e. also for this one, so push_reload() is called on it. * push_reload doesn't expect a SUBREG of MEM which isn't paradoxical, and has even some gcc_assert to that effect in some of it's conditional blocks. * OTOH it also has code to explicitely handle SUBREGs where the inner reg is not REG_P, but perhaps that is supposed to only handle subregs of constants, not (subreg(mem)). And it has to expect some non-paradoxical (subreg(mem)) on WORD_REGISTER_OPERATIONS machines anyway. If either the stackslots would have been set up already by the time calculate_needs_all_insns runs, or find_reloads_toplev would also deal with only reg_equiv_memory_loc being set (which it can't) this problem wouldn't have occured. Sooo, the easiest solution for this I believe is that patch which Richard already mentioned (perhaps attach it here?), which simply also tests REG_P (SUBREG_REG (in/out)) in both places. The other solution would be to reinstate the invariant of subreg(mem) never occuring except on some machines, but that would be much harder to prove correct. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26826