This is the mail archive of the gcc-bugs@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]

[Bug rtl-optimization/62151] [5 Regression] wrong code at -O2 and -O3 on x86_64-linux-gnu


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

--- Comment #16 from amker at gcc dot gnu.org ---
For calls of distribute_notes with from_insn != NULL, I kind of understand why
it is vulnerable, at least when handling REG_DEAD notes.

When we distribute REG_DEAD note of one register from FROM_INSN, generally it
means live range shrink of that register.  For example:
  i1: r1 <- const_0
  i2: r2 <- rx & const_0
            REG_DEAD (rx)
  i3: r3 <- i3src (using r2)
In this case, we need to search backward in instruction flow, find previous
reference of rx and put a REG_DEAD note there, or delete the definition of rx
if there is no other reference.

But in combine, thing is complicate when use of rx in r1 is combined into i2. 
It means live range extend of register rx.  In this case, we need to search
forward and decide whether we need to put a REG_DEAD for rx at i2.  Sometimes
we are lucky when i2 is the predecessor of i3, which means we can infer the
insert point directly.  This is why the code handles this specially (as
quoting):

          /* ...
         If the register is used as an input in I3, it dies there.
         Similarly for I2, if it is nonzero and adjacent to I3.
             ...  */

          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)))
        place = i2;

For other cases, GCC just start from i3 and search backward in flow.  This
causes this PR.

Thing becomes even complicated when we support four insn combination because
it's possible that i1dest is re-set in i2, like below example:
  i0: r0 <- const_0
  i1: r1 <- i1src (using r0)
            REG_DEAD (r0)
  i2: r0 <- i2src (using r1)
  i3: r3 <- i3src (using r0)

Since GCC wrongly handles live range shrink of r0 as live range extend, it
searches from r3 backward in flow, resulting in i2 deleted.

So distribute_notes is complicated and vulnerable because it tries to
understand live range change by guessing based on information like
elim_ix/i2/i3, etc., rather than real live range information.

>From my point of view, all distribute_notes needs to do when "FROM_INSN!=NULL"
are three live range changes:
1) live range shrink, like the first example.
2) live range shrink, but the instruction has already deleted by combine, like
the last example.
3) live range extend, like below example:
      before combine       after combine
  i0: r0 <- const        i0: INSN_DELETED
  i1: r1 <- rx & r0      i1: INSN_DELETED
            REG_DEAD(rx)
  i2: r2 <- r1           i2: r2 <- rx & const
                                   REG_DEAD(rx)
  i3: r3 <- i3src        i3: r3 <- i3src'

Problem is if we can infer live range change from order of i0/i1/i2/i3, using
INSN_LUID maybe?


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