https://gcc.gnu.org/g:fe8678d96b0402f4eb707a191848aa7d0e62796a
commit r16-7638-gfe8678d96b0402f4eb707a191848aa7d0e62796a Author: Alice Carlotti <[email protected]> Date: Tue Dec 30 08:53:57 2025 +0000 aarch64: Use __arm_get_current_vg for CFI We can't use the cntd instruction in non-streaming mode if SVE is not available, so instead use __arm_get_current_vg to get the value for the VG save slot. This is more expensive, so continue using cntd if we know we're in streaming mode or have +sve enabled. gcc/ChangeLog: * config/aarch64/aarch64-sme.md (UNSPEC_GET_CURRENT_VG): New enum value. (aarch64_get_current_vg): New insn. * config/aarch64/aarch64.cc (aarch64_save_callee_saves): Use __arm_get_current_vg if cntd is unavailable. Diff: --- gcc/config/aarch64/aarch64-sme.md | 14 ++++++++++++++ gcc/config/aarch64/aarch64.cc | 31 +++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/gcc/config/aarch64/aarch64-sme.md b/gcc/config/aarch64/aarch64-sme.md index 72823e528ded..f24e91997fd6 100644 --- a/gcc/config/aarch64/aarch64-sme.md +++ b/gcc/config/aarch64/aarch64-sme.md @@ -78,6 +78,7 @@ (define_c_enum "unspec" [ UNSPEC_OLD_VG_SAVED UNSPEC_UPDATE_VG + UNSPEC_GET_CURRENT_VG UNSPEC_GET_SME_STATE UNSPEC_READ_SVCR ]) @@ -103,6 +104,19 @@ [(set_attr "type" "no_insn")] ) +(define_insn "aarch64_get_current_vg" + [(set (reg:DI R0_REGNUM) + (unspec_volatile:DI [(const_int 0)] UNSPEC_GET_CURRENT_VG)) + (clobber (reg:DI R16_REGNUM)) + (clobber (reg:DI R17_REGNUM)) + (clobber (reg:DI R18_REGNUM)) + (clobber (reg:DI R30_REGNUM)) + (clobber (reg:CC CC_REGNUM))] + "" + "bl\t__arm_get_current_vg" + [(set_attr "is_call" "yes")] +) + (define_insn "aarch64_get_sme_state" [(set (reg:TI R0_REGNUM) (unspec_volatile:TI [(const_int 0)] UNSPEC_GET_SME_STATE)) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 00e619f26c5f..c6ba4dc56a3a 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -9526,11 +9526,30 @@ aarch64_save_callee_saves (poly_int64 bytes_below_sp, machine_mode mode = aarch64_reg_save_mode (regno); rtx reg = gen_rtx_REG (mode, regno); rtx move_src = reg; + rtx old_r0 = NULL_RTX; offset = frame.reg_offset[regno] - bytes_below_sp; if (regno == VG_REGNUM) { - move_src = gen_rtx_REG (DImode, IP0_REGNUM); - emit_move_insn (move_src, gen_int_mode (aarch64_sve_vg, DImode)); + if (AARCH64_HAVE_ISA (SVE) + || aarch64_cfun_incoming_pstate_sm () == AARCH64_ISA_MODE_SM_ON) + { + /* This check cannot just use TARGET_SVE, because the streaming + state (and hence instruction availability) differs between the + function body and prologue in locally streaming functions. */ + move_src = gen_rtx_REG (DImode, IP0_REGNUM); + emit_move_insn (move_src, gen_int_mode (aarch64_sve_vg, DImode)); + } + else + { + auto &args = crtl->args.info; + if (args.aapcs_ncrn > 0) + { + old_r0 = gen_rtx_REG (DImode, PROBE_STACK_FIRST_REGNUM); + emit_move_insn (old_r0, gen_rtx_REG (DImode, R0_REGNUM)); + } + emit_insn (gen_aarch64_get_current_vg ()); + move_src = gen_rtx_REG (DImode, R0_REGNUM); + } } rtx base_rtx = stack_pointer_rtx; poly_int64 sp_offset = offset; @@ -9621,9 +9640,13 @@ aarch64_save_callee_saves (poly_int64 bytes_below_sp, RTX_FRAME_RELATED_P (insn) = frame_related_p; /* Emit a fake instruction to indicate that the VG save slot has - been initialized. */ + been initialized, and then restore R0 if necessary. */ if (regno == VG_REGNUM) - emit_insn (gen_aarch64_old_vg_saved (move_src, mem)); + { + emit_insn (gen_aarch64_old_vg_saved (move_src, mem)); + if (old_r0) + emit_move_insn (gen_rtx_REG (DImode, R0_REGNUM), old_r0); + } } }
