https://gcc.gnu.org/g:c7c77ec3190e37cc079ef1a88521af485d7224be

commit r16-9318-gc7c77ec3190e37cc079ef1a88521af485d7224be
Author: Alice Carlotti <[email protected]>
Date:   Thu Apr 16 13:02:35 2026 +0100

    aarch64: Fix ZA state transition [PR119210]
    
    In the INACTIVE_CALLER -> INACTIVE LOCAL transition, ensure ZA is active
    and zeroed before setting tpidr2_el0.
    
    gcc/ChangeLog:
    
            PR target/119210
            * config/aarch64/aarch64.cc (aarch64_mode_emit_local_sme_state):
            Add PSTATE.ZA enablement, and zero it if already enabled.
    
    gcc/testsuite/ChangeLog:
    
            PR target/119210
            * gcc.target/aarch64/sme/za_state_8.c: New test.

Diff:
---
 gcc/config/aarch64/aarch64.cc                     | 13 +++++++++++-
 gcc/testsuite/gcc.target/aarch64/sme/za_state_8.c | 25 +++++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0b9cb043c665..99890a463d4c 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -31984,7 +31984,8 @@ aarch64_mode_emit_local_sme_state 
(aarch64_local_sme_state mode,
       emit_insn (gen_aarch64_tpidr2_save ());
       emit_insn (gen_aarch64_clear_tpidr2 ());
       if (mode == aarch64_local_sme_state::ACTIVE_LIVE
-         || mode == aarch64_local_sme_state::ACTIVE_DEAD)
+         || mode == aarch64_local_sme_state::ACTIVE_DEAD
+         || mode == aarch64_local_sme_state::INACTIVE_LOCAL)
        {
          if (aarch64_cfun_has_state ("za"))
            emit_insn (gen_aarch64_initial_zero_za ());
@@ -32066,6 +32067,16 @@ aarch64_mode_emit_local_sme_state 
(aarch64_local_sme_state mode,
 
   if (mode == aarch64_local_sme_state::INACTIVE_LOCAL)
     {
+      if (prev_mode == aarch64_local_sme_state::INACTIVE_CALLER)
+       /* Enable ZA (if it wasn't already enabled on entry).  Enabling ZA has
+          the side-effect of zeroing ZA.
+
+          A functionally correct alternative would be to leave TPIDR2_EL0 null
+          and zero the save buffer.  However, zeroing the save buffer would 
require
+          more code and would optimize for the case in which a callee also
+          initialises private ZA state (which should be a rare event).  */
+       emit_insn (gen_aarch64_smstart_za ());
+
       if (prev_mode == aarch64_local_sme_state::ACTIVE_LIVE
          || prev_mode == aarch64_local_sme_state::ACTIVE_DEAD
          || prev_mode == aarch64_local_sme_state::INACTIVE_CALLER)
diff --git a/gcc/testsuite/gcc.target/aarch64/sme/za_state_8.c 
b/gcc/testsuite/gcc.target/aarch64/sme/za_state_8.c
new file mode 100644
index 000000000000..9b7a6ffa69cb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme/za_state_8.c
@@ -0,0 +1,25 @@
+// { dg-options "-O -fomit-frame-pointer -fno-optimize-sibling-calls" }
+// { dg-final { check-function-bodies "**" "" } }
+
+#include <arm_sme.h>
+
+void callee_ns();
+__arm_streaming __arm_inout("za") void callee_s();
+
+/*
+** foo:
+**     ...
+**     smstart za
+**     ...
+**     msr     tpidr2_el0, x\d+
+**     ...
+*/
+__arm_locally_streaming __arm_new("za") const float * foo(const float* x) {
+    callee_ns ();
+    const float32_t *x_f_in = x;
+    svzero_za();
+    callee_s ();
+    return x_f_in;
+}
+
+

Reply via email to