commit 30038a207c10a2783fa2695b62c7c8458ef05e73 Author: Vladimir N. Makarov Date: Tue May 30 15:54:28 2023 -0400 LRA: Update insn sp offset if its input reload changes SP 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. diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index 42206366669..68225339cb6 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -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) diff --git a/gcc/lra-int.h b/gcc/lra-int.h index a400a0f85e2..4dbe6672f3a 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -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 *); diff --git a/gcc/lra.cc b/gcc/lra.cc index eb3ee1f8b63..c8b3f139acd 100644 --- a/gcc/lra.cc +++ b/gcc/lra.cc @@ -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) {