https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106602
--- Comment #12 from Jeffrey A. Law <law at gcc dot gnu.org> --- But insns 6, 7 and 8 aren't important here. We have a REG_EQUAL on insn 9 which indicates that (reg:DI 77) has the value 0xffffffffffffffc0. So I would have expected combine to substitute that into the use of (reg:DI 77) in insn 10 which would give you a shot a recognizing the result is just a pair of shifts. But the REG_EQUAL doesn't seem to be used in that case. My insn #s are different, but here's the relevant part of the dump: Trying 9 -> 15: 9: r139:DI=r141:DI-0x40 REG_DEAD r141:DI REG_EQUAL 0x3fffffffc0 15: a0:DI=r138:DI&r139:DI REG_DEAD r138:DI REG_DEAD r139:DI Failed to match this instruction: (set (reg/i:DI 10 a0) (and:DI (plus:DI (reg:DI 141) (const_int -64 [0xffffffffffffffc0])) (reg:DI 138))) BUt we know the (and (plus ...))) is just 0x3fffffffc0, what's not clear is why we don't use that information and try to recognize (set (reg:DI 10) (and (reg:DI 138) (const_int 0x3fffffffc0)) Which is just a pair of shifts.