https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116039
--- Comment #2 from Jeffrey A. Law <law at gcc dot gnu.org> --- Very interesting little testcase. This may be the loongarch bug that was recently reported. It appears the root cause is this insn (from a hacked up version, so the insn #s may not match up perfectly): (insn 82 79 83 4 (set (reg:DI 246 [ _123 ]) (sign_extend:DI (subreg/s/u:QI (reg:DI 260) 0))) "j.c":11:11 128 {*extendqidi2} (expr_list:REG_DEAD (reg:DI 260) (expr_list:REG_EQUAL (sign_extend:DI (mem/c:QI (const:DI (plus:DI (symbol_ref:DI ("*.LANCHOR0") [flags 0x182]) (const_int 57 [0x39]))) [0 d[9]+0 S1 A8])) Note the /s/u flags on the SUBREG. Those tell the optimizers that the value is actually a sign extended object already and the optimizers can drop the extraneous extension. In a subtle way those flags essentially mean that bits outside the subreg's mode are live. So we really should have marked additional groups in (reg 260) as live. That in turn would have kept key bit groups live in a different register and inhibited extension removal. There's a nonzero chance this is also the loongarch bug that just got reported.