[LRA]: Check and update frame to stack pointer elimination after stack slot allocation

Avr is an interesting target which does not use stack pointer to
address stack slots.  The elimination of stack pointer to frame pointer
is impossible if there are stack slots.  During LRA works, the
stack slots can be allocated and used and the elimination can be done
anymore.  The situation can be complicated even more if some pseudos
were allocated to the frame pointer.

gcc/ChangeLog:

	* lra-int.h (lra_update_fp2sp_elimination): New prototype.
	(lra_asm_insn_error): New prototype.
	* lra-spills.cc (remove_pseudos): Add check for pseudo slot memory
	existence.
	(lra_spill): Call lra_update_fp2sp_elimination.
	* lra-eliminations.cc: Remove trailing spaces.
	(elimination_fp2sp_occured_p): New static flag.
	(lra_eliminate_regs_1): Set the flag up.
	(update_reg_eliminate): Modify the assert for stack to frame
	pointer elimination.
	(lra_update_fp2sp_elimination): New function.
	(lra_eliminate): Clear flag elimination_fp2sp_occured_p.

gcc/testsuite/ChangeLog:

	* gcc.target/avr/lra-elim.c: New test.
This commit is contained in:
Vladimir N. Makarov 2023-07-19 09:35:37 -04:00
parent 029c7ebe7f
commit 2971ff7b1d
4 changed files with 77 additions and 13 deletions

View file

@ -286,7 +286,7 @@ move_plus_up (rtx x)
{
rtx subreg_reg;
machine_mode x_mode, subreg_reg_mode;
if (GET_CODE (x) != SUBREG || !subreg_lowpart_p (x))
return x;
subreg_reg = SUBREG_REG (x);
@ -309,6 +309,9 @@ move_plus_up (rtx x)
return x;
}
/* Flag that we already did frame pointer to stack pointer elimination. */
static bool elimination_fp2sp_occured_p = false;
/* Scan X and replace any eliminable registers (such as fp) with a
replacement (such as sp) if SUBST_P, plus an offset. The offset is
a change in the offset between the eliminable register and its
@ -366,6 +369,9 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
{
rtx to = subst_p ? ep->to_rtx : ep->from_rtx;
if (ep->to_rtx == stack_pointer_rtx && ep->from == FRAME_POINTER_REGNUM)
elimination_fp2sp_occured_p = true;
if (maybe_ne (update_sp_offset, 0))
{
if (ep->to_rtx == stack_pointer_rtx)
@ -396,9 +402,12 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
poly_int64 offset, curr_offset;
rtx to = subst_p ? ep->to_rtx : ep->from_rtx;
if (ep->to_rtx == stack_pointer_rtx && ep->from == FRAME_POINTER_REGNUM)
elimination_fp2sp_occured_p = true;
if (! update_p && ! full_p)
return gen_rtx_PLUS (Pmode, to, XEXP (x, 1));
if (maybe_ne (update_sp_offset, 0))
offset = ep->to_rtx == stack_pointer_rtx ? update_sp_offset : 0;
else
@ -456,6 +465,9 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
{
rtx to = subst_p ? ep->to_rtx : ep->from_rtx;
if (ep->to_rtx == stack_pointer_rtx && ep->from == FRAME_POINTER_REGNUM)
elimination_fp2sp_occured_p = true;
if (maybe_ne (update_sp_offset, 0))
{
if (ep->to_rtx == stack_pointer_rtx)
@ -500,7 +512,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
case LE: case LT: case LEU: case LTU:
{
rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode,
subst_p, update_p,
subst_p, update_p,
update_sp_offset, full_p);
rtx new1 = XEXP (x, 1)
? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode,
@ -749,7 +761,7 @@ mark_not_eliminable (rtx x, machine_mode mem_mode)
&& poly_int_rtx_p (XEXP (XEXP (x, 1), 1), &offset))))
{
poly_int64 size = GET_MODE_SIZE (mem_mode);
#ifdef PUSH_ROUNDING
/* If more bytes than MEM_MODE are pushed, account for
them. */
@ -822,7 +834,7 @@ mark_not_eliminable (rtx x, machine_mode mem_mode)
{
/* See if this is setting the replacement hard register for
an elimination.
If DEST is the hard frame pointer, we do nothing because
we assume that all assignments to the frame pointer are
for non-local gotos and are being done at a time when
@ -838,7 +850,7 @@ mark_not_eliminable (rtx x, machine_mode mem_mode)
&& SET_DEST (x) != hard_frame_pointer_rtx)
setup_can_eliminate (ep, false);
}
mark_not_eliminable (SET_SRC (x), mem_mode);
return;
@ -1047,7 +1059,7 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p,
&& GET_CODE (XEXP (SET_SRC (set), 0)) == PLUS)
{
rtx reg1, reg2, op1, op2;
reg1 = op1 = XEXP (XEXP (SET_SRC (set), 0), 0);
reg2 = op2 = XEXP (SET_SRC (set), 1);
if (GET_CODE (reg1) == SUBREG)
@ -1160,11 +1172,17 @@ update_reg_eliminate (bitmap insns_with_changed_offsets)
fprintf (lra_dump_file,
" Elimination %d to %d is not possible anymore\n",
ep->from, ep->to);
/* If after processing RTL we decides that SP can be used as
a result of elimination, it cannot be changed. */
gcc_assert ((ep->to_rtx != stack_pointer_rtx)
|| (ep->from < FIRST_PSEUDO_REGISTER
/* If after processing RTL we decides that SP can be used as a result
of elimination, it cannot be changed. For frame pointer to stack
pointer elimination the condition is a bit relaxed and we just require
that actual elimination has not been done yet. */
gcc_assert (ep->to_rtx != stack_pointer_rtx
|| (ep->from == FRAME_POINTER_REGNUM
&& !elimination_fp2sp_occured_p)
|| (ep->from != FRAME_POINTER_REGNUM
&& ep->from < FIRST_PSEUDO_REGISTER
&& fixed_regs [ep->from]));
/* Mark that is not eliminable anymore. */
elimination_map[ep->from] = NULL;
for (ep1 = ep + 1; ep1 < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep1++)
@ -1363,6 +1381,30 @@ process_insn_for_elimination (rtx_insn *insn, bool final_p, bool first_p)
}
}
/* Update frame pointer to stack pointer elimination if we started with
permitted frame pointer elimination and now target reports that we can not
do this elimination anymore. */
void
lra_update_fp2sp_elimination (void)
{
HARD_REG_SET set;
class lra_elim_table *ep;
if (frame_pointer_needed || !targetm.frame_pointer_required ())
return;
gcc_assert (!elimination_fp2sp_occured_p);
if (lra_dump_file != NULL)
fprintf (lra_dump_file,
" Frame pointer can not be eliminated anymore\n");
frame_pointer_needed = true;
CLEAR_HARD_REG_SET (set);
add_to_hard_reg_set (&set, Pmode, FRAME_POINTER_REGNUM);
spill_pseudos (set);
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from == FRAME_POINTER_REGNUM && ep->to == STACK_POINTER_REGNUM)
setup_can_eliminate (ep, false);
}
/* Entry function to do final elimination if FINAL_P or to update
elimination register offsets (FIRST_P if we are doing it the first
time). */
@ -1379,7 +1421,10 @@ lra_eliminate (bool final_p, bool first_p)
timevar_push (TV_LRA_ELIMINATE);
if (first_p)
init_elimination ();
{
elimination_fp2sp_occured_p = false;
init_elimination ();
}
bitmap_initialize (&insns_with_changed_offsets, &reg_obstack);
if (final_p)

