[gcc(refs/users/aoliva/heads/testme)] [lra] simplify disabling of fp2sp elimination [PR120424]
Alexandre Oliva
aoliva@gcc.gnu.org
Sat Jun 21 01:44:59 GMT 2025
https://gcc.gnu.org/g:23c8aa5860bd6eacf759ad9ad6431d28a6724458
commit 23c8aa5860bd6eacf759ad9ad6431d28a6724458
Author: Alexandre Oliva <oliva@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 2719a11d9dd6..227064e2d84a 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 < ®_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, ®_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 0cf7266ce646..05d28af7c9e0 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..494ef3c96c8e 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 ();
+ 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. */
More information about the Gcc-cvs
mailing list