]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64: Use __arm_get_current_vg for CFI
authorAlice Carlotti <alice.carlotti@arm.com>
Tue, 30 Dec 2025 08:53:57 +0000 (08:53 +0000)
committerAlice Carlotti <alice.carlotti@arm.com>
Mon, 23 Feb 2026 11:16:42 +0000 (11:16 +0000)
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.

gcc/config/aarch64/aarch64-sme.md
gcc/config/aarch64/aarch64.cc

index 72823e528ded7c6c6f1a8bad99190a6a8e4254b9..f24e91997fd640f82c11353dd196fe334daec630 100644 (file)
@@ -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
 ])
   [(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))
index 00e619f26c5f2832dce3a4d99cb405872e78df5f..c6ba4dc56a3a661537e557c63b80cce3c60e01f6 100644 (file)
@@ -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);
+       }
     }
 }