https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108892

Jeffrey A. Law <law at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|unassigned at gcc dot gnu.org      |law at gcc dot gnu.org

--- Comment #3 from Jeffrey A. Law <law at gcc dot gnu.org> ---
This looks like a long-standing latent bug in combine.

About 20 years ago support was added to combine to allow it to utilize a
REG_EQUAL note to help simplifications.  The code looks like this:
                  /* Temporarily replace the set's source with the
                     contents of the REG_EQUAL note.  The insn will
                     be deleted or recognized by try_combine.  */
                  rtx orig_src = SET_SRC (set); 
                  rtx orig_dest = SET_DEST (set); 
                  if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT)
                    SET_DEST (set) = XEXP (SET_DEST (set), 0);
                  SET_SRC (set) = note;
                  i2mod = temp;
                  i2mod_old_rhs = copy_rtx (orig_src);
                  i2mod_new_rhs = copy_rtx (note);
                  next = try_combine (insn, i2mod, NULL, NULL,
                                      &new_direct_jump_p, 
                                      last_combined_insn);
                  i2mod = NULL;
                  if (next)
                    {
                      statistics_counter_event (cfun, "insn-with-note combine",
1);
                      goto retry;
                    } 
                  SET_SRC (set) = orig_src;
                  SET_DEST (set) = orig_dest;

So assume that temp (from which SET in the above code was extracted) looks like
this:

(insn 122 117 127 2 (set (reg:DI 157 [ _46 ])
        (ior:DI (reg:DI 200)
            (reg:DI 251))) "j.c":14:5 -1
     (expr_list:REG_EQUAL (const_int 25769803782 [0x600000006])
        (nil)))

Basically the constant isn't one we can load with a single insn, so we
construct the constant using several insns and attach a REG_EQUAL note for the
final result.  Totally normal.

We replace the SET_SRC with the contents of the note.  This results in the
following insn that gets passed down to try_combine as I2MOD:


(insn 122 117 127 2 (set (reg:DI 157 [ _46 ])
        (const_int 25769803782 [0x600000006])) "j.c":14:5 -1
     (expr_list:REG_EQUAL (const_int 25769803782 [0x600000006])
        (nil)))

Exactly what I would expect.  try_combine will actually try to recognize that
insn and gets a match on the mvconst_internal.  So when try_combine returns the
insn looks like this:

(insn 122 117 127 2 (set (reg:DI 157 [ _46 ])
        (const_int 25769803782 [0x600000006])) "j.c":14:5 177
{*mvconst_internal}
     (expr_list:REG_EQUAL (const_int 25769803782 [0x600000006])
        (nil)))

Again, totally normal.  Nothing wrong at this point.  But note how we restore
the SET_SRC/SET_DEST objects after returning from try_combine.  After
restoration we have:

(insn 122 117 127 2 (set (reg:DI 157 [ _46 ])
        (ior:DI (reg:DI 200)
            (reg:DI 251))) "j.c":14:5 177 {*mvconst_internal}
     (expr_list:REG_EQUAL (const_int 25769803782 [0x600000006])
        (nil)))

And that's where things have gone off the rails.  When we restore the
SET_SRC/SET_DEST we need to either re-recognize or at least clear the
INSN_CODE.

This has *absolutely nothing* to do with multiple matching patterns.  It's just
a latent bug in the combiner.

Reply via email to