https://gcc.gnu.org/g:3c46d079e46aceee46aaf7ce13ea5c58e31f186d
commit 3c46d079e46aceee46aaf7ce13ea5c58e31f186d 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 | 45 ++++++++++++++++++++++++++------------------- gcc/lra-int.h | 2 +- gcc/lra-spills.cc | 13 +++---------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index 6663d1c37e8b..914b064743bd 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -1172,7 +1172,16 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) /* If it is a currently used elimination: update the previous offset. */ if (elimination_map[ep->from] == ep) - ep->previous_offset = ep->offset; + { + ep->previous_offset = ep->offset; + /* Restore the stack_pointer_rtx into to_rtx, that + lra_update_fp2sp_elimination set to from_rtx, so that the assert + below still checks what it was supposed to check. */ + if (ep->from_rtx == ep->to_rtx + && ep->from != ep->to + && ep->from == FRAME_POINTER_REGNUM) + ep->to_rtx = stack_pointer_rtx; + } prev = ep->prev_can_eliminate; setup_can_eliminate (ep, targetm.can_eliminate (ep->from, ep->to)); @@ -1405,30 +1414,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 +1434,22 @@ 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) + ep = elimination_map[FRAME_POINTER_REGNUM]; + if (ep->to == STACK_POINTER_REGNUM) + { + /* Prevent any further uses of fp, say in spill addresses, from being + eliminated to sp and affected by sp offsets. Alas, deactivating the + elimination altogether causes the next chosen fp elimination to miss + the offset propagation, so it may keep -1 as its prev_offset, and that + will make subsequent offsets incorrect. */ + ep->to_rtx = ep->from_rtx; + 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. */ 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. */