public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "amker at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug rtl-optimization/62151] [5 Regression] wrong code at -O2 and -O3 on x86_64-linux-gnu
Date: Sat, 16 Aug 2014 12:11:00 -0000	[thread overview]
Message-ID: <bug-62151-4-CvRjfECY78@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-62151-4@http.gcc.gnu.org/bugzilla/>

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

--- Comment #7 from amker at gcc dot gnu.org ---
It's a combine pass issue and it happens on x86 too.  Dump before combine pass
is fine as below.

   30: r83:SI=0
   71: flags:CC=cmp(r83:SI,0x1)
      REG_DEAD r83:SI
   72: {r83:SI=-ltu(flags:CC,0);clobber flags:CC;}
      REG_DEAD flags:CC
      REG_UNUSED flags:CC
   41: [`i']=r83:SI
   42: [`g']=r83:SI

Combine pass optimizes it in a wrong way and generates below dump.

   30: NOTE_INSN_DELETED
   71: NOTE_INSN_DELETED
   72: NOTE_INSN_DELETED
   41: [`i']=0xffffffffffffffff
   42: [`g']=r83:SI

Apparently, insns 30/71/72/41 are combined.  The intermediate state of code
during combine is as below.

   30: NOTE_INSN_DELETED
   71: NOTE_INSN_DELETED
   72: r83:SI=0xffffffffffffffff
   41: [`i']=0xffffffffffffffff
   42: [`g']=r83:SI

Since r83 is used across 41, insn72 shouldn't be deleted here.  Though
try_combine take this into consideration at the first place, it falsely deletes
it in calling to distribute_notes as in below calling stack.

#0  set_insn_deleted (insn=0xb7bd6438) at ../../gcc/gcc/emit-rtl.c:4040
#1  0x08f22c3c in distribute_notes (notes=0xb7bd5f10, from_insn=0xb7bd6414,
i3=0xb7bd6120, i2=0xb7bd6438, elim_i2=0x0, elim_i1=0xb7bd5cf0, elim_i0=0x0) at
../../gcc/gcc/combine.c:13560
#2  0x08f09fc4 in try_combine (i3=0xb7bd6120, i2=0xb7bd6438, i1=0xb7bd6414,
i0=0xb7bd6000, new_direct_jump_p=0xbfffed14, last_combined_insn=0xb7bd6120) at
../../gcc/gcc/combine.c:4177
#3  0x08f01605 in combine_instructions (f=0xb7b36ec0, nregs=107) at
../../gcc/gcc/combine.c:1385
#4  0x08f23b10 in rest_of_handle_combine () at ../../gcc/gcc/combine.c:13896

I assume distribute_notes is trying to get notes of insn71 and link it to
appropriate instruction.  Code snippet of distribute_notes shows it checks
whether tem(i2/insn72) is a set to r83 (which is the register of the REG_DEAD
note of insn71), since the check is true, it just deletes tem(i2/insn72).


      if (place == 0)
        {
          basic_block bb = this_basic_block;

          for (tem = PREV_INSN (tem); place == 0; tem = PREV_INSN (tem))
        {
          if (!NONDEBUG_INSN_P (tem))
            {
              if (tem == BB_HEAD (bb))
            break;
              continue;
            }

          /* If the register is being set at TEM, see if that is all
             TEM is doing.  If so, delete TEM.  Otherwise, make this
             into a REG_UNUSED note instead. Don't delete sets to
             global register vars.  */
          if ((REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER
               || !global_regs[REGNO (XEXP (note, 0))])
              && reg_set_p (XEXP (note, 0), PATTERN (tem)))
            {
              rtx set = single_set (tem);
              rtx inner_dest = 0;
#ifdef HAVE_cc0
              rtx cc0_setter = NULL_RTX;
#endif

              if (set != 0)
            for (inner_dest = SET_DEST (set);
                 (GET_CODE (inner_dest) == STRICT_LOW_PART
                  || GET_CODE (inner_dest) == SUBREG
                  || GET_CODE (inner_dest) == ZERO_EXTRACT);
                 inner_dest = XEXP (inner_dest, 0))
              ;

              /* Verify that it was the set, and not a clobber that
             modified the register.

             CC0 targets must be careful to maintain setter/user
             pairs.  If we cannot delete the setter due to side
             effects, mark the user with an UNUSED note instead
             of deleting it.  */

              if (set != 0 && ! side_effects_p (SET_SRC (set))
              && rtx_equal_p (XEXP (note, 0), inner_dest)
#ifdef HAVE_cc0
              && (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
                  || ((cc0_setter = prev_cc0_setter (tem)) != NULL
                  && sets_cc0_p (PATTERN (cc0_setter)) > 0))
#endif
              )
            {
              /* Move the notes and links of TEM elsewhere.
                 This might delete other dead insns recursively.
                 First set the pattern to something that won't use
                 any register.  */
              rtx old_notes = REG_NOTES (tem);

              PATTERN (tem) = pc_rtx;
              REG_NOTES (tem) = NULL;

              distribute_notes (old_notes, tem, tem, NULL_RTX,
                        NULL_RTX, NULL_RTX, NULL_RTX);
              distribute_links (LOG_LINKS (tem));

              SET_INSN_DELETED (tem);
              if (tem == i2)
                i2 = NULL_RTX;


To be honest, I don't fully understand above code, but it seems wrong to delete
an instruction after from_insn which sets a previously DEAD register.

Quoted from same function, there is :

      /* If the register is set or already dead at PLACE, we needn't do
         anything with this note if it is still a REG_DEAD note.
         We check here if it is set at all, not if is it totally replaced,
         which is what `dead_or_set_p' checks, so also check for it being
         set partially.  */

      if (place && REG_NOTE_KIND (note) == REG_DEAD)
        {
          unsigned int regno = REGNO (XEXP (note, 0));
          reg_stat_type *rsp = &reg_stat[regno];

          if (dead_or_set_p (place, XEXP (note, 0))
          || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
        {
          /* Unless the register previously died in PLACE, clear
             last_death.  [I no longer understand why this is
             being done.] */
          if (rsp->last_death != place)
            rsp->last_death = 0;
          place = 0;
        }
          else
        rsp->last_death = place;

It says we don't need to do anything about this REG_DEAD note if the register
is set or already dead at place.  This seems right to be and we need to adapt
previous code by considering register setting.  For example, below code can fix
the issue.

          if (from_insn
          && CALL_P (from_insn)
          && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
        place = from_insn;
          else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
        place = i3;
          else if (i2 != 0 && next_nonnote_nondebug_insn (i2) == i3
               && (reg_referenced_p (XEXP (note, 0), PATTERN (i2))
               || reg_set_p (XEXP (note, 0), PATTERN (i2))))
        place = i2;
          else if ((rtx_equal_p (XEXP (note, 0), elim_i2)
            && !(i2mod
                 && reg_overlap_mentioned_p (XEXP (note, 0),
                             i2mod_old_rhs)))
               || rtx_equal_p (XEXP (note, 0), elim_i1)
               || rtx_equal_p (XEXP (note, 0), elim_i0))
        break;

          tem = i3;

Or it can be fixed by setting tem to the first register setting instruction (in
this case, i2), rather than i3 by default.

I will try to test a patch, meanwhile, I am wondering if any combine expert has
something to share.  BTW, combine pass seems to be another ad-hoc
implementation like reload, I saw several "Don't know" in comments during this
investigation!

Thanks,
bin


  parent reply	other threads:[~2014-08-16 12:11 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-15  6:14 [Bug tree-optimization/62151] New: " su at cs dot ucdavis.edu
2014-08-15  7:33 ` [Bug tree-optimization/62151] [5 Regression] " mpolacek at gcc dot gnu.org
2014-08-15  7:34 ` mpolacek at gcc dot gnu.org
2014-08-15  7:42 ` [Bug rtl-optimization/62151] " mpolacek at gcc dot gnu.org
2014-08-15  7:55 ` jakub at gcc dot gnu.org
2014-08-15  8:04 ` amker at gcc dot gnu.org
2014-08-15  9:53 ` rguenth at gcc dot gnu.org
2014-08-15  9:53 ` rguenth at gcc dot gnu.org
2014-08-15 15:39 ` amker at gcc dot gnu.org
2014-08-16 12:11 ` amker at gcc dot gnu.org [this message]
2014-08-19 18:55 ` ebotcazou at gcc dot gnu.org
2014-08-20  2:32 ` amker at gcc dot gnu.org
2014-10-02  2:18 ` segher at gcc dot gnu.org
2014-10-02  2:30 ` segher at gcc dot gnu.org
2014-12-09  8:48 ` amker.cheng at gmail dot com
2014-12-09  9:27 ` amker.cheng at gmail dot com
2014-12-10  8:14 ` amker at gcc dot gnu.org
2014-12-11  3:10 ` amker.cheng at gmail dot com
2014-12-11  8:52 ` amker at gcc dot gnu.org
2014-12-22 10:25 ` amker at gcc dot gnu.org
2014-12-22 10:29 ` amker at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-62151-4-CvRjfECY78@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).