https://gcc.gnu.org/g:4bcf6c461a9b8fb6e68de3f0b695881b9ac6e934
commit r16-7891-g4bcf6c461a9b8fb6e68de3f0b695881b9ac6e934 Author: Robin Dapp <[email protected]> Date: Wed Mar 4 10:02:07 2026 +0100 lra: Validate regno and mode in equiv substitution. [PR124041] We can perform equivalence substitution in subreg context: (insn 34 32 36 3 (set (reg:SI 103 [ _7 ]) (subreg:SI (reg/f:DI 119) 0)) "bla.c":7:41 104 {*movsi_aarch64} becomes (insn 34 32 36 3 (set (reg:SI 103 [ _7 ]) (subreg:SI (reg/f:DI 64 sfp) 0)) "bla.c":7:41 104 {*movsi_aarch64} (nil)) but aarch64_hard_regno_mode_ok doesn't like that: if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) return mode == Pmode; and ICEs further on. Therefore, this patch checks hard_regno_mode_ok if we substitute a hard reg in subreg context. PR rtl-optimization/124041 gcc/ChangeLog: * lra-constraints.cc (curr_insn_transform): Check if hardreg is valid in subreg context. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr124041.c: New test. Signed-off-by: Robin Dapp <[email protected]> Diff: --- gcc/lra-constraints.cc | 14 +++++++++++++- gcc/testsuite/gcc.dg/torture/pr124041.c | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 84f78b40d6ac..fae7b49bdbde 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -4402,11 +4402,23 @@ curr_insn_transform (bool check_only_p) continue; old = op = *curr_id->operand_loc[i]; + machine_mode outer_mode = GET_MODE (old); + bool subreg_p = false; if (GET_CODE (old) == SUBREG) - old = SUBREG_REG (old); + { + old = SUBREG_REG (old); + subreg_p = true; + } subst = get_equiv_with_elimination (old, curr_insn); original_subreg_reg_mode[i] = VOIDmode; equiv_substition_p[i] = false; + + /* If we are about to replace a register inside a subreg, check if + the target can handle that. */ + if (subreg_p && REG_P (subst) && HARD_REGISTER_P (subst) + && !targetm.hard_regno_mode_ok (REGNO (subst), outer_mode)) + continue; + if (subst != old) { equiv_substition_p[i] = true; diff --git a/gcc/testsuite/gcc.dg/torture/pr124041.c b/gcc/testsuite/gcc.dg/torture/pr124041.c new file mode 100644 index 000000000000..f966757e4b5d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr124041.c @@ -0,0 +1,17 @@ +/* { dg-compile } */ +/* { dg-additional-options "-O2 -fno-strict-aliasing -fstack-protector -ftrivial-auto-var-init=zero -fsanitize=thread -Wall" } */ + +char *trick_compiler(void *); +int do_usercopy_stack_callee_i; +char *do_usercopy_stack_callee(long value) +{ + char buf[28]; + for (; do_usercopy_stack_callee_i < sizeof(buf); do_usercopy_stack_callee_i++) + buf[do_usercopy_stack_callee_i] = value; + return trick_compiler(buf); +} +void do_usercopy_stack(void) +{ + char *bad_stack; + bad_stack = do_usercopy_stack_callee((long)&bad_stack); +}
