diff options
Diffstat (limited to '0213-Backport-SME-aarch64-Handle-PSTATE.SM-across-abnorma.patch')
-rw-r--r-- | 0213-Backport-SME-aarch64-Handle-PSTATE.SM-across-abnorma.patch | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/0213-Backport-SME-aarch64-Handle-PSTATE.SM-across-abnorma.patch b/0213-Backport-SME-aarch64-Handle-PSTATE.SM-across-abnorma.patch new file mode 100644 index 0000000..f120a98 --- /dev/null +++ b/0213-Backport-SME-aarch64-Handle-PSTATE.SM-across-abnorma.patch @@ -0,0 +1,708 @@ +From ef9c800309fa326ca56dd9d9affd7d5498624bb8 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 5 Dec 2023 10:11:29 +0000 +Subject: [PATCH 114/157] [Backport][SME] aarch64: Handle PSTATE.SM across + abnormal edges + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=275706fc59b5fdcc26d46d9f19951fc86b40c515 + +PSTATE.SM is always off on entry to an exception handler, and on entry +to a nonlocal goto receiver. Those entry points need to switch +PSTATE.SM back to the appropriate state for the current function. +In the case of streaming-compatible functions, they need to restore +the mode that the caller was originally using. + +The requirement on nonlocal goto receivers means that nonlocal +jumps need to ensure that PSTATE.SM is zero. + +gcc/ + * config/aarch64/aarch64.cc: Include except.h + (aarch64_sme_mode_switch_regs::add_call_preserved_reg): New function. + (aarch64_sme_mode_switch_regs::add_call_preserved_regs): Likewise. + (aarch64_need_old_pstate_sm): Return true if the function has + a nonlocal-goto or exception receiver. + (aarch64_switch_pstate_sm_for_landing_pad): New function. + (aarch64_switch_pstate_sm_for_jump): Likewise. + (pass_switch_pstate_sm::gate): Enable the pass for all + streaming and streaming-compatible functions. + (pass_switch_pstate_sm::execute): Handle non-local gotos and their + receivers. Handle exception handler entry points. + +gcc/testsuite/ + * g++.target/aarch64/sme/exceptions_2.C: New test. + * gcc.target/aarch64/sme/nonlocal_goto_1.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_2.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_3.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_4.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_5.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_6.c: Likewise. + * gcc.target/aarch64/sme/nonlocal_goto_7.c: Likewise. +--- + gcc/config/aarch64/aarch64.cc | 141 ++++++++++++++++- + .../g++.target/aarch64/sme/exceptions_2.C | 148 ++++++++++++++++++ + .../gcc.target/aarch64/sme/nonlocal_goto_1.c | 58 +++++++ + .../gcc.target/aarch64/sme/nonlocal_goto_2.c | 44 ++++++ + .../gcc.target/aarch64/sme/nonlocal_goto_3.c | 46 ++++++ + .../gcc.target/aarch64/sme/nonlocal_goto_4.c | 25 +++ + .../gcc.target/aarch64/sme/nonlocal_goto_5.c | 26 +++ + .../gcc.target/aarch64/sme/nonlocal_goto_6.c | 31 ++++ + .../gcc.target/aarch64/sme/nonlocal_goto_7.c | 25 +++ + 9 files changed, 537 insertions(+), 7 deletions(-) + create mode 100644 gcc/testsuite/g++.target/aarch64/sme/exceptions_2.C + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_1.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_2.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_3.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_4.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_5.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_6.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_7.c + +diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc +index 4cb43c2e2..effb567c2 100644 +--- a/gcc/config/aarch64/aarch64.cc ++++ b/gcc/config/aarch64/aarch64.cc +@@ -82,6 +82,7 @@ + #include "tree-dfa.h" + #include "asan.h" + #include "aarch64-feature-deps.h" ++#include "except.h" + #include "tree-pass.h" + #include "cfgbuild.h" + +@@ -7295,6 +7296,8 @@ public: + void add_reg (machine_mode, unsigned int); + void add_call_args (rtx_call_insn *); + void add_call_result (rtx_call_insn *); ++ void add_call_preserved_reg (unsigned int); ++ void add_call_preserved_regs (bitmap); + + void emit_prologue (); + void emit_epilogue (); +@@ -7427,6 +7430,46 @@ aarch64_sme_mode_switch_regs::add_call_result (rtx_call_insn *call_insn) + add_reg (GET_MODE (dest), REGNO (dest)); + } + ++/* REGNO is a register that is call-preserved under the current function's ABI. ++ Record that it must be preserved around the mode switch. */ ++ ++void ++aarch64_sme_mode_switch_regs::add_call_preserved_reg (unsigned int regno) ++{ ++ if (FP_REGNUM_P (regno)) ++ switch (crtl->abi->id ()) ++ { ++ case ARM_PCS_SVE: ++ add_reg (VNx16QImode, regno); ++ break; ++ case ARM_PCS_SIMD: ++ add_reg (V16QImode, regno); ++ break; ++ case ARM_PCS_AAPCS64: ++ add_reg (DImode, regno); ++ break; ++ default: ++ gcc_unreachable (); ++ } ++ else if (PR_REGNUM_P (regno)) ++ add_reg (VNx16BImode, regno); ++} ++ ++/* The hard registers in REGS are call-preserved under the current function's ++ ABI. Record that they must be preserved around the mode switch. */ ++ ++void ++aarch64_sme_mode_switch_regs::add_call_preserved_regs (bitmap regs) ++{ ++ bitmap_iterator bi; ++ unsigned int regno; ++ EXECUTE_IF_SET_IN_BITMAP (regs, 0, regno, bi) ++ if (HARD_REGISTER_NUM_P (regno)) ++ add_call_preserved_reg (regno); ++ else ++ break; ++} ++ + /* Emit code to save registers before the mode switch. */ + + void +@@ -9825,6 +9868,23 @@ aarch64_need_old_pstate_sm () + if (aarch64_cfun_enables_pstate_sm ()) + return true; + ++ /* Non-local goto receivers are entered with PSTATE.SM equal to 0, ++ but the function needs to return with PSTATE.SM unchanged. */ ++ if (nonlocal_goto_handler_labels) ++ return true; ++ ++ /* Likewise for exception handlers. */ ++ eh_landing_pad lp; ++ for (unsigned int i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i) ++ if (lp && lp->post_landing_pad) ++ return true; ++ ++ /* Non-local gotos need to set PSTATE.SM to zero. It's possible to call ++ streaming-compatible functions without SME being available, so PSTATE.SM ++ should only be changed if it is currently set to one. */ ++ if (crtl->has_nonlocal_goto) ++ return true; ++ + if (cfun->machine->call_switches_pstate_sm) + for (auto insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (auto *call = dyn_cast<rtx_call_insn *> (insn)) +@@ -30209,6 +30269,59 @@ aarch64_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs, + return seq; + } + ++/* BB is the target of an exception or nonlocal goto edge, which means ++ that PSTATE.SM is known to be 0 on entry. Put it into the state that ++ the current function requires. */ ++ ++static bool ++aarch64_switch_pstate_sm_for_landing_pad (basic_block bb) ++{ ++ if (TARGET_NON_STREAMING) ++ return false; ++ ++ start_sequence (); ++ rtx_insn *guard_label = nullptr; ++ if (TARGET_STREAMING_COMPATIBLE) ++ guard_label = aarch64_guard_switch_pstate_sm (IP0_REGNUM, ++ AARCH64_FL_SM_OFF); ++ aarch64_sme_mode_switch_regs args_switch; ++ args_switch.add_call_preserved_regs (df_get_live_in (bb)); ++ args_switch.emit_prologue (); ++ aarch64_switch_pstate_sm (AARCH64_FL_SM_OFF, AARCH64_FL_SM_ON); ++ args_switch.emit_epilogue (); ++ if (guard_label) ++ emit_label (guard_label); ++ auto seq = get_insns (); ++ end_sequence (); ++ ++ emit_insn_after (seq, bb_note (bb)); ++ return true; ++} ++ ++/* JUMP is a nonlocal goto. Its target requires PSTATE.SM to be 0 on entry, ++ so arrange to make it so. */ ++ ++static bool ++aarch64_switch_pstate_sm_for_jump (rtx_insn *jump) ++{ ++ if (TARGET_NON_STREAMING) ++ return false; ++ ++ start_sequence (); ++ rtx_insn *guard_label = nullptr; ++ if (TARGET_STREAMING_COMPATIBLE) ++ guard_label = aarch64_guard_switch_pstate_sm (IP0_REGNUM, ++ AARCH64_FL_SM_OFF); ++ aarch64_switch_pstate_sm (AARCH64_FL_SM_ON, AARCH64_FL_SM_OFF); ++ if (guard_label) ++ emit_label (guard_label); ++ auto seq = get_insns (); ++ end_sequence (); ++ ++ emit_insn_before (seq, jump); ++ return true; ++} ++ + /* If CALL involves a change in PSTATE.SM, emit the instructions needed + to switch to the new mode and the instructions needed to restore the + original mode. Return true if something changed. */ +@@ -30292,9 +30405,10 @@ public: + }; + + bool +-pass_switch_pstate_sm::gate (function *) ++pass_switch_pstate_sm::gate (function *fn) + { +- return cfun->machine->call_switches_pstate_sm; ++ return (aarch64_fndecl_pstate_sm (fn->decl) != AARCH64_FL_SM_OFF ++ || cfun->machine->call_switches_pstate_sm); + } + + /* Emit any instructions needed to switch PSTATE.SM. */ +@@ -30307,11 +30421,24 @@ pass_switch_pstate_sm::execute (function *fn) + bitmap_clear (blocks); + FOR_EACH_BB_FN (bb, fn) + { +- rtx_insn *insn; +- FOR_BB_INSNS (bb, insn) +- if (auto *call = dyn_cast<rtx_call_insn *> (insn)) +- if (aarch64_switch_pstate_sm_for_call (call)) +- bitmap_set_bit (blocks, bb->index); ++ if (has_abnormal_call_or_eh_pred_edge_p (bb) ++ && aarch64_switch_pstate_sm_for_landing_pad (bb)) ++ bitmap_set_bit (blocks, bb->index); ++ ++ if (cfun->machine->call_switches_pstate_sm) ++ { ++ rtx_insn *insn; ++ FOR_BB_INSNS (bb, insn) ++ if (auto *call = dyn_cast<rtx_call_insn *> (insn)) ++ if (aarch64_switch_pstate_sm_for_call (call)) ++ bitmap_set_bit (blocks, bb->index); ++ } ++ ++ auto end = BB_END (bb); ++ if (JUMP_P (end) ++ && find_reg_note (end, REG_NON_LOCAL_GOTO, NULL_RTX) ++ && aarch64_switch_pstate_sm_for_jump (end)) ++ bitmap_set_bit (blocks, bb->index); + } + find_many_sub_basic_blocks (blocks); + clear_aux_for_blocks (); +diff --git a/gcc/testsuite/g++.target/aarch64/sme/exceptions_2.C b/gcc/testsuite/g++.target/aarch64/sme/exceptions_2.C +new file mode 100644 +index 000000000..f791b6ecc +--- /dev/null ++++ b/gcc/testsuite/g++.target/aarch64/sme/exceptions_2.C +@@ -0,0 +1,148 @@ ++// { dg-options "-O -fno-optimize-sibling-calls" } ++// { dg-final { check-function-bodies "**" "" } } ++ ++void n_callee(); ++void s_callee() __arm_streaming; ++void sc_callee() __arm_streaming_compatible; ++ ++void n_callee_ne() noexcept; ++void s_callee_ne() noexcept __arm_streaming; ++void sc_callee_ne() noexcept __arm_streaming_compatible; ++ ++void n_caller1() ++{ ++ try ++ { ++ n_callee(); ++ sc_callee(); ++ } ++ catch (...) ++ { ++ n_callee_ne(); ++ sc_callee_ne(); ++ } ++} ++// { dg-final { scan-assembler {_Z9n_caller1v:(?:(?!smstart|smstop).)*\tret} } } ++ ++/* ++** _Z9n_caller2v: ++** ... ++** cntd (x[0-9]+) ++** str \1, [^\n]+ ++** ... ++** bl __cxa_begin_catch ++** smstart sm ++** bl _Z11s_callee_nev ++** smstop sm ++** bl __cxa_end_catch ++** ... ++*/ ++void n_caller2() ++{ ++ try ++ { ++ n_callee(); ++ sc_callee(); ++ } ++ catch (...) ++ { ++ s_callee_ne(); ++ } ++} ++ ++/* ++** _Z9s_caller1v: ++** ... ++** bl __cxa_end_catch ++** smstart sm ++** ... ++*/ ++int s_caller1() __arm_streaming ++{ ++ try ++ { ++ s_callee(); ++ return 1; ++ } ++ catch (...) ++ { ++ return 2; ++ } ++} ++ ++/* ++** _Z9s_caller2v: ++** ... ++** bl __cxa_begin_catch ++** smstart sm ++** bl _Z11s_callee_nev ++** smstop sm ++** bl __cxa_end_catch ++** smstart sm ++** ... ++*/ ++int s_caller2() __arm_streaming ++{ ++ try ++ { ++ n_callee(); ++ return 1; ++ } ++ catch (...) ++ { ++ s_callee_ne(); ++ return 2; ++ } ++} ++ ++/* ++** _Z10sc_caller1v: ++** ... ++** cntd (x[0-9]+) ++** str \1, [^\n]+ ++** mrs (x[0-9]+), svcr ++** str \2, ([^\n]+) ++** ... ++** bl __cxa_end_catch ++** ldr (x[0-9]+), \3 ++** tbz \4, 0, [^\n]+ ++** smstart sm ++** ... ++*/ ++int sc_caller1() __arm_streaming_compatible ++{ ++ try ++ { ++ sc_callee(); ++ return 1; ++ } ++ catch (...) ++ { ++ return 2; ++ } ++} ++ ++/* ++** _Z10ls_caller1v: ++** ... ++** cntd (x[0-9]+) ++** str \1, [^\n]+ ++** ... ++** bl __cxa_begin_catch ++** smstart sm ++** bl _Z12sc_callee_nev ++** smstop sm ++** bl __cxa_end_catch ++** ... ++*/ ++__arm_locally_streaming void ls_caller1() ++{ ++ try ++ { ++ sc_callee(); ++ } ++ catch (...) ++ { ++ sc_callee_ne(); ++ } ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_1.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_1.c +new file mode 100644 +index 000000000..4e3869fcc +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_1.c +@@ -0,0 +1,58 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)()); ++ ++/* ++** foo: ++** ... ++** mrs x16, svcr ++** ... ++** str x16, (.*) ++** ... ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstop sm ++** bl __clear_cache ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstart sm ++** add x0, .* ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstop sm ++** bl run ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstart sm ++** mov w0, 1 ++** ... ++** ret ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstart sm ++** mov w0, 0 ++** ... ++*/ ++int ++foo (int *ptr) __arm_streaming_compatible ++{ ++ __label__ failure; ++ ++ void bar () { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler {\tstp\tx19, x20,} } } ++// { dg-final { scan-assembler {\tstp\tx21, x22,} } } ++// { dg-final { scan-assembler {\tstp\tx23, x24,} } } ++// { dg-final { scan-assembler {\tstp\tx25, x26,} } } ++// { dg-final { scan-assembler {\tstp\tx27, x28,} } } ++// { dg-final { scan-assembler {\tstp\td8, d9,} } } ++// { dg-final { scan-assembler {\tstp\td10, d11,} } } ++// { dg-final { scan-assembler {\tstp\td12, d13,} } } ++// { dg-final { scan-assembler {\tstp\td14, d15,} } } +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_2.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_2.c +new file mode 100644 +index 000000000..2a2db72c3 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_2.c +@@ -0,0 +1,44 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)()); ++ ++/* ++** foo: ++** ... ++** smstop sm ++** bl __clear_cache ++** smstart sm ++** add x0, .* ++** smstop sm ++** bl run ++** smstart sm ++** mov w0, 1 ++** ... ++** ret ++** smstart sm ++** mov w0, 0 ++** ... ++*/ ++int ++foo (int *ptr) __arm_streaming ++{ ++ __label__ failure; ++ ++ void bar () { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler {\tstp\tx19, x20,} } } ++// { dg-final { scan-assembler {\tstp\tx21, x22,} } } ++// { dg-final { scan-assembler {\tstp\tx23, x24,} } } ++// { dg-final { scan-assembler {\tstp\tx25, x26,} } } ++// { dg-final { scan-assembler {\tstp\tx27, x28,} } } ++// { dg-final { scan-assembler {\tstp\td8, d9,} } } ++// { dg-final { scan-assembler {\tstp\td10, d11,} } } ++// { dg-final { scan-assembler {\tstp\td12, d13,} } } ++// { dg-final { scan-assembler {\tstp\td14, d15,} } } +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_3.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_3.c +new file mode 100644 +index 000000000..022b04052 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_3.c +@@ -0,0 +1,46 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)()); ++ ++/* ++** foo: ++** ... ++** smstart sm ++** ... ++** smstop sm ++** bl __clear_cache ++** smstart sm ++** add x0, .* ++** smstop sm ++** bl run ++** smstart sm ++** mov w0, 1 ++** ... ++** smstart sm ++** mov w0, 0 ++** smstop sm ++** ... ++*/ ++__arm_locally_streaming int ++foo (int *ptr) ++{ ++ __label__ failure; ++ ++ void bar () { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler {\tstp\tx19, x20,} } } ++// { dg-final { scan-assembler {\tstp\tx21, x22,} } } ++// { dg-final { scan-assembler {\tstp\tx23, x24,} } } ++// { dg-final { scan-assembler {\tstp\tx25, x26,} } } ++// { dg-final { scan-assembler {\tstp\tx27, x28,} } } ++// { dg-final { scan-assembler {\tstp\td8, d9,} } } ++// { dg-final { scan-assembler {\tstp\td10, d11,} } } ++// { dg-final { scan-assembler {\tstp\td12, d13,} } } ++// { dg-final { scan-assembler {\tstp\td14, d15,} } } +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_4.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_4.c +new file mode 100644 +index 000000000..044607628 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_4.c +@@ -0,0 +1,25 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)()); ++ ++/* ++** bar.0: ++** ... ++** smstart sm ++** ... ++** smstop sm ++** br x[0-9]+ ++*/ ++int ++foo (int *ptr) ++{ ++ __label__ failure; ++ ++ __arm_locally_streaming void bar () { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_5.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_5.c +new file mode 100644 +index 000000000..4246aec8b +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_5.c +@@ -0,0 +1,26 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)() __arm_streaming); ++ ++/* ++** bar.0: ++** ... ++** smstop sm ++** br x[0-9]+ ++*/ ++int ++foo (int *ptr) ++{ ++ __label__ failure; ++ ++ void bar () __arm_streaming { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler-not {smstart\t} } } ++// { dg-final { scan-assembler-not {mrs\t} } } +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_6.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_6.c +new file mode 100644 +index 000000000..151e2f22d +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_6.c +@@ -0,0 +1,31 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void run(void (*)() __arm_streaming_compatible); ++ ++/* ++** bar.0: ++** ... ++** mrs x16, svcr ++** ... ++** str x16, (.*) ++** ... ++** ldr x16, \1 ++** tbz x16, 0, .* ++** smstop sm ++** br x[0-9]+ ++*/ ++int ++foo (int *ptr) ++{ ++ __label__ failure; ++ ++ void bar () __arm_streaming_compatible { *ptr += 1; goto failure; } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler-not {smstart\t} } } +diff --git a/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_7.c b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_7.c +new file mode 100644 +index 000000000..9cc3ad5d2 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/sme/nonlocal_goto_7.c +@@ -0,0 +1,25 @@ ++/* { dg-options "-O2 -fno-schedule-insns -fno-schedule-insns2" } */ ++ ++void run(void (*)() __arm_inout("za")); ++void callee () __arm_inout("za"); ++ ++int ++foo (int *ptr) ++{ ++ __label__ failure; ++ ++ void bar () __arm_inout("za") ++ { ++ callee (); ++ *ptr += 1; ++ goto failure; ++ } ++ run (bar); ++ return 1; ++ ++failure: ++ return 0; ++} ++ ++// { dg-final { scan-assembler-not {\tsmstart\t} } } ++// { dg-final { scan-assembler-not {\tsmstop\t} } } +-- +2.33.0 + |