From: Alice Carlotti Date: Thu, 16 Apr 2026 12:02:35 +0000 (+0100) Subject: aarch64: Fix ZA state transition [PR119210] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=960c8597962a9816fd992072bcb911566dbb58ea;p=thirdparty%2Fgcc.git 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 --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 62194b96450..693ce8b4d25 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -31951,7 +31951,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 ()); @@ -32033,6 +32034,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 00000000000..9b7a6ffa69c --- /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 + +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; +} + +