------- 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

Reply via email to