------- Comment #14 from uweigand at gcc dot gnu dot org  2010-09-03 18:30 
-------
(In reply to comment #12)
> Yes, it would but I think the reload should still generate the right code in
> this particular order of insns.  IMHO, fixing the order of insn is not the
> right thing to do because there might be situation of cycle (e.g. value of 
> p600
> is inherited from 2 but should be reloaded into 3 and p356 is inherited from 3
> and should be reloaded into 2). 
> 
> The problem is definitely in reload inheritance.  Reg_last_reload_reg is not
> invalidated by insn #1407 which is generated by another reload of insn #675.

Actually, I think this really is a reload insn ordering problem. Note that
reload inheritance tracking via reg_last_reload_reg works on the whole reloaded
insn including all the generated reload insns as a whole. Conflicts between
different reloads of the same original insn should be treated specially, taking
into account reload insn ordering (this is done in free_for_value_p).

In this particular case, what happens is this.  After initial reload register
selection, we have this set of reloads:

Reload 0: reload_in (SI) = (reg/v/f:SI 132 [ kpte ])
        GENERAL_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 0)
        reload_in_reg: (reg/v/f:SI 132 [ kpte ])
        reload_reg_rtx: (reg:SI 5 di)
Reload 1: reload_in (SI) = (reg/v/f:SI 132 [ kpte ])
        DIREG, RELOAD_FOR_INPUT (opnum = 1)
        reload_in_reg: (reg/v/f:SI 132 [ kpte ])
        reload_reg_rtx: (reg:SI 5 di)
Reload 2: reload_in (SI) = (reg:SI 588 [ D.29684 ])
        BREG, RELOAD_FOR_INPUT (opnum = 2)
        reload_in_reg: (reg:SI 588 [ D.29684 ])
        reload_reg_rtx: (reg:SI 3 bx)
Reload 3: reload_in (SI) = (reg:SI 356)
        CREG, RELOAD_FOR_INPUT (opnum = 3)
        reload_in_reg: (reg:SI 356)
        reload_reg_rtx: (reg:SI 2 cx)

Reload inheritance notes that reload_in of reload 2 (reg:SI 588) is already
available in CX at this point.  While this cannot be used as reload register
due to the BREG class, it is chosen as "override input", i.e. reload_in is set
to (reg:SI 2 cx) instead of of (reg:SI 588).

Code near the end of choose_reload_regs then verifies whether this causes any
problems due to re-use of the CX register, and comes to the (correct) decision
that it does not, since it knows the reload insn for reload 3 (a
RELOAD_FOR_INPUT for operand 3) which clobbers CX will certainly be generated
*after* the override-input reload insn for reload 2 (a RELOAD_FOR_INPUT for
operand 2).

Unfortunately, some time *after* this decision has been made, the when_needed
field of reload 3 is changed from RELOAD_FOR_INPUT to RELOAD_OTHER.  This
causes the sequence of generated reload insns to change (RELOAD_OTHER reloads
are emitted before RELOAD_FOR_INPUT reloads) -- this breaks the assumptions the
reload inheritance code made, and causes wrong code to be generated.

Now the question is, why does this change to RELOAD_OTHER happen.  This is done
in merge_assigned_reloads, which is called because i386 is a target with
SMALL_REGISTER_CLASSES.  This routine notices that reloads 0 and 1 share a
reload register DI, and decides to merge them, making reload 0 a RELOAD_OTHER
reload (and cancelling reload 1).  It then goes through all other reloads:

          /* If this is now RELOAD_OTHER, look for any reloads that
             load parts of this operand and set them to
             RELOAD_FOR_OTHER_ADDRESS if they were for inputs,
             RELOAD_OTHER for outputs.  Note that this test is
             equivalent to looking for reloads for this operand
             number.

This loop now appears to detect reload 3 as a reload that "loads part of" the
operand 0.  This happens because 
               reg_overlap_mentioned_for_reload_p (rld[j].in,
                                                   rld[i].in))
returns true since both reload-in values are stack slots, and
reg_overlap_mentioned_for_reload_p conservatively assumes that all memory
accesses conflict.

Therefore, when_needed for reload 3 is also set to RELOAD_OTHER.  This is not
only unnecessary, but in turn causes the breakage.

Now in this particular case, it might be possible to fix the problem by using a
better detection of which additional reloads need to be modified.  (The comment
says, "Note that this test is equivalent to looking for reloads for this
operand number." -- which is not true, but could be implemented instead ...)

However, the problem seems to be more fundamental.  If *any* change, even
necessary changes, to when_needed flags are made at this point, *any* decision
on reload inheritance or input overrides that was based on reload insn ordering
may now be incorrect.

I guess a conservative fix could be to check whether any reload inheritance was
indeed or input override was indeed performed on this insn, and if so, refuse
to perform the merge ...


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45312

Reply via email to