https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119291
--- Comment #14 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So, the buggy try_combine is the second case of 22 -> 25 combination. Trying 22 -> 25: 22: r104:SI=0 25: {flags:CCZ=cmp(-r104:SI,0);r116:SI=-r104:SI;} REG_DEAD r104:SI Failed to match this instruction: (parallel [ (set (pc) (pc)) (set (reg/v:SI 116 [ e ]) (const_int 0 [0])) ]) Failed to match this instruction: (parallel [ (set (pc) (pc)) (set (reg/v:SI 116 [ e ]) (const_int 0 [0])) ]) Successfully matched this instruction: (set (reg/v:SI 116 [ e ]) (const_int 0 [0])) Failed to match this instruction: (set (pc) (pc)) Successfully matched this instruction: (set (reg:DI 128 [ _9 ]) (const_int 0 [0])) allowing combination of insns 22 and 25 original costs 4 + 4 = 12 replacement costs 4 + 4 = 12 modifying other_insn 27: r128:DI=0 deferring rescan insn with uid = 27. modifying insn i2 22: r116:SI=0 deferring rescan insn with uid = 22. modifying insn i3 25: pc=pc deferring rescan insn with uid = 25. At that point we have (insn 22 21 23 4 (set (reg:SI 104 [ _7 ]) (const_int 0 [0])) "pr119291.c":25:15 96 {*movsi_internal} (nil)) (insn 23 22 24 4 (set (reg/v:SI 117 [ e ]) (reg/v:SI 116 [ e ])) 96 {*movsi_internal} (expr_list:REG_DEAD (reg/v:SI 116 [ e ]) (nil))) (note 24 23 25 4 NOTE_INSN_DELETED) (insn 25 24 26 4 (parallel [ (set (reg:CCZ 17 flags) (compare:CCZ (neg:SI (reg:SI 104 [ _7 ])) (const_int 0 [0]))) (set (reg/v:SI 116 [ e ]) (neg:SI (reg:SI 104 [ _7 ]))) ]) "pr119291.c":26:13 977 {*negsi_2} (expr_list:REG_DEAD (reg:SI 104 [ _7 ]) (nil))) (note 26 25 27 4 NOTE_INSN_DELETED) (insn 27 26 28 4 (set (reg:DI 128 [ _9 ]) (ne:DI (reg:CCZ 17 flags) (const_int 0 [0]))) "pr119291.c":26:13 1447 {*setcc_di_1} (expr_list:REG_DEAD (reg:CCZ 17 flags) (nil))) and this try_combine incorrectly decides to do a 2->2 insn combine (but with modification of insn 27 as well) which turns that into (insn 22 21 23 4 (set (reg/v:SI 116 [ e ]) (const_int 0 [0])) "pr119291.c":25:15 96 {*movsi_internal} (nil)) (insn 23 22 24 4 (set (reg/v:SI 117 [ e ]) (reg/v:SI 116 [ e ])) 96 {*movsi_internal} (expr_list:REG_DEAD (reg/v:SI 116 [ e ]) (nil))) (note 24 23 25 4 NOTE_INSN_DELETED) (insn 25 24 26 4 (set (pc) (pc)) "pr119291.c":26:13 2147483647 {NOOP_MOVE} (nil)) (note 26 25 27 4 NOTE_INSN_DELETED) (insn 27 26 28 4 (set (reg:DI 128 [ _9 ]) (const_int 0 [0])) "pr119291.c":26:13 95 {*movdi_internal} (nil)) The reason why this is wrong is that pseudo 116 was used in the insn 23 in between 22 and 25 and even had a REG_DEAD note there, so by putting the clearing of pseudo 116 before insn 23 it both modifies the value of pseudo 117 and makes the value 116 (which is used later on) dead there as well. I see the same happening already in GCC 9 (just the e = e copy insn is insn 24 rather than 23 there and pseudos 102/103 rather than 116/117). Is there some code that should prevent this (i.e. moving pseudo setting from i3 to i2 despite the pseudo being used or clobbered or REG_DEAD/REG_UNUSED in between i2 and i3) and it just doesn't work correctly here or is such a check missing altogether? Segher, could you please have a look?