https://gcc.gnu.org/g:f5b3ed79efe40bae658954edd2e94f1a7dd29ec1
commit f5b3ed79efe40bae658954edd2e94f1a7dd29ec1 Author: Alexandre Oliva <ol...@adacore.com> Date: Sat Jun 21 05:58:22 2025 -0300 [lra] propagate fp2sp elimination offset after disabling it [PR120424] Deactivating the fp2sp elimination early causes __do_global_ctors_aux on arm-linux-gnueabihf to be miscompiled (with -fnon-call-exceptions -fstack-clash-protection) because, after fp2sp is disabled, we'd choose another elimination and use its -1 prev_offset. But keeping it active causes e.g. pr103973-18.c to be miscompiled on x86_64-linux-gnu (with ix86_frame_pointer_required modified to return true when ix86_get_frame_size () > 0, to exercise the fp2sp elimination deactivation), because two adjacent pushes of two adjacent temporaries end up pushing the same slot, because one of them gets offset by the sp variation. The solution is to keep the early disabling of the elimination, which fixes x86_64, but retain the code to propagate the offset to the next FP elimination, which fixes arm. (I was concerned that disabling the fp2sp elimination too soon could drop offsets already applied to fp, that would have to be reverted or passed on to the next fp elimination, but we know the elimination was not used, and if there were any insns or offsets to propagate, the previous round of lra_eliminate, in which update_reg_eliminations would have selected the fp2sp elimination, would also have set elimination_fp2sp_occured if any insn used the fp2sp elimination's offset. Since we know there weren't any, because elimination_fp2sp_occured is clear, we know other fp eliminations can safely use their initial offsets if needed.) Diff: --- gcc/lra-eliminations.cc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index f8a761e6eeaa..400857587b3a 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -312,6 +312,11 @@ move_plus_up (rtx x) /* Flag that we already did frame pointer to stack pointer elimination. */ static bool elimination_fp2sp_occured_p = false; +/* Hold the fp2sp elimination that was disabled and inactivated, but + whose offsets we wish to propagate to any subsequently-chosen fp + elimination. */ +static class lra_elim_table *disabled_fp2sp_elimination; + /* 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 a change in the offset between the eliminable register and its @@ -1185,7 +1190,9 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) setup_can_eliminate (ep, false); continue; } - if (!ep->can_eliminate && elimination_map[ep->from] == ep) + if (!ep->can_eliminate + && (elimination_map[ep->from] == ep + || disabled_fp2sp_elimination == ep)) { /* We cannot use this elimination anymore -- find another one. */ @@ -1233,6 +1240,7 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->offset); } + disabled_fp2sp_elimination = NULL; setup_elimination_map (); result = false; CLEAR_HARD_REG_SET (temp_hard_reg_set); @@ -1319,6 +1327,7 @@ init_elimination (void) rtx_insn *insn; class lra_elim_table *ep; + disabled_fp2sp_elimination = NULL; init_elim_table (); FOR_EACH_BB_FN (bb, cfun) { @@ -1432,7 +1441,13 @@ lra_update_fp2sp_elimination (void) during update_reg_eliminate. */ ep = elimination_map[FRAME_POINTER_REGNUM]; if (ep->to == STACK_POINTER_REGNUM) - setup_can_eliminate (ep, false); + { + /* Avoid using this known-unused elimination when removing + spilled pseudos. */ + elimination_map[FRAME_POINTER_REGNUM] = NULL; + disabled_fp2sp_elimination = ep; + 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)