https://gcc.gnu.org/g:c6ce3a5fe59c2668354cc4cf9a3e946a8215f57a

commit c6ce3a5fe59c2668354cc4cf9a3e946a8215f57a
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Thu Jun 19 11:05:36 2025 -0300

    [lra] simplify disabling of fp2sp elimination [PR120424]
    
    Whether with or without the lra fp2sp elimination accumulated
    improvements, building a native arm-linux-gnueabihf toolchain with
    {BOOT_CFLAGS,TFLAGS}='-O2 -g -fnon-call-exceptions
    -fstack-clash-protection' doesn't get very far: crtbegin.o gets
    miscompiled in __do_global_dtors_aux, as spilled pseudos get assigned
    stack slots that get incorrectly adjusted after the fp2sp elimination
    is disabled.
    
    AFAICT eliminations are reversible before the final round, and ISTM
    that deferring spilling of registers in disabled eliminations to
    update_reg_eliminate would avoid the incorrect adjustments I saw in
    spilling within or after lra_update_fp2sp_elimination: the logic to
    deal with them was already there, we just have to set the stage for it
    to do its job, and only be concerned with disabled fp2sp eliminations
    during the final round, during which no further disabling of
    eliminations is expected.

Diff:
---
 gcc/lra-eliminations.cc | 68 ++++++++++++++++++++++++++++---------------------
 gcc/lra-int.h           |  2 +-
 gcc/lra-spills.cc       | 13 +++-------
 3 files changed, 43 insertions(+), 40 deletions(-)

diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index 09959bbe3ed9..56f07520d12f 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -309,8 +309,12 @@ 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;
+/* elimination_fp2sp_final is set as we start the final round of
+   elimination.  elimination_fp2sp_used is copied from
+   elimination_fp2sp_final whenever any frame pointer to stack pointer
+   is encountered.  */
+static bool elimination_fp2sp_final = false;
+static bool elimination_fp2sp_used = 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
@@ -318,7 +322,7 @@ static bool elimination_fp2sp_occured_p = false;
    substitution if UPDATE_P, or the full offset if FULL_P, or
    otherwise zero.  If FULL_P, we also use the SP offsets for
    elimination to SP.  If UPDATE_P, use UPDATE_SP_OFFSET for updating
-   offsets of register elimnable to SP.  If UPDATE_SP_OFFSET is
+   offsets of register eliminable to SP.  If UPDATE_SP_OFFSET is
    non-zero, don't use difference of the offset and the previous
    offset.
 
@@ -370,7 +374,7 @@ 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;
+           elimination_fp2sp_used = elimination_fp2sp_final;
 
          if (maybe_ne (update_sp_offset, 0))
            {
@@ -402,8 +406,9 @@ 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 (ep->to_rtx == stack_pointer_rtx
+                 && ep->from == FRAME_POINTER_REGNUM)
+               elimination_fp2sp_used = elimination_fp2sp_final;
 
              if (! update_p && ! full_p)
                return simplify_gen_binary (PLUS, Pmode, to, XEXP (x, 1));
@@ -465,8 +470,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 (ep->to_rtx == stack_pointer_rtx
+             && ep->from == FRAME_POINTER_REGNUM)
+           elimination_fp2sp_used = elimination_fp2sp_final;
 
          if (maybe_ne (update_sp_offset, 0))
            {
@@ -1199,7 +1205,8 @@ update_reg_eliminate (bitmap insns_with_changed_offsets)
             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)
+                         && !(elimination_fp2sp_final
+                              && elimination_fp2sp_used))
                      || (ep->from < FIRST_PSEUDO_REGISTER
                          && fixed_regs [ep->from]));
 
@@ -1405,30 +1412,19 @@ process_insn_for_elimination (rtx_insn *insn, bool 
final_p, bool first_p)
    permitted frame pointer elimination and now target reports that we can not
    do this elimination anymore.  Record spilled pseudos in SPILLED_PSEUDOS
    unless it is null, and return the recorded pseudos number.  */
