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?