]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LRA: Update insn sp offset if its input reload changes SP
authorVladimir N. Makarov <vmakarov@redhat.com>
Tue, 30 May 2023 19:54:28 +0000 (15:54 -0400)
committerVladimir N. Makarov <vmakarov@redhat.com>
Tue, 30 May 2023 19:57:18 +0000 (15:57 -0400)
The patch fixes a bug when there is input reload changing SP.  The bug was
triggered by switching H8300 target to LRA.  The insn in question is

(insn 21 20 22 2 (set (mem/f:SI (pre_dec:SI (reg/f:SI 7 sp)) [3  S4 A32])
        (reg/f:SI 31)) "j.c":10:3 19 {*movsi}
     (expr_list:REG_DEAD (reg/f:SI 31)
        (expr_list:REG_ARGS_SIZE (const_int 4 [0x4])
            (nil))))

The memory address is reloaded but the SP offset for the original insn was not updated.

gcc/ChangeLog:

* lra-int.h (lra_update_sp_offset): Add the prototype.
* lra.cc (setup_sp_offset): Change the return type.  Use
lra_update_sp_offset.
* lra-eliminations.cc (lra_update_sp_offset): New function.
(lra_process_new_insns): Push the current insn to reprocess if the
input reload changes sp offset.

gcc/lra-eliminations.cc
gcc/lra-int.h
gcc/lra.cc

index 4220636666906257a7ae638a762a1edf04532b06..68225339cb6bfb0991eeb733f7912387b336befa 100644 (file)
@@ -1308,6 +1308,16 @@ init_elimination (void)
   setup_elimination_map ();
 }
 
+/* Update and return stack pointer OFFSET after processing X.  */
+poly_int64
+lra_update_sp_offset (rtx x, poly_int64 offset)
+{
+  curr_sp_change = offset;
+  mark_not_eliminable (x, VOIDmode);
+  return curr_sp_change;
+}
+
+
 /* Eliminate hard reg given by its location LOC.  */
 void
 lra_eliminate_reg_if_possible (rtx *loc)
index a400a0f85e291d961c9fa2f64cc3425472245843..4dbe6672f3ae41d0e92ec78947882636dae6dd2b 100644 (file)
@@ -412,6 +412,7 @@ extern rtx lra_eliminate_regs_1 (rtx_insn *, rtx, machine_mode,
 extern void eliminate_regs_in_insn (rtx_insn *insn, bool, bool, poly_int64);
 extern void lra_eliminate (bool, bool);
 
+extern poly_int64 lra_update_sp_offset (rtx, poly_int64);
 extern void lra_eliminate_reg_if_possible (rtx *);
 
 \f
index eb3ee1f8b63a78f0b0b6a614236d1adaee84375d..c8b3f139acd79266b138f991125d7d7e8a736408 100644 (file)
@@ -1838,10 +1838,10 @@ push_insns (rtx_insn *from, rtx_insn *to)
       lra_push_insn (insn);
 }
 
-/* Set up sp offset for insn in range [FROM, LAST].  The offset is
+/* Set up and return sp offset for insns in range [FROM, LAST].  The offset is
    taken from the next BB insn after LAST or zero if there in such
    insn.  */
-static void
+static poly_int64
 setup_sp_offset (rtx_insn *from, rtx_insn *last)
 {
   rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
@@ -1849,7 +1849,11 @@ setup_sp_offset (rtx_insn *from, rtx_insn *last)
                       ? 0 : lra_get_insn_recog_data (before)->sp_offset);
 
   for (rtx_insn *insn = from; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
-    lra_get_insn_recog_data (insn)->sp_offset = offset;
+    {
+      lra_get_insn_recog_data (insn)->sp_offset = offset;
+      offset = lra_update_sp_offset (PATTERN (insn), offset);
+    }
+  return offset;
 }
 
 /* Emit insns BEFORE before INSN and insns AFTER after INSN.  Put the
@@ -1875,8 +1879,25 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after,
       if (cfun->can_throw_non_call_exceptions)
        copy_reg_eh_region_note_forward (insn, before, NULL);
       emit_insn_before (before, insn);
+      poly_int64 old_sp_offset = lra_get_insn_recog_data (insn)->sp_offset;
+      poly_int64 new_sp_offset = setup_sp_offset (before, PREV_INSN (insn));
+      if (maybe_ne (old_sp_offset, new_sp_offset))
+       {
+         if (lra_dump_file != NULL)
+           {
+             fprintf (lra_dump_file, "    Changing sp offset from ");
+             print_dec (old_sp_offset, lra_dump_file);
+             fprintf (lra_dump_file, " to ");
+             print_dec (new_sp_offset, lra_dump_file);
+             fprintf (lra_dump_file, " for insn");
+             dump_rtl_slim (lra_dump_file, insn, NULL, -1, 0);
+           }
+         lra_get_insn_recog_data (insn)->sp_offset = new_sp_offset;
+         eliminate_regs_in_insn (insn, false, false,
+                                 old_sp_offset - new_sp_offset);
+         lra_push_insn (insn);
+       }
       push_insns (PREV_INSN (insn), PREV_INSN (before));
-      setup_sp_offset (before, PREV_INSN (insn));
     }
   if (after != NULL_RTX)
     {