https://gcc.gnu.org/g:95913b192448b8f17208186a87e58f5282720eb2
commit 95913b192448b8f17208186a87e58f5282720eb2 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. Diff: --- gcc/lra-eliminations.cc | 38 +++++++++++++++++++------------------- gcc/lra-int.h | 2 +- gcc/lra-spills.cc | 13 +++---------- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index 2719a11d9dd6..2278661097a3 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -1405,30 +1405,18 @@ 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; + return; 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; 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 +1425,24 @@ 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) + { + /* Avoid using this known-unused elimination when removing + spilled pseudos. */ + elimination_map[FRAME_POINTER_REGNUM] = NULL; + 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; + setup_can_eliminate (ep, false); + return; } /* Return true if we have a pseudo assigned to hard frame pointer. */ 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. */