This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

A reload inheritance bug


I have had the misfortune to discover a reload inheritance bug which,
after a long period of analysis, has turned out to be very similar to
the situation described by Richard Sandiford in
http://gcc.gnu.org/ml/gcc-patches/2007-01/msg01977.html.

This being my first serious foray into reload, I would appreciate some
advice as to whether it looks like my current patch is going in the
right direction.  (Ian, I've copied this to you since you approved
Richard's patch linked above; any help would be appreciated.)

The bug is currently only exhibiting itself on a proprietary testcase
when compiled for an ARM target and is extremely sensitive to the
particular code involved.  It arises as follows, using the same notation
as in Richard's mail:

    A: reg1 <- reg2
       ...
    B: last use of reg2
       ...
    C: use of reg1

where:

    - reg1 is not allocated a hard register, and is spilled to the stack;
    - reg2 is allocated a hard register H;
    - reg2 has a death note in B;
    - the last use of reg2 (in B) is inside a matched input operand;
    - reg1 and reg2 are not modified between A and C;
    - there are no labels between A and C.

The reload used for the instruction at B looks like this:

Reload 0: reload_in (SI) = (plus:SI (reg/f:SI 9 r9 [3275])
                                                    (reg:SI 10 sl [3812]))
        GENERAL_REGS, RELOAD_FOR_INPUT (opnum = 1), inc by 8
        reload_in_reg: (plus:SI (reg/f:SI 9 r9 [3275])
                                                    (reg:SI 10 sl [3812]))
        reload_reg_rtx: (reg:SI 9 r9)

where, in the notation from above, r9 is H and pseudo 3275 is reg2.
Since 3275 dies in the corresponding instruction, reload has chosen
r9 as the reload register.  Unfortunately when we later arrive at
instruction C during inheritance, the current code believes that r9
is still holding the value that it had at A -- which it is not, because
the use of r9 as the reload register at B has clobbered it.

In order to fix this I think that reload1.c:emit_reload_insns should,
at the point of discovery of an input reload whose reload register is a
non-spill hard register H, invalidate all previous reloads involving
that hard register.  That is what the patch below does, or aims to
do.  (The patch is actually against a 4.2-based branch but the code
looks to be the same on the mainline.)  It at least fixes this
particular test case, and appears to be in line with Richard's patch.

I'm fairly certain that this is the correct approach to fix this
issue, but I'm less certain that I have correctly guarded the call
to forget_old_reloads_1, and indeed that I've done everything to
eradicate the previous reloads involving H.  For example, should I be
wiping the necessary range in reg_last_reload_reg?  On the subject of
the guard, I am unsure because the existing code involves a much
more complicated check:

      if (i < 0
          && ((rld[r].out != 0
               && (REG_P (rld[r].out)
                   || (MEM_P (rld[r].out)
                       && REG_P (rld[r].out_reg))))
              || (rld[r].out == 0 && rld[r].out_reg
                  && REG_P (rld[r].out_reg))))

Should I perhaps be mirroring this check for the input case too?
I'm quite keen to make the fix for this bug cover all eventualities
in terms of the various varieties of reload that might arise, if
possible...

Thanks in advance for any help.  Once this is fixed, I shall add the
necessary comments, test it appropriately, and submit it for approval
on the mainline.

Mark

--


Index: reload1.c =================================================================== --- reload1.c (revision 170932) +++ reload1.c (working copy) @@ -7506,6 +7506,9 @@ emit_reload_insns (struct insn_chain *ch } }

+      if (i < 0 && rld[r].in != NULL_RTX && rld[r].reg_rtx != NULL_RTX)
+       forget_old_reloads_1 (rld[r].reg_rtx, NULL_RTX, NULL);
+
       /* The following if-statement was #if 0'd in 1.34 (or before...).
         It's reenabled in 1.35 because supposedly nothing else
         deals with this problem.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]