https://gcc.gnu.org/g:23c8aa5860bd6eacf759ad9ad6431d28a6724458
commit 23c8aa5860bd6eacf759ad9ad6431d28a6724458 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 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. */