diff mbox series

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

Message ID 10df283b-93c8-1d05-fa8a-11c5b256f943@redhat.com
State New
Headers show
Series [pushed,LRA] : Check and update frame to stack pointer elimination after stack slot allocation | expand

Commit Message

Vladimir Makarov July 19, 2023, 5:59 p.m. UTC
The following patch is necessary for porting avr to LRA.

The patch was successfully bootstrapped and tested on x86-64, aarch64, 
and ppc64le.

There is still avr poring problem with reloading of subreg of frame 
pointer.  I'll address it later on this week.
commit 2971ff7b1d564ac04b537d907c70e6093af70832
Author: Vladimir N. Makarov <vmakarov@redhat.com>
Date:   Wed Jul 19 09:35:37 2023 -0400

    [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.

Comments

Rainer Orth July 20, 2023, 8:45 p.m. UTC | #1
Hi Vladimir,

> The following patch is necessary for porting avr to LRA.
>
> The patch was successfully bootstrapped and tested on x86-64, aarch64, and
> ppc64le.
>
> There is still avr poring problem with reloading of subreg of frame
> pointer.  I'll address it later on this week.

this patch most likely broke sparc-sun-solaris2.11 bootstrap:

/var/gcc/regression/master/11.4-gcc/build/./gcc/xgcc -B/var/gcc/regression/master/11.4-gcc/build/./gcc/ -B/vol/gcc/sparc-sun-solaris2.11/bin/ -B/vol/gcc/sparc-sun-solaris2.11/lib/ -isystem /vol/gcc/sparc-sun-solaris2.11/include -isystem /vol/gcc/sparc-sun-solaris2.11/sys-include   -fchecking=1 -c -g -O2   -W -Wall -gnatpg -nostdinc   g-alleve.adb -o g-alleve.o
+===========================GNAT BUG DETECTED==============================+ 
| 14.0.0 20230720 (experimental) [master 506f068e7d01ad2fb107185b8fb204a0ec23785c] (sparc-sun-solaris2.11) GCC error:|
| in update_reg_eliminate, at lra-eliminations.cc:1179                     |
| Error detected around g-alleve.adb:4132:8                

This is in stage 3.  I haven't investigated further yet.

	Rainer
Vladimir Makarov July 21, 2023, 8:02 p.m. UTC | #2
On 7/20/23 16:45, Rainer Orth wrote:
> Hi Vladimir,
>
>> The following patch is necessary for porting avr to LRA.
>>
>> The patch was successfully bootstrapped and tested on x86-64, aarch64, and
>> ppc64le.
>>
>> There is still avr poring problem with reloading of subreg of frame
>> pointer.  I'll address it later on this week.
> this patch most likely broke sparc-sun-solaris2.11 bootstrap:
>
> /var/gcc/regression/master/11.4-gcc/build/./gcc/xgcc -B/var/gcc/regression/master/11.4-gcc/build/./gcc/ -B/vol/gcc/sparc-sun-solaris2.11/bin/ -B/vol/gcc/sparc-sun-solaris2.11/lib/ -isystem /vol/gcc/sparc-sun-solaris2.11/include -isystem /vol/gcc/sparc-sun-solaris2.11/sys-include   -fchecking=1 -c -g -O2   -W -Wall -gnatpg -nostdinc   g-alleve.adb -o g-alleve.o
> +===========================GNAT BUG DETECTED==============================+
> | 14.0.0 20230720 (experimental) [master 506f068e7d01ad2fb107185b8fb204a0ec23785c] (sparc-sun-solaris2.11) GCC error:|
> | in update_reg_eliminate, at lra-eliminations.cc:1179                     |
> | Error detected around g-alleve.adb:4132:8
>
> This is in stage 3.  I haven't investigated further yet.

Thank you for reporting this.  I'll try to fix on this week.  I have a 
patch but unfortunately bootstrap is too slow.  If the patch does not 
work, I'll revert the original patch.
diff mbox series

Patch

diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index 68225339cb6..cf0aa94b69a 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -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)
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index a32359e5772..633d9af8058 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -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);
diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc
index 4af85c49d43..3a7bb7e8cd9 100644
--- a/gcc/lra-spills.cc
+++ b/gcc/lra-spills.cc
@@ -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
diff --git a/gcc/testsuite/gcc.target/avr/lra-elim.c b/gcc/testsuite/gcc.target/avr/lra-elim.c
new file mode 100644
index 00000000000..d5086a7fd5d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/lra-elim.c
@@ -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;
+}