https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116374
--- Comment #5 from Michael Matz <matz at gcc dot gnu.org> --- Little by little... So, there's a special case in eliminate_regs_in_insn for a simple regset from a reg+cst source. That special case isn't doing quite the same as the generic elimination code in lra_eliminate_regs_1, but it matches only simple insns that don't exist anymore with -O1 and above. That's why it only breaks with -O0. The special case doesn't handle the case that is called 'update_p' in lra_eliminate_regs_1, which makes it differ between selecting either ep->offset of (ep->offset-ep->previous_offset) as addend. Solution: add that distinction also to the special case, as below. (update_p is basically !replace_p&&!first_p): diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index 5bed259cffe..96772f2904a 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -969,7 +969,8 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p, if (! replace_p) { if (known_eq (update_sp_offset, 0)) - offset += (ep->offset - ep->previous_offset); + offset += (!first_p + ? ep->offset - ep->previous_offset : ep->offset); if (ep->to_rtx == stack_pointer_rtx) { if (first_p)