View file

@ -414,6 +414,7 @@ extern int lra_get_elimination_hard_regno (int);
extern rtx lra_eliminate_regs_1 (rtx_insn *, rtx, machine_mode,
bool, bool, poly_int64, bool);
extern void eliminate_regs_in_insn (rtx_insn *insn, bool, bool, poly_int64);
extern void lra_update_fp2sp_elimination (void);
extern void lra_eliminate (bool, bool);
extern poly_int64 lra_update_sp_offset (rtx, poly_int64);

View file

@ -453,7 +453,10 @@ remove_pseudos (rtx *loc, rtx_insn *insn)
return true;
if ((hard_reg = spill_hard_reg[i]) != NULL_RTX)
*loc = copy_rtx (hard_reg);
else
else if (pseudo_slots[i].mem != NULL_RTX)
/* There might be no memory slot or hard reg for a pseudo when we spill
the frame pointer after elimination of frame pointer to stack
pointer became impossible. */
{
rtx x = lra_eliminate_regs_1 (insn, pseudo_slots[i].mem,
GET_MODE (pseudo_slots[i].mem),
@ -629,6 +632,7 @@ lra_spill (void)
for (i = 0; i < n; i++)
if (pseudo_slots[pseudo_regnos[i]].mem == NULL_RTX)
assign_mem_slot (pseudo_regnos[i]);
lra_update_fp2sp_elimination ();
if (n > 0 && crtl->stack_alignment_needed)
/* If we have a stack frame, we must align it now. The stack size
may be a part of the offset computation for register

View file

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-mmcu=avr25 -Os" } */
typedef int HItype __attribute__ ((mode (HI)));
HItype
__mulvhi3 (HItype a, HItype b)
{
HItype w;
if (__builtin_mul_overflow (a, b, &w))
__builtin_trap ();
return w;
}