[One-liner alert!]

On Wed, Jun 27, 2007 at 07:54:36PM +0200, Eric Botcazou wrote:
> > Combine knows how to add clobbers to make insns recognizable. I'm guessing
> > it accidentally clobbers the original insn in doing so. Where would I look?
> 
> Anywhere in combine. :-)  This is by design, see the SUBST macro and the undo 
> buffer machinery.  You need to put a watchpoint on your insn.

   recog_for_combine (rtx *pnewpat, ...) may allocate (and return) a new
pattern instead of reusing the old one:

  /* If we had any clobbers to add, make a new pattern than contains
     them.  Then check to make sure that all of them are dead.  */
  if (num_clobbers_to_add)
    {
      rtx newpat = gen_rtx_PARALLEL (VOIDmode,
                                     rtvec_alloc (GET_CODE (pat) == PARALLEL
                                                  ? (XVECLEN (pat, 0)
                                                     + num_clobbers_to_add)
                                                  : num_clobbers_to_add + 1));
...
      pat = newpat;
    }

  *pnewpat = pat;


But try_combine() doesn't take that into account:

  /* If we had to change another insn, make sure it is valid also.  */
  if (undobuf.other_insn)
    {
      rtx other_pat = PATTERN (undobuf.other_insn);
...
      other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
                                             &new_other_notes);
...
      PATTERN (undobuf.other_insn) = other_pat;

This is not (necessarily) the same other_pat that we started with.

I set a watchpoint on the element count on the parallel:

Continuing.
Hardware watchpoint 6: *(int *) 3086592448

Old value = 3
New value = 1
do_SUBST_INT (into=0xb7f9a9c0, newval=1) at
../../../cvssrc/gcc/gcc/combine.c:709
709       buf->next = undobuf.undos, undobuf.undos = buf;
(gdb) print undobuf.other_insn->u.fld[5].rt_rtx
$25 = (rtx) 0xb7f9b008

This is the original PATTERN (undobuf.other_insn).

(gdb) c
Continuing.
Hardware watchpoint 6: *(int *) 3086592448

Old value = 1
New value = 3
undo_all () at ../../../cvssrc/gcc/gcc/combine.c:3755
3755              break;

   Good, we restore the parallel's vector to 3 elements. But:

(gdb) print undobuf.other_insn->u.fld[5].rt_rtx
$26 = (rtx) 0xb7f9b060

   We keep the new PATTERN (undobuf.other_insn). :-(

   With that, the fix seems simple enough:

Index: gcc/combine.c
===================================================================
--- gcc/combine.c       (revision 125984)
+++ gcc/combine.c       (working copy)
@@ -3298,7 +3298,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int
          return 0;
        }
 
-      PATTERN (undobuf.other_insn) = other_pat;
+      SUBST (PATTERN (undobuf.other_insn), other_pat);
 
       /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
         are still valid.  Then add any non-duplicate notes added by

(gdb) print undobuf.other_insn->u.fld[5].rt_rtx
$27 = (rtx) 0xb7f73008
(gdb) c
Continuing.
Hardware watchpoint 7: *(int *) 3086428608

Old value = 3
New value = 1
do_SUBST_INT (into=0xb7f729c0, newval=1) at
../../../cvssrc/gcc/gcc/combine.c:709
709       buf->next = undobuf.undos, undobuf.undos = buf;

(gdb) c
Continuing.
Hardware watchpoint 7: *(int *) 3086428608

Old value = 1
New value = 3
undo_all () at ../../../cvssrc/gcc/gcc/combine.c:3755
3755              break;
(gdb) print undobuf.other_insn->u.fld[5].rt_rtx
$29 = (rtx) 0xb7f73008

   Now the original insn pattern has been restored and the compiler works
again.

   SVN blame points at revision 357 dated 1992-02-22, log message "Initial
revision". It's amazing that this bug hasn't been discovered before.

   I'll test and submit the patch as usual.

   Of course, the replacement that combine rejected was supposed to be
cheaper, so I'm off to see if I can mung^Wcorrect the costs.

-- 
Rask Ingemann Lambertsen

Reply via email to