https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126412
--- Comment #9 from Konstantinos Eleftheriou <konstantinos.eleftheriou at vrull
dot eu> ---
Hi David, thanks for reporting. I reproduced this and there seems to
be an issue with our cancellation logic.
Several globals are reached off one anchor base:
r0 = r7 + 976.
r0 feeds three memory access roots: g_13+4 at [r0,#4], g_253 at [r0,#32],
and g_590 through a second add r3 = r0 + 32, at [r3,#-8] / [r3,#-4].
g_590 folds fine to [r7,#1000] / [r7,#1004], and doing so zeroes the
constants in both r3 = r0 + 32 and the shared r0 = r7 + 976, leaving
r0 == r7. g_253 is the one that can't be folded: it would need
ldrsb [r0,#1008], and 1008 is outside LDRSB's +/-255 range, so recog
rejects it and its group is cancelled.
Dump:
INSN 376: Memory offset changed from -4 to 1004.
INSN 631: Constant set to zero. (r3 = r0 + 32 -> r3 = r0)
INSN 648: Constant set to zero. (r0 = r7 + 976 -> r0 = r7)
INSN 375: Memory offset changed from -8 to 1000.
failed to match this instruction:
(set (reg:SI 0 r0 [orig:114 g_253_lsm.49 ])
(sign_extend:SI (mem/c:QI (plus:SI (reg:SI 0 r0)
(const_int 1008)) [0 g_253+0 S1 A8])))
Recog/verify: Cannot update INSN 114.
The problem is that the cancellation doesn't undo the zeroing of
r0 = r7 + 976. Changes are grouped by the destination register of the
last fold insn, so g_590 lands under r3 while g_253 and g_13+4 land under
r0; the r0 group is cancelled, but r0 = r7 + 976 was already committed as
part of the r3 group and stays zeroed. The g_13+4 update is dropped along
with the group too, even though [r0,#4] -> [r7,#980] would have been fine.
So r0 ends up as r7 while those two roots keep their old offsets:
g_13+4 [r0,#4] -> [r7,#4] (should be [r7,#980])
g_253 [r0,#32] -> [r7,#32] (should be [r7,#1008])
g_13 is the value being checked, so the result comes out wrong.