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)

Reply via email to