-int
-lra_update_fp2sp_elimination (int *spilled_pseudos)
+void
+lra_update_fp2sp_elimination (void)
 {
-  int n;
-  HARD_REG_SET set;
   class lra_elim_table *ep;
 
   if (frame_pointer_needed || !targetm.frame_pointer_required ())
-    return 0;
-  gcc_assert (!elimination_fp2sp_occured_p);
-  ep = elimination_map[FRAME_POINTER_REGNUM];
-  if (ep->to == STACK_POINTER_REGNUM)
-    {
-      elimination_map[FRAME_POINTER_REGNUM] = NULL;
-      setup_can_eliminate (ep, false);
-    }
-  else
-    ep = NULL;
+    return;
+  /* We do not expect fp2sp to be disabled during the final round.  */
+  gcc_assert (!elimination_fp2sp_final);
   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, HARD_FRAME_POINTER_REGNUM);
   /* If !lra_reg_spill_p, we likely have incomplete range information
      for pseudos assigned to the frame pointer that will have to be
      spilled, and so we may end up incorrectly sharing them unless we
@@ -1437,12 +1433,19 @@ lra_update_fp2sp_elimination (int *spilled_pseudos)
     /* If lives ranges changed, update the aggregate live ranges in
        slots as well before spilling any further pseudos.  */
     lra_recompute_slots_live_ranges ();
-  n = spill_pseudos (set, spilled_pseudos);
-  if (!ep)
+  /* Conceivably, we wouldn't need to disable the fp2sp elimination
+     unless the target says so, but we have to vacate the frame
+     pointer register to make room for the frame pointer proper, and
+     disabling the elimination will spill everything assigned to it
+     during update_reg_eliminate.  */
+  ep = elimination_map[FRAME_POINTER_REGNUM];
+  if (ep->to == STACK_POINTER_REGNUM)
+    setup_can_eliminate (ep, false);
+  else
     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);
-  return n;
+  return;
 }
 
 /* Return true if we have a pseudo assigned to hard frame pointer.  */
@@ -1481,9 +1484,15 @@ lra_eliminate (bool final_p, bool first_p)
 
   if (first_p)
     {
-      elimination_fp2sp_occured_p = false;
+      elimination_fp2sp_final = false;
+      elimination_fp2sp_used = false;
       init_elimination ();
     }
+  else if (final_p)
+    {
+      elimination_fp2sp_final = true;
+      elimination_fp2sp_used = false;
+    }
 
   bitmap_initialize (&insns_with_changed_offsets, &reg_obstack);
   if (final_p)
@@ -1514,6 +1523,7 @@ lra_eliminate (bool final_p, bool first_p)
       process_insn_for_elimination (lra_insn_recog_data[uid]->insn,
                                    final_p, first_p);
   bitmap_clear (&insns_with_changed_offsets);
+  gcc_assert (!(elimination_fp2sp_used && elimination_fp2sp_final));
 
 lra_eliminate_done:
   timevar_pop (TV_LRA_ELIMINATE);
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 99e4699648cc..a69447905374 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -433,7 +433,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 int lra_update_fp2sp_elimination (int *spilled_pseudos);
+extern void lra_update_fp2sp_elimination (void);
 extern bool lra_fp_pseudo_p (void);
 extern void lra_eliminate (bool, bool);
 
diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc
index 7603d0dcf163..e3a9e2f8caad 100644
--- a/gcc/lra-spills.cc
+++ b/gcc/lra-spills.cc
@@ -658,7 +658,7 @@ lra_need_for_spills_p (void)
 void
 lra_spill (void)
 {
-  int i, n, n2, curr_regno;
+  int i, n, curr_regno;
   int *pseudo_regnos;
 
   regs_num = max_reg_num ();
@@ -685,15 +685,8 @@ lra_spill (void)
   for (i = 0; i < n; i++)
     if (pseudo_slots[pseudo_regnos[i]].mem == NULL_RTX)
       assign_mem_slot (pseudo_regnos[i]);
-  if ((n2 = lra_update_fp2sp_elimination (pseudo_regnos)) > 0)
-    {
-      /* Assign stack slots to spilled pseudos assigned to fp.  */
-      assign_stack_slot_num_and_sort_pseudos (pseudo_regnos, n2);
-      for (i = 0; i < n2; i++)
-       if (pseudo_slots[pseudo_regnos[i]].mem == NULL_RTX)
-         assign_mem_slot (pseudo_regnos[i]);
-    }
-  if (n + n2 > 0 && crtl->stack_alignment_needed)
+  lra_update_fp2sp_elimination (pseudo_regnos);
+  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
        elimination.  */

Reply via email to