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);
+       }
     }
 }

Reply via email to