https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106585
--- Comment #12 from Jeffrey A. Law <law at gcc dot gnu.org> --- Looking at this again after nearly 2 years. At ud-dce things are actually not in bad shape: (insn 7 4 8 2 (set (reg:SI 141) (const_int 1 [0x1])) "j.c":2:20 278 {*movsi_internal} (nil)) (insn 8 7 10 2 (set (reg:DI 142) (sign_extend:DI (ashift:SI (reg:SI 141) (subreg:QI (reg/v:DI 138 [ rs2 ]) 0)))) "j.c":2:20 314 {ashlsi3_extend} (expr_list:REG_DEAD (reg:SI 141) (expr_list:REG_DEAD (reg/v:DI 138 [ rs2 ]) (expr_list:REG_EQUAL (sign_extend:DI (ashift:SI (const_int 1 [0x1]) (subreg:QI (reg/v:DI 138 [ rs2 ]) 0))) (nil))))) (insn 10 8 12 2 (set (reg:DI 143) (not:DI (reg:DI 142))) "j.c":2:17 115 {one_cmpldi2} (expr_list:REG_DEAD (reg:DI 142) (nil))) (insn 12 10 13 2 (set (reg:DI 145) (and:DI (reg/v:DI 137 [ rs1 ]) (reg:DI 143))) "j.c":2:15 106 {*anddi3} (expr_list:REG_DEAD (reg:DI 143) (expr_list:REG_DEAD (reg/v:DI 137 [ rs1 ]) (nil)))) (insn 13 12 18 2 (set (reg:DI 146) (sign_extend:DI (subreg:SI (reg:DI 145) 0))) "j.c":2:15 discrim 1 127 {*extendsidi2_internal} (expr_list:REG_DEAD (reg:DI 145) (nil))) (insn 18 13 19 2 (set (reg/i:DI 10 a0) (reg:DI 146)) "j.c":3:1 277 {*movdi_64bit} (expr_list:REG_DEAD (reg:DI 146) (nil))) insn 13 is critical. It essentially says we only care about the low 32 bits of (reg:DI 145). But we lose that info during the combination steps: Trying 12 -> 13: 12: r145:DI=~r142:DI&r147:DI REG_DEAD r142:DI REG_DEAD r147:DI 13: r146:DI=sign_extend(r145:DI#0) REG_DEAD r145:DI Successfully matched this instruction: (set (reg:DI 146) (and:DI (not:DI (reg:DI 142)) (reg:DI 147 [ rs1 ]))) Which makes sense on many levels. But after that combination we have literally no chance to generate the code we want as it makes bits 32..63 as set by insn 8 live. One idea would be to have ext-dce eliminate the sign extension at insn 8. I think I tried that in another context a year or so ago. But that does seem like a necessary step to break the logjam we've got with this kind of